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

upgrade jest-snapshot to v30 and cleanup types #117

Merged
merged 1 commit 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
@@ -1,6 +1,6 @@
{
"name": "jest-editor-support",
"version": "32.0.0-beta.0",
"version": "32.0.0-beta.1",
"repository": {
"type": "git",
"url": "https://github.com/jest-community/jest-editor-support"
Expand All @@ -10,7 +10,7 @@
"scripts": {
"clean": "rimraf ./build ./index.d.ts",
"build": "tsc --noEmit",
"build:types": "dts-bundle-generator -o ./index.d.ts src/index.ts",
"build:types": "dts-bundle-generator -o ./index.d.ts src/index.ts --project ./tsconfig.types.json",
"build:prod": "yarn clean & tsc -p tsconfig.prod.json",
"prepublish": "yarn build:prod && yarn build:types",
"test": "jest",
Expand All @@ -24,10 +24,10 @@
"devDependencies": {
"@babel/core": "^7.20.12",
"@types/jest": "^29.2.4",
"@types/node": "^18.11.16",
"@types/node": "^20.12.7",
"@typescript-eslint/eslint-plugin": "^5.46.1",
"@typescript-eslint/parser": "^5.46.1",
"dts-bundle-generator": "^9.3.1",
"dts-bundle-generator": "^9.5.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^27.9.0",
Expand All @@ -42,9 +42,10 @@
"@babel/parser": "^7.20.7",
"@babel/traverse": "7.23.2",
"@babel/types": "^7.20.7",
"@jest/snapshot-utils": "^30.0.0-alpha.5",
"@jest/test-result": "^29.3.1",
"@jest/types": "^29.3.1",
"jest-snapshot": "^27.2.0"
"jest-snapshot": "^30.0.0-alpha.5"
},
"jest": {
"preset": "ts-jest",
Expand Down
44 changes: 30 additions & 14 deletions src/Runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,47 @@ import type {Options, MessageType} from './types';
import ProjectWorkspace from './project_workspace';
import {createProcess} from './Process';

export type RunnerEvent =
| 'processClose'
| 'processExit'
| 'executableJSON'
| 'executableStdErr'
| 'executableOutput'
| 'terminalError';
export type RunnerEventMap = {
processClose: [code: number | null, signal: string | null];
processExit: [code: number | null, signal: string | null];
executableJSON: [data: object, {noTestsFound: boolean}];
executableStdErr: [data: Buffer, {type: MessageType}];
executableOutput: [data: string];
terminalError: [error: string];
debuggerProcessExit: [];
};

export type AllRunnerEvent = keyof RunnerEventMap;
export type RunnerEvent = Exclude<AllRunnerEvent, 'debuggerProcessExit'>;

// This class represents the running process, and
// passes out events when it understands what data is being
// pass sent out of the process
export default class Runner extends EventEmitter {
export default class Runner extends EventEmitter<RunnerEventMap> {
/** @internal */
runProcess?: ChildProcess;

/** @internal */
outputPath: string;

/** @internal */
workspace: ProjectWorkspace;

_createProcess: (workspace: ProjectWorkspace, args: string[]) => ChildProcess;
/** @internal */
private _createProcess: (workspace: ProjectWorkspace, args: string[]) => ChildProcess;

watchMode = false;

watchAll = false;

/** @internal */
options: Options;

/** @internal */
prevMessageTypes: MessageType[];

_exited: boolean;
/** @internal */
private _exited: boolean;

constructor(workspace: ProjectWorkspace, options?: Options) {
super();
Expand All @@ -56,7 +68,8 @@ export default class Runner extends EventEmitter {
this._exited = false;
}

__convertDashedArgs(args: string[]): string[] {
/** @internal */
private __convertDashedArgs(args: string[]): string[] {
if (!this.workspace.useDashedArgs) {
return args;
}
Expand All @@ -66,7 +79,8 @@ export default class Runner extends EventEmitter {
);
}

_getArgs(): string[] {
/** @internal */
private _getArgs(): string[] {
if (this.options.args && this.options.args.replace) {
return this.options.args.skipConversion
? this.options.args.args
Expand Down Expand Up @@ -153,6 +167,7 @@ export default class Runner extends EventEmitter {
}

/**
* @internal
* parse the stdin/out stream buffer for recognized messages.
*
* note: if these messages coming in in separate chucks, we might not be able to
Expand All @@ -165,7 +180,7 @@ export default class Runner extends EventEmitter {
* @returns {MessageType}
* @memberof Runner
*/
_parseOutput(data: Buffer, isStdErr: boolean): MessageType {
private _parseOutput(data: Buffer, isStdErr: boolean): MessageType {
const msgType = this.findMessageType(data);
switch (msgType) {
case MessageTypes.testResults:
Expand Down Expand Up @@ -248,7 +263,7 @@ export default class Runner extends EventEmitter {
this.runProcess = undefined;
}

// eslint-disable-next-line class-methods-use-this
/** @internal */
findMessageType(buf: Buffer): MessageType {
const noTestRegex = /No tests found related to files changed since ((last commit)|("[a-z0-9]+"))./;
const watchUsageRegex = /^\s*Watch Usage\b/;
Expand All @@ -265,6 +280,7 @@ export default class Runner extends EventEmitter {
return match ? match.messageType : MessageTypes.unknown;
}

/** @internal */
doResultsFollowNoTestsFoundMessage(): boolean {
if (this.prevMessageTypes.length === 1) {
return this.prevMessageTypes[0] === MessageTypes.noTests;
Expand Down
32 changes: 16 additions & 16 deletions src/Snapshot.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
Expand All @@ -13,17 +9,15 @@

import traverse, {NodePath} from '@babel/traverse';
import * as t from '@babel/types';
import type {SnapshotResolver} from 'jest-snapshot';
import {buildSnapshotResolver, utils} from 'jest-snapshot';
import {SnapshotResolver, buildSnapshotResolver} from 'jest-snapshot';
import * as utils from '@jest/snapshot-utils';
import type {Config} from '@jest/types';

import {getASTfor} from './parsers/babel_parser';
import type {JESParserOptions} from './parsers';
import {shallowAttr} from './parsers/helper';
import {SnapshotData} from 'jest-snapshot/build/types';

type ParserFunc = typeof getASTfor;

export type SnapshotNode = t.Identifier;
export interface SnapshotBlock {
node: SnapshotNode;
Expand Down Expand Up @@ -106,15 +100,20 @@ export interface SnapshotParserOptions {
parserOptions?: JESParserOptions;
}
export default class Snapshot {
_parser: ParserFunc;
/** @internal */
private _parser: ParserFunc;

_matchers: string[];
/** @internal */
private _matchers: string[];

_projectConfig?: Config.ProjectConfig;
/** @internal */
private _projectConfig?: Config.ProjectConfig;

snapshotResolver?: SnapshotResolver;
/** @internal */
private snapshotResolver?: SnapshotResolver;

_resolverPromise: Promise<SnapshotResolver>;
/** @internal */
private _resolverPromise: Promise<SnapshotResolver>;

constructor(parser?: ParserFunc, customMatchers?: string[], projectConfig?: Config.ProjectConfig) {
this._parser = parser || getASTfor;
Expand Down Expand Up @@ -160,7 +159,8 @@ export default class Snapshot {
}));
}

async _getSnapshotResolver(): Promise<SnapshotResolver> {
/** @internal */
private async _getSnapshotResolver(): Promise<SnapshotResolver> {
if (!this.snapshotResolver) {
this.snapshotResolver = await this._resolverPromise;
}
Expand All @@ -175,7 +175,7 @@ export default class Snapshot {
* a SnapshotData object will be returned with all matched snapshots. If nothing matched, null will be returned.
* @throws throws exception if the snapshot version mismatched or any other unexpected error.
*/
async getSnapshotContent(filePath: string, name: string | RegExp): Promise<string | SnapshotData | null> {
async getSnapshotContent(filePath: string, name: string | RegExp): Promise<string | utils.SnapshotData | null> {
const snapshotResolver = await this._getSnapshotResolver();

const snapshotPath = snapshotResolver.resolveSnapshotPath(filePath);
Expand All @@ -184,7 +184,7 @@ export default class Snapshot {
return snapshots[name];
}
const regex = name;
const data: SnapshotData = {};
const data: utils.SnapshotData = {};
Object.entries(snapshots).forEach(([key, value]) => {
if (regex.test(key)) {
data[key] = value;
Expand Down
24 changes: 15 additions & 9 deletions src/__tests__/snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,26 @@

import path from 'path';
import Snapshot from '../Snapshot';
import jestSnapshot from 'jest-snapshot';
import * as jestSnapshot from 'jest-snapshot';

jest.mock('jest-snapshot', () => {
const original = jest.requireActual('jest-snapshot');
return {
...original,
buildSnapshotResolver: jest.fn(),
};
});

const snapshotFixturePath = path.resolve(__dirname, 'fixtures/snapshots');

describe('Snapshot', () => {
let buildSnapshotResolverSpy: jest.SpyInstance;
let snapshotHelper: Snapshot;
beforeEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
(jestSnapshot.buildSnapshotResolver as jest.Mocked<any>).mockImplementation(
jest.requireActual('jest-snapshot').buildSnapshotResolver
);
snapshotHelper = new Snapshot();
buildSnapshotResolverSpy = jest.spyOn(jestSnapshot, 'buildSnapshotResolver');
});
afterEach(() => {
jest.restoreAllMocks();
});

describe('getMetadata', () => {
Expand Down Expand Up @@ -134,7 +140,7 @@ describe('Snapshot', () => {
});
it('when the resolver is not yet ready', () => {
// simulate when buildSnapshotResolver did not resolve yet
buildSnapshotResolverSpy.mockImplementation((() => {
(jestSnapshot.buildSnapshotResolver as jest.Mocked<any>).mockImplementation((() => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
return new Promise(() => {});
}) as any);
Expand Down Expand Up @@ -239,7 +245,7 @@ describe('Snapshot', () => {
const snapshot = new Snapshot(undefined, undefined, customConfig);
const filePath = path.join(snapshotFixturePath, 'inline-and-each.example');
await snapshot.getSnapshotContent(filePath, /not existing test/);
expect(buildSnapshotResolverSpy).toHaveBeenCalledWith(customConfig, expect.any(Function));
expect(jestSnapshot.buildSnapshotResolver).toHaveBeenCalledWith(customConfig, expect.any(Function));
});
});
});
15 changes: 10 additions & 5 deletions src/test_reconciler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ export type TestFileAssertionStatus = Omit<JestFileResults, 'status' | 'assertio
* at a file level, generating useful error messages and providing a nice API.
*/
export default class TestReconciler {
fileStatuses: {[key: string]: TestFileAssertionStatus};
/** @internal */
private fileStatuses: {[key: string]: TestFileAssertionStatus};

constructor() {
this.fileStatuses = {};
Expand Down Expand Up @@ -93,7 +94,8 @@ export default class TestReconciler {
// we don't get this as structured data, but what we get
// is useful enough to make it for ourselves

mapAssertions(filename: string, assertions: JestAssertionResults[]): TestAssertionStatus[] {
/** @internal */
private mapAssertions(filename: string, assertions: JestAssertionResults[]): TestAssertionStatus[] {
// convert jest location (column is 0-based and line is 1-based) to all 0-based location used internally in this package
/* eslint-disable no-param-reassign */
const convertJestLocation = (jestLocation?: CodeLocation) => {
Expand Down Expand Up @@ -135,7 +137,8 @@ export default class TestReconciler {
}

// Do everything we can to try make a one-liner from the error report
sanitizeShortErrorMessage(string: string): string {
/** @internal */
private sanitizeShortErrorMessage(string: string): string {
if (string.includes('does not match stored snapshot')) {
return 'Snapshot has changed';
}
Expand All @@ -154,13 +157,15 @@ export default class TestReconciler {
}

// Pull the line out from the stack trace
lineOfError(message: string, filePath: string): number | undefined {
/** @internal */
private lineOfError(message: string, filePath: string): number | undefined {
const filename = path.basename(filePath);
const restOfTrace = message.split(filename, 2)[1];
return restOfTrace ? parseInt(restOfTrace.split(':')[1], 10) : undefined;
}

statusToReconciliationState(status: string): TestReconciliationState {
/** @internal */
private statusToReconciliationState(status: string): TestReconciliationState {
switch (status) {
case 'passed':
return 'KnownSuccess';
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
},
"include": ["./src/**/*.ts", "src/__tests__/parsers/helper.test.ts"]
"include": ["./src/**/*.ts"],
}
3 changes: 2 additions & 1 deletion tsconfig.prod.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"sourceMap": false, // Disable source maps for production
"declaration": false, // Disable declaration files generation
"outDir": "./build", // Output directory for compiled JS files
"removeComments": true // Optional: Remove comments in the production build
"removeComments": true, // Optional: Remove comments in the production build
"stripInternal": true,
},
"exclude": [
"**/__tests__/**", // Exclude all test files
Expand Down
6 changes: 6 additions & 0 deletions tsconfig.types.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "./tsconfig.prod.json",
"compilerOptions": {
"removeComments": false, // Optional: Remove comments in the production build
},
}
Loading
Loading