web_test.dart 25.7 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 6
// @dart = 2.8

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

import '../../../src/common.dart';
18
import '../../../src/fake_process_manager.dart';
19 20
import '../../../src/testbed.dart';

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

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

  setUp(() {
    testbed = Testbed(setup: () {
43
      globals.fs.file('.packages')
44
        ..createSync(recursive: true)
45
        ..writeAsStringSync('foo:foo/lib/\n');
46
      globals.fs.currentDirectory.childDirectory('bar').createSync();
47
      processManager = FakeProcessManager.empty();
48

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

  test('WebEntrypointTarget generates an entrypoint with plugins and init platform', () => testbed.run(() async {
72 73 74 75
    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;
76 77 78 79 80 81
    environment.defines[kHasWebPlugins] = 'true';
    await const WebEntrypointTarget().build(environment);

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

    // Plugins
82
    expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
83
    expect(generated, contains('registerPlugins(webPluginRegistrar);'));
84 85 86 87 88

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

    // Import.
89
    expect(generated, contains("import 'package:foo/main.dart' as entrypoint;"));
90 91
  }));

92 93 94 95 96 97 98 99 100 101 102
  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);
  }));

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
  test('Base href is created in index.html with given base-href after release build', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
    environment.defines[kBaseHref] = '/basehreftest/';
    final Directory webResources = environment.projectDir.childDirectory('web');
    webResources.childFile('index.html').createSync(recursive: true);
    webResources.childFile('index.html').writeAsStringSync('''
<!DOCTYPE html><html><base href="$kBaseHrefPlaceholder"><head></head></html>
    ''');
    environment.buildDir.childFile('main.dart.js').createSync();
    await const WebReleaseBundle().build(environment);

    expect(environment.outputDir.childFile('index.html').readAsStringSync(), contains('/basehreftest/'));
  }));

  test('null base href does not override existing base href in index.html', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
    final Directory webResources = environment.projectDir.childDirectory('web');
    webResources.childFile('index.html').createSync(recursive: true);
    webResources.childFile('index.html').writeAsStringSync('''
<!DOCTYPE html><html><head><base href='/basehreftest/'></head></html>
    ''');
    environment.buildDir.childFile('main.dart.js').createSync();
    await const WebReleaseBundle().build(environment);

    expect(environment.outputDir.childFile('index.html').readAsStringSync(), contains('/basehreftest/'));
  }));

130
  test('WebReleaseBundle copies dart2js output and resource files to output directory', () => testbed.run(() async {
131
    environment.defines[kBuildMode] = 'release';
132 133
    final Directory webResources = environment.projectDir.childDirectory('web');
    webResources.childFile('index.html')
134 135 136 137 138 139 140 141 142
      ..createSync(recursive: true)
      ..writeAsStringSync('''
<html>
  <script src="main.dart.js" type="application/javascript"></script>
  <script>
    navigator.serviceWorker.register('flutter_service_worker.js');
  </script>
</html>
''');
143
    webResources.childFile('foo.txt')
144
      .writeAsStringSync('A');
145 146 147 148 149 150 151 152 153 154 155
    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);

156
    // Update to arbitrary resource file triggers rebuild.
157 158 159 160 161 162
    webResources.childFile('foo.txt').writeAsStringSync('B');

    await const WebReleaseBundle().build(environment);

    expect(environment.outputDir.childFile('foo.txt')
      .readAsStringSync(), 'B');
163
    // Appends number to requests for service worker only
164
    expect(environment.outputDir.childFile('index.html').readAsStringSync(), allOf(
165
      contains('<script src="main.dart.js" type="application/javascript">'),
166 167
      contains('flutter_service_worker.js?v='),
    ));
168 169
  }));

170
  test('WebEntrypointTarget generates an entrypoint for a file outside of main', () => testbed.run(() async {
171 172 173 174
    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;
175 176 177 178 179 180 181 182
    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;"));
  }));

183
  test('WebEntrypointTarget generates a plugin registrant for a file outside of main', () => testbed.run(() async {
184 185 186 187
    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;
188 189 190 191 192 193 194
    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;"));
195
    expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
196 197
  }));

198

