@@ -8,32 +8,184 @@ import {
88import { createIFF } from '../test-util/fixture.js' ;
99import { formatPath , launchTsserver , normalizeCodeFixActions } from '../test-util/tsserver.js' ;
1010
11- describe ( 'Get Code Fixes' , async ( ) => {
11+ test . each ( [
12+ {
13+ namedExports : false ,
14+ importStatement : "import styles from './a.module.css';" ,
15+ } ,
16+ {
17+ namedExports : true ,
18+ importStatement : "import * as styles from './a.module.css';" ,
19+ } ,
20+ ] ) (
21+ 'fixMissingCSSRule inserts a new CSS rule for a missing class property (namedExports: $namedExports)' ,
22+ async ( { namedExports, importStatement } ) => {
23+ const tsserver = launchTsserver ( ) ;
24+ const iff = await createIFF ( {
25+ 'a.tsx' : dedent `
26+ ${ importStatement }
27+ import bStyles from './b.module.css';
28+ styles.a_1;
29+ bStyles.b_2;
30+ ` ,
31+ 'a.module.css' : '' ,
32+ 'b.module.css' : dedent `
33+ .b_1 {
34+ color: red;
35+ }
36+ ` ,
37+ 'tsconfig.json' : dedent `
38+ {
39+ "cmkOptions": {
40+ "enabled": true,
41+ "namedExports": ${ namedExports }
42+ }
43+ }
44+ ` ,
45+ } ) ;
46+ await tsserver . sendUpdateOpen ( {
47+ openFiles : [ { file : iff . paths [ 'tsconfig.json' ] } ] ,
48+ } ) ;
49+
50+ const res1 = await tsserver . sendGetCodeFixes ( {
51+ errorCodes : [ PROPERTY_DOES_NOT_EXIST_ERROR_CODES [ 0 ] ] ,
52+ file : iff . paths [ 'a.tsx' ] ,
53+ startLine : 3 ,
54+ startOffset : 11 ,
55+ endLine : 3 ,
56+ endOffset : 11 ,
57+ } ) ;
58+ expect ( normalizeCodeFixActions ( res1 . body ! ) ) . toStrictEqual (
59+ normalizeCodeFixActions ( [
60+ {
61+ fixName : 'fixMissingCSSRule' ,
62+ changes : [
63+ {
64+ fileName : formatPath ( iff . paths [ 'a.module.css' ] ) ,
65+ textChanges : [ { start : { line : 1 , offset : 1 } , end : { line : 1 , offset : 1 } , newText : '\n.a_1 {\n \n}' } ] ,
66+ } ,
67+ ] ,
68+ } ,
69+ ] ) ,
70+ ) ;
71+
72+ const res2 = await tsserver . sendGetCodeFixes ( {
73+ errorCodes : [ PROPERTY_DOES_NOT_EXIST_ERROR_CODES [ 1 ] ] ,
74+ file : iff . paths [ 'a.tsx' ] ,
75+ startLine : 3 ,
76+ startOffset : 11 ,
77+ endLine : 3 ,
78+ endOffset : 11 ,
79+ } ) ;
80+ expect ( normalizeCodeFixActions ( res2 . body ! ) ) . toStrictEqual (
81+ normalizeCodeFixActions ( [
82+ {
83+ fixName : 'fixMissingCSSRule' ,
84+ changes : [
85+ {
86+ fileName : formatPath ( iff . paths [ 'a.module.css' ] ) ,
87+ textChanges : [ { start : { line : 1 , offset : 1 } , end : { line : 1 , offset : 1 } , newText : '\n.a_1 {\n \n}' } ] ,
88+ } ,
89+ ] ,
90+ } ,
91+ ] ) ,
92+ ) ;
93+
94+ const res3 = await tsserver . sendGetCodeFixes ( {
95+ errorCodes : [ PROPERTY_DOES_NOT_EXIST_ERROR_CODES [ 0 ] ] ,
96+ file : iff . paths [ 'a.tsx' ] ,
97+ startLine : 4 ,
98+ startOffset : 12 ,
99+ endLine : 4 ,
100+ endOffset : 12 ,
101+ } ) ;
102+ expect ( normalizeCodeFixActions ( res3 . body ! ) ) . toStrictEqual (
103+ normalizeCodeFixActions ( [
104+ {
105+ fixName : 'fixMissingCSSRule' ,
106+ changes : [
107+ {
108+ fileName : formatPath ( iff . paths [ 'b.module.css' ] ) ,
109+ textChanges : [ { start : { line : 3 , offset : 2 } , end : { line : 3 , offset : 2 } , newText : '\n.b_2 {\n \n}' } ] ,
110+ } ,
111+ ] ,
112+ } ,
113+ ] ) ,
114+ ) ;
115+ } ,
116+ ) ;
117+
118+ test . each ( [
119+ {
120+ name : 'auto-import inserts default import statement if namedExports is false' ,
121+ namedExports : false ,
122+ importStatement : `import styles from "./a.module.css";` ,
123+ } ,
124+ {
125+ name : 'auto-import inserts namespace import statement if namedExports is true' ,
126+ namedExports : true ,
127+ importStatement : `import * as styles from "./a.module.css";` ,
128+ } ,
129+ ] ) ( '$name' , async ( { namedExports, importStatement } ) => {
12130 const tsserver = launchTsserver ( ) ;
13131 const iff = await createIFF ( {
14- 'a.tsx' : dedent `
15- import styles from './a.module.css';
16- import bStyles from './b.module.css';
17- styles.a_1;
18- bStyles.b_2;
19- ` ,
20- 'b.tsx' : dedent `
132+ 'index.ts' : dedent `
21133 styles;
22134 ` ,
23135 'a.module.css' : '' ,
24- 'b.module.css' : dedent `
25- .b_1 {
26- color: red;
136+ 'tsconfig.json' : dedent `
137+ {
138+ "cmkOptions": {
139+ "enabled": true,
140+ "namedExports": ${ namedExports }
141+ }
27142 }
28143 ` ,
29- // Generated files should be excluded from completion candidates.
30- 'generated/generated.module.css.d.ts' : dedent `
144+ } ) ;
145+ await tsserver . sendUpdateOpen ( {
146+ openFiles : [ { file : iff . paths [ 'tsconfig.json' ] } ] ,
147+ } ) ;
148+ const res = await tsserver . sendGetCodeFixes ( {
149+ errorCodes : [ CANNOT_FIND_NAME_ERROR_CODE ] ,
150+ file : iff . paths [ 'index.ts' ] ,
151+ startLine : 1 ,
152+ startOffset : 1 ,
153+ endLine : 1 ,
154+ endOffset : 7 ,
155+ } ) ;
156+ expect ( normalizeCodeFixActions ( res . body ! ) ) . toStrictEqual (
157+ normalizeCodeFixActions ( [
158+ {
159+ fixName : 'import' ,
160+ changes : [
161+ {
162+ fileName : formatPath ( iff . paths [ 'index.ts' ] ) ,
163+ textChanges : [
164+ {
165+ start : { line : 1 , offset : 1 } ,
166+ end : { line : 1 , offset : 1 } ,
167+ newText : `${ importStatement } ${ ts . sys . newLine } ${ ts . sys . newLine } ` ,
168+ } ,
169+ ] ,
170+ } ,
171+ ] ,
172+ } ,
173+ ] ) ,
174+ ) ;
175+ } ) ;
176+
177+ test ( 'auto-import excludes generated files from suggestions' , async ( ) => {
178+ const tsserver = launchTsserver ( ) ;
179+ const iff = await createIFF ( {
180+ 'index.ts' : dedent `
181+ styles;
182+ ` ,
183+ 'generated/a.module.css.d.ts' : dedent `
31184 const styles: {};
32185 export default styles;
33186 ` ,
34187 'tsconfig.json' : dedent `
35188 {
36- "compilerOptions": {},
37189 "cmkOptions": {
38190 "enabled": true,
39191 "dtsOutDir": "generated"
@@ -44,108 +196,83 @@ describe('Get Code Fixes', async () => {
44196 await tsserver . sendUpdateOpen ( {
45197 openFiles : [ { file : iff . paths [ 'tsconfig.json' ] } ] ,
46198 } ) ;
199+ const res = await tsserver . sendGetCodeFixes ( {
200+ errorCodes : [ CANNOT_FIND_NAME_ERROR_CODE ] ,
201+ file : iff . paths [ 'index.ts' ] ,
202+ startLine : 1 ,
203+ startOffset : 1 ,
204+ endLine : 1 ,
205+ endOffset : 7 ,
206+ } ) ;
207+ expect ( normalizeCodeFixActions ( res . body ! ) ) . toStrictEqual ( [ ] ) ;
208+ } ) ;
209+
210+ describe ( 'auto-import suggests named exports instead of namespace import when prioritizeNamedImports is true' , async ( ) => {
211+ const tsserver = launchTsserver ( ) ;
212+ const iff = await createIFF ( {
213+ 'index.ts' : dedent `
214+ styles;
215+ a_1;
216+ ` ,
217+ 'a.module.css' : dedent `
218+ .a_1 { color: red; }
219+ ` ,
220+ 'tsconfig.json' : dedent `
221+ {
222+ "cmkOptions": {
223+ "enabled": true,
224+ "namedExports": true,
225+ "prioritizeNamedImports": true
226+ }
227+ }
228+ ` ,
229+ } ) ;
230+ await tsserver . sendUpdateOpen ( {
231+ openFiles : [ { file : iff . paths [ 'tsconfig.json' ] } ] ,
232+ } ) ;
47233 test . each ( [
48234 {
49235 name : 'styles' ,
50- file : iff . paths [ 'b.tsx' ] ,
51- line : 1 ,
52- offset : 1 ,
53- errorCodes : [ CANNOT_FIND_NAME_ERROR_CODE ] ,
236+ file : iff . paths [ 'index.ts' ] ,
237+ startLine : 1 ,
238+ startOffset : 1 ,
239+ endLine : 1 ,
240+ endOffset : 7 ,
241+ expected : [ ] ,
242+ } ,
243+ {
244+ name : 'a_1' ,
245+ file : iff . paths [ 'index.ts' ] ,
246+ startLine : 2 ,
247+ startOffset : 1 ,
248+ endLine : 2 ,
249+ endOffset : 4 ,
54250 expected : [
55251 {
56252 fixName : 'import' ,
57253 changes : [
58254 {
59- fileName : formatPath ( iff . paths [ 'b.tsx' ] ) ,
60- textChanges : [
61- {
62- start : { line : 1 , offset : 1 } ,
63- end : { line : 1 , offset : 1 } ,
64- newText : `import styles from "./a.module.css";${ ts . sys . newLine } ${ ts . sys . newLine } ` ,
65- } ,
66- ] ,
67- } ,
68- ] ,
69- } ,
70- {
71- fixName : 'import' ,
72- changes : [
73- {
74- fileName : formatPath ( iff . paths [ 'b.tsx' ] ) ,
255+ fileName : formatPath ( iff . paths [ 'index.ts' ] ) ,
75256 textChanges : [
76257 {
77258 start : { line : 1 , offset : 1 } ,
78259 end : { line : 1 , offset : 1 } ,
79- newText : `import styles from "./b .module.css";${ ts . sys . newLine } ${ ts . sys . newLine } ` ,
260+ newText : `import { a_1 } from "./a .module.css";${ ts . sys . newLine } ${ ts . sys . newLine } ` ,
80261 } ,
81262 ] ,
82263 } ,
83264 ] ,
84265 } ,
85266 ] ,
86267 } ,
87- {
88- name : 'styles.a_1' ,
89- file : iff . paths [ 'a.tsx' ] ,
90- line : 3 ,
91- offset : 11 ,
92- errorCodes : [ PROPERTY_DOES_NOT_EXIST_ERROR_CODES [ 0 ] ] ,
93- expected : [
94- {
95- fixName : 'fixMissingCSSRule' ,
96- changes : [
97- {
98- fileName : formatPath ( iff . paths [ 'a.module.css' ] ) ,
99- textChanges : [ { start : { line : 1 , offset : 1 } , end : { line : 1 , offset : 1 } , newText : '\n.a_1 {\n \n}' } ] ,
100- } ,
101- ] ,
102- } ,
103- ] ,
104- } ,
105- {
106- name : 'styles.a_1' ,
107- file : iff . paths [ 'a.tsx' ] ,
108- line : 3 ,
109- offset : 11 ,
110- errorCodes : [ PROPERTY_DOES_NOT_EXIST_ERROR_CODES [ 1 ] ] ,
111- expected : [
112- {
113- fixName : 'fixMissingCSSRule' ,
114- changes : [
115- {
116- fileName : formatPath ( iff . paths [ 'a.module.css' ] ) ,
117- textChanges : [ { start : { line : 1 , offset : 1 } , end : { line : 1 , offset : 1 } , newText : '\n.a_1 {\n \n}' } ] ,
118- } ,
119- ] ,
120- } ,
121- ] ,
122- } ,
123- {
124- name : 'bStyles.b_2' ,
125- file : iff . paths [ 'a.tsx' ] ,
126- line : 4 ,
127- offset : 12 ,
128- errorCodes : [ PROPERTY_DOES_NOT_EXIST_ERROR_CODES [ 0 ] ] ,
129- expected : [
130- {
131- fixName : 'fixMissingCSSRule' ,
132- changes : [
133- {
134- fileName : formatPath ( iff . paths [ 'b.module.css' ] ) ,
135- textChanges : [ { start : { line : 3 , offset : 2 } , end : { line : 3 , offset : 2 } , newText : '\n.b_2 {\n \n}' } ] ,
136- } ,
137- ] ,
138- } ,
139- ] ,
140- } ,
141- ] ) ( '$name' , async ( { file, line, offset, errorCodes, expected } ) => {
268+ ] ) ( '$name' , async ( { file, startLine, startOffset, endLine, endOffset, expected } ) => {
142269 const res = await tsserver . sendGetCodeFixes ( {
143- errorCodes,
270+ errorCodes : [ 2304 ] ,
144271 file,
145- startLine : line ,
146- startOffset : offset ,
147- endLine : line ,
148- endOffset : offset ,
272+ startLine,
273+ startOffset,
274+ endLine,
275+ endOffset,
149276 } ) ;
150277 expect ( normalizeCodeFixActions ( res . body ! ) ) . toStrictEqual ( normalizeCodeFixActions ( expected ) ) ;
151278 } ) ;
0 commit comments