• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Integration tests which invoke flutter instead of unit testing the code
6// will not produce meaningful coverage information - we can measure coverage
7// from the isolate running the test, but not from the isolate started via
8// the command line process.
9@Tags(<String>['no_coverage'])
10import 'dart:async';
11
12import 'package:file/file.dart';
13import 'package:flutter_tools/src/base/common.dart';
14import 'package:flutter_tools/src/base/file_system.dart';
15import 'package:vm_service/vm_service.dart';
16
17import '../src/common.dart';
18import 'test_data/hot_reload_project.dart';
19import 'test_driver.dart';
20import 'test_utils.dart';
21
22void main() {
23  group('hot reload tests', () {
24    Directory tempDir;
25    final HotReloadProject _project = HotReloadProject();
26    FlutterRunTestDriver _flutter;
27
28    setUp(() async {
29      tempDir = createResolvedTempDirectorySync('hot_reload_test.');
30      await _project.setUpIn(tempDir);
31      _flutter = FlutterRunTestDriver(tempDir);
32    });
33
34    tearDown(() async {
35      await _flutter?.stop();
36      tryToDelete(tempDir);
37    });
38
39    test('hot reload works without error', () async {
40      await _flutter.run();
41      await _flutter.hotReload();
42    });
43
44    test('newly added code executes during hot reload', () async {
45      await _flutter.run();
46      _project.uncommentHotReloadPrint();
47      final StringBuffer stdout = StringBuffer();
48      final StreamSubscription<String> subscription = _flutter.stdout.listen(stdout.writeln);
49      try {
50        await _flutter.hotReload();
51        expect(stdout.toString(), contains('(((((RELOAD WORKED)))))'));
52      } finally {
53        await subscription.cancel();
54      }
55    });
56
57    test('hot restart works without error', () async {
58      await _flutter.run();
59      await _flutter.hotRestart();
60    });
61
62    test('breakpoints are hit after hot reload', () async {
63      Isolate isolate;
64      await _flutter.run(withDebugger: true, startPaused: true);
65      final Completer<void> sawTick1 = Completer<void>();
66      final Completer<void> sawTick3 = Completer<void>();
67      final Completer<void> sawDebuggerPausedMessage = Completer<void>();
68      final StreamSubscription<String> subscription = _flutter.stdout.listen(
69        (String line) {
70          if (line.contains('((((TICK 1))))')) {
71            expect(sawTick1.isCompleted, isFalse);
72            sawTick1.complete();
73          }
74          if (line.contains('((((TICK 3))))')) {
75            expect(sawTick3.isCompleted, isFalse);
76            sawTick3.complete();
77          }
78          if (line.contains('The application is paused in the debugger on a breakpoint.')) {
79            expect(sawDebuggerPausedMessage.isCompleted, isFalse);
80            sawDebuggerPausedMessage.complete();
81          }
82        },
83      );
84      await _flutter.resume(); // we start paused so we can set up our TICK 1 listener before the app starts
85      unawaited(sawTick1.future.timeout(
86        const Duration(seconds: 5),
87        onTimeout: () { print('The test app is taking longer than expected to print its synchronization line...'); },
88      ));
89      await sawTick1.future; // after this, app is in steady state
90      await _flutter.addBreakpoint(
91        _project.scheduledBreakpointUri,
92        _project.scheduledBreakpointLine,
93      );
94      await _flutter.hotReload(); // reload triggers code which eventually hits the breakpoint
95      isolate = await _flutter.waitForPause();
96      expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));
97      await _flutter.resume();
98      await _flutter.addBreakpoint(
99        _project.buildBreakpointUri,
100        _project.buildBreakpointLine,
101      );
102      bool reloaded = false;
103      final Future<void> reloadFuture = _flutter.hotReload().then((void value) { reloaded = true; });
104      await sawTick3.future; // this should happen before it pauses
105      isolate = await _flutter.waitForPause();
106      expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));
107      await sawDebuggerPausedMessage.future;
108      expect(reloaded, isFalse);
109      await _flutter.resume();
110      await reloadFuture;
111      expect(reloaded, isTrue);
112      reloaded = false;
113      await subscription.cancel();
114    });
115
116    test('hot reload doesn\'t reassemble if paused', () async {
117      await _flutter.run(withDebugger: true);
118      final Completer<void> sawTick2 = Completer<void>();
119      final Completer<void> sawTick3 = Completer<void>();
120      final Completer<void> sawDebuggerPausedMessage1 = Completer<void>();
121      final Completer<void> sawDebuggerPausedMessage2 = Completer<void>();
122      final StreamSubscription<String> subscription = _flutter.stdout.listen(
123        (String line) {
124          if (line.contains('((((TICK 2))))')) {
125            expect(sawTick2.isCompleted, isFalse);
126            sawTick2.complete();
127          }
128          if (line.contains('The application is paused in the debugger on a breakpoint.')) {
129            expect(sawDebuggerPausedMessage1.isCompleted, isFalse);
130            sawDebuggerPausedMessage1.complete();
131          }
132          if (line.contains('The application is paused in the debugger on a breakpoint; interface might not update.')) {
133            expect(sawDebuggerPausedMessage2.isCompleted, isFalse);
134            sawDebuggerPausedMessage2.complete();
135          }
136        },
137      );
138      await _flutter.addBreakpoint(
139        _project.buildBreakpointUri,
140        _project.buildBreakpointLine,
141      );
142      bool reloaded = false;
143      final Future<void> reloadFuture = _flutter.hotReload().then((void value) { reloaded = true; });
144      await sawTick2.future; // this should happen before it pauses
145      final Isolate isolate = await _flutter.waitForPause();
146      expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));
147      expect(reloaded, isFalse);
148      await sawDebuggerPausedMessage1.future; // this is the one where it say "uh, you broke into the debugger while reloading"
149      await reloadFuture; // this is the one where it times out because you're in the debugger
150      expect(reloaded, isTrue);
151      await _flutter.hotReload(); // now we're already paused
152      expect(sawTick3.isCompleted, isFalse);
153      await sawDebuggerPausedMessage2.future; // so we just get told that nothing is going to happen
154      await _flutter.resume();
155      await subscription.cancel();
156    });
157  }, timeout: const Timeout.factor(10), tags: <String>['integration']); // The DevFS sync takes a really long time, so these tests can be slow.
158}
159