Skip to content

Commit 43f82ae

Browse files
mizdraclaude
andauthored
test(ts-plugin): split diagnostics and file-operation e2e tests (#381)
* test(ts-plugin): split diagnostics and file-operation e2e tests into per-behavior cases Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ts-plugin): add hover e2e test for the styles binding type Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ts-plugin): flatten describe groups in semantic-diagnostics e2e test Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ts-plugin): consolidate semantic-diagnostics e2e test to a single representative case Exhaustive coverage of core checker diagnostic kinds is owned by packages/core/src/checker.test.ts. The e2e test now keeps only one representative case to verify that a CSS-side diagnostic surfaces in tsserver via ts-plugin. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ts-plugin): rename the consolidated semantic-diagnostics e2e test to focus on the behavior Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ts-plugin): consolidate syntactic-diagnostics e2e test to a single representative case Exhaustive coverage of parser-side diagnostic kinds is owned by the parser tests under packages/core/src/parser/. The e2e test now keeps only one representative case to verify that a CSS-side syntactic diagnostic surfaces in tsserver via ts-plugin. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ts-plugin): drop redundant comments from diagnostics e2e tests Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(ts-plugin): consolidate file-operation e2e tests around importer diagnostic updates Restore the original 1-test-per-file-operation structure and rename each test to focus on the behavior being verified: that adding, modifying, or removing a CSS module updates the importer's diagnostics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Revert "test(ts-plugin): add hover e2e test for the styles binding type" This reverts commit c3f8e95. * test(ts-plugin): verify the styles binding type via assignment in semantic-diagnostics e2e Replaces the reverted hover-based check with a structural type assignment (`type Expected = { a_1: string }; const _t: Expected = styles;`) inside semantic-diagnostics.test.ts. This avoids hard-coding the TypeScript compiler's hover wording while still exercising the .d.ts-generated type on the styles binding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4563420 commit 43f82ae

3 files changed

Lines changed: 158 additions & 304 deletions

File tree

Lines changed: 61 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,71 @@
11
import dedent from 'dedent';
2-
import { expect, test } from 'vite-plus/test';
3-
import { createIFF } from '../test-util/fixture.js';
2+
import { describe, expect, test } from 'vite-plus/test';
3+
import { buildStylesImport, buildTSConfigJSON } from '../../src/test/builder.js';
4+
import { setupFixture } from '../test-util/fixture.js';
45
import { launchTsserver } from '../test-util/tsserver.js';
56

6-
test('Semantic Diagnostics', async () => {
7-
const tsserver = launchTsserver();
8-
const iff = await createIFF({
9-
'index.ts': dedent`
10-
import styles from './a.module.css';
11-
type Expected = { a_1: string, a_2: string, b_1: string, c_1: string, c_alias: string, c_3: string };
12-
const t1: Expected = styles;
13-
const t2: typeof styles = t1;
14-
styles.unknown;
15-
`,
16-
'a.module.css': dedent`
17-
@import './b.module.css';
18-
@value c_1, c_2 as c_alias, c_3 from './c.module.css';
19-
@import './unresolvable.module.css';
20-
.a_1 { color: red; }
21-
@value a_2: red;
22-
`,
23-
'b.module.css': dedent`
24-
.b_1 { color: red; }
25-
`,
26-
'c.module.css': dedent`
27-
@value c_1: red;
28-
@value c_2: red;
29-
`,
30-
'tsconfig.json': dedent`
31-
{
32-
"compilerOptions": {},
33-
"cmkOptions": {
34-
"enabled": true,
35-
"dtsOutDir": "generated"
36-
}
37-
}
38-
`,
39-
});
40-
await tsserver.sendUpdateOpen({
41-
openFiles: [{ file: iff.paths['index.ts'] }],
42-
});
43-
const res1 = await tsserver.sendSemanticDiagnosticsSync({
44-
file: iff.paths['index.ts'],
45-
});
46-
expect(res1.body).toMatchInlineSnapshot(`
47-
[
7+
const tsserver = launchTsserver();
8+
9+
describe.each([{ namedExports: false }, { namedExports: true }])('namedExports: $namedExports', ({ namedExports }) => {
10+
test('reports an unknown property access on a styles binding', async () => {
11+
const { iff, getRange } = await setupFixture({
12+
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
13+
'index.ts': dedent`
14+
${buildStylesImport('./a.module.css', { namedExports })}
15+
styles.unknown;
16+
`,
17+
'a.module.css': `.a_1 { color: red; }`,
18+
});
19+
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['index.ts'] }] });
20+
21+
const res = await tsserver.sendSemanticDiagnosticsSync({ file: iff.paths['index.ts'] });
22+
23+
expect(res.body).toStrictEqual([
4824
{
49-
"category": "error",
50-
"code": 2339,
51-
"end": {
52-
"line": 5,
53-
"offset": 15,
54-
},
55-
"start": {
56-
"line": 5,
57-
"offset": 8,
58-
},
59-
"text": "Property 'unknown' does not exist on type '{ c_1: string; c_alias: string; c_3: any; b_1: string; a_1: string; a_2: string; }'.",
25+
category: 'error',
26+
code: 2339,
27+
...getRange('index.ts', 'unknown'),
28+
// The `text` is not asserted because the message contains the type shape that
29+
// varies with `namedExports` and is owned by the TypeScript compiler, not ts-plugin.
30+
text: expect.any(String),
6031
},
61-
]
62-
`);
32+
]);
33+
});
6334

64-
const res2 = await tsserver.sendSemanticDiagnosticsSync({
65-
file: iff.paths['a.module.css'],
35+
test('provides the .d.ts-generated type on the styles binding', async () => {
36+
const { iff } = await setupFixture({
37+
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
38+
'index.ts': dedent`
39+
${buildStylesImport('./a.module.css', { namedExports })}
40+
type Expected = { a_1: string };
41+
const _t: Expected = styles;
42+
`,
43+
'a.module.css': `.a_1 { color: red; }`,
44+
});
45+
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['index.ts'] }] });
46+
47+
const res = await tsserver.sendSemanticDiagnosticsSync({ file: iff.paths['index.ts'] });
48+
49+
expect(res.body).toStrictEqual([]);
6650
});
67-
expect(res2.body).toMatchInlineSnapshot(`
68-
[
69-
{
70-
"category": "error",
71-
"code": 0,
72-
"end": {
73-
"line": 2,
74-
"offset": 32,
75-
},
76-
"source": "css-modules-kit",
77-
"start": {
78-
"line": 2,
79-
"offset": 29,
80-
},
81-
"text": "Module './c.module.css' has no exported token 'c_3'.",
82-
},
51+
52+
test('reports a semantic diagnostic on a CSS module file', async () => {
53+
const { iff, getRange } = await setupFixture({
54+
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
55+
'a.module.css': `@import './unresolvable.module.css';`,
56+
});
57+
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.module.css'] }] });
58+
59+
const res = await tsserver.sendSemanticDiagnosticsSync({ file: iff.paths['a.module.css'] });
60+
61+
expect(res.body).toStrictEqual([
8362
{
84-
"category": "error",
85-
"code": 0,
86-
"end": {
87-
"line": 3,
88-
"offset": 35,
89-
},
90-
"source": "css-modules-kit",
91-
"start": {
92-
"line": 3,
93-
"offset": 10,
94-
},
95-
"text": "Cannot import module './unresolvable.module.css'",
63+
category: 'error',
64+
code: 0,
65+
source: 'css-modules-kit',
66+
text: "Cannot import module './unresolvable.module.css'",
67+
...getRange('a.module.css', './unresolvable.module.css'),
9668
},
97-
]
98-
`);
69+
]);
70+
});
9971
});
Lines changed: 23 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,28 @@
1-
import dedent from 'dedent';
2-
import { expect, test } from 'vite-plus/test';
3-
import { createIFF } from '../test-util/fixture.js';
1+
import { describe, expect, test } from 'vite-plus/test';
2+
import { buildTSConfigJSON } from '../../src/test/builder.js';
3+
import { setupFixture } from '../test-util/fixture.js';
44
import { launchTsserver } from '../test-util/tsserver.js';
55

6-
test('Syntactic Diagnostics', async () => {
7-
const tsserver = launchTsserver();
8-
const iff = await createIFF({
9-
'a.module.css': dedent`
10-
@value;
11-
:local(:global(.a_1)) { color: red; }
12-
:local .a_2 { color: red; }
13-
`,
14-
'tsconfig.json': dedent`
15-
{
16-
"compilerOptions": {},
17-
"cmkOptions": {
18-
"enabled": true,
19-
"dtsOutDir": "generated"
20-
}
21-
}
22-
`,
23-
});
24-
await tsserver.sendUpdateOpen({
25-
openFiles: [{ file: iff.paths['a.module.css'] }],
26-
});
27-
const res1 = await tsserver.sendSyntacticDiagnosticsSync({
28-
file: iff.paths['a.module.css'],
29-
});
30-
expect(res1.body).toMatchInlineSnapshot(`
31-
[
32-
{
33-
"category": "error",
34-
"code": 0,
35-
"end": {
36-
"line": 1,
37-
"offset": 8,
38-
},
39-
"source": "css-modules-kit",
40-
"start": {
41-
"line": 1,
42-
"offset": 1,
43-
},
44-
"text": "\`@value\` is a invalid syntax.",
45-
},
46-
{
47-
"category": "error",
48-
"code": 0,
49-
"end": {
50-
"line": 2,
51-
"offset": 21,
52-
},
53-
"source": "css-modules-kit",
54-
"start": {
55-
"line": 2,
56-
"offset": 8,
57-
},
58-
"text": "A \`:global(...)\` is not allowed inside of \`:local(...)\`.",
59-
},
6+
const tsserver = launchTsserver();
7+
8+
describe.each([{ namedExports: false }, { namedExports: true }])('namedExports: $namedExports', ({ namedExports }) => {
9+
test('reports a syntactic diagnostic on a CSS module file', async () => {
10+
const { iff, getRange } = await setupFixture({
11+
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
12+
'a.module.css': `@value;`,
13+
});
14+
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.module.css'] }] });
15+
16+
const res = await tsserver.sendSyntacticDiagnosticsSync({ file: iff.paths['a.module.css'] });
17+
18+
expect(res.body).toStrictEqual([
6019
{
61-
"category": "error",
62-
"code": 0,
63-
"end": {
64-
"line": 3,
65-
"offset": 7,
66-
},
67-
"source": "css-modules-kit",
68-
"start": {
69-
"line": 3,
70-
"offset": 1,
71-
},
72-
"text": "css-modules-kit does not support \`:local\`. Use \`:local(...)\` instead.",
20+
category: 'error',
21+
code: 0,
22+
source: 'css-modules-kit',
23+
text: '`@value` is a invalid syntax.',
24+
...getRange('a.module.css', '@value;'),
7325
},
74-
]
75-
`);
26+
]);
27+
});
7628
});

0 commit comments

Comments
 (0)