hot_reload_test.dart 6.54 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
import 'dart:async';

7
import 'package:file/file.dart';
8
import 'package:flutter_tools/src/base/common.dart';
9
import 'package:flutter_tools/src/base/file_system.dart';
10
import 'package:vm_service/vm_service.dart';
11

12
import '../src/common.dart';
13
import 'test_data/hot_reload_project.dart';
14
import 'test_driver.dart';
15
import 'test_utils.dart';
16 17

void main() {
18 19 20
  Directory tempDir;
  final HotReloadProject _project = HotReloadProject();
  FlutterRunTestDriver _flutter;
21

22 23 24 25 26
  setUp(() async {
    tempDir = createResolvedTempDirectorySync('hot_reload_test.');
    await _project.setUpIn(tempDir);
    _flutter = FlutterRunTestDriver(tempDir);
  });
27

28 29 30 31
  tearDown(() async {
    await _flutter?.stop();
    tryToDelete(tempDir);
  });
32

33 34 35 36 37 38
  test('hot reload works without error', () async {
    await _flutter.run();
    await _flutter.hotReload();
  });

  test('newly added code executes during hot reload', () async {
39 40
    final StringBuffer stdout = StringBuffer();
    final StreamSubscription<String> subscription = _flutter.stdout.listen(stdout.writeln);
41 42
    await _flutter.run();
    _project.uncommentHotReloadPrint();
43
    try {
44
      await _flutter.hotReload();
45 46 47 48 49
      expect(stdout.toString(), contains('(((((RELOAD WORKED)))))'));
    } finally {
      await subscription.cancel();
    }
  });
50

51
  test('reloadMethod triggers hot reload behavior', () async {
52 53
    final StringBuffer stdout = StringBuffer();
    final StreamSubscription<String> subscription = _flutter.stdout.listen(stdout.writeln);
54 55
    await _flutter.run();
    _project.uncommentHotReloadPrint();
56 57 58 59 60 61 62 63 64 65 66 67
    try {
      final String libraryId = _project.buildBreakpointUri.toString();
      await _flutter.reloadMethod(libraryId: libraryId, classId: 'MyApp');
      // reloadMethod does not wait for the next frame, to allow scheduling a new
      // update while the previous update was pending.
      await Future<void>.delayed(const Duration(seconds: 1));
      expect(stdout.toString(), contains('(((((RELOAD WORKED)))))'));
    } finally {
      await subscription.cancel();
    }
  });

68 69 70 71
  test('hot restart works without error', () async {
    await _flutter.run();
    await _flutter.hotRestart();
  });
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
  test('breakpoints are hit after hot reload', () async {
    Isolate isolate;
    final Completer<void> sawTick1 = Completer<void>();
    final Completer<void> sawDebuggerPausedMessage = Completer<void>();
    final StreamSubscription<String> subscription = _flutter.stdout.listen(
      (String line) {
        if (line.contains('((((TICK 1))))')) {
          expect(sawTick1.isCompleted, isFalse);
          sawTick1.complete();
        }
        if (line.contains('The application is paused in the debugger on a breakpoint.')) {
          expect(sawDebuggerPausedMessage.isCompleted, isFalse);
          sawDebuggerPausedMessage.complete();
        }
      },
    );
89
    await _flutter.run(withDebugger: true, startPaused: true);
90 91 92 93 94 95 96 97 98 99
    await _flutter.resume(); // we start paused so we can set up our TICK 1 listener before the app starts
    unawaited(sawTick1.future.timeout(
      const Duration(seconds: 5),
      onTimeout: () { print('The test app is taking longer than expected to print its synchronization line...'); },
    ));
    await sawTick1.future; // after this, app is in steady state
    await _flutter.addBreakpoint(
      _project.scheduledBreakpointUri,
      _project.scheduledBreakpointLine,
    );
100
    await Future<void>.delayed(const Duration(seconds: 2));
101 102 103 104 105 106 107 108 109 110
    await _flutter.hotReload(); // reload triggers code which eventually hits the breakpoint
    isolate = await _flutter.waitForPause();
    expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));
    await _flutter.resume();
    await _flutter.addBreakpoint(
      _project.buildBreakpointUri,
      _project.buildBreakpointLine,
    );
    bool reloaded = false;
    final Future<void> reloadFuture = _flutter.hotReload().then((void value) { reloaded = true; });
111
    print('waiting for pause...');
112 113
    isolate = await _flutter.waitForPause();
    expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));
114
    print('waiting for debugger message...');
115 116
    await sawDebuggerPausedMessage.future;
    expect(reloaded, isFalse);
117
    print('waiting for resume...');
118
    await _flutter.resume();
119
    print('waiting for reload future...');
120 121 122
    await reloadFuture;
    expect(reloaded, isTrue);
    reloaded = false;
123
    print('subscription cancel...');
124 125
    await subscription.cancel();
  });
126

127
  test("hot reload doesn't reassemble if paused", () async {
128
    final Completer<void> sawTick1 = Completer<void>();
129 130 131 132
    final Completer<void> sawDebuggerPausedMessage1 = Completer<void>();
    final Completer<void> sawDebuggerPausedMessage2 = Completer<void>();
    final StreamSubscription<String> subscription = _flutter.stdout.listen(
      (String line) {
133
        print('[LOG]:"$line"');
134 135 136
        if (line.contains('(((TICK 1)))')) {
          expect(sawTick1.isCompleted, isFalse);
          sawTick1.complete();
137 138 139 140 141 142 143 144 145 146 147
        }
        if (line.contains('The application is paused in the debugger on a breakpoint.')) {
          expect(sawDebuggerPausedMessage1.isCompleted, isFalse);
          sawDebuggerPausedMessage1.complete();
        }
        if (line.contains('The application is paused in the debugger on a breakpoint; interface might not update.')) {
          expect(sawDebuggerPausedMessage2.isCompleted, isFalse);
          sawDebuggerPausedMessage2.complete();
        }
      },
    );
148
    await _flutter.run(withDebugger: true);
149
    await Future<void>.delayed(const Duration(seconds: 1));
150
    await sawTick1.future;
151 152 153 154 155
    await _flutter.addBreakpoint(
      _project.buildBreakpointUri,
      _project.buildBreakpointLine,
    );
    bool reloaded = false;
156
    await Future<void>.delayed(const Duration(seconds: 1));
157 158 159 160 161 162 163 164 165 166 167 168
    final Future<void> reloadFuture = _flutter.hotReload().then((void value) { reloaded = true; });
    final Isolate isolate = await _flutter.waitForPause();
    expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));
    expect(reloaded, isFalse);
    await sawDebuggerPausedMessage1.future; // this is the one where it say "uh, you broke into the debugger while reloading"
    await reloadFuture; // this is the one where it times out because you're in the debugger
    expect(reloaded, isTrue);
    await _flutter.hotReload(); // now we're already paused
    await sawDebuggerPausedMessage2.future; // so we just get told that nothing is going to happen
    await _flutter.resume();
    await subscription.cancel();
  });
169
}