Skip to content

Commit 48a9835

Browse files
authored
chore(parser): finish migrating to vitest (#11191)
* update `vitest` to version 3.1.3 * chore(parser): finish migrating to `vitest` * fix unit-tests for `parser`
1 parent 8f79ad0 commit 48a9835

File tree

8 files changed

+88
-135
lines changed

8 files changed

+88
-135
lines changed

package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@
9898
"markdownlint-cli": "^0.44.0",
9999
"nx": "20.7.2",
100100
"prettier": "3.5.0",
101-
"pretty-format": "^29.7.0",
102101
"rimraf": "^5.0.5",
103102
"semver": "7.7.0",
104103
"tsx": "*",
@@ -116,7 +115,6 @@
116115
"@types/react": "^18.2.14",
117116
"eslint-plugin-eslint-plugin@^5.5.0": "patch:eslint-plugin-eslint-plugin@npm%3A5.5.1#./.yarn/patches/eslint-plugin-eslint-plugin-npm-5.5.1-4206c2506d.patch",
118117
"prettier": "3.5.0",
119-
"pretty-format": "^29",
120118
"react-split-pane@^0.1.92": "patch:react-split-pane@npm%3A0.1.92#./.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch",
121119
"tmp": "0.2.1",
122120
"tsx": "^4.7.2",

packages/parser/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@
4040
],
4141
"scripts": {
4242
"build": "tsc -b tsconfig.build.json",
43-
"clean": "tsc -b tsconfig.build.json --clean",
44-
"postclean": "rimraf dist/ coverage/",
43+
"clean": "rimraf dist/ coverage/",
4544
"format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore",
4645
"lint": "npx nx lint",
4746
"test": "vitest --run --config=$INIT_CWD/vitest.config.mts",

packages/parser/tests/lib/parser.test.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,30 @@ import type { ParserOptions } from '@typescript-eslint/types';
22

33
import * as scopeManager from '@typescript-eslint/scope-manager';
44
import * as typescriptESTree from '@typescript-eslint/typescript-estree';
5-
import path from 'node:path';
65
import { ScriptTarget } from 'typescript';
76

8-
import { parse, parseForESLint } from '../../src/parser';
7+
import { parse, parseForESLint } from '../../src/parser.js';
8+
import { FIXTURES_DIR } from '../test-utils/test-utils.js';
99

1010
describe('parser', () => {
11-
beforeEach(() => {
11+
afterEach(() => {
1212
vi.clearAllMocks();
1313
});
1414

15+
afterAll(() => {
16+
vi.restoreAllMocks();
17+
});
18+
1519
it('parse() should return just the AST from parseForESLint()', () => {
1620
const code = 'const valid = true;';
17-
expect(parse(code)).toEqual(parseForESLint(code).ast);
21+
expect(parse(code)).toStrictEqual(parseForESLint(code).ast);
1822
});
1923

2024
it('parseForESLint() should work if options are `null`', () => {
2125
const code = 'const valid = true;';
22-
expect(() => parseForESLint(code, null)).not.toThrow();
26+
expect(() => {
27+
parseForESLint(code, null);
28+
}).not.toThrow();
2329
});
2430

2531
it('parseAndGenerateServices() should be called with options', () => {
@@ -36,7 +42,7 @@ describe('parser', () => {
3642
extraFileExtensions: ['.foo'],
3743
filePath: './isolated-file.src.ts',
3844
project: 'tsconfig.json',
39-
tsconfigRootDir: path.join(__dirname, '..', 'fixtures', 'services'),
45+
tsconfigRootDir: FIXTURES_DIR,
4046
};
4147
parseForESLint(code, config);
4248
expect(spy).toHaveBeenCalledExactlyOnceWith(code, {
@@ -107,7 +113,7 @@ describe('parser', () => {
107113
errorOnTypeScriptSyntacticAndSemanticIssues: false,
108114
filePath: 'isolated-file.src.ts',
109115
project: 'tsconfig.json',
110-
tsconfigRootDir: path.join(__dirname, '..', 'fixtures', 'services'),
116+
tsconfigRootDir: FIXTURES_DIR,
111117
};
112118

113119
parseForESLint(code, config);
@@ -141,7 +147,7 @@ describe('parser', () => {
141147
const config: ParserOptions = {
142148
filePath: 'isolated-file.src.ts',
143149
project: 'tsconfig.json',
144-
tsconfigRootDir: path.join(__dirname, '..', 'fixtures', 'services'),
150+
tsconfigRootDir: FIXTURES_DIR,
145151
};
146152

147153
vi.spyOn(
@@ -185,7 +191,7 @@ describe('parser', () => {
185191
extraFileExtensions: ['.foo'],
186192
filePath: 'isolated-file.src.ts',
187193
project: 'tsconfig.json',
188-
tsconfigRootDir: path.join(__dirname, '..', 'fixtures', 'services'),
194+
tsconfigRootDir: FIXTURES_DIR,
189195
};
190196

191197
parseForESLint(code, config);
Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,58 @@
11
import { createProgram } from '@typescript-eslint/typescript-estree';
22
import * as glob from 'glob';
3-
import fs from 'node:fs/promises';
4-
import path from 'node:path';
5-
6-
import type { ParserOptions } from '../../src/parser';
3+
import * as fs from 'node:fs/promises';
4+
import * as path from 'node:path';
75

6+
import { parseForESLint } from '../../src/index.js';
87
import {
9-
createSnapshotTestBlock,
10-
formatSnapshotName,
11-
testServices,
12-
} from '../test-utils/test-utils';
8+
createConfig,
9+
FIXTURES_DIR,
10+
getRaw,
11+
} from '../test-utils/test-utils.js';
1312

1413
//------------------------------------------------------------------------------
1514
// Setup
1615
//------------------------------------------------------------------------------
1716

18-
const FIXTURES_DIR = path.join(
19-
__dirname,
20-
'..',
21-
'..',
22-
'tests',
23-
'fixtures',
24-
'services',
25-
);
26-
const testFiles = glob.sync(`**/*.src.ts`, {
17+
const testFiles = glob.sync('**/*.src.ts', {
18+
absolute: true,
2719
cwd: FIXTURES_DIR,
2820
});
2921

30-
function createConfig(filename: string): ParserOptions {
31-
return {
32-
filePath: filename,
33-
project: './tsconfig.json',
34-
tsconfigRootDir: path.resolve(FIXTURES_DIR),
35-
};
36-
}
37-
3822
//------------------------------------------------------------------------------
3923
// Tests
4024
//------------------------------------------------------------------------------
4125

42-
const program = createProgram(path.resolve(FIXTURES_DIR, 'tsconfig.json'));
26+
const program = createProgram(path.join(FIXTURES_DIR, 'tsconfig.json'));
4327

4428
describe.for(testFiles)('services', async filename => {
45-
const code = await fs.readFile(path.join(FIXTURES_DIR, filename), {
29+
const code = await fs.readFile(filename, {
4630
encoding: 'utf-8',
4731
});
48-
const config = createConfig(filename);
49-
const snapshotName = formatSnapshotName(filename, FIXTURES_DIR, '.ts');
50-
it(snapshotName, createSnapshotTestBlock(code, config));
32+
33+
const { base, name } = path.parse(filename);
34+
35+
const config = createConfig(base);
36+
37+
const snapshotName = path.posix.join('fixtures', name);
38+
39+
it(snapshotName, () => {
40+
const { ast } = parseForESLint(code, config);
41+
42+
const result = getRaw(ast);
43+
44+
expect(result).toMatchSnapshot();
45+
});
46+
5147
it(`${snapshotName} services`, () => {
52-
testServices(code, config);
48+
const { services } = parseForESLint(code, config);
49+
50+
assert.isNotNull(services.program);
5351
});
52+
5453
it(`${snapshotName} services with provided program`, () => {
55-
testServices(code, { ...config, program });
54+
const { services } = parseForESLint(code, { ...config, program });
55+
56+
assert.isNotNull(services.program);
5657
});
5758
});

packages/parser/tests/lib/tsx.test.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { parseForESLint } from '../../src/parser';
2-
import { serializer } from '../test-utils/ts-error-serializer';
1+
import { parseForESLint } from '../../src/index.js';
2+
import { serializer } from '../test-utils/ts-error-serializer.js';
33

44
//------------------------------------------------------------------------------
55
// Tests
@@ -12,7 +12,9 @@ describe('TSX', () => {
1212
it('filePath was not provided', () => {
1313
const code = 'const element = <T/>';
1414

15-
expect(() => parseForESLint(code)).toThrowErrorMatchingInlineSnapshot(`
15+
expect(() => {
16+
parseForESLint(code);
17+
}).toThrowErrorMatchingInlineSnapshot(`
1618
TSError {
1719
"column": 18,
1820
"index": 18,
@@ -24,22 +26,22 @@ describe('TSX', () => {
2426

2527
it("filePath was not provided and 'jsx:true' option", () => {
2628
const code = 'const element = <T/>';
27-
expect(() =>
29+
expect(() => {
2830
parseForESLint(code, {
2931
ecmaFeatures: {
3032
jsx: true,
3133
},
32-
}),
33-
).not.toThrow();
34+
});
35+
}).not.toThrow();
3436
});
3537

3638
it('test.ts', () => {
3739
const code = 'const element = <T/>';
38-
expect(() =>
40+
expect(() => {
3941
parseForESLint(code, {
4042
filePath: 'test.ts',
41-
}),
42-
).toThrowErrorMatchingInlineSnapshot(`
43+
});
44+
}).toThrowErrorMatchingInlineSnapshot(`
4345
TSError {
4446
"column": 18,
4547
"index": 18,
@@ -52,14 +54,14 @@ describe('TSX', () => {
5254
it("test.ts with 'jsx:true' option", () => {
5355
const code = 'const element = <T/>';
5456

55-
expect(() =>
57+
expect(() => {
5658
parseForESLint(code, {
5759
ecmaFeatures: {
5860
jsx: true,
5961
},
6062
filePath: 'test.ts',
61-
}),
62-
).toThrowErrorMatchingInlineSnapshot(`
63+
});
64+
}).toThrowErrorMatchingInlineSnapshot(`
6365
TSError {
6466
"column": 18,
6567
"index": 18,
@@ -71,23 +73,23 @@ describe('TSX', () => {
7173

7274
it('test.tsx', () => {
7375
const code = 'const element = <T/>';
74-
expect(() =>
76+
expect(() => {
7577
parseForESLint(code, {
7678
filePath: 'test.tsx',
77-
}),
78-
).not.toThrow();
79+
});
80+
}).not.toThrow();
7981
});
8082

8183
it("test.tsx with 'jsx:false' option", () => {
8284
const code = 'const element = <T/>';
83-
expect(() =>
85+
expect(() => {
8486
parseForESLint(code, {
8587
ecmaFeatures: {
8688
jsx: false,
8789
},
8890
filePath: 'test.tsx',
89-
}),
90-
).not.toThrow();
91+
});
92+
}).not.toThrow();
9193
});
9294
});
9395
});
Lines changed: 16 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
1+
import type { ParserOptions } from '@typescript-eslint/types';
12
import type { TSESTree } from '@typescript-eslint/typescript-estree';
23

3-
import type { ParserOptions } from '../../src/parser';
4+
import * as path from 'node:path';
45

5-
import * as parser from '../../src/parser';
6+
export const FIXTURES_DIR = path.join(__dirname, '..', 'fixtures', 'services');
67

7-
const defaultConfig = {
8+
const DEFAULT_PARSER_OPTIONS = {
89
comment: true,
910
errorOnUnknownASTType: true,
1011
loc: true,
1112
range: true,
1213
raw: true,
13-
sourceType: 'module' as const,
14+
sourceType: 'module',
1415
tokens: true,
15-
};
16+
} as const satisfies ParserOptions;
17+
18+
export function createConfig(filename: string): ParserOptions {
19+
return {
20+
...DEFAULT_PARSER_OPTIONS,
21+
filePath: filename,
22+
project: './tsconfig.json',
23+
tsconfigRootDir: FIXTURES_DIR,
24+
};
25+
}
1626

1727
/**
1828
* Returns a raw copy of the given AST
1929
* @param ast the AST object
2030
* @returns copy of the AST object
2131
*/
22-
function getRaw(ast: TSESTree.Program): TSESTree.Program {
32+
export function getRaw(ast: TSESTree.Program): TSESTree.Program {
2333
return JSON.parse(
2434
JSON.stringify(ast, (key, value) => {
2535
if ((key === 'start' || key === 'end') && typeof value === 'number') {
@@ -29,65 +39,3 @@ function getRaw(ast: TSESTree.Program): TSESTree.Program {
2939
}),
3040
);
3141
}
32-
33-
/**
34-
* Returns a function which can be used as the callback of a Jest test() block,
35-
* and which performs an assertion on the snapshot for the given code and config.
36-
* @param code The source code to parse
37-
* @param config the parser configuration
38-
* @returns callback for Jest test() block
39-
*/
40-
export function createSnapshotTestBlock(
41-
code: string,
42-
config: ParserOptions = {},
43-
): () => void {
44-
config = { ...defaultConfig, ...config };
45-
46-
/**
47-
* @returns the AST object
48-
*/
49-
function parse(): TSESTree.Program {
50-
const ast = parser.parseForESLint(code, config).ast;
51-
return getRaw(ast);
52-
}
53-
54-
return (): void => {
55-
try {
56-
const result = parse();
57-
expect(result).toMatchSnapshot();
58-
} catch (error) {
59-
/**
60-
* If we are deliberately throwing because of encountering an unknown
61-
* AST_NODE_TYPE, we rethrow to cause the test to fail
62-
*/
63-
if ((error as Error).message.includes('Unknown AST_NODE_TYPE')) {
64-
throw error;
65-
}
66-
expect(parse).toThrowErrorMatchingSnapshot();
67-
}
68-
};
69-
}
70-
71-
/**
72-
* @param code The code being parsed
73-
* @param config The configuration object for the parser
74-
*/
75-
export function testServices(code: string, config: ParserOptions = {}): void {
76-
config = { ...defaultConfig, ...config };
77-
78-
const services = parser.parseForESLint(code, config).services;
79-
expect(services).toBeDefined();
80-
expect(services.program).toBeDefined();
81-
expect(services.esTreeNodeToTSNodeMap).toBeDefined();
82-
expect(services.tsNodeToESTreeNodeMap).toBeDefined();
83-
}
84-
85-
export function formatSnapshotName(
86-
filename: string,
87-
fixturesDir: string,
88-
fileExtension = '.js',
89-
): string {
90-
return `fixtures/${filename
91-
.replace(`${fixturesDir}/`, '')
92-
.replace(fileExtension, '')}`;
93-
}

0 commit comments

Comments
 (0)