-
Notifications
You must be signed in to change notification settings - Fork 4.9k
feat: pause on --debug
#38345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: pause on --debug
#38345
Changes from 12 commits
892e2ce
bcf2fec
c40f102
4b87e41
b26031f
c1c9867
b515837
0a611bb
db2419d
0996534
8381924
d075147
7f90a0f
2242b4c
6061a29
bda2662
3999df2
807eafe
c420d97
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,7 @@ import type { ProcessExitData } from './processHost'; | |
| import type { TestGroup } from './testGroups'; | ||
| import type { TestError, TestResult, TestStep } from '../../types/testReporter'; | ||
| import type { FullConfigInternal } from '../common/config'; | ||
| import type { AttachmentPayload, DonePayload, RunPayload, SerializedConfig, StepBeginPayload, StepEndPayload, TeardownErrorsPayload, TestBeginPayload, TestEndPayload, TestOutputPayload, TestPausedPayload } from '../common/ipc'; | ||
| import type { AttachmentPayload, DonePayload, RunPayload, SerializedConfig, StepBeginPayload, StepEndPayload, TeardownErrorsPayload, TestBeginPayload, TestEndPayload, TestErrorPayload, TestOutputPayload, TestPausedPayload } from '../common/ipc'; | ||
| import type { Suite } from '../common/test'; | ||
| import type { TestCase } from '../common/test'; | ||
| import type { ReporterV2 } from '../reporters/reporterV2'; | ||
|
|
@@ -322,7 +322,6 @@ class JobDispatcher { | |
| // Do not show more than one error to avoid confusion, but report | ||
| // as interrupted to indicate that we did actually start the test. | ||
| params.status = 'interrupted'; | ||
| params.errors = []; | ||
| } | ||
| const data = this._dataByTestId.get(params.testId); | ||
| if (!data) { | ||
|
|
@@ -333,8 +332,6 @@ class JobDispatcher { | |
| this._remainingByTestId.delete(params.testId); | ||
| const { result, test } = data; | ||
| result.duration = params.duration; | ||
| result.errors = params.errors; | ||
| result.error = result.errors[0]; | ||
| result.status = params.status; | ||
| result.annotations = params.annotations; | ||
| test.annotations = [...params.annotations]; // last test result wins | ||
|
|
@@ -429,6 +426,17 @@ class JobDispatcher { | |
| } | ||
| } | ||
|
|
||
| private _onErrors(params: TestErrorPayload) { | ||
| const data = this._dataByTestId.get(params.testId)!; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we should check |
||
| if (!data) | ||
| return; | ||
| const { result } = data; | ||
| for (const error of params.errors) | ||
| addLocationAndSnippetToError(this._config.config, error); | ||
|
||
| result.errors.push(...params.errors); | ||
| result.error = result.errors[0]; | ||
| } | ||
|
|
||
| private _failTestWithErrors(test: TestCase, errors: TestError[]) { | ||
| const runData = this._dataByTestId.get(test.id); | ||
| // There might be a single test that has started but has not finished yet. | ||
|
|
@@ -439,7 +447,7 @@ class JobDispatcher { | |
| result = test._appendTestResult(); | ||
| this._reporter.onTestBegin?.(test, result); | ||
| } | ||
| result.errors = [...errors]; | ||
| result.errors.push(...errors); | ||
| result.error = result.errors[0]; | ||
| result.status = errors.length ? 'failed' : 'skipped'; | ||
| this._reportTestEnd(test, result); | ||
|
|
@@ -578,6 +586,7 @@ class JobDispatcher { | |
| eventsHelper.addEventListener(worker, 'stepBegin', this._onStepBegin.bind(this)), | ||
| eventsHelper.addEventListener(worker, 'stepEnd', this._onStepEnd.bind(this)), | ||
| eventsHelper.addEventListener(worker, 'attach', this._onAttach.bind(this)), | ||
| eventsHelper.addEventListener(worker, 'errors', this._onErrors.bind(this)), | ||
Skn0tt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| eventsHelper.addEventListener(worker, 'testPaused', this._onTestPaused.bind(this, worker)), | ||
| eventsHelper.addEventListener(worker, 'done', this._onDone.bind(this)), | ||
| eventsHelper.addEventListener(worker, 'exit', this.onExit.bind(this)), | ||
|
|
@@ -600,9 +609,11 @@ class JobDispatcher { | |
| } | ||
| }; | ||
|
|
||
| for (const error of params.errors) | ||
| addLocationAndSnippetToError(this._config.config, error); | ||
| this._failureTracker.onTestPaused?.({ ...params, sendMessage }); | ||
| const data = this._dataByTestId.get(params.testId); | ||
| if (!data) | ||
| return; | ||
|
|
||
| this._failureTracker.onTestPaused?.({ errors: data.result.errors, sendMessage }); | ||
| } | ||
|
|
||
| skipWholeJob(): boolean { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| /** | ||
| * Copyright (c) Microsoft Corporation. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| import path from 'path'; | ||
| import { traverse, babelParse, ParseResult, T, types as t } from './babelBundle'; | ||
| import type { Location } from '../../types/testReporter'; | ||
|
|
||
| const astCache = new Map<string, { text: string, ast?: ParseResult }>(); | ||
Skn0tt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| export function pruneAstCaches(fsPathsToRetain: string[]) { | ||
| const retain = new Set(fsPathsToRetain); | ||
| for (const key of astCache.keys()) { | ||
| if (!retain.has(key)) | ||
| astCache.delete(key); | ||
| } | ||
| } | ||
|
|
||
| function getAst(text: string, fsPath: string) { | ||
| const cached = astCache.get(fsPath); | ||
| let ast = cached?.ast; | ||
| if (!cached || cached.text !== text) { | ||
| try { | ||
| ast = babelParse(text, path.basename(fsPath), false); | ||
| astCache.set(fsPath, { text, ast }); | ||
| } catch (e) { | ||
| astCache.set(fsPath, { text, ast: undefined }); | ||
| } | ||
| } | ||
| return ast; | ||
| } | ||
|
|
||
| function containsPosition(location: T.SourceLocation, position: Location): boolean { | ||
| if (position.line < location.start.line || position.line > location.end.line) | ||
| return false; | ||
| if (position.line === location.start.line && position.column < location.start.column) | ||
| return false; | ||
| if (position.line === location.end.line && position.column > location.end.column) | ||
| return false; | ||
| return true; | ||
| } | ||
|
|
||
| export function findTestEndPosition(text: string, location: Location): Location | undefined { | ||
Skn0tt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const ast = getAst(text, location.file); | ||
| if (!ast) | ||
| return; | ||
| let result: Location | undefined; | ||
| traverse(ast, { | ||
| enter(path) { | ||
| if (t.isCallExpression(path.node) && path.node.loc && containsPosition(path.node.loc, location)) { | ||
| const callNode = path.node; | ||
| const funcNode = callNode.arguments[callNode.arguments.length - 1]; | ||
| if (callNode.arguments.length >= 2 && t.isFunction(funcNode) && funcNode.body.loc) | ||
| result = { file: location.file, ...funcNode.body.loc.end }; | ||
| } | ||
| } | ||
| }); | ||
| return result; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, this will definitely produce double snippets. We should figure out this part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you say "produce double snippets", you mean that we wastefully compute them twice, right? Because I don't see how we store them multiple times