@stencil/vitest 1.5.0 → 1.6.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/dist/bin/__tests__/stencil-test.spec.js +139 -2
- package/dist/bin/stencil-test.js +97 -29
- package/dist/config.js +10 -0
- package/package.json +2 -2
|
@@ -213,8 +213,8 @@ export default {
|
|
|
213
213
|
writeFileSync(join(testDir, 'vitest.config.ts'), vitestConfig);
|
|
214
214
|
writeFileSync(join(testDir, 'package.json'), JSON.stringify({ name: 'test', type: 'module' }));
|
|
215
215
|
const result = await runCLIInDir(testDir, ['--watch', '--verbose'], 2000);
|
|
216
|
-
// Should add watch ignore patterns
|
|
217
|
-
expect(result.stdout).toMatch(/Added.*
|
|
216
|
+
// Should add watch ignore patterns (screenshot and test file patterns)
|
|
217
|
+
expect(result.stdout).toMatch(/Added.*screenshot patterns and.*test file patterns/);
|
|
218
218
|
});
|
|
219
219
|
it('should merge user watchIgnoredRegex with screenshot patterns', async () => {
|
|
220
220
|
const stencilConfig = `
|
|
@@ -250,6 +250,143 @@ export default {
|
|
|
250
250
|
}
|
|
251
251
|
});
|
|
252
252
|
});
|
|
253
|
+
describe('test file ignore patterns', () => {
|
|
254
|
+
it('should extract test file patterns from vitest config include', async () => {
|
|
255
|
+
const stencilConfig = `
|
|
256
|
+
export const config = {
|
|
257
|
+
namespace: 'test',
|
|
258
|
+
outputTargets: [{ type: 'dist' }]
|
|
259
|
+
};
|
|
260
|
+
`;
|
|
261
|
+
writeFileSync(join(testDir, 'stencil.config.ts'), stencilConfig);
|
|
262
|
+
const vitestConfig = `
|
|
263
|
+
export default {
|
|
264
|
+
test: {
|
|
265
|
+
include: ['**/*.spec.ts', '**/*.test.ts']
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
`;
|
|
269
|
+
writeFileSync(join(testDir, 'vitest.config.ts'), vitestConfig);
|
|
270
|
+
writeFileSync(join(testDir, 'package.json'), JSON.stringify({ name: 'test', type: 'module' }));
|
|
271
|
+
const result = await runCLIInDir(testDir, ['--watch', '--verbose'], 2000);
|
|
272
|
+
// Should extract test file patterns
|
|
273
|
+
expect(result.stdout).toMatch(/Extracted.*test file patterns/);
|
|
274
|
+
});
|
|
275
|
+
it('should extract test file patterns from project-level include', async () => {
|
|
276
|
+
const stencilConfig = `
|
|
277
|
+
export const config = {
|
|
278
|
+
namespace: 'test',
|
|
279
|
+
outputTargets: [{ type: 'dist' }]
|
|
280
|
+
};
|
|
281
|
+
`;
|
|
282
|
+
writeFileSync(join(testDir, 'stencil.config.ts'), stencilConfig);
|
|
283
|
+
const vitestConfig = `
|
|
284
|
+
export default {
|
|
285
|
+
test: {
|
|
286
|
+
projects: [
|
|
287
|
+
{
|
|
288
|
+
test: {
|
|
289
|
+
include: ['src/**/*.unit.ts']
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
test: {
|
|
294
|
+
include: ['e2e/**/*.e2e.ts']
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
]
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
`;
|
|
301
|
+
writeFileSync(join(testDir, 'vitest.config.ts'), vitestConfig);
|
|
302
|
+
writeFileSync(join(testDir, 'package.json'), JSON.stringify({ name: 'test', type: 'module' }));
|
|
303
|
+
const result = await runCLIInDir(testDir, ['--watch', '--verbose'], 2000);
|
|
304
|
+
// Should extract test file patterns from projects
|
|
305
|
+
expect(result.stdout).toMatch(/Extracted.*test file patterns/);
|
|
306
|
+
});
|
|
307
|
+
it('should include test file patterns in temporary config', async () => {
|
|
308
|
+
const stencilConfig = `
|
|
309
|
+
export const config = {
|
|
310
|
+
namespace: 'test',
|
|
311
|
+
outputTargets: [{ type: 'dist' }]
|
|
312
|
+
};
|
|
313
|
+
`;
|
|
314
|
+
writeFileSync(join(testDir, 'stencil.config.ts'), stencilConfig);
|
|
315
|
+
const vitestConfig = `
|
|
316
|
+
export default {
|
|
317
|
+
test: {
|
|
318
|
+
include: ['**/*.mytest.ts']
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
`;
|
|
322
|
+
writeFileSync(join(testDir, 'vitest.config.ts'), vitestConfig);
|
|
323
|
+
writeFileSync(join(testDir, 'package.json'), JSON.stringify({ name: 'test', type: 'module' }));
|
|
324
|
+
const result = await runCLIInDir(testDir, ['--watch', '--verbose'], 3000);
|
|
325
|
+
// Check that temp config was created with test file patterns
|
|
326
|
+
expect(result.stdout).toMatch(/Created temporary/);
|
|
327
|
+
const tempConfigs = require('fs')
|
|
328
|
+
.readdirSync(testDir)
|
|
329
|
+
.filter((f) => f.startsWith('.stencil-test-'));
|
|
330
|
+
if (tempConfigs.length > 0) {
|
|
331
|
+
const tempConfigContent = require('fs').readFileSync(join(testDir, tempConfigs[0]), 'utf-8');
|
|
332
|
+
// Should have test file pattern converted to regex
|
|
333
|
+
expect(tempConfigContent).toMatch(/mytest/);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
it('should use default test file patterns when no include specified', async () => {
|
|
337
|
+
const stencilConfig = `
|
|
338
|
+
export const config = {
|
|
339
|
+
namespace: 'test',
|
|
340
|
+
outputTargets: [{ type: 'dist' }]
|
|
341
|
+
};
|
|
342
|
+
`;
|
|
343
|
+
writeFileSync(join(testDir, 'stencil.config.ts'), stencilConfig);
|
|
344
|
+
const vitestConfig = `
|
|
345
|
+
export default {
|
|
346
|
+
test: {
|
|
347
|
+
projects: []
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
`;
|
|
351
|
+
writeFileSync(join(testDir, 'vitest.config.ts'), vitestConfig);
|
|
352
|
+
writeFileSync(join(testDir, 'package.json'), JSON.stringify({ name: 'test', type: 'module' }));
|
|
353
|
+
const result = await runCLIInDir(testDir, ['--watch', '--verbose'], 3000);
|
|
354
|
+
// Check that temp config was created
|
|
355
|
+
expect(result.stdout).toMatch(/Created temporary/);
|
|
356
|
+
const tempConfigs = require('fs')
|
|
357
|
+
.readdirSync(testDir)
|
|
358
|
+
.filter((f) => f.startsWith('.stencil-test-'));
|
|
359
|
+
if (tempConfigs.length > 0) {
|
|
360
|
+
const tempConfigContent = require('fs').readFileSync(join(testDir, tempConfigs[0]), 'utf-8');
|
|
361
|
+
// Should have default test file patterns (.spec. and .test.)
|
|
362
|
+
// The patterns are written as regex literals with escaped dots (e.g., /\.spec\.[jt]sx?$/)
|
|
363
|
+
expect(tempConfigContent).toContain('spec');
|
|
364
|
+
expect(tempConfigContent).toContain('test');
|
|
365
|
+
expect(tempConfigContent).toContain('[jt]sx');
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
it('should report both screenshot and test file pattern counts', async () => {
|
|
369
|
+
const stencilConfig = `
|
|
370
|
+
export const config = {
|
|
371
|
+
namespace: 'test',
|
|
372
|
+
outputTargets: [{ type: 'dist' }]
|
|
373
|
+
};
|
|
374
|
+
`;
|
|
375
|
+
writeFileSync(join(testDir, 'stencil.config.ts'), stencilConfig);
|
|
376
|
+
const vitestConfig = `
|
|
377
|
+
export default {
|
|
378
|
+
test: {
|
|
379
|
+
include: ['**/*.spec.ts']
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
`;
|
|
383
|
+
writeFileSync(join(testDir, 'vitest.config.ts'), vitestConfig);
|
|
384
|
+
writeFileSync(join(testDir, 'package.json'), JSON.stringify({ name: 'test', type: 'module' }));
|
|
385
|
+
const result = await runCLIInDir(testDir, ['--watch', '--verbose'], 2000);
|
|
386
|
+
// Should report both screenshot and test file pattern counts
|
|
387
|
+
expect(result.stdout).toMatch(/Added.*screenshot patterns and.*test file patterns/);
|
|
388
|
+
});
|
|
389
|
+
});
|
|
253
390
|
describe('temp file cleanup', () => {
|
|
254
391
|
it('should cleanup temporary config on exit', async () => {
|
|
255
392
|
const stencilConfig = `
|
package/dist/bin/stencil-test.js
CHANGED
|
@@ -265,31 +265,98 @@ function handleStencilOutput(data) {
|
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
/**
|
|
268
|
-
*
|
|
268
|
+
* Resolves the vitest config path from custom path or default locations
|
|
269
269
|
*/
|
|
270
|
-
|
|
271
|
-
|
|
270
|
+
function resolveVitestConfigPath(customVitestConfig) {
|
|
271
|
+
// Use custom config if provided via --config flag
|
|
272
|
+
if (customVitestConfig) {
|
|
273
|
+
const resolvedPath = join(cwd, customVitestConfig);
|
|
274
|
+
if (existsSync(resolvedPath)) {
|
|
275
|
+
return resolvedPath;
|
|
276
|
+
}
|
|
277
|
+
if (verbose) {
|
|
278
|
+
log(`Specified vitest config not found: ${customVitestConfig}, falling back to defaults`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Look for vitest.config.ts/js in common locations
|
|
282
|
+
const possibleConfigs = [
|
|
283
|
+
join(cwd, 'vitest.config.ts'),
|
|
284
|
+
join(cwd, 'vitest.config.js'),
|
|
285
|
+
join(cwd, 'vitest.config.mjs'),
|
|
286
|
+
];
|
|
287
|
+
return possibleConfigs.find(existsSync);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Loads and parses the vitest config file
|
|
291
|
+
*/
|
|
292
|
+
async function loadVitestConfig(vitestConfigPath) {
|
|
293
|
+
const jiti = createJiti(cwd, { interopDefault: true });
|
|
294
|
+
const vitestConfig = await jiti.import(vitestConfigPath);
|
|
295
|
+
return vitestConfig?.default || vitestConfig;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Converts a glob pattern to a RegExp for use in watchIgnoredRegex
|
|
299
|
+
*/
|
|
300
|
+
function globToRegex(glob) {
|
|
301
|
+
// Escape special regex characters except glob wildcards
|
|
302
|
+
let pattern = glob
|
|
303
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex special chars
|
|
304
|
+
.replace(/\*\*/g, '<<GLOBSTAR>>') // Placeholder for **
|
|
305
|
+
.replace(/\*/g, '[^/]*') // * matches anything except /
|
|
306
|
+
.replace(/<<GLOBSTAR>>/g, '.*') // ** matches anything including /
|
|
307
|
+
.replace(/\?/g, '.'); // ? matches single char
|
|
308
|
+
return new RegExp(pattern);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Extracts test file include patterns from vitest config to ignore in Stencil watch
|
|
312
|
+
*/
|
|
313
|
+
async function getTestFilePatternsFromVitestConfig(customVitestConfig) {
|
|
314
|
+
const defaultPatterns = [/\.spec\.[jt]sx?$/, /\.test\.[jt]sx?$/];
|
|
272
315
|
try {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
316
|
+
const vitestConfigPath = resolveVitestConfigPath(customVitestConfig);
|
|
317
|
+
if (!vitestConfigPath) {
|
|
318
|
+
return defaultPatterns;
|
|
319
|
+
}
|
|
320
|
+
if (verbose) {
|
|
321
|
+
log(`Loading test file patterns from ${vitestConfigPath}`);
|
|
322
|
+
}
|
|
323
|
+
const configObj = await loadVitestConfig(vitestConfigPath);
|
|
324
|
+
const testConfig = configObj?.test || configObj;
|
|
325
|
+
// Extract include patterns from various possible locations
|
|
326
|
+
const includePatterns = [];
|
|
327
|
+
// Root level include
|
|
328
|
+
if (testConfig?.include) {
|
|
329
|
+
includePatterns.push(...(Array.isArray(testConfig.include) ? testConfig.include : [testConfig.include]));
|
|
330
|
+
}
|
|
331
|
+
// Check projects for include patterns
|
|
332
|
+
const projects = testConfig?.projects || [];
|
|
333
|
+
for (const project of projects) {
|
|
334
|
+
const projectTest = project?.test || project;
|
|
335
|
+
if (projectTest?.include) {
|
|
336
|
+
includePatterns.push(...(Array.isArray(projectTest.include) ? projectTest.include : [projectTest.include]));
|
|
282
337
|
}
|
|
283
338
|
}
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
339
|
+
// Convert glob patterns to RegExp
|
|
340
|
+
const patterns = includePatterns.map(globToRegex);
|
|
341
|
+
if (verbose && patterns.length > 0) {
|
|
342
|
+
log(`Extracted ${patterns.length} test file patterns from vitest config`);
|
|
343
|
+
}
|
|
344
|
+
return patterns.length > 0 ? patterns : defaultPatterns;
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
if (verbose) {
|
|
348
|
+
log(`Failed to parse vitest config for test patterns: ${error instanceof Error ? error.message : String(error)}`);
|
|
292
349
|
}
|
|
350
|
+
return defaultPatterns;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Extracts screenshot directory patterns from vitest config to ignore in Stencil watch
|
|
355
|
+
*/
|
|
356
|
+
async function getScreenshotPatternsFromVitestConfig(customVitestConfig) {
|
|
357
|
+
const patterns = [];
|
|
358
|
+
try {
|
|
359
|
+
const vitestConfigPath = resolveVitestConfigPath(customVitestConfig);
|
|
293
360
|
if (!vitestConfigPath) {
|
|
294
361
|
if (verbose) {
|
|
295
362
|
log('No vitest config found, using default screenshot patterns');
|
|
@@ -300,9 +367,7 @@ async function getScreenshotPatternsFromVitestConfig(customVitestConfig) {
|
|
|
300
367
|
if (verbose) {
|
|
301
368
|
log(`Loading vitest config from ${vitestConfigPath}`);
|
|
302
369
|
}
|
|
303
|
-
|
|
304
|
-
const jiti = createJiti(cwd, { interopDefault: true });
|
|
305
|
-
const vitestConfig = await jiti.import(vitestConfigPath);
|
|
370
|
+
const vitestConfig = await loadVitestConfig(vitestConfigPath);
|
|
306
371
|
// Extract screenshot directory from browser test config
|
|
307
372
|
const projects = vitestConfig?.default?.test?.projects || vitestConfig?.test?.projects || [];
|
|
308
373
|
const customScreenshotDirs = new Set();
|
|
@@ -341,7 +406,7 @@ async function getScreenshotPatternsFromVitestConfig(customVitestConfig) {
|
|
|
341
406
|
}
|
|
342
407
|
/**
|
|
343
408
|
* Creates a temporary stencil config that extends the user's config
|
|
344
|
-
* and adds watchIgnoredRegex patterns for screenshots
|
|
409
|
+
* and adds watchIgnoredRegex patterns for screenshots and test files
|
|
345
410
|
*/
|
|
346
411
|
async function createTemporaryStencilConfig(userSpecifiedConfig, vitestConfigPath) {
|
|
347
412
|
try {
|
|
@@ -374,8 +439,11 @@ async function createTemporaryStencilConfig(userSpecifiedConfig, vitestConfigPat
|
|
|
374
439
|
return null;
|
|
375
440
|
}
|
|
376
441
|
}
|
|
377
|
-
// Get
|
|
378
|
-
const screenshotPatterns = await
|
|
442
|
+
// Get patterns to ignore from vitest config
|
|
443
|
+
const [screenshotPatterns, testFilePatterns] = await Promise.all([
|
|
444
|
+
getScreenshotPatternsFromVitestConfig(vitestConfigPath),
|
|
445
|
+
getTestFilePatternsFromVitestConfig(vitestConfigPath),
|
|
446
|
+
]);
|
|
379
447
|
// Load the user's config using jiti
|
|
380
448
|
const jiti = createJiti(cwd, { interopDefault: true });
|
|
381
449
|
const userConfig = await jiti.import(userConfigPath);
|
|
@@ -384,7 +452,7 @@ async function createTemporaryStencilConfig(userSpecifiedConfig, vitestConfigPat
|
|
|
384
452
|
// Merge with watchIgnoredRegex
|
|
385
453
|
const mergedConfig = {
|
|
386
454
|
...actualConfig,
|
|
387
|
-
watchIgnoredRegex: [...(actualConfig?.watchIgnoredRegex || []), ...screenshotPatterns],
|
|
455
|
+
watchIgnoredRegex: [...(actualConfig?.watchIgnoredRegex || []), ...screenshotPatterns, ...testFilePatterns],
|
|
388
456
|
};
|
|
389
457
|
// Create temp file as sibling of stencil.config so tsconfig.json can be found
|
|
390
458
|
// Stencil looks for tsconfig.json relative to the config file location
|
|
@@ -415,7 +483,7 @@ async function createTemporaryStencilConfig(userSpecifiedConfig, vitestConfigPat
|
|
|
415
483
|
writeFileSync(tempConfigPath, tempConfigContent, 'utf-8');
|
|
416
484
|
if (verbose) {
|
|
417
485
|
log(`Created temporary stencil config at ${tempConfigPath}`);
|
|
418
|
-
log(`Added ${screenshotPatterns.length} watch ignore
|
|
486
|
+
log(`Added ${screenshotPatterns.length} screenshot patterns and ${testFilePatterns.length} test file patterns to watch ignore`);
|
|
419
487
|
}
|
|
420
488
|
return tempConfigPath;
|
|
421
489
|
}
|
|
@@ -490,7 +558,7 @@ process.on('SIGTERM', () => cleanup());
|
|
|
490
558
|
if (tempStencilConfigPath) {
|
|
491
559
|
stencilArgs.push('--config', tempStencilConfigPath);
|
|
492
560
|
if (verbose) {
|
|
493
|
-
log('Using temporary config with
|
|
561
|
+
log('Using temporary config with watch ignore patterns for screenshots and test files');
|
|
494
562
|
}
|
|
495
563
|
}
|
|
496
564
|
else if (args.stencilConfig) {
|
package/dist/config.js
CHANGED
|
@@ -162,6 +162,16 @@ function applyStencilDefaults(config, stencilConfig) {
|
|
|
162
162
|
if (!result.server.watch) {
|
|
163
163
|
result.server.watch = {};
|
|
164
164
|
}
|
|
165
|
+
// Ignore source map files to prevent unnecessary test re-runs
|
|
166
|
+
// Stencil may touch .map files without changing content, triggering Vite's watcher
|
|
167
|
+
if (!result.server.watch.ignored) {
|
|
168
|
+
result.server.watch.ignored = [];
|
|
169
|
+
}
|
|
170
|
+
const ignoredArray = Array.isArray(result.server.watch.ignored)
|
|
171
|
+
? result.server.watch.ignored
|
|
172
|
+
: [result.server.watch.ignored];
|
|
173
|
+
const mapIgnorePatterns = ['**/*.map', '**/*.map.js'];
|
|
174
|
+
result.server.watch.ignored = [...new Set([...ignoredArray, ...mapIgnorePatterns])];
|
|
165
175
|
// Ensure test config exists
|
|
166
176
|
if (!result.test) {
|
|
167
177
|
result.test = {};
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"type": "git",
|
|
5
5
|
"url": "https://github.com/stenciljs/vitest"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.6.1",
|
|
8
8
|
"description": "First-class testing utilities for Stencil design systems with Vitest",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"type": "module",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"dependencies": {
|
|
98
98
|
"jiti": "^2.6.1",
|
|
99
99
|
"local-pkg": "^1.1.2",
|
|
100
|
-
"vitest-environment-stencil": "1.
|
|
100
|
+
"vitest-environment-stencil": "1.6.1"
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
103
|
"@eslint/js": "^9.39.2",
|