web_test.dart 23.1 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:file_testing/file_testing.dart';
6
import 'package:flutter_tools/src/artifacts.dart';
7
import 'package:flutter_tools/src/base/file_system.dart';
8
import 'package:flutter_tools/src/base/platform.dart';
9
import 'package:flutter_tools/src/build_info.dart';
10
import 'package:flutter_tools/src/build_system/build_system.dart';
11
import 'package:flutter_tools/src/build_system/depfile.dart';
12
import 'package:flutter_tools/src/build_system/targets/common.dart';
13
import 'package:flutter_tools/src/build_system/targets/web.dart';
14
import 'package:flutter_tools/src/globals.dart' as globals;
15 16 17 18
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';

import '../../../src/common.dart';
19
import '../../../src/context.dart';
20 21 22
import '../../../src/mocks.dart';
import '../../../src/testbed.dart';

23 24
const List<String> kDart2jsLinuxArgs = <String>[
  'bin/cache/dart-sdk/bin/dart',
25
   '--disable-dart-dev',
26 27 28 29
  'bin/cache/dart-sdk/bin/snapshots/dart2js.dart.snapshot',
  '--libraries-spec=bin/cache/flutter_web_sdk/libraries.json',
];

30 31 32
void main() {
  Testbed testbed;
  Environment environment;
33 34 35 36 37 38 39 40 41
  FakeProcessManager processManager;
  final Platform linux = FakePlatform(
    operatingSystem: 'linux',
    environment: <String, String>{},
  );
  final Platform windows = FakePlatform(
    operatingSystem: 'windows',
    environment: <String, String>{},
  );
42
  DepfileService depfileService;
43 44 45

  setUp(() {
    testbed = Testbed(setup: () {
46
      globals.fs.file('.packages')
47
        ..createSync(recursive: true)
48
        ..writeAsStringSync('foo:foo/lib/\n');
49
      globals.fs.currentDirectory.childDirectory('bar').createSync();
50
      processManager = FakeProcessManager.list(<FakeCommand>[]);
51

52 53
      environment = Environment.test(
        globals.fs.currentDirectory,
54
        projectDir: globals.fs.currentDirectory.childDirectory('foo'),
55
        outputDir: globals.fs.currentDirectory.childDirectory('bar'),
56
        defines: <String, String>{
57
          kTargetFile: globals.fs.path.join('foo', 'lib', 'main.dart'),
58
        },
59
        artifacts: Artifacts.test(),
60 61 62
        processManager: FakeProcessManager.any(),
        logger: globals.logger,
        fileSystem: globals.fs,
63
      );
64 65 66 67
      depfileService = DepfileService(
      fileSystem: globals.fs,
      logger: globals.logger,
    );
68 69
      environment.buildDir.createSync(recursive: true);
    }, overrides: <Type, Generator>{
70
      Platform: () => linux,
71 72 73 74
    });
  });

  test('WebEntrypointTarget generates an entrypoint with plugins and init platform', () => testbed.run(() async {
75 76 77 78
    final File mainFile = globals.fs.file(globals.fs.path.join('foo', 'lib', 'main.dart'))
      ..createSync(recursive: true)
      ..writeAsStringSync('void main() {}');
    environment.defines[kTargetFile] = mainFile.path;
79 80 81 82 83 84
    environment.defines[kHasWebPlugins] = 'true';
    await const WebEntrypointTarget().build(environment);

    final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();

    // Plugins
85
    expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
86 87 88 89 90 91
    expect(generated, contains('registerPlugins(webPluginRegistry);'));

    // Main
    expect(generated, contains('entrypoint.main();'));

    // Import.
92
    expect(generated, contains("import 'package:foo/main.dart' as entrypoint;"));
93 94
  }));

95 96 97 98 99 100 101 102 103 104 105
  test('version.json is created after release build', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
    final Directory webResources = environment.projectDir.childDirectory('web');
    webResources.childFile('index.html')
        .createSync(recursive: true);
    environment.buildDir.childFile('main.dart.js').createSync();
    await const WebReleaseBundle().build(environment);

    expect(environment.outputDir.childFile('version.json'), exists);
  }));

