Skip to content

Commit 6a3a7e7

Browse files
authored
jest-editor-support v32 upgrade (#1141)
* refactor and fixes upon jest-editor-support upgrade * update version * update jest-editor-support version * adding more tests and fix source for missing location use cases * upgrade jest-editor-support to v30 1. adjust the webpack to bundle the new jest-snapshot 2. fix some lint issues 3. update version to 7.0.0
1 parent d241cb3 commit 6a3a7e7

21 files changed

+1520
-1312
lines changed

package.json

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "vscode-jest",
33
"displayName": "Jest",
44
"description": "Use Facebook's Jest With Pleasure.",
5-
"version": "6.2.5",
5+
"version": "7.0.0",
66
"publisher": "Orta",
77
"engines": {
88
"vscode": "^1.68.1"
@@ -655,9 +655,11 @@
655655
"ci": "yarn lint && yarn test --coverage",
656656
"clean-out": "rimraf ./out",
657657
"vscode:prepublish": "yarn clean-out && yarn compile",
658-
"compile": "webpack --mode production",
659-
"watch": "webpack --mode development --watch --progress",
658+
"compile": "webpack --config webpack/webpack.config.js --mode production",
659+
"compile:dev": "webpack --config webpack/webpack.config.js --mode development",
660+
"watch": "webpack --config webpack/webpack.config.js --mode development --watch --progress",
660661
"lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"*.json\" \"*.js\" ",
662+
"lint:fix": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"*.json\" \"*.js\" --fix",
661663
"test": "jest",
662664
"watch-test": "yarn test -- --watch",
663665
"tsc": "tsc --noEmit",
@@ -667,7 +669,7 @@
667669
"dependencies": {
668670
"istanbul-lib-coverage": "^3.2.0",
669671
"istanbul-lib-source-maps": "^4.0.1",
670-
"jest-editor-support": "^31.1.2"
672+
"jest-editor-support": "^32.0.0-beta.1"
671673
},
672674
"devDependencies": {
673675
"@types/fs-extra": "^11.0.2",
@@ -686,7 +688,6 @@
686688
"eslint-plugin-prettier": "^5.0.1",
687689
"fs-extra": "^11.1.1",
688690
"jest": "^29.7",
689-
"jest-snapshot": "^27.2.0",
690691
"prettier": "^3.0.3",
691692
"raw-loader": "^4.0.1",
692693
"rimraf": "^5.0.5",

src/DebugConfigurationProvider.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
227227
let program = path.isAbsolute(cmd)
228228
? cmd
229229
: absoluteRootPath
230-
? path.resolve(absoluteRootPath, cmd)
231-
: ['${workspaceFolder}', cmd].join(path.sep);
230+
? path.resolve(absoluteRootPath, cmd)
231+
: ['${workspaceFolder}', cmd].join(path.sep);
232232
program = this.adjustProgram(program);
233233
const args = [...cmdArgs, ...config.args];
234234
finalConfig = { ...finalConfig, cwd, program, args };

src/StatusBar.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ export class StatusBar {
217217
const summary: SummaryState = stats.isDirty
218218
? 'stats-not-sync'
219219
: stats.fail + stats.unknown === 0 && stats.success > 0
220-
? 'summary-pass'
221-
: 'summary-warning';
220+
? 'summary-pass'
221+
: 'summary-warning';
222222
const output: string[] = [this.getMessageByState(summary, showIcon)];
223223

224224
if (summary !== 'summary-pass' || alwaysShowDetails) {

src/TestResults/TestReconciliationState.ts

-17
This file was deleted.

src/TestResults/TestResult.ts

+30-23
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
import { TestReconciliationStateType } from './TestReconciliationState';
2-
import { JestFileResults, JestTotalResults } from 'jest-editor-support';
3-
import { FileCoverage } from 'istanbul-lib-coverage';
1+
import {
2+
JestFileResults,
3+
JestTotalResults,
4+
CodeLocation as Location,
5+
TestReconciliationState,
6+
} from 'jest-editor-support';
7+
import { CoverageMapData, FileCoverageData } from 'istanbul-lib-coverage';
48
import * as path from 'path';
59
import { cleanAnsi, toLowerCaseDriveLetter } from '../helpers';
610
import { MatchEvent } from './match-node';
711

8-
export interface Location {
9-
/** Zero-based column number */
10-
column: number;
11-
12-
/** Zero-based line number */
13-
line: number;
14-
}
15-
1612
export interface LocationRange {
1713
start: Location;
1814
end: Location;
@@ -28,7 +24,7 @@ export interface TestResult extends LocationRange {
2824

2925
identifier: TestIdentifier;
3026

31-
status: TestReconciliationStateType;
27+
status: TestReconciliationState;
3228
shortMessage?: string;
3329
terseMessage?: string;
3430

@@ -65,7 +61,9 @@ export const testResultsWithLowerCaseWindowsDriveLetters = (
6561
return testResults.map(testResultWithLowerCaseWindowsDriveLetter);
6662
};
6763

68-
function fileCoverageWithLowerCaseWindowsDriveLetter(fileCoverage: FileCoverage) {
64+
function fileCoverageWithLowerCaseWindowsDriveLetter(
65+
fileCoverage: FileCoverageData
66+
): FileCoverageData {
6967
const newFilePath = toLowerCaseDriveLetter(fileCoverage.path);
7068
if (newFilePath) {
7169
return {
@@ -77,20 +75,18 @@ function fileCoverageWithLowerCaseWindowsDriveLetter(fileCoverage: FileCoverage)
7775
return fileCoverage;
7876
}
7977

80-
// TODO should fix jest-editor-support type declaration, the coverageMap should not be "any"
81-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
82-
export const coverageMapWithLowerCaseWindowsDriveLetters = (data: JestTotalResults): any => {
78+
export const coverageMapWithLowerCaseWindowsDriveLetters = (
79+
data: JestTotalResults
80+
): CoverageMapData | undefined => {
8381
if (!data.coverageMap) {
8482
return;
8583
}
8684

87-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
88-
const result: any = {};
85+
const result: CoverageMapData = {};
8986
const filePaths = Object.keys(data.coverageMap);
87+
9088
for (const filePath of filePaths) {
91-
const newFileCoverage = fileCoverageWithLowerCaseWindowsDriveLetter(
92-
data.coverageMap[filePath] as FileCoverage
93-
);
89+
const newFileCoverage = fileCoverageWithLowerCaseWindowsDriveLetter(data.coverageMap[filePath]);
9490
result[newFileCoverage.path] = newFileCoverage;
9591
}
9692

@@ -133,19 +129,30 @@ export const resultsWithoutAnsiEscapeSequence = (data: JestTotalResults): JestTo
133129
message: cleanAnsi(result.message),
134130
assertionResults: result.assertionResults.map((assertion) => ({
135131
...assertion,
136-
failureMessages: assertion.failureMessages.map((message) => cleanAnsi(message)),
132+
failureMessages: (assertion.failureMessages ?? []).map((message) => cleanAnsi(message)),
137133
})),
138134
})),
139135
};
140136
};
141137

138+
// enum based on TestReconciliationState
139+
export const TestStatus: {
140+
[key in TestReconciliationState]: TestReconciliationState;
141+
} = {
142+
Unknown: 'Unknown',
143+
KnownSuccess: 'KnownSuccess',
144+
KnownFail: 'KnownFail',
145+
KnownSkip: 'KnownSkip',
146+
KnownTodo: 'KnownTodo',
147+
};
148+
142149
// export type StatusInfo<T> = {[key in TestReconciliationState]: T};
143150
export interface StatusInfo {
144151
precedence: number;
145152
desc: string;
146153
}
147154

148-
export const TestResultStatusInfo: { [key in TestReconciliationStateType]: StatusInfo } = {
155+
export const TestResultStatusInfo: { [key in TestReconciliationState]: StatusInfo } = {
149156
KnownFail: { precedence: 1, desc: 'Failed' },
150157
Unknown: {
151158
precedence: 2,

src/TestResults/TestResultProvider.ts

+14-13
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import {
88
ParsedRange,
99
ItBlock,
1010
SnapshotParserOptions,
11+
TestReconciliationState,
1112
} from 'jest-editor-support';
12-
import { TestReconciliationState, TestReconciliationStateType } from './TestReconciliationState';
13-
import { TestResult, TestResultStatusInfo } from './TestResult';
13+
import { TestResult, TestResultStatusInfo, TestStatus } from './TestResult';
1414
import * as match from './match-by-context';
1515
import { JestSessionEvents } from '../JestExt';
1616
import { TestStats } from '../types';
@@ -25,7 +25,7 @@ interface TestSuiteParseResultRaw {
2525
testBlocks: TestBlocks | 'failed';
2626
}
2727
interface TestSuiteResultRaw {
28-
status: TestReconciliationStateType;
28+
status: TestReconciliationState;
2929
message: string;
3030
assertionContainer?: ContainerNode<TestAssertionStatus>;
3131
results?: TestResult[];
@@ -53,7 +53,7 @@ const sortByStatus = (a: TestResult, b: TestResult): number => {
5353
};
5454

5555
export class TestSuiteRecord implements TestSuiteUpdatable {
56-
private _status: TestReconciliationStateType;
56+
private _status: TestReconciliationState;
5757
private _message: string;
5858
private _results?: TestResult[];
5959
private _sorted?: SortedTestResults;
@@ -67,10 +67,10 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
6767
private reconciler: TestReconciler,
6868
private parser: Parser
6969
) {
70-
this._status = TestReconciliationState.Unknown;
70+
this._status = TestStatus.Unknown;
7171
this._message = '';
7272
}
73-
public get status(): TestReconciliationStateType {
73+
public get status(): TestReconciliationState {
7474
return this._status;
7575
}
7676
public get message(): string {
@@ -114,7 +114,7 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
114114
}
115115
}
116116

117-
return this._testBlocks ?? 'failed';
117+
return this._testBlocks;
118118
}
119119

120120
public get assertionContainer(): ContainerNode<TestAssertionStatus> | undefined {
@@ -132,6 +132,10 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
132132
snapshots: ExtSnapshotBlock[]
133133
): void {
134134
const isWithin = (snapshot: ExtSnapshotBlock, range?: ParsedRange): boolean => {
135+
if (!snapshot.node.loc) {
136+
console.warn('snapshot will be ignored because it has no loc:', snapshot.node);
137+
return false;
138+
}
135139
const zeroBasedLine = snapshot.node.loc.start.line - 1;
136140
return !!range && range.start.line <= zeroBasedLine && range.end.line >= zeroBasedLine;
137141
};
@@ -226,9 +230,6 @@ export class TestResultProvider {
226230
}
227231

228232
private groupByRange(results: TestResult[]): TestResult[] {
229-
if (!results.length) {
230-
return results;
231-
}
232233
// build a range based map
233234
const byRange: Map<string, TestResult[]> = new Map();
234235
results.forEach((r) => {
@@ -402,11 +403,11 @@ export class TestResultProvider {
402403
return;
403404
}
404405
for (const test of testResults) {
405-
if (test.status === TestReconciliationState.KnownFail) {
406+
if (test.status === TestStatus.KnownFail) {
406407
sorted.fail.push(test);
407-
} else if (test.status === TestReconciliationState.KnownSkip) {
408+
} else if (test.status === TestStatus.KnownSkip) {
408409
sorted.skip.push(test);
409-
} else if (test.status === TestReconciliationState.KnownSuccess) {
410+
} else if (test.status === TestStatus.KnownSuccess) {
410411
sorted.success.push(test);
411412
} else {
412413
sorted.unknown.push(test);

src/TestResults/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
export * from './TestReconciliationState';
21
export {
32
TestResult,
43
resultsWithLowerCaseWindowsDriveLetters,
54
TestResultStatusInfo,
65
TestIdentifier,
6+
TestStatus,
77
} from './TestResult';
88
export * from './TestResultProvider';

src/TestResults/match-by-context.ts

+35-11
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ import {
1414
TestAssertionStatus,
1515
ParsedNode,
1616
DescribeBlock,
17-
Location,
17+
CodeLocation as Location,
1818
NamedBlock,
19-
ParsedNodeTypes,
19+
ParsedNodeType,
2020
} from 'jest-editor-support';
21-
import { TestReconciliationState } from './TestReconciliationState';
22-
import { TestResult } from './TestResult';
21+
import { TestResult, TestStatus, LocationRange } from './TestResult';
2322
import {
2423
DataNode,
2524
ContainerNode,
@@ -32,6 +31,14 @@ import {
3231
MatchOptions,
3332
} from './match-node';
3433

34+
interface MaybeWithLocation {
35+
start?: Location;
36+
end?: Location;
37+
}
38+
39+
export const hasLocation = (loc: MaybeWithLocation): loc is LocationRange =>
40+
loc.start != null && loc.end != null;
41+
3542
export const buildAssertionContainer = (
3643
assertions: TestAssertionStatus[]
3744
): ContainerNode<TestAssertionStatus> => {
@@ -80,11 +87,12 @@ export const buildSourceContainer = (sourceRoot: ParsedNode): ContainerNode<ItBl
8087
end: namedNode.end ? adjustLocation(namedNode.end) : UnknownRange.end,
8188
},
8289
});
90+
const start = (node.start?.line ?? 0) - 1;
8391
if (isDescribeBlock(node)) {
84-
container = new ContainerNode(node.name, node.start?.line - 1, attrs(node));
92+
container = new ContainerNode(node.name, start, attrs(node));
8593
parent.addContainerNode(container);
8694
} else if (isItBlock(node)) {
87-
parent.addDataNode(new DataNode(node.name, node.start.line - 1, node, attrs(node)));
95+
parent.addDataNode(new DataNode(node.name, start, node, attrs(node)));
8896
}
8997

9098
node.children?.forEach((n) => buildNode(n, container));
@@ -101,8 +109,14 @@ export const buildSourceContainer = (sourceRoot: ParsedNode): ContainerNode<ItBl
101109
return root;
102110
};
103111

104-
const adjustLocation = (l: Location): Location => ({ column: l.column - 1, line: l.line - 1 });
112+
const adjustLocation = (l?: Location): Location => ({
113+
column: l ? l.column - 1 : 0,
114+
line: l ? l.line - 1 : 0,
115+
});
105116
const matchPos = (t: ItBlock, a: TestAssertionStatus, forError = false): boolean => {
117+
if (!hasLocation(t)) {
118+
return false;
119+
}
106120
const line = forError ? a.line : a.line ?? a.location?.line;
107121
return (line != null && line >= t.start.line && line <= t.end.line) || false;
108122
};
@@ -125,7 +139,11 @@ export const toMatchResult = (
125139
? [undefined, undefined, assertionOrErr]
126140
: [assertionOrErr.data, assertionOrErr.history(reason), undefined];
127141

142+
if (!test.start || !test.end) {
143+
console.warn(`missing location for test block: ${test.name}`);
144+
}
128145
// Note the shift from one-based to zero-based line number and columns
146+
// assumption: if we reached here, the test start/end must have been defined
129147
return {
130148
name: assertion?.fullName ?? assertion?.title ?? sourceName,
131149
identifier: {
@@ -134,11 +152,15 @@ export const toMatchResult = (
134152
},
135153
start: adjustLocation(test.start),
136154
end: adjustLocation(test.end),
137-
status: assertion?.status ?? TestReconciliationState.Unknown,
155+
status: assertion?.status ?? TestStatus.Unknown,
138156
shortMessage: assertion?.shortMessage ?? err,
139157
terseMessage: assertion?.terseMessage,
140158
lineNumberOfError:
141-
assertion?.line && matchPos(test, assertion, true) ? assertion.line - 1 : test.end.line - 1,
159+
assertion?.line && matchPos(test, assertion, true)
160+
? assertion.line - 1
161+
: test.end
162+
? test.end.line - 1
163+
: 0,
142164
sourceHistory,
143165
assertionHistory,
144166
};
@@ -458,8 +480,10 @@ const ContextMatch = (): ContextMatchAlgorithm => {
458480

459481
const { match } = ContextMatch();
460482
const isParsedNode = (source: ParsedNode | ContainerNode<ItBlock>): source is ParsedNode =>
461-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
462-
(source as any).type in ParsedNodeTypes;
483+
typeof source === 'object' &&
484+
'type' in source &&
485+
Object.values(ParsedNodeType).includes(source.type);
486+
463487
export const matchTestAssertions = (
464488
fileName: string,
465489
source: ParsedNode | ContainerNode<ItBlock>,

0 commit comments

Comments
 (0)