|
8 | 8 | library;
|
9 | 9 |
|
10 | 10 | import 'dart:async';
|
11 |
| -import 'dart:io'; |
12 | 11 |
|
13 | 12 | import 'package:dwds/expression_compiler.dart';
|
14 | 13 | import 'package:test/test.dart';
|
@@ -207,6 +206,37 @@ void main() {
|
207 | 206 | Future<void> waitForBreakpoint() =>
|
208 | 207 | expectLater(stream, emitsThrough(_hasKind(EventKind.kPauseBreakpoint)));
|
209 | 208 |
|
| 209 | + test('empty hot reload keeps breakpoints', () async { |
| 210 | + final genString = 'main gen0'; |
| 211 | + |
| 212 | + final bp = await addBreakpoint( |
| 213 | + file: mainFile, |
| 214 | + breakpointMarker: callLogMarker, |
| 215 | + ); |
| 216 | + |
| 217 | + var breakpointFuture = waitForBreakpoint(); |
| 218 | + |
| 219 | + await callEvaluate(); |
| 220 | + |
| 221 | + // Should break at `callLog`. |
| 222 | + await breakpointFuture; |
| 223 | + await resumeAndExpectLog(genString); |
| 224 | + |
| 225 | + await context.recompile(fullRestart: false); |
| 226 | + |
| 227 | + await hotReloadAndHandlePausePost([ |
| 228 | + (file: mainFile, breakpointMarker: callLogMarker, bp: bp), |
| 229 | + ]); |
| 230 | + |
| 231 | + breakpointFuture = waitForBreakpoint(); |
| 232 | + |
| 233 | + await callEvaluate(); |
| 234 | + |
| 235 | + // Should break at `callLog`. |
| 236 | + await breakpointFuture; |
| 237 | + await resumeAndExpectLog(genString); |
| 238 | + }); |
| 239 | + |
210 | 240 | test('after edit and hot reload, breakpoint is in new file', () async {
|
211 | 241 | final oldString = 'main gen0';
|
212 | 242 | final newString = 'main gen1';
|
@@ -359,52 +389,109 @@ void main() {
|
359 | 389 | },
|
360 | 390 | );
|
361 | 391 |
|
362 |
| - test( |
363 |
| - 'breakpoint in captured code is deleted', |
364 |
| - () async { |
365 |
| - var bp = await addBreakpoint( |
366 |
| - file: mainFile, |
367 |
| - breakpointMarker: capturedStringMarker, |
368 |
| - ); |
| 392 | + // Test that we wait for all scripts to be parsed first before computing |
| 393 | + // location metadata. |
| 394 | + test('after adding many files and putting breakpoint in the last one,' |
| 395 | + 'breakpoint is correctly registered', () async { |
| 396 | + final genLog = 'main gen0'; |
369 | 397 |
|
370 |
| - final oldLog = "log('\$mainValue');"; |
371 |
| - final newLog = "log('\${closure()}');"; |
372 |
| - await makeEditAndRecompile(mainFile, oldLog, newLog); |
| 398 | + final bp = await addBreakpoint( |
| 399 | + file: mainFile, |
| 400 | + breakpointMarker: callLogMarker, |
| 401 | + ); |
373 | 402 |
|
374 |
| - bp = |
375 |
| - (await hotReloadAndHandlePausePost([ |
376 |
| - (file: mainFile, breakpointMarker: capturedStringMarker, bp: bp), |
377 |
| - ])).first; |
| 403 | + var breakpointFuture = waitForBreakpoint(); |
378 | 404 |
|
379 |
| - final breakpointFuture = waitForBreakpoint(); |
| 405 | + await callEvaluate(); |
380 | 406 |
|
381 |
| - await callEvaluate(); |
| 407 | + // Should break at `callLog`. |
| 408 | + await breakpointFuture; |
| 409 | + await resumeAndExpectLog(genLog); |
382 | 410 |
|
383 |
| - // Should break at `capturedString`. |
384 |
| - await breakpointFuture; |
385 |
| - final oldCapturedString = 'captured closure gen0'; |
386 |
| - // Closure gets evaluated for the first time. |
387 |
| - await resumeAndExpectLog(oldCapturedString); |
388 |
| - |
389 |
| - final newCapturedString = 'captured closure gen1'; |
390 |
| - await makeEditAndRecompile( |
391 |
| - mainFile, |
392 |
| - oldCapturedString, |
393 |
| - newCapturedString, |
| 411 | + // Add library files, import them, but only refer to the last one in main. |
| 412 | + final numFiles = 50; |
| 413 | + for (var i = 1; i <= numFiles; i++) { |
| 414 | + final libFile = 'library$i.dart'; |
| 415 | + context.addLibraryFile( |
| 416 | + libFileName: libFile, |
| 417 | + contents: '''String get libraryValue$i { |
| 418 | + return 'lib gen$i'; // Breakpoint: libValue$i |
| 419 | + }''', |
394 | 420 | );
|
| 421 | + final oldImports = "import 'dart:js_interop';"; |
| 422 | + final newImports = |
| 423 | + '$oldImports\n' |
| 424 | + "import 'package:_test_hot_reload_breakpoints/$libFile';"; |
| 425 | + makeEdit(mainFile, oldImports, newImports); |
| 426 | + } |
| 427 | + final oldLog = "log('\$mainValue');"; |
| 428 | + final newLog = "log('\$libraryValue$numFiles');"; |
| 429 | + await makeEditAndRecompile(mainFile, oldLog, newLog); |
395 | 430 |
|
396 |
| - await hotReloadAndHandlePausePost([ |
397 |
| - (file: mainFile, breakpointMarker: capturedStringMarker, bp: bp), |
398 |
| - ]); |
| 431 | + await hotReloadAndHandlePausePost([ |
| 432 | + (file: mainFile, breakpointMarker: callLogMarker, bp: bp), |
| 433 | + ( |
| 434 | + file: 'library$numFiles.dart', |
| 435 | + breakpointMarker: 'libValue$numFiles', |
| 436 | + bp: null, |
| 437 | + ), |
| 438 | + ]); |
399 | 439 |
|
400 |
| - // Breakpoint should not be hit as it's now deleted. We should also see |
401 |
| - // the old string still as the closure has not been reevaluated. |
402 |
| - await callEvaluateAndExpectLog(oldCapturedString); |
403 |
| - }, |
404 |
| - // TODO(srujzs): Re-enable after |
405 |
| - // https://github.com/dart-lang/webdev/issues/2640. |
406 |
| - skip: Platform.isWindows, |
407 |
| - ); |
| 440 | + breakpointFuture = waitForBreakpoint(); |
| 441 | + |
| 442 | + await callEvaluate(); |
| 443 | + |
| 444 | + // Should break at `callLog`. |
| 445 | + await breakpointFuture; |
| 446 | + |
| 447 | + breakpointFuture = waitForBreakpoint(); |
| 448 | + |
| 449 | + await resume(); |
| 450 | + // Should break at the breakpoint in the last file. |
| 451 | + await breakpointFuture; |
| 452 | + await resumeAndExpectLog('lib gen$numFiles'); |
| 453 | + }); |
| 454 | + |
| 455 | + test('breakpoint in captured code is deleted', () async { |
| 456 | + var bp = await addBreakpoint( |
| 457 | + file: mainFile, |
| 458 | + breakpointMarker: capturedStringMarker, |
| 459 | + ); |
| 460 | + |
| 461 | + final oldLog = "log('\$mainValue');"; |
| 462 | + final newLog = "log('\${closure()}');"; |
| 463 | + await makeEditAndRecompile(mainFile, oldLog, newLog); |
| 464 | + |
| 465 | + bp = |
| 466 | + (await hotReloadAndHandlePausePost([ |
| 467 | + (file: mainFile, breakpointMarker: capturedStringMarker, bp: bp), |
| 468 | + ])).first; |
| 469 | + |
| 470 | + final breakpointFuture = waitForBreakpoint(); |
| 471 | + |
| 472 | + await callEvaluate(); |
| 473 | + |
| 474 | + // Should break at `capturedString`. |
| 475 | + await breakpointFuture; |
| 476 | + final oldCapturedString = 'captured closure gen0'; |
| 477 | + // Closure gets evaluated for the first time. |
| 478 | + await resumeAndExpectLog(oldCapturedString); |
| 479 | + |
| 480 | + final newCapturedString = 'captured closure gen1'; |
| 481 | + await makeEditAndRecompile( |
| 482 | + mainFile, |
| 483 | + oldCapturedString, |
| 484 | + newCapturedString, |
| 485 | + ); |
| 486 | + |
| 487 | + await hotReloadAndHandlePausePost([ |
| 488 | + (file: mainFile, breakpointMarker: capturedStringMarker, bp: bp), |
| 489 | + ]); |
| 490 | + |
| 491 | + // Breakpoint should not be hit as it's now deleted. We should also see |
| 492 | + // the old string still as the closure has not been reevaluated. |
| 493 | + await callEvaluateAndExpectLog(oldCapturedString); |
| 494 | + }); |
408 | 495 | }, timeout: Timeout.factor(2));
|
409 | 496 |
|
410 | 497 | group('when pause_isolates_on_start is false', () {
|
|
0 commit comments