106
  test('WebReleaseBundle copies dart2js output and resource files to output directory', () => testbed.run(() async {
107
    environment.defines[kBuildMode] = 'release';
108 109
    final Directory webResources = environment.projectDir.childDirectory('web');
    webResources.childFile('index.html')
110 111 112 113 114 115 116 117 118
      ..createSync(recursive: true)
      ..writeAsStringSync('''
<html>
  <script src="main.dart.js" type="application/javascript"></script>
  <script>
    navigator.serviceWorker.register('flutter_service_worker.js');
  </script>
</html>
''');
119
    webResources.childFile('foo.txt')
120
      .writeAsStringSync('A');
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    environment.buildDir.childFile('main.dart.js').createSync();

    await const WebReleaseBundle().build(environment);

    expect(environment.outputDir.childFile('foo.txt')
      .readAsStringSync(), 'A');
    expect(environment.outputDir.childFile('main.dart.js')
      .existsSync(), true);
    expect(environment.outputDir.childDirectory('assets')
      .childFile('AssetManifest.json').existsSync(), true);

    // Update to arbitary resource file triggers rebuild.
    webResources.childFile('foo.txt').writeAsStringSync('B');

    await const WebReleaseBundle().build(environment);

    expect(environment.outputDir.childFile('foo.txt')
      .readAsStringSync(), 'B');
139
    // Appends number to requests for service worker only
140
    expect(environment.outputDir.childFile('index.html').readAsStringSync(), allOf(
141
      contains('<script src="main.dart.js" type="application/javascript">'),
142 143
      contains('flutter_service_worker.js?v='),
    ));
144 145
  }));

146
  test('WebEntrypointTarget generates an entrypoint for a file outside of main', () => testbed.run(() async {
147 148 149 150
    final File mainFile = globals.fs.file(globals.fs.path.join('other', 'lib', 'main.dart'))
      ..createSync(recursive: true)
      ..writeAsStringSync('void main() {}');
    environment.defines[kTargetFile] = mainFile.path;
151 152 153 154 155 156 157 158
    await const WebEntrypointTarget().build(environment);

    final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();

    // Import.
    expect(generated, contains("import 'file:///other/lib/main.dart' as entrypoint;"));
  }));

159
  test('WebEntrypointTarget generates a plugin registrant for a file outside of main', () => testbed.run(() async {
160 161 162 163
    final File mainFile = globals.fs.file(globals.fs.path.join('other', 'lib', 'main.dart'))
      ..createSync(recursive: true)
      ..writeAsStringSync('void main() {}');
    environment.defines[kTargetFile] = mainFile.path;
164 165 166 167 168 169 170
    environment.defines[kHasWebPlugins] = 'true';
    await const WebEntrypointTarget().build(environment);

    final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();

    // Import.
    expect(generated, contains("import 'file:///other/lib/main.dart' as entrypoint;"));
171
    expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
172 173
  }));

174

