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
26 changes: 11 additions & 15 deletions packages/ts-plugin/e2e-test/disabled.test.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import dedent from 'dedent';
import { expect, test } from 'vite-plus/test';
import { createIFF } from './test-util/fixture.js';
import { setupFixture } from './test-util/fixture.js';
import { launchTsserver, normalizeDefinitions } from './test-util/tsserver.js';

test('does not provide language features when cmkOptions.enabled is false', async () => {
const tsserver = launchTsserver();
const iff = await createIFF({
const tsserver = launchTsserver();

test('returns no Go to Definition results when cmkOptions.enabled is false', async () => {
const { iff, getLoc } = await setupFixture({
'tsconfig.json': `{ "cmkOptions": { "enabled": false } }`,
'index.ts': dedent`
import styles from './a.module.css';
styles.a_1;
`,
'a.module.css': dedent`
.a_1 { color: red; }
`,
'tsconfig.json': dedent`
{ "cmkOptions": { "enabled": false } }
`,
});
await tsserver.sendUpdateOpen({
openFiles: [{ file: iff.paths['index.ts'] }],
'a.module.css': `.a_1 { color: red; }`,
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['index.ts'] }] });

const res = await tsserver.sendDefinitionAndBoundSpan({
file: iff.paths['index.ts'],
line: 2,
offset: 8,
...getLoc('index.ts', 'a_1'),
});

expect(normalizeDefinitions(res.body?.definitions ?? [])).toStrictEqual([]);
});
114 changes: 63 additions & 51 deletions packages/ts-plugin/e2e-test/feature/refactor.test.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1,83 @@
import dedent from 'dedent';
import { describe, expect, test } from 'vite-plus/test';
import { createCssModuleFileRefactor } from '../../src/language-service/feature/refactor.js';
import { createIFF } from '../test-util/fixture.js';
import { buildTSConfigJSON } from '../../src/test/builder.js';
import { setupFixture } from '../test-util/fixture.js';
import { launchTsserver } from '../test-util/tsserver.js';

describe('Refactor', async () => {
const tsserver = launchTsserver();
const iff = await createIFF({
'a.tsx': '',
'b.ts': '',
'tsconfig.json': dedent`
{
"compilerOptions": { "jsx": "react-jsx" },
"cmkOptions": {
"enabled": true,
"dtsOutDir": "generated"
}
}
`,
});
await tsserver.sendUpdateOpen({
openFiles: [{ file: iff.paths['a.tsx'] }],
});
test.each([
{
name: 'a.tsx',
const tsserver = launchTsserver();

describe('Get Applicable Refactors', () => {
test('offers Create CSS Module file for a component file when no paired CSS module exists', async () => {
const { iff } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ compilerOptions: { jsx: 'react-jsx' } }),
'a.tsx': '',
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.tsx'] }] });

const res = await tsserver.sendGetApplicableRefactors({
file: iff.paths['a.tsx'],
line: 1,
offset: 1,
expected: [createCssModuleFileRefactor],
},
{
name: 'b.ts',
file: iff.paths['b.ts'],
});

expect(res.body).toStrictEqual([createCssModuleFileRefactor]);
});

test('omits Create CSS Module file for a non-component file', async () => {
const { iff } = await setupFixture({
'tsconfig.json': buildTSConfigJSON(),
'a.ts': '',
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.ts'] }] });

const res = await tsserver.sendGetApplicableRefactors({
file: iff.paths['a.ts'],
line: 1,
offset: 1,
expected: [],
},
])('Get Applicable Refactors for $name', async ({ file, line, offset, expected }) => {
const res = await tsserver.sendGetApplicableRefactors({
file,
line,
offset,
});
expect(res.body).toStrictEqual(expected);

expect(res.body).toStrictEqual([]);
});
test.each([
{
name: 'a.tsx',

test('omits Create CSS Module file when the paired CSS module already exists', async () => {
const { iff } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ compilerOptions: { jsx: 'react-jsx' } }),
'a.tsx': '',
'a.module.css': '',
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.tsx'] }] });

const res = await tsserver.sendGetApplicableRefactors({
file: iff.paths['a.tsx'],
line: 1,
offset: 1,
expected: [
{
fileName: iff.join('a.module.css'),
textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: '' }],
},
],
},
])('Get Edits For Refactor for $name', async ({ file, line, offset, expected }) => {
});

expect(res.body).toStrictEqual([]);
});
});

describe('Get Edits For Refactor', () => {
test('emits an edit that creates a new empty CSS module file paired with the component file', async () => {
const { iff } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ compilerOptions: { jsx: 'react-jsx' } }),
'a.tsx': '',
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.tsx'] }] });

const res = await tsserver.sendGetEditsForRefactor({
refactor: createCssModuleFileRefactor.name,
action: createCssModuleFileRefactor.actions[0].name,
file,
line,
offset,
file: iff.paths['a.tsx'],
line: 1,
offset: 1,
});
expect(res.body?.edits).toStrictEqual(expected);

expect(res.body?.edits).toStrictEqual([
{
fileName: iff.join('a.module.css'),
textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: '' }],
},
]);
});
});
120 changes: 59 additions & 61 deletions packages/ts-plugin/e2e-test/feature/rename-file.test.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,73 @@
import dedent from 'dedent';
import { describe, expect, test } from 'vite-plus/test';
import { createIFF } from '../test-util/fixture.js';
import { buildStylesImport, buildTSConfigJSON } from '../../src/test/builder.js';
import { setupFixture } from '../test-util/fixture.js';
import { formatPath, launchTsserver } from '../test-util/tsserver.js';

describe('Rename File', async () => {
const tsserver = launchTsserver();
const iff = await createIFF({
'index.ts': dedent`
import styles from './a.module.css';
`,
'a.module.css': dedent`
@import './b.module.css';
@value c_1 from './c.module.css';
`,
'b.module.css': dedent`
.b_1 { color: red; }
`,
'c.module.css': dedent`
@value c_1: red;
`,
'tsconfig.json': dedent`
{
"compilerOptions": {
"paths": { "@/*": ["./*"] }
},
"cmkOptions": {
"enabled": true,
"dtsOutDir": "generated"
}
}
`,
});
await tsserver.sendUpdateOpen({
openFiles: [{ file: iff.paths['index.ts'] }],
});
test.each([
{
name: 'a.module.css',
oldFilePath: iff.paths['a.module.css'],
newFilePath: iff.join('aa.module.css'),
expected: [
const tsserver = launchTsserver();

describe.each([{ namedExports: false }, { namedExports: true }])('namedExports: $namedExports', ({ namedExports }) => {
describe('rewrites the import specifier when a CSS module is renamed', () => {
test('from `import ... from` in TS', async () => {
const { iff, getRange } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
'index.ts': buildStylesImport('./a.module.css', { namedExports }),
'a.module.css': '',
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['index.ts'] }] });

const res = await tsserver.sendGetEditsForFileRename({
oldFilePath: iff.paths['a.module.css'],
newFilePath: iff.join('aa.module.css'),
});

expect(res.body).toStrictEqual([
{
fileName: formatPath(iff.paths['index.ts']),
textChanges: [{ start: { line: 1, offset: 21 }, end: { line: 1, offset: 35 }, newText: './aa.module.css' }],
textChanges: [{ ...getRange('index.ts', './a.module.css'), newText: './aa.module.css' }],
},
],
},
{
name: 'b.module.css',
oldFilePath: iff.paths['b.module.css'],
newFilePath: iff.join('bb.module.css'),
expected: [
]);
});

test('from `@import` in CSS', async () => {
const { iff, getRange } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
'a.module.css': `@import './b.module.css';`,
'b.module.css': '',
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.module.css'] }] });

const res = await tsserver.sendGetEditsForFileRename({
oldFilePath: iff.paths['b.module.css'],
newFilePath: iff.join('bb.module.css'),
});

expect(res.body).toStrictEqual([
{
fileName: formatPath(iff.paths['a.module.css']),
textChanges: [{ start: { line: 1, offset: 10 }, end: { line: 1, offset: 24 }, newText: './bb.module.css' }],
textChanges: [{ ...getRange('a.module.css', './b.module.css'), newText: './bb.module.css' }],
},
],
},
{
name: 'c.module.css',
oldFilePath: iff.paths['c.module.css'],
newFilePath: iff.join('cc.module.css'),
expected: [
]);
});

test('from `@value ... from` in CSS', async () => {
const { iff, getRange } = await setupFixture({
'tsconfig.json': buildTSConfigJSON({ cmkOptions: { namedExports } }),
'a.module.css': `@value b_1 from './b.module.css';`,
'b.module.css': `@value b_1: red;`,
});
await tsserver.sendUpdateOpen({ openFiles: [{ file: iff.paths['a.module.css'] }] });

const res = await tsserver.sendGetEditsForFileRename({
oldFilePath: iff.paths['b.module.css'],
newFilePath: iff.join('bb.module.css'),
});

expect(res.body).toStrictEqual([
{
fileName: formatPath(iff.paths['a.module.css']),
textChanges: [{ start: { line: 2, offset: 18 }, end: { line: 2, offset: 32 }, newText: './cc.module.css' }],
textChanges: [{ ...getRange('a.module.css', './b.module.css'), newText: './bb.module.css' }],
},
],
},
])('for $name', async ({ oldFilePath, newFilePath, expected }) => {
const res = await tsserver.sendGetEditsForFileRename({ oldFilePath, newFilePath });
expect(res.body).toStrictEqual(expected);
]);
});
});
});
64 changes: 24 additions & 40 deletions packages/ts-plugin/e2e-test/ignore-generated-files.test.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,36 @@
import dedent from 'dedent';
import { expect, test } from 'vite-plus/test';
import { createIFF } from './test-util/fixture.js';
import { setupFixture } from './test-util/fixture.js';
import { launchTsserver } from './test-util/tsserver.js';

test('report the import of files where .d.ts exists but .module.css does not exist', async () => {
const tsserver = launchTsserver();
const iff = await createIFF({
// `a.module.css` is not exist, and the .d.ts file is exist.
// But `'./a.module.css'` should report an error.
'index.ts': dedent`
import styles from './a.module.css';
`,
'generated/a.module.css.d.ts': dedent`
const styles: {};
export default styles;
`,
const tsserver = launchTsserver();

test('excludes generated .d.ts files from module resolution even when listed in rootDirs', async () => {
const { iff, getRange } = await setupFixture({
'tsconfig.json': dedent`
{
"compilerOptions": {
"rootDirs": [".", "generated"],
"rootDirs": [".", "generated"]
},
"cmkOptions": {
"enabled": true
}
"cmkOptions": { "enabled": true }
}
`,
'index.ts': `import styles from './a.module.css';`,
'generated/a.module.css.d.ts': dedent`
const styles: {};
export default styles;
`,
});
await tsserver.sendUpdateOpen({
openFiles: [{ file: iff.paths['index.ts'] }],
});
const res = await tsserver.sendSemanticDiagnosticsSync({
file: iff.paths['index.ts'],
});
expect(res.body).toMatchInlineSnapshot(`
[
{
"category": "error",
"code": 2307,
"end": {
"line": 1,
"offset": 36,
},
"start": {
"line": 1,
"offset": 20,
},
"text": "Cannot find module './a.module.css' or its corresponding type declarations.",
},
]
`);
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: 2307,
...getRange('index.ts', `'./a.module.css'`),
text: `Cannot find module './a.module.css' or its corresponding type declarations.`,
},
]);
});
Loading
Loading