199
  test('WebEntrypointTarget generates an entrypoint with plugins and init platform on windows', () => testbed.run(() async {
200 201 202 203 204
    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;

205 206 207 208 209 210
    environment.defines[kHasWebPlugins] = 'true';
    await const WebEntrypointTarget().build(environment);

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

    // Plugins
211
    expect(generated, contains("import 'package:foo/generated_plugin_registrant.dart';"));
212
    expect(generated, contains('registerPlugins(webPluginRegistrar);'));
213 214 215 216 217

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

    // Import.
218
    expect(generated, contains("import 'package:foo/main.dart' as entrypoint;"));
219
  }, overrides: <Type, Generator>{
220
    Platform: () => windows,
221 222 223
  }));

  test('WebEntrypointTarget generates an entrypoint without plugins and init platform', () => testbed.run(() async {
224 225 226 227
    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;
228 229 230 231 232 233
    environment.defines[kHasWebPlugins] = 'false';
    await const WebEntrypointTarget().build(environment);

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

    // Plugins
234
    expect(generated, isNot(contains("import 'package:foo/generated_plugin_registrant.dart';")));
235
    expect(generated, isNot(contains('registerPlugins(webPluginRegistrar);')));
236 237 238 239
    // Main
    expect(generated, contains('entrypoint.main();'));
  }));

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
  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
265
    expect(generated, contains('// @dart=2.7'));
266 267
  }));

268
  test('WebEntrypointTarget generates an entrypoint without plugins and without init platform', () => testbed.run(() async {
269 270 271 272
    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;
273 274 275 276 277 278
    environment.defines[kHasWebPlugins] = 'false';
    await const WebEntrypointTarget().build(environment);

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

    // Plugins
279
    expect(generated, isNot(contains("import 'package:foo/generated_plugin_registrant.dart';")));
280
    expect(generated, isNot(contains('registerPlugins(webPluginRegistrar);')));
281 282 283 284 285

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

286 287 288
  test('Dart2JSTarget calls dart2js with expected args with csp', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'profile';
    environment.defines[kCspMode] = 'true';
289 290 291
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
292
        '-Ddart.vm.profile=true',
293
        '--no-source-maps',
294 295
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
296
        '--packages=.packages',
297 298 299 300 301 302 303 304
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.profile=true',
305
        '--no-source-maps',
306
        '-O4',
307 308 309 310 311 312 313
        '--no-minify',
        '--csp',
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
314

315
    await const Dart2JSTarget().build(environment);
316
  }, overrides: <Type, Generator>{
317
    ProcessManager: () => processManager,
318 319 320
  }));


321 322
  test('Dart2JSTarget calls dart2js with expected args with enabled experiment', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'profile';
323
    environment.defines[kExtraFrontEndOptions] = '--enable-experiment=non-nullable';
324 325 326 327
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '--enable-experiment=non-nullable',
328
        '-Ddart.vm.profile=true',
329
        '--no-source-maps',
330 331
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
332
        '--packages=.packages',
333 334 335 336 337 338 339 340 341
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '--enable-experiment=non-nullable',
        '-Ddart.vm.profile=true',
342
        '--no-source-maps',
343
        '-O4',
344 345 346 347 348 349 350 351 352 353 354 355
        '--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,
  }));

356 357
  test('Dart2JSTarget calls dart2js with expected args in profile mode', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'profile';
358 359 360
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
361
        '-Ddart.vm.profile=true',
362
        '--no-source-maps',
363 364
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
365
        '--packages=.packages',
366 367 368 369 370 371 372 373
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.profile=true',
374
        '--no-source-maps',
375
        '-O4',
376 377 378 379 380 381
        '--no-minify',
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
382

383
    await const Dart2JSTarget().build(environment);
384
  }, overrides: <Type, Generator>{
385
    ProcessManager: () => processManager,
386 387 388 389
  }));

  test('Dart2JSTarget calls dart2js with expected args in release mode', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
390 391 392
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
393
        '-Ddart.vm.product=true',
394
        '--no-source-maps',
395 396
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
397
        '--packages=.packages',
398 399 400 401 402 403 404 405
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
406
        '--no-source-maps',
407
        '-O4',
408 409 410 411 412
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
413

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

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
  test('Dart2JSTarget calls dart2js with expected args in release mode with native null assertions', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
    environment.defines[kNativeNullAssertions] = 'true';
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '--native-null-assertions',
        '-Ddart.vm.product=true',
        '--no-source-maps',
        '-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,
        '--native-null-assertions',
        '-Ddart.vm.product=true',
        '--no-source-maps',
        '-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,
  }));

453 454 455
  test('Dart2JSTarget calls dart2js with expected args in release with dart2js optimization override', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
    environment.defines[kDart2jsOptimization] = 'O3';
456 457 458
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
459
        '-Ddart.vm.product=true',
460
        '--no-source-maps',
461 462
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
463
        '--packages=.packages',
464 465 466 467 468 469 470 471
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
472
        '--no-source-maps',
473
        '-O3',
474 475 476 477 478
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
479

480
    await const Dart2JSTarget().build(environment);
481
  }, overrides: <Type, Generator>{
482
    ProcessManager: () => processManager,
483
  }));
484 485 486

  test('Dart2JSTarget produces expected depfile', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
        '--no-source-maps',
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
        '--packages=.packages',
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ], onRun: () {
        environment.buildDir.childFile('app.dill.deps')
          .writeAsStringSync('file:///a.dart');
      },
    ));
502 503
    await const Dart2JSTarget().build(environment);

504
    expect(environment.buildDir.childFile('dart2js.d'), exists);
505
    final Depfile depfile = depfileService.parse(environment.buildDir.childFile('dart2js.d'));
506

507
    expect(depfile.inputs.single.path, globals.fs.path.absolute('a.dart'));
508 509 510
    expect(depfile.outputs.single.path,
      environment.buildDir.childFile('main.dart.js').absolute.path);
  }, overrides: <Type, Generator>{
511
    ProcessManager: () => processManager,
512
  }));
513 514 515

  test('Dart2JSTarget calls dart2js with Dart defines in release mode', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'release';
516
    environment.defines[kDartDefines] = encodeDartDefines(<String>['FOO=bar', 'BAZ=qux']);
517 518 519
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
520
        '-Ddart.vm.product=true',
521 522
        '-DFOO=bar',
        '-DBAZ=qux',
523
        '--no-source-maps',
524 525 526
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
        '--packages=.packages',
527
       '--cfe-only',
528 529 530 531 532 533 534 535 536
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.product=true',
        '-DFOO=bar',
        '-DBAZ=qux',
537
        '--no-source-maps',
538
        '-O4',
539 540 541 542 543
        '-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 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
  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,
  }));


581 582
  test('Dart2JSTarget calls dart2js with Dart defines in profile mode', () => testbed.run(() async {
    environment.defines[kBuildMode] = 'profile';
583
    environment.defines[kDartDefines] = encodeDartDefines(<String>['FOO=bar', 'BAZ=qux']);
584 585 586
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
587
        '-Ddart.vm.profile=true',
588 589
        '-DFOO=bar',
        '-DBAZ=qux',
590
        '--no-source-maps',
591 592 593
        '-o',
        environment.buildDir.childFile('app.dill').absolute.path,
        '--packages=.packages',
594 595 596 597 598 599 600 601 602 603
        '--cfe-only',
        environment.buildDir.childFile('main.dart').absolute.path,
      ]
    ));
    processManager.addCommand(FakeCommand(
      command: <String>[
        ...kDart2jsLinuxArgs,
        '-Ddart.vm.profile=true',
        '-DFOO=bar',
        '-DBAZ=qux',
604
        '--no-source-maps',
605
        '-O4',
606 607 608 609 610 611
        '--no-minify',
        '-o',
        environment.buildDir.childFile('main.dart.js').absolute.path,
        environment.buildDir.childFile('app.dill').absolute.path,
      ]
    ));
612

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

618 619 620 621 622 623
  test('Generated service worker is empty with none-strategy', () {
    final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>[], serviceWorkerStrategy: ServiceWorkerStrategy.none);

    expect(result, '');
  });

624
  test('Generated service worker correctly inlines file hashes', () {
625
    final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>[], serviceWorkerStrategy: ServiceWorkerStrategy.offlineFirst);
626 627 628 629

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

630
  test('Generated service worker includes core files', () {
631
    final String result = generateServiceWorker(<String, String>{'/foo': 'abcd'}, <String>['foo', 'bar'], serviceWorkerStrategy: ServiceWorkerStrategy.offlineFirst);
632 633 634 635

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

636
  test('WebServiceWorker generates a service_worker for a web resource folder', () => testbed.run(() async {
637
    environment.outputDir.childDirectory('a').childFile('a.txt')
638 639
      ..createSync(recursive: true)
      ..writeAsStringSync('A');
640
    await WebServiceWorker(globals.fs, globals.cache).build(environment);
641 642 643 644

    expect(environment.outputDir.childFile('flutter_service_worker.js'), exists);
    // Contains file hash.
    expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
645
      contains('"a/a.txt": "7fc56270e7a70fa81a5935b72eacbe29"'));
646 647
    expect(environment.buildDir.childFile('service_worker.d'), exists);
    // Depends on resource file.
648 649 650 651 652
    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'));
653
  }));
654 655 656 657 658

  test('WebServiceWorker contains baseUrl cache', () => testbed.run(() async {
    environment.outputDir
      .childFile('index.html')
      .createSync(recursive: true);
659
    await WebServiceWorker(globals.fs, globals.cache).build(environment);
660 661 662 663 664 665 666 667 668

    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);
  }));
669 670 671 672 673 674 675 676

  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);
677
    await WebServiceWorker(globals.fs, globals.cache).build(environment);
678 679 680 681 682 683 684 685

    // 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"'));
  }));
686
}