175
  test('WebEntrypointTarget generates an entrypoint with plugins and init platform on windows', () => testbed.run(() async {
176 177 178 179 180
    final File mainFile = globals.fs.file(globals.fs.path.join('foo', 'lib', 'main.dart'))
      ..createSync(recursive: true)
      ..writeAsStringSync('void main() {}');
    environment.defines[kTargetFile] = mainFile.path;

181 182 183 184 185 186
    environment.defines[kHasWebPlugins] = 'true';
    await const WebEntrypointTarget().build(environment);

    final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();

    // Plugins
187
    expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
188 189 190 191 192 193
    expect(generated, contains('registerPlugins(webPluginRegistry);'));

    // Main
    expect(generated, contains('entrypoint.main();'));

    // Import.
194
    expect(generated, contains("import 'package:foo/main.dart' as entrypoint;"));
195
  }, overrides: <Type, Generator>{
196
    Platform: () => windows,
197 198 199
  }));

  test('WebEntrypointTarget generates an entrypoint without plugins and init platform', () => testbed.run(() async {
200 201 202 203
    final File mainFile = globals.fs.file(globals.fs.path.join('foo', 'lib', 'main.dart'))
      ..createSync(recursive: true)
      ..writeAsStringSync('void main() {}');
    environment.defines[kTargetFile] = mainFile.path;
204 205 206 207 208 209
    environment.defines[kHasWebPlugins] = 'false';
    await const WebEntrypointTarget().build(environment);

    final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();

    // Plugins
210
    expect(generated, isNot(contains("import 'package:foo/generated_plugin_registrant.dart';")));
211 212 213 214 215
    expect(generated, isNot(contains('registerPlugins(webPluginRegistry);')));
    // Main
    expect(generated, contains('entrypoint.main();'));
  }));

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
  test('WebEntrypointTarget generates an entrypoint with a language version', () => testbed.run(() async {
    final File mainFile = globals.fs.file(globals.fs.path.join('foo', 'lib', 'main.dart'))
      ..createSync(recursive: true)
      ..writeAsStringSync('// @dart=2.8\nvoid main() {}');
    environment.defines[kTargetFile] = mainFile.path;
    await const WebEntrypointTarget().build(environment);

    final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();

    // Language version
    expect(generated, contains('// @dart=2.8'));
  }));

  test('WebEntrypointTarget generates an entrypoint with a language version from a package config', () => testbed.run(() async {
    final File mainFile = globals.fs.file(globals.fs.path.join('foo', 'lib', 'main.dart'))
      ..createSync(recursive: true)
      ..writeAsStringSync('void main() {}');
    globals.fs.file(globals.fs.path.join('pubspec.yaml'))
      .writeAsStringSync('name: foo\n');
    environment.defines[kTargetFile] = mainFile.path;
    await const WebEntrypointTarget().build(environment);

    final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();

    // Language version
    expect(generated, contains('// @dart = 2.7'));
  }));

244
  test('WebEntrypointTarget generates an entrypoint without plugins and without init platform', () => testbed.run(() async {
245 246 247 248
    final File mainFile = globals.fs.file(globals.fs.path.join('foo', 'lib', 'main.dart'))
      ..createSync(recursive: true)
      ..writeAsStringSync('void main() {}');
    environment.defines[kTargetFile] = mainFile.path;
249 250 251 252 253 254
    environment.defines[kHasWebPlugins] = 'false';
    await const WebEntrypointTarget().build(environment);

    final String generated = environment.buildDir.childFile('main.dart').readAsStringSync();

    // Plugins
255
    expect(generated, isNot(contains("import 'package:foo/generated_plugin_registrant.dart';")));
256 257 258 259 260 261
    expect(generated, isNot(contains('registerPlugins(webPluginRegistry);')));

    // Main
    expect(generated, contains('entrypoint.main();'));
  }));

262 263 264
  test('Dart2JSTarget calls dart2js with expected args with csp', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'profile';
    environment.defines[kCspMode] = 'true';
265 266 267
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
268
        '-Ddart.vm.profile=true',
269
        '--no-source-maps',
270 271
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
272
        '--packages=.packages',
273 274 275 276 277 278 279 280
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.profile=true',
281
        '--no-source-maps',
282
        '-O4',
283 284 285 286 287 288 289
        '--no-minify',
        '--csp',
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
290

291
    await const Dart2JSTarget().build(environment);
292
  }, overrides: <Type, Generator>{
293
    ProcessManager: () => processManager,
294 295 296
  }));


297 298
  test('Dart2JSTarget calls dart2js with expected args with enabled experiment', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'profile';
299
    environment.defines[kExtraFrontEndOptions] = '--enable-experiment=non-nullable';
300 301 302 303
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '--enable-experiment=non-nullable',
304
        '-Ddart.vm.profile=true',
305
        '--no-source-maps',
306 307
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
308
        '--packages=.packages',
309 310 311 312 313 314 315 316 317
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '--enable-experiment=non-nullable',
        '-Ddart.vm.profile=true',
318
        '--no-source-maps',
319
        '-O4',
320 321 322 323 324 325 326 327 328 329 330 331
        '--no-minify',
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));

    await const Dart2JSTarget().build(environment);
  }, overrides: <Type, Generator>{
    ProcessManager: () => processManager,
  }));

332 333
  test('Dart2JSTarget calls dart2js with expected args in profile mode', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'profile';
334 335 336
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
337
        '-Ddart.vm.profile=true',
338
        '--no-source-maps',
339 340
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
341
        '--packages=.packages',
342 343 344 345 346 347 348 349
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.profile=true',
350
        '--no-source-maps',
351
        '-O4',
352 353 354 355 356 357
        '--no-minify',
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
358

359
    await const Dart2JSTarget().build(environment);
360
  }, overrides: <Type, Generator>{
361
    ProcessManager: () => processManager,
362 363 364 365
  }));

  test('Dart2JSTarget calls dart2js with expected args in release mode', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
366 367 368
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
369
        '-Ddart.vm.product=true',
370
        '--no-source-maps',
371 372
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
373
        '--packages=.packages',
374 375 376 377 378 379 380 381
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
382
        '--no-source-maps',
383
        '-O4',
384 385 386 387 388
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
389

390
    await const Dart2JSTarget().build(environment);
391
  }, overrides: <Type, Generator>{
392
    ProcessManager: () => processManager,
393 394 395 396 397
  }));

  test('Dart2JSTarget calls dart2js with expected args in release with dart2js optimization override', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
    environment.defines[kDart2jsOptimization] = 'O3';
398 399 400
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
401
        '-Ddart.vm.product=true',
402
        '--no-source-maps',
403 404
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
405
        '--packages=.packages',
406 407 408 409 410 411 412 413
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
414
        '--no-source-maps',
415
        '-O3',
416 417 418 419 420
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
421

422
    await const Dart2JSTarget().build(environment);
423
  }, overrides: <Type, Generator>{
424
    ProcessManager: () => processManager,
425
  }));
426 427 428

  test('Dart2JSTarget produces expected depfile', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
429
    when(globals.processManager.run(any)).thenAnswer((Invocation invocation) async {
430
      environment.buildDir.childFile('app.dill.deps')
431
        .writeAsStringSync('file:///a.dart');
432 433 434 435
      return FakeProcessResult(exitCode: 0);
    });
    await const Dart2JSTarget().build(environment);

436
    expect(environment.buildDir.childFile('dart2js.d'), exists);
437
    final Depfile depfile = depfileService.parse(environment.buildDir.childFile('dart2js.d'));
438

439
    expect(depfile.inputs.single.path, globals.fs.path.absolute('a.dart'));
440 441 442 443 444
    expect(depfile.outputs.single.path,
      environment.buildDir.childFile('main.dart.js').absolute.path);
  }, overrides: <Type, Generator>{
    ProcessManager: () => MockProcessManager(),
  }));
445 446 447

  test('Dart2JSTarget calls dart2js with Dart defines in release mode', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
448
    environment.defines[kDartDefines] = 'FOO=bar,BAZ=qux';
449 450 451
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
452
        '-Ddart.vm.product=true',
453 454
        '-DFOO=bar',
        '-DBAZ=qux',
455
        '--no-source-maps',
456 457 458
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
        '--packages=.packages',
459
       '--cfe-only',
460 461 462 463 464 465 466 467 468
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
        '-DFOO=bar',
        '-DBAZ=qux',
469
        '--no-source-maps',
470
        '-O4',
471 472 473 474 475
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
476

477
    await const Dart2JSTarget().build(environment);
478
  }, overrides: <Type, Generator>{
479
    ProcessManager: () => processManager,
480 481
  }));

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
  test('Dart2JSTarget can enable source maps', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
    environment.defines[kSourceMapsEnabled] = 'true';
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
        '--packages=.packages',
       '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
        '-O4',
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));

    await const Dart2JSTarget().build(environment);
  }, overrides: <Type, Generator>{
    ProcessManager: () => processManager,
  }));


513 514
  test('Dart2JSTarget calls dart2js with Dart defines in profile mode', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'profile';
515
    environment.defines[kDartDefines] = 'FOO=bar,BAZ=qux';
516 517 518
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
519
        '-Ddart.vm.profile=true',
520 521
        '-DFOO=bar',
        '-DBAZ=qux',
522
        '--no-source-maps',
523 524 525
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
        '--packages=.packages',
526 527 528 529 530 531 532 533 534 535
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.profile=true',
        '-DFOO=bar',
        '-DBAZ=qux',
536
        '--no-source-maps',
537
        '-O4',
538 539 540 541 542 543
        '--no-minify',
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
544

545
    await const Dart2JSTarget().build(environment);
546
  }, overrides: <Type, Generator>{
547
    ProcessManager: () => processManager,
548 549
  }));

550 551 552 553 554 555
  test('Generated service worker is empty with none-strategy', () {
    final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>[], serviceWorkerStrategy: ServiceWorkerStrategy.none);

    expect(result, '');
  });

556
  test('Generated service worker correctly inlines file hashes', () {
557
    final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>[], serviceWorkerStrategy: ServiceWorkerStrategy.offlineFirst);
558 559 560 561

    expect(result, contains('{\n  "/foo": "abcd"\n};'));
  });

562
  test('Generated service worker includes core files', () {
563
    final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>['foo', 'bar'], serviceWorkerStrategy: ServiceWorkerStrategy.offlineFirst);
564 565 566 567

    expect(result, contains('"foo",\n"bar"'));
  });

568
  test('WebServiceWorker generates a service_worker for a web resource folder', () => testbed.run(() async {
569
    environment.outputDir.childDirectory('a').childFile('a.txt')
570 571 572 573 574 575 576
      ..createSync(recursive: true)
      ..writeAsStringSync('A');
    await const WebServiceWorker().build(environment);

    expect(environment.outputDir.childFile('flutter_service_worker.js'), exists);
    // Contains file hash.
    expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
577
      contains('"a/a.txt": "7fc56270e7a70fa81a5935b72eacbe29"'));
578 579
    expect(environment.buildDir.childFile('service_worker.d'), exists);
    // Depends on resource file.
580 581 582 583 584
    expect(environment.buildDir.childFile('service_worker.d').readAsStringSync(),
      contains('a/a.txt'));
    // Contains NOTICES
    expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
      contains('NOTICES'));
585
  }));
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600

  test('WebServiceWorker contains baseUrl cache', () => testbed.run(() async {
    environment.outputDir
      .childFile('index.html')
      .createSync(recursive: true);
    await const WebServiceWorker().build(environment);

    expect(environment.outputDir.childFile('flutter_service_worker.js'), exists);
    // Contains file hash for both `/` and index.html.
    expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
      contains('"/": "d41d8cd98f00b204e9800998ecf8427e"'));
    expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
      contains('"index.html": "d41d8cd98f00b204e9800998ecf8427e"'));
    expect(environment.buildDir.childFile('service_worker.d'), exists);
  }));
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617

  test('WebServiceWorker does not cache source maps', () => testbed.run(() async {
    environment.outputDir
      .childFile('main.dart.js')
      .createSync(recursive: true);
    environment.outputDir
      .childFile('main.dart.js.map')
      .createSync(recursive: true);
    await const WebServiceWorker().build(environment);

    // No caching of source maps.
    expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
      isNot(contains('"main.dart.js.map"')));
    // Expected twice, once for RESOURCES and once for CORE.
    expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
      contains('"main.dart.js"'));
  }));
618 619 620
}

class MockProcessManager extends Mock implements ProcessManager {}