nextjs-ide-helper 1.1.3 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +175 -10
- package/lib/__tests__/loader.test.js +480 -0
- package/lib/index.ts +8 -0
- package/lib/loader.js +222 -33
- package/lib/plugin.js +26 -2
- package/lib/withIdeButton.tsx +97 -0
- package/package.json +9 -2
- package/src/__tests__/loader.test.js +480 -0
- package/src/loader.js +222 -33
- package/src/plugin.js +25 -1
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const loader = require('../loader.js');
|
|
3
|
+
|
|
4
|
+
describe('cursorButtonLoader', function() {
|
|
5
|
+
let mockContext;
|
|
6
|
+
|
|
7
|
+
beforeEach(function() {
|
|
8
|
+
mockContext = {
|
|
9
|
+
resourcePath: process.cwd() + '/src/components/Button.tsx',
|
|
10
|
+
getOptions: jest.fn(() => ({}))
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
process.env.NODE_ENV = 'development';
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(function() {
|
|
17
|
+
jest.clearAllMocks();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('when enabled', function() {
|
|
21
|
+
beforeEach(function() {
|
|
22
|
+
mockContext.getOptions.mockReturnValue({ enabled: true });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should wrap a React component with withIdeButton', function() {
|
|
26
|
+
const source = `import React from 'react';
|
|
27
|
+
|
|
28
|
+
const Button = () => {
|
|
29
|
+
return <button>Click me</button>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default Button;`;
|
|
33
|
+
|
|
34
|
+
const result = loader.call(mockContext, source);
|
|
35
|
+
|
|
36
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
37
|
+
expect(result).toContain("export default withIdeButton(Button,");
|
|
38
|
+
expect(result).toMatch(/projectRoot: ['"][^'"]*['"]/); // Accept both single and double quotes and any valid path
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should handle JSX files', function() {
|
|
42
|
+
mockContext.resourcePath = process.cwd() + '/src/components/Button.jsx';
|
|
43
|
+
const source = `const Button = () => <button>Click</button>;
|
|
44
|
+
export default Button;`;
|
|
45
|
+
|
|
46
|
+
const result = loader.call(mockContext, source);
|
|
47
|
+
|
|
48
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
49
|
+
expect(result).toContain("export default withIdeButton(Button,");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should handle components with existing imports', function() {
|
|
53
|
+
const source = `import React from 'react';
|
|
54
|
+
import { useState } from 'react';
|
|
55
|
+
|
|
56
|
+
const Counter = () => {
|
|
57
|
+
const [count, setCount] = useState(0);
|
|
58
|
+
return <div>{count}</div>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default Counter;`;
|
|
62
|
+
|
|
63
|
+
const result = loader.call(mockContext, source);
|
|
64
|
+
|
|
65
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
66
|
+
expect(result).toContain("export default withIdeButton(Counter,");
|
|
67
|
+
|
|
68
|
+
const lines = result.split('\n');
|
|
69
|
+
const importIndex = lines.findIndex(line => line.includes("import { withIdeButton }"));
|
|
70
|
+
const useStateIndex = lines.findIndex(line => line.includes("import { useState }"));
|
|
71
|
+
expect(importIndex).toBeGreaterThan(useStateIndex);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should handle components with no imports', function() {
|
|
75
|
+
const source = `const SimpleButton = () => {
|
|
76
|
+
return <button>Simple</button>;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default SimpleButton;`;
|
|
80
|
+
|
|
81
|
+
const result = loader.call(mockContext, source);
|
|
82
|
+
|
|
83
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
84
|
+
expect(result).toContain("export default withIdeButton(SimpleButton,");
|
|
85
|
+
expect(result.indexOf("import { withIdeButton }")).toBe(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should include relative path in the wrapper', function() {
|
|
89
|
+
mockContext.resourcePath = process.cwd() + '/src/components/ui/Button.tsx';
|
|
90
|
+
mockContext.getOptions.mockReturnValue({
|
|
91
|
+
enabled: true,
|
|
92
|
+
projectRoot: process.cwd()
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const source = `const Button = () => <button>Click</button>;
|
|
96
|
+
export default Button;`;
|
|
97
|
+
|
|
98
|
+
const result = loader.call(mockContext, source);
|
|
99
|
+
|
|
100
|
+
expect(result).toContain("'src/components/ui/Button.tsx'");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should use custom import path when specified', function() {
|
|
104
|
+
mockContext.getOptions.mockReturnValue({
|
|
105
|
+
enabled: true,
|
|
106
|
+
importPath: 'custom-ide-helper'
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const source = `const Button = () => <button>Click</button>;
|
|
110
|
+
export default Button;`;
|
|
111
|
+
|
|
112
|
+
const result = loader.call(mockContext, source);
|
|
113
|
+
|
|
114
|
+
expect(result).toContain("import { withIdeButton } from 'custom-ide-helper';");
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('when disabled', function() {
|
|
119
|
+
it('should return source unchanged when enabled is false', function() {
|
|
120
|
+
mockContext.getOptions.mockReturnValue({ enabled: false });
|
|
121
|
+
const source = `const Button = () => <button>Click</button>;
|
|
122
|
+
export default Button;`;
|
|
123
|
+
|
|
124
|
+
const result = loader.call(mockContext, source);
|
|
125
|
+
|
|
126
|
+
expect(result).toBe(source);
|
|
127
|
+
expect(result).not.toContain('withIdeButton');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should return source unchanged when NODE_ENV is production and enabled not explicitly set', function() {
|
|
131
|
+
process.env.NODE_ENV = 'production';
|
|
132
|
+
const source = `const Button = () => <button>Click</button>;
|
|
133
|
+
export default Button;`;
|
|
134
|
+
|
|
135
|
+
const result = loader.call(mockContext, source);
|
|
136
|
+
|
|
137
|
+
expect(result).toBe(source);
|
|
138
|
+
expect(result).not.toContain('withIdeButton');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('file filtering', function() {
|
|
143
|
+
beforeEach(function() {
|
|
144
|
+
mockContext.getOptions.mockReturnValue({ enabled: true });
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should not process files outside component directories', function() {
|
|
148
|
+
mockContext.resourcePath = process.cwd() + '/src/utils/helper.tsx';
|
|
149
|
+
const source = `const Helper = () => <div>Helper</div>;
|
|
150
|
+
export default Helper;`;
|
|
151
|
+
|
|
152
|
+
const result = loader.call(mockContext, source);
|
|
153
|
+
|
|
154
|
+
expect(result).toBe(source);
|
|
155
|
+
expect(result).not.toContain('withIdeButton');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should process files in custom component directories', function() {
|
|
159
|
+
mockContext.resourcePath = process.cwd() + '/src/widgets/MyWidget.tsx';
|
|
160
|
+
mockContext.getOptions.mockReturnValue({
|
|
161
|
+
enabled: true,
|
|
162
|
+
componentPaths: ['src/widgets'],
|
|
163
|
+
projectRoot: process.cwd()
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const source = `const MyWidget = () => <div>Widget</div>;
|
|
167
|
+
export default MyWidget;`;
|
|
168
|
+
|
|
169
|
+
const result = loader.call(mockContext, source);
|
|
170
|
+
|
|
171
|
+
expect(result).toContain('withIdeButton');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should not process non-JSX/TSX files', function() {
|
|
175
|
+
mockContext.resourcePath = process.cwd() + '/src/components/Button.js';
|
|
176
|
+
const source = `const Button = () => <button>Click</button>;
|
|
177
|
+
export default Button;`;
|
|
178
|
+
|
|
179
|
+
const result = loader.call(mockContext, source);
|
|
180
|
+
|
|
181
|
+
expect(result).toBe(source);
|
|
182
|
+
expect(result).not.toContain('withIdeButton');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('component detection', function() {
|
|
187
|
+
beforeEach(function() {
|
|
188
|
+
mockContext.getOptions.mockReturnValue({ enabled: true });
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should not process files without default export', function() {
|
|
192
|
+
const source = `export const Button = () => <button>Click</button>;`;
|
|
193
|
+
|
|
194
|
+
const result = loader.call(mockContext, source);
|
|
195
|
+
|
|
196
|
+
expect(result).toBe(source);
|
|
197
|
+
expect(result).not.toContain('withIdeButton');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should not process files with lowercase default export', function() {
|
|
201
|
+
const source = `const button = () => <button>Click</button>;
|
|
202
|
+
export default button;`;
|
|
203
|
+
|
|
204
|
+
const result = loader.call(mockContext, source);
|
|
205
|
+
|
|
206
|
+
expect(result).toBe(source);
|
|
207
|
+
expect(result).not.toContain('withIdeButton');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should process files with PascalCase default export', function() {
|
|
211
|
+
const source = `const MyButton = () => <button>Click</button>;
|
|
212
|
+
export default MyButton;`;
|
|
213
|
+
|
|
214
|
+
const result = loader.call(mockContext, source);
|
|
215
|
+
|
|
216
|
+
expect(result).toContain('withIdeButton');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should process direct export default function declarations', function() {
|
|
220
|
+
const source = `export default function MyCoolComponent() {
|
|
221
|
+
return <div>My Cool Component</div>;
|
|
222
|
+
}`;
|
|
223
|
+
|
|
224
|
+
const result = loader.call(mockContext, source);
|
|
225
|
+
|
|
226
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
227
|
+
expect(result).toContain("export default withIdeButton(MyCoolComponent,");
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should process direct export default arrow function expressions', function() {
|
|
231
|
+
const source = `export default () => {
|
|
232
|
+
return <div>Anonymous Component</div>;
|
|
233
|
+
};`;
|
|
234
|
+
|
|
235
|
+
const result = loader.call(mockContext, source);
|
|
236
|
+
|
|
237
|
+
// Should process anonymous components using file path
|
|
238
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
239
|
+
expect(result).toContain("export default withIdeButton(");
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should process anonymous function expressions', function() {
|
|
243
|
+
const source = `export default function() {
|
|
244
|
+
return <div>Anonymous Function Component</div>;
|
|
245
|
+
}`;
|
|
246
|
+
|
|
247
|
+
const result = loader.call(mockContext, source);
|
|
248
|
+
|
|
249
|
+
// Should process anonymous function components
|
|
250
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
251
|
+
expect(result).toContain("export default withIdeButton(");
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should process direct export default class components', function() {
|
|
255
|
+
const source = `import React from 'react';
|
|
256
|
+
|
|
257
|
+
export default class MyClassComponent extends React.Component {
|
|
258
|
+
render() {
|
|
259
|
+
return <div>Class Component</div>;
|
|
260
|
+
}
|
|
261
|
+
}`;
|
|
262
|
+
|
|
263
|
+
const result = loader.call(mockContext, source);
|
|
264
|
+
|
|
265
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
266
|
+
expect(result).toContain("export default withIdeButton(MyClassComponent,");
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should not process lowercase direct export default functions', function() {
|
|
270
|
+
const source = `export default function myLowercaseComponent() {
|
|
271
|
+
return <div>Lowercase Component</div>;
|
|
272
|
+
}`;
|
|
273
|
+
|
|
274
|
+
const result = loader.call(mockContext, source);
|
|
275
|
+
|
|
276
|
+
expect(result).toBe(source);
|
|
277
|
+
expect(result).not.toContain('withIdeButton');
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should handle direct export default with complex function names', function() {
|
|
281
|
+
const source = `export default function MyComplexComponent123WithNumbers() {
|
|
282
|
+
return <div>Complex Named Component</div>;
|
|
283
|
+
}`;
|
|
284
|
+
|
|
285
|
+
const result = loader.call(mockContext, source);
|
|
286
|
+
|
|
287
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
288
|
+
expect(result).toContain("export default withIdeButton(MyComplexComponent123WithNumbers,");
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should handle function components with TypeScript', function() {
|
|
292
|
+
const source = `interface Props {
|
|
293
|
+
title: string;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export default function TypeScriptComponent(props: Props) {
|
|
297
|
+
return <div>{props.title}</div>;
|
|
298
|
+
}`;
|
|
299
|
+
|
|
300
|
+
const result = loader.call(mockContext, source);
|
|
301
|
+
|
|
302
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
303
|
+
expect(result).toContain("export default withIdeButton(TypeScriptComponent,");
|
|
304
|
+
expect(result).toContain("function TypeScriptComponent(props: Props)");
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('should handle class components with TypeScript', function() {
|
|
308
|
+
const source = `import React, { Component } from 'react';
|
|
309
|
+
|
|
310
|
+
interface Props {
|
|
311
|
+
name: string;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export default class TSClassComponent extends Component<Props> {
|
|
315
|
+
render() {
|
|
316
|
+
return <div>Hello {this.props.name}</div>;
|
|
317
|
+
}
|
|
318
|
+
}`;
|
|
319
|
+
|
|
320
|
+
const result = loader.call(mockContext, source);
|
|
321
|
+
|
|
322
|
+
expect(result).toContain("import { withIdeButton } from 'nextjs-ide-helper';");
|
|
323
|
+
expect(result).toContain("export default withIdeButton(TSClassComponent,");
|
|
324
|
+
expect(result).toContain("class TSClassComponent extends Component<Props>");
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
describe('already wrapped components', function() {
|
|
329
|
+
beforeEach(function() {
|
|
330
|
+
mockContext.getOptions.mockReturnValue({ enabled: true });
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('should not wrap components that are already wrapped', function() {
|
|
334
|
+
const source = `import { withIdeButton } from 'nextjs-ide-helper';
|
|
335
|
+
|
|
336
|
+
const Button = () => <button>Click</button>;
|
|
337
|
+
|
|
338
|
+
export default withIdeButton(Button, 'src/components/Button.tsx');`;
|
|
339
|
+
|
|
340
|
+
const result = loader.call(mockContext, source);
|
|
341
|
+
|
|
342
|
+
expect(result).toBe(source);
|
|
343
|
+
expect((result.match(/withIdeButton/g) || []).length).toBe(2);
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
describe('edge cases', function() {
|
|
348
|
+
beforeEach(function() {
|
|
349
|
+
mockContext.getOptions.mockReturnValue({ enabled: true });
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should handle export default with semicolon', function() {
|
|
353
|
+
const source = `const Button = () => <button>Click</button>;
|
|
354
|
+
export default Button;`;
|
|
355
|
+
|
|
356
|
+
const result = loader.call(mockContext, source);
|
|
357
|
+
|
|
358
|
+
expect(result).toContain("export default withIdeButton(Button,");
|
|
359
|
+
expect(result).not.toContain("export default Button;");
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('should handle export default without semicolon', function() {
|
|
363
|
+
const source = `const Button = () => <button>Click</button>
|
|
364
|
+
export default Button`;
|
|
365
|
+
|
|
366
|
+
const result = loader.call(mockContext, source);
|
|
367
|
+
|
|
368
|
+
expect(result).toContain("export default withIdeButton(Button,");
|
|
369
|
+
expect(result).not.toContain("export default Button");
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('should handle complex component names', function() {
|
|
373
|
+
const source = `const MyComplexComponent123 = () => <div>Complex</div>;
|
|
374
|
+
export default MyComplexComponent123;`;
|
|
375
|
+
|
|
376
|
+
const result = loader.call(mockContext, source);
|
|
377
|
+
|
|
378
|
+
expect(result).toContain("export default withIdeButton(MyComplexComponent123,");
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('should handle files with multiple component paths', function() {
|
|
382
|
+
mockContext.resourcePath = process.cwd() + '/lib/components/Button.tsx';
|
|
383
|
+
mockContext.getOptions.mockReturnValue({
|
|
384
|
+
enabled: true,
|
|
385
|
+
componentPaths: ['src/components', 'lib/components'],
|
|
386
|
+
projectRoot: process.cwd()
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const source = `const Button = () => <button>Click</button>;
|
|
390
|
+
export default Button;`;
|
|
391
|
+
|
|
392
|
+
const result = loader.call(mockContext, source);
|
|
393
|
+
|
|
394
|
+
expect(result).toContain('withIdeButton');
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('should support regex patterns in component paths for nested directories', function() {
|
|
398
|
+
mockContext.resourcePath = process.cwd() + '/src/components/ui/forms/Button.tsx';
|
|
399
|
+
mockContext.getOptions.mockReturnValue({
|
|
400
|
+
enabled: true,
|
|
401
|
+
componentPaths: ['src/components/**'],
|
|
402
|
+
projectRoot: process.cwd()
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
const source = `const Button = () => <button>Click</button>;
|
|
406
|
+
export default Button;`;
|
|
407
|
+
|
|
408
|
+
const result = loader.call(mockContext, source);
|
|
409
|
+
|
|
410
|
+
expect(result).toContain('withIdeButton');
|
|
411
|
+
expect(result).toContain("'src/components/ui/forms/Button.tsx'");
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it('should support regex patterns matching any nested directory structure', function() {
|
|
415
|
+
mockContext.resourcePath = process.cwd() + '/app/components/dashboard/widgets/Chart.tsx';
|
|
416
|
+
mockContext.getOptions.mockReturnValue({
|
|
417
|
+
enabled: true,
|
|
418
|
+
componentPaths: ['**/components/**'],
|
|
419
|
+
projectRoot: process.cwd()
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
const source = `const Chart = () => <div>Chart</div>;
|
|
423
|
+
export default Chart;`;
|
|
424
|
+
|
|
425
|
+
const result = loader.call(mockContext, source);
|
|
426
|
+
|
|
427
|
+
expect(result).toContain('withIdeButton');
|
|
428
|
+
expect(result).toContain("'app/components/dashboard/widgets/Chart.tsx'");
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('should support multiple regex patterns for different nested structures', function() {
|
|
432
|
+
mockContext.resourcePath = process.cwd() + '/modules/feature-a/components/deep/nested/Widget.tsx';
|
|
433
|
+
mockContext.getOptions.mockReturnValue({
|
|
434
|
+
enabled: true,
|
|
435
|
+
componentPaths: ['src/components/**', 'modules/**/components/**', 'lib/ui/**'],
|
|
436
|
+
projectRoot: process.cwd()
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
const source = `const Widget = () => <div>Widget</div>;
|
|
440
|
+
export default Widget;`;
|
|
441
|
+
|
|
442
|
+
const result = loader.call(mockContext, source);
|
|
443
|
+
|
|
444
|
+
expect(result).toContain('withIdeButton');
|
|
445
|
+
expect(result).toContain("'modules/feature-a/components/deep/nested/Widget.tsx'");
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
describe('options handling', function() {
|
|
450
|
+
it('should use default options when none provided', function() {
|
|
451
|
+
mockContext.getOptions.mockReturnValue(null);
|
|
452
|
+
process.env.NODE_ENV = 'development';
|
|
453
|
+
|
|
454
|
+
const source = `const Button = () => <button>Click</button>;
|
|
455
|
+
export default Button;`;
|
|
456
|
+
|
|
457
|
+
const result = loader.call(mockContext, source);
|
|
458
|
+
|
|
459
|
+
expect(result).toContain('withIdeButton');
|
|
460
|
+
expect(result).toContain("'nextjs-ide-helper'");
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('should handle custom project root', function() {
|
|
464
|
+
const customRoot = '/custom/project';
|
|
465
|
+
mockContext.resourcePath = customRoot + '/src/components/Button.tsx';
|
|
466
|
+
mockContext.getOptions.mockReturnValue({
|
|
467
|
+
enabled: true,
|
|
468
|
+
projectRoot: customRoot
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
const source = `const Button = () => <button>Click</button>;
|
|
472
|
+
export default Button;`;
|
|
473
|
+
|
|
474
|
+
const result = loader.call(mockContext, source);
|
|
475
|
+
|
|
476
|
+
expect(result).toMatch(new RegExp("projectRoot:\\s*['\"]" + customRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + "['\"]"));
|
|
477
|
+
expect(result).toContain("'src/components/Button.tsx'");
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
});
|