Skip to content
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

jest-editor-support v32 upgrade #1141

Merged
merged 8 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-jest",
"displayName": "Jest",
"description": "Use Facebook's Jest With Pleasure.",
"version": "6.2.5",
"version": "7.0.0",
"publisher": "Orta",
"engines": {
"vscode": "^1.68.1"
Expand Down Expand Up @@ -655,9 +655,11 @@
"ci": "yarn lint && yarn test --coverage",
"clean-out": "rimraf ./out",
"vscode:prepublish": "yarn clean-out && yarn compile",
"compile": "webpack --mode production",
"watch": "webpack --mode development --watch --progress",
"compile": "webpack --config webpack/webpack.config.js --mode production",
"compile:dev": "webpack --config webpack/webpack.config.js --mode development",
"watch": "webpack --config webpack/webpack.config.js --mode development --watch --progress",
"lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"*.json\" \"*.js\" ",
"lint:fix": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"*.json\" \"*.js\" --fix",
"test": "jest",
"watch-test": "yarn test -- --watch",
"tsc": "tsc --noEmit",
Expand All @@ -667,7 +669,7 @@
"dependencies": {
"istanbul-lib-coverage": "^3.2.0",
"istanbul-lib-source-maps": "^4.0.1",
"jest-editor-support": "^31.1.2"
"jest-editor-support": "^32.0.0-beta.1"
},
"devDependencies": {
"@types/fs-extra": "^11.0.2",
Expand All @@ -686,7 +688,6 @@
"eslint-plugin-prettier": "^5.0.1",
"fs-extra": "^11.1.1",
"jest": "^29.7",
"jest-snapshot": "^27.2.0",
"prettier": "^3.0.3",
"raw-loader": "^4.0.1",
"rimraf": "^5.0.5",
Expand Down
4 changes: 2 additions & 2 deletions src/DebugConfigurationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
let program = path.isAbsolute(cmd)
? cmd
: absoluteRootPath
? path.resolve(absoluteRootPath, cmd)
: ['${workspaceFolder}', cmd].join(path.sep);
? path.resolve(absoluteRootPath, cmd)
: ['${workspaceFolder}', cmd].join(path.sep);
program = this.adjustProgram(program);
const args = [...cmdArgs, ...config.args];
finalConfig = { ...finalConfig, cwd, program, args };
Expand Down
4 changes: 2 additions & 2 deletions src/StatusBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ export class StatusBar {
const summary: SummaryState = stats.isDirty
? 'stats-not-sync'
: stats.fail + stats.unknown === 0 && stats.success > 0
? 'summary-pass'
: 'summary-warning';
? 'summary-pass'
: 'summary-warning';
const output: string[] = [this.getMessageByState(summary, showIcon)];

if (summary !== 'summary-pass' || alwaysShowDetails) {
Expand Down
17 changes: 0 additions & 17 deletions src/TestResults/TestReconciliationState.ts

This file was deleted.

53 changes: 30 additions & 23 deletions src/TestResults/TestResult.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { TestReconciliationStateType } from './TestReconciliationState';
import { JestFileResults, JestTotalResults } from 'jest-editor-support';
import { FileCoverage } from 'istanbul-lib-coverage';
import {
JestFileResults,
JestTotalResults,
CodeLocation as Location,
TestReconciliationState,
} from 'jest-editor-support';
import { CoverageMapData, FileCoverageData } from 'istanbul-lib-coverage';
import * as path from 'path';
import { cleanAnsi, toLowerCaseDriveLetter } from '../helpers';
import { MatchEvent } from './match-node';

export interface Location {
/** Zero-based column number */
column: number;

/** Zero-based line number */
line: number;
}

export interface LocationRange {
start: Location;
end: Location;
Expand All @@ -28,7 +24,7 @@ export interface TestResult extends LocationRange {

identifier: TestIdentifier;

status: TestReconciliationStateType;
status: TestReconciliationState;
shortMessage?: string;
terseMessage?: string;

Expand Down Expand Up @@ -65,7 +61,9 @@ export const testResultsWithLowerCaseWindowsDriveLetters = (
return testResults.map(testResultWithLowerCaseWindowsDriveLetter);
};

function fileCoverageWithLowerCaseWindowsDriveLetter(fileCoverage: FileCoverage) {
function fileCoverageWithLowerCaseWindowsDriveLetter(
fileCoverage: FileCoverageData
): FileCoverageData {
const newFilePath = toLowerCaseDriveLetter(fileCoverage.path);
if (newFilePath) {
return {
Expand All @@ -77,20 +75,18 @@ function fileCoverageWithLowerCaseWindowsDriveLetter(fileCoverage: FileCoverage)
return fileCoverage;
}

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

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result: any = {};
const result: CoverageMapData = {};
const filePaths = Object.keys(data.coverageMap);

for (const filePath of filePaths) {
const newFileCoverage = fileCoverageWithLowerCaseWindowsDriveLetter(
data.coverageMap[filePath] as FileCoverage
);
const newFileCoverage = fileCoverageWithLowerCaseWindowsDriveLetter(data.coverageMap[filePath]);
result[newFileCoverage.path] = newFileCoverage;
}

Expand Down Expand Up @@ -133,19 +129,30 @@ export const resultsWithoutAnsiEscapeSequence = (data: JestTotalResults): JestTo
message: cleanAnsi(result.message),
assertionResults: result.assertionResults.map((assertion) => ({
...assertion,
failureMessages: assertion.failureMessages.map((message) => cleanAnsi(message)),
failureMessages: (assertion.failureMessages ?? []).map((message) => cleanAnsi(message)),
})),
})),
};
};

// enum based on TestReconciliationState
export const TestStatus: {
[key in TestReconciliationState]: TestReconciliationState;
} = {
Unknown: 'Unknown',
KnownSuccess: 'KnownSuccess',
KnownFail: 'KnownFail',
KnownSkip: 'KnownSkip',
KnownTodo: 'KnownTodo',
};

// export type StatusInfo<T> = {[key in TestReconciliationState]: T};
export interface StatusInfo {
precedence: number;
desc: string;
}

export const TestResultStatusInfo: { [key in TestReconciliationStateType]: StatusInfo } = {
export const TestResultStatusInfo: { [key in TestReconciliationState]: StatusInfo } = {
KnownFail: { precedence: 1, desc: 'Failed' },
Unknown: {
precedence: 2,
Expand Down
27 changes: 14 additions & 13 deletions src/TestResults/TestResultProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {
ParsedRange,
ItBlock,
SnapshotParserOptions,
TestReconciliationState,
} from 'jest-editor-support';
import { TestReconciliationState, TestReconciliationStateType } from './TestReconciliationState';
import { TestResult, TestResultStatusInfo } from './TestResult';
import { TestResult, TestResultStatusInfo, TestStatus } from './TestResult';
import * as match from './match-by-context';
import { JestSessionEvents } from '../JestExt';
import { TestStats } from '../types';
Expand All @@ -25,7 +25,7 @@ interface TestSuiteParseResultRaw {
testBlocks: TestBlocks | 'failed';
}
interface TestSuiteResultRaw {
status: TestReconciliationStateType;
status: TestReconciliationState;
message: string;
assertionContainer?: ContainerNode<TestAssertionStatus>;
results?: TestResult[];
Expand Down Expand Up @@ -53,7 +53,7 @@ const sortByStatus = (a: TestResult, b: TestResult): number => {
};

export class TestSuiteRecord implements TestSuiteUpdatable {
private _status: TestReconciliationStateType;
private _status: TestReconciliationState;
private _message: string;
private _results?: TestResult[];
private _sorted?: SortedTestResults;
Expand All @@ -67,10 +67,10 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
private reconciler: TestReconciler,
private parser: Parser
) {
this._status = TestReconciliationState.Unknown;
this._status = TestStatus.Unknown;
this._message = '';
}
public get status(): TestReconciliationStateType {
public get status(): TestReconciliationState {
return this._status;
}
public get message(): string {
Expand Down Expand Up @@ -114,7 +114,7 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
}
}

return this._testBlocks ?? 'failed';
return this._testBlocks;
}

public get assertionContainer(): ContainerNode<TestAssertionStatus> | undefined {
Expand All @@ -132,6 +132,10 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
snapshots: ExtSnapshotBlock[]
): void {
const isWithin = (snapshot: ExtSnapshotBlock, range?: ParsedRange): boolean => {
if (!snapshot.node.loc) {
console.warn('snapshot will be ignored because it has no loc:', snapshot.node);
return false;
}
const zeroBasedLine = snapshot.node.loc.start.line - 1;
return !!range && range.start.line <= zeroBasedLine && range.end.line >= zeroBasedLine;
};
Expand Down Expand Up @@ -226,9 +230,6 @@ export class TestResultProvider {
}

private groupByRange(results: TestResult[]): TestResult[] {
if (!results.length) {
return results;
}
// build a range based map
const byRange: Map<string, TestResult[]> = new Map();
results.forEach((r) => {
Expand Down Expand Up @@ -402,11 +403,11 @@ export class TestResultProvider {
return;
}
for (const test of testResults) {
if (test.status === TestReconciliationState.KnownFail) {
if (test.status === TestStatus.KnownFail) {
sorted.fail.push(test);
} else if (test.status === TestReconciliationState.KnownSkip) {
} else if (test.status === TestStatus.KnownSkip) {
sorted.skip.push(test);
} else if (test.status === TestReconciliationState.KnownSuccess) {
} else if (test.status === TestStatus.KnownSuccess) {
sorted.success.push(test);
} else {
sorted.unknown.push(test);
Expand Down
2 changes: 1 addition & 1 deletion src/TestResults/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export * from './TestReconciliationState';
export {
TestResult,
resultsWithLowerCaseWindowsDriveLetters,
TestResultStatusInfo,
TestIdentifier,
TestStatus,
} from './TestResult';
export * from './TestResultProvider';
46 changes: 35 additions & 11 deletions src/TestResults/match-by-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ import {
TestAssertionStatus,
ParsedNode,
DescribeBlock,
Location,
CodeLocation as Location,
NamedBlock,
ParsedNodeTypes,
ParsedNodeType,
} from 'jest-editor-support';
import { TestReconciliationState } from './TestReconciliationState';
import { TestResult } from './TestResult';
import { TestResult, TestStatus, LocationRange } from './TestResult';
import {
DataNode,
ContainerNode,
Expand All @@ -32,6 +31,14 @@ import {
MatchOptions,
} from './match-node';

interface MaybeWithLocation {
start?: Location;
end?: Location;
}

export const hasLocation = (loc: MaybeWithLocation): loc is LocationRange =>
loc.start != null && loc.end != null;

export const buildAssertionContainer = (
assertions: TestAssertionStatus[]
): ContainerNode<TestAssertionStatus> => {
Expand Down Expand Up @@ -80,11 +87,12 @@ export const buildSourceContainer = (sourceRoot: ParsedNode): ContainerNode<ItBl
end: namedNode.end ? adjustLocation(namedNode.end) : UnknownRange.end,
},
});
const start = (node.start?.line ?? 0) - 1;
if (isDescribeBlock(node)) {
container = new ContainerNode(node.name, node.start?.line - 1, attrs(node));
container = new ContainerNode(node.name, start, attrs(node));
parent.addContainerNode(container);
} else if (isItBlock(node)) {
parent.addDataNode(new DataNode(node.name, node.start.line - 1, node, attrs(node)));
parent.addDataNode(new DataNode(node.name, start, node, attrs(node)));
}

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

const adjustLocation = (l: Location): Location => ({ column: l.column - 1, line: l.line - 1 });
const adjustLocation = (l?: Location): Location => ({
column: l ? l.column - 1 : 0,
line: l ? l.line - 1 : 0,
});
const matchPos = (t: ItBlock, a: TestAssertionStatus, forError = false): boolean => {
if (!hasLocation(t)) {
return false;
}
const line = forError ? a.line : a.line ?? a.location?.line;
return (line != null && line >= t.start.line && line <= t.end.line) || false;
};
Expand All @@ -125,7 +139,11 @@ export const toMatchResult = (
? [undefined, undefined, assertionOrErr]
: [assertionOrErr.data, assertionOrErr.history(reason), undefined];

if (!test.start || !test.end) {
console.warn(`missing location for test block: ${test.name}`);
}
// Note the shift from one-based to zero-based line number and columns
// assumption: if we reached here, the test start/end must have been defined
return {
name: assertion?.fullName ?? assertion?.title ?? sourceName,
identifier: {
Expand All @@ -134,11 +152,15 @@ export const toMatchResult = (
},
start: adjustLocation(test.start),
end: adjustLocation(test.end),
status: assertion?.status ?? TestReconciliationState.Unknown,
status: assertion?.status ?? TestStatus.Unknown,
shortMessage: assertion?.shortMessage ?? err,
terseMessage: assertion?.terseMessage,
lineNumberOfError:
assertion?.line && matchPos(test, assertion, true) ? assertion.line - 1 : test.end.line - 1,
assertion?.line && matchPos(test, assertion, true)
? assertion.line - 1
: test.end
? test.end.line - 1
: 0,
sourceHistory,
assertionHistory,
};
Expand Down Expand Up @@ -458,8 +480,10 @@ const ContextMatch = (): ContextMatchAlgorithm => {

const { match } = ContextMatch();
const isParsedNode = (source: ParsedNode | ContainerNode<ItBlock>): source is ParsedNode =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(source as any).type in ParsedNodeTypes;
typeof source === 'object' &&
'type' in source &&
Object.values(ParsedNodeType).includes(source.type);

export const matchTestAssertions = (
fileName: string,
source: ParsedNode | ContainerNode<ItBlock>,
Expand Down
Loading
Loading