Skip to content
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
150 changes: 61 additions & 89 deletions packages/ts-plugin/e2e-test/feature/semantic-diagnostics.test.ts
Original file line number Diff line number Diff line change
@@ -1,99 +1,71 @@
import dedent from 'dedent';
import { expect, test } from 'vite-plus/test';
import { createIFF } from '../test-util/fixture.js';
import { describe, expect, test } from 'vite-plus/test';
import { buildStylesImport, buildTSConfigJSON } from '../../src/test/builder.js';
import { setupFixture } from '../test-util/fixture.js';
import { launchTsserver } from '../test-util/tsserver.js';

test('Semantic Diagnostics', async () => {
const tsserver = launchTsserver();
const iff = await createIFF({
'index.ts': dedent`
import styles from './a.module.css';
type Expected = { a_1: string, a_2: string, b_1: string, c_1: string, c_alias: string, c_3: string };
const t1: Expected = styles;
const t2: typeof styles = t1;
styles.unknown;
`,
'a.module.css': dedent`
@import './b.module.css';
@value c_1, c_2 as c_alias, c_3 from './c.module.css';
@import './unresolvable.module.css';
.a_1 { color: red; }
@value a_2: red;
`,
'b.module.css': dedent`
.b_1 { color: red; }
`,
'c.module.css': dedent`
@value c_1: red;
@value c_2: red;
`,
'tsconfig.json': dedent`
{
"compilerOptions": {},
"cmkOptions": {
"enabled": true,
"dtsOutDir": "generated"
}
}
`,
});
await tsserver.sendUpdateOpen({
openFiles: [{ file: iff.paths['index.ts'] }],
});
const res1 = await tsserver.sendSemanticDiagnosticsSync({
file: iff.paths['index.ts'],
});
expect(res1.body).toMatchInlineSnapshot(`
[
const tsserver = launchTsserver();

describe.each([{ namedExports: false }, { namedExports: true }])('namedExports: $namedExports', ({ namedExports }) => {
test('reports an unknown property access on a styles binding', async () => {
const { iff, getRange } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
'index.ts': dedent`
${buildStylesImport('./a.module.css', { namedExports })}
styles.unknown;
`,
'a.module.css': `.a_1 { color: red; }`,
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['index.ts'] }] });

const res = await tsserver.sendSemanticDiagnosticsSync({ file: iff.paths['index.ts'] });

expect(res.body).toStrictEqual([
{
"category": "error",
"code": 2339,
"end": {
"line": 5,
"offset": 15,
},
"start": {
"line": 5,
"offset": 8,
},
"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; }'.",
category: 'error',
code: 2339,
...getRange('index.ts', 'unknown'),
// The `text` is not asserted because the message contains the type shape that
// varies with `namedExports` and is owned by the TypeScript compiler, not ts-plugin.
text: expect.any(String),
},
]
`);
]);
});

const res2 = await tsserver.sendSemanticDiagnosticsSync({
file: iff.paths['a.module.css'],
test('provides the .d.ts-generated type on the styles binding', async () => {
const { iff } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
'index.ts': dedent`
${buildStylesImport('./a.module.css', { namedExports })}
type Expected = { a_1: string };
const _t: Expected = styles;
`,
'a.module.css': `.a_1 { color: red; }`,
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['index.ts'] }] });

const res = await tsserver.sendSemanticDiagnosticsSync({ file: iff.paths['index.ts'] });

expect(res.body).toStrictEqual([]);
});
expect(res2.body).toMatchInlineSnapshot(`
[
{
"category": "error",
"code": 0,
"end": {
"line": 2,
"offset": 32,
},
"source": "css-modules-kit",
"start": {
"line": 2,
"offset": 29,
},
"text": "Module './c.module.css' has no exported token 'c_3'.",
},

test('reports a semantic diagnostic on a CSS module file', async () => {
const { iff, getRange } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
'a.module.css': `@import './unresolvable.module.css';`,
});
Comment thread
mizdra marked this conversation as resolved.
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.module.css'] }] });

const res = await tsserver.sendSemanticDiagnosticsSync({ file: iff.paths['a.module.css'] });

expect(res.body).toStrictEqual([
{
"category": "error",
"code": 0,
"end": {
"line": 3,
"offset": 35,
},
"source": "css-modules-kit",
"start": {
"line": 3,
"offset": 10,
},
"text": "Cannot import module './unresolvable.module.css'",
category: 'error',
code: 0,
source: 'css-modules-kit',
text: "Cannot import module './unresolvable.module.css'",
...getRange('a.module.css', './unresolvable.module.css'),
},
]
`);
]);
});
});
94 changes: 23 additions & 71 deletions packages/ts-plugin/e2e-test/feature/syntactic-diagnostics.test.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,28 @@
import dedent from 'dedent';
import { expect, test } from 'vite-plus/test';
import { createIFF } from '../test-util/fixture.js';
import { describe, expect, test } from 'vite-plus/test';
import { buildTSConfigJSON } from '../../src/test/builder.js';
import { setupFixture } from '../test-util/fixture.js';
import { launchTsserver } from '../test-util/tsserver.js';

test('Syntactic Diagnostics', async () => {
const tsserver = launchTsserver();
const iff = await createIFF({
'a.module.css': dedent`
@value;
:local(:global(.a_1)) { color: red; }
:local .a_2 { color: red; }
`,
'tsconfig.json': dedent`
{
"compilerOptions": {},
"cmkOptions": {
"enabled": true,
"dtsOutDir": "generated"
}
}
`,
});
await tsserver.sendUpdateOpen({
openFiles: [{ file: iff.paths['a.module.css'] }],
});
const res1 = await tsserver.sendSyntacticDiagnosticsSync({
file: iff.paths['a.module.css'],
});
expect(res1.body).toMatchInlineSnapshot(`
[
{
"category": "error",
"code": 0,
"end": {
"line": 1,
"offset": 8,
},
"source": "css-modules-kit",
"start": {
"line": 1,
"offset": 1,
},
"text": "\`@value\` is a invalid syntax.",
},
{
"category": "error",
"code": 0,
"end": {
"line": 2,
"offset": 21,
},
"source": "css-modules-kit",
"start": {
"line": 2,
"offset": 8,
},
"text": "A \`:global(...)\` is not allowed inside of \`:local(...)\`.",
},
const tsserver = launchTsserver();

describe.each([{ namedExports: false }, { namedExports: true }])('namedExports: $namedExports', ({ namedExports }) => {
test('reports a syntactic diagnostic on a CSS module file', async () => {
const { iff, getRange } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
'a.module.css': `@value;`,
Comment thread
mizdra marked this conversation as resolved.
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.module.css'] }] });

const res = await tsserver.sendSyntacticDiagnosticsSync({ file: iff.paths['a.module.css'] });

expect(res.body).toStrictEqual([
{
"category": "error",
"code": 0,
"end": {
"line": 3,
"offset": 7,
},
"source": "css-modules-kit",
"start": {
"line": 3,
"offset": 1,
},
"text": "css-modules-kit does not support \`:local\`. Use \`:local(...)\` instead.",
category: 'error',
code: 0,
source: 'css-modules-kit',
text: '`@value` is a invalid syntax.',
...getRange('a.module.css', '@value;'),
},
]
`);
]);
});
});
Loading
Loading