@stencil/vitest 1.13.3 → 1.15.0

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.
@@ -78,14 +78,6 @@ describe('wizard.generate.fileTemplates', () => {
78
78
  expect(content).not.toContain("import './my-button'");
79
79
  expect(content).toContain("describe('my-button'");
80
80
  });
81
- it('passes subdirectory to templates', async () => {
82
- const ctx = {
83
- prompts: { text: vi.fn().mockResolvedValue('__tests__'), isCancel: noCancel },
84
- config: { rootDir: tmpDir, fsNamespace: 'my-lib', outputTargets: [] },
85
- };
86
- const templates = await callFileTemplates(ctx);
87
- expect(templates[0].subdirectory).toBe('__tests__');
88
- });
89
81
  it('uses project-based templates when vitest.config.ts has a node project', async () => {
90
82
  writeFileSync(join(tmpDir, 'vitest.config.ts'), `export default {
91
83
  test: {
@@ -129,6 +121,29 @@ describe('wizard.generate.fileTemplates', () => {
129
121
  expect(templates).toHaveLength(1);
130
122
  expect(templates[0].selectedByDefault).toBe(false);
131
123
  });
124
+ it('includes a component import for a browser project using the unplugin plugin', async () => {
125
+ writeFileSync(join(tmpDir, 'vitest.config.ts'), `export default {
126
+ test: {
127
+ projects: [
128
+ {
129
+ plugins: [{}],
130
+ test: {
131
+ name: 'browser',
132
+ include: ['**/*.browser.spec.{ts,tsx}'],
133
+ browser: { enabled: true },
134
+ },
135
+ },
136
+ ],
137
+ },
138
+ };\n`);
139
+ const ctx = {
140
+ prompts: { text: vi.fn().mockResolvedValue(''), isCancel: noCancel },
141
+ config: { rootDir: tmpDir, fsNamespace: 'my-lib', outputTargets: [] },
142
+ };
143
+ const templates = await callFileTemplates(ctx);
144
+ const content = templates[0].template('my-button');
145
+ expect(content).toContain("import './my-button'");
146
+ });
132
147
  });
133
148
  describe('wizard.init.run', () => {
134
149
  let tmpDir;
@@ -160,14 +175,15 @@ describe('wizard.init.run', () => {
160
175
  const configContent = readFileSync(join(tmpDir, 'vitest.config.ts'), 'utf8');
161
176
  expect(configContent).toContain("name: 'unit'");
162
177
  });
163
- it('creates vitest.config.ts with stencilVitestPlugin for a node+plugin project', async () => {
178
+ it('creates vitest.config.ts with @stencil/unplugin for a node+plugin project', async () => {
164
179
  const ctx = makeInitCtx(tmpDir);
165
180
  ctx.prompts.text.mockResolvedValueOnce('unit').mockResolvedValueOnce('**/*.spec.{ts,tsx}');
166
181
  ctx.prompts.select.mockResolvedValueOnce('node').mockResolvedValueOnce('mock-doc').mockResolvedValueOnce('plugin');
167
182
  ctx.prompts.confirm.mockResolvedValueOnce(false);
168
183
  await wizard.init.run(ctx);
169
184
  const config = readFileSync(join(tmpDir, 'vitest.config.ts'), 'utf8');
170
- expect(config).toContain('stencilVitestPlugin()');
185
+ expect(config).toContain("import { stencilVite } from '@stencil/unplugin';");
186
+ expect(config).toContain('stencilVite()');
171
187
  expect(config).toContain("name: 'unit'");
172
188
  expect(config).toContain("include: ['**/*.spec.{ts,tsx}']");
173
189
  expect(config).not.toContain('setupFiles');
@@ -182,7 +198,7 @@ describe('wizard.init.run', () => {
182
198
  ctx.prompts.confirm.mockResolvedValueOnce(false);
183
199
  await wizard.init.run(ctx);
184
200
  const config = readFileSync(join(tmpDir, 'vitest.config.ts'), 'utf8');
185
- expect(config).not.toContain('stencilVitestPlugin');
201
+ expect(config).not.toContain('stencilVite');
186
202
  expect(config).toContain("setupFiles: ['./vitest-setup.ts']");
187
203
  expect(config).toContain("domEnvironment: 'happy-dom'");
188
204
  });
@@ -220,23 +236,52 @@ describe('wizard.init.run', () => {
220
236
  await wizard.init.run(ctx);
221
237
  expect(ctx.nypm.addDependency).toHaveBeenCalledWith(expect.arrayContaining(['vitest', 'jsdom']), expect.objectContaining({ dev: true }));
222
238
  });
223
- it('installs playwright packages for a browser+playwright project', async () => {
239
+ it('installs playwright packages for a browser+playwright+full-build project', async () => {
224
240
  const ctx = makeInitCtx(tmpDir);
225
241
  ctx.prompts.text.mockResolvedValueOnce('browser').mockResolvedValueOnce('**/*.browser.spec.{ts,tsx}');
226
- ctx.prompts.select.mockResolvedValueOnce('browser').mockResolvedValueOnce('playwright');
242
+ ctx.prompts.select
243
+ .mockResolvedValueOnce('browser')
244
+ .mockResolvedValueOnce('playwright')
245
+ .mockResolvedValueOnce('full-build');
227
246
  ctx.prompts.confirm.mockResolvedValueOnce(false);
228
247
  await wizard.init.run(ctx);
229
248
  expect(ctx.nypm.addDependency).toHaveBeenCalledWith(expect.arrayContaining(['vitest', '@vitest/browser', '@vitest/browser-playwright', 'playwright']), expect.objectContaining({ dev: true }));
249
+ expect(ctx.nypm.addDependency).not.toHaveBeenCalledWith(expect.arrayContaining(['@stencil/unplugin']), expect.anything());
230
250
  });
231
- it('installs wdio packages for a browser+webdriverio project', async () => {
251
+ it('installs wdio packages for a browser+webdriverio+full-build project', async () => {
232
252
  const ctx = makeInitCtx(tmpDir);
233
253
  ctx.prompts.text.mockResolvedValueOnce('browser').mockResolvedValueOnce('**/*.browser.spec.{ts,tsx}');
234
- ctx.prompts.select.mockResolvedValueOnce('browser').mockResolvedValueOnce('wdio');
254
+ ctx.prompts.select
255
+ .mockResolvedValueOnce('browser')
256
+ .mockResolvedValueOnce('wdio')
257
+ .mockResolvedValueOnce('full-build');
235
258
  ctx.prompts.confirm.mockResolvedValueOnce(false);
236
259
  await wizard.init.run(ctx);
237
260
  expect(ctx.nypm.addDependency).toHaveBeenCalledWith(expect.arrayContaining(['vitest', '@vitest/browser', '@vitest/browser-webdriverio']), expect.objectContaining({ dev: true }));
238
261
  expect(ctx.nypm.addDependency).not.toHaveBeenCalledWith(expect.arrayContaining(['playwright']), expect.anything());
239
262
  });
263
+ it('sets up a browser+plugin project with @stencil/unplugin - no build required', async () => {
264
+ const ctx = makeInitCtx(tmpDir);
265
+ ctx.prompts.text.mockResolvedValueOnce('browser').mockResolvedValueOnce('**/*.browser.spec.{ts,tsx}');
266
+ ctx.prompts.select
267
+ .mockResolvedValueOnce('browser')
268
+ .mockResolvedValueOnce('playwright')
269
+ .mockResolvedValueOnce('plugin');
270
+ ctx.prompts.confirm.mockResolvedValueOnce(false);
271
+ await wizard.init.run(ctx);
272
+ expect(ctx.nypm.addDependency).toHaveBeenCalledWith(expect.arrayContaining([
273
+ 'vitest',
274
+ '@vitest/browser',
275
+ '@vitest/browser-playwright',
276
+ 'playwright',
277
+ '@stencil/unplugin',
278
+ ]), expect.objectContaining({ dev: true }));
279
+ const config = readFileSync(join(tmpDir, 'vitest.config.ts'), 'utf8');
280
+ expect(config).toContain("import { stencilVite } from '@stencil/unplugin';");
281
+ expect(config).toContain('stencilVite()');
282
+ expect(config).not.toContain('setupFiles');
283
+ expect(existsSync(join(tmpDir, 'vitest-setup.ts'))).toBe(false);
284
+ });
240
285
  it('writes test and test:<name> scripts to package.json', async () => {
241
286
  const ctx = makeInitCtx(tmpDir);
242
287
  ctx.prompts.text.mockResolvedValueOnce('unit').mockResolvedValueOnce('**/*.spec.{ts,tsx}');
@@ -280,8 +325,7 @@ export class MyButton { render() { return <button />; } }
280
325
  const ctx = makeInitCtx(tmpDir, [], true);
281
326
  ctx.prompts.text
282
327
  .mockResolvedValueOnce('unit') // project name
283
- .mockResolvedValueOnce('**/*.spec.{ts,tsx}') // pattern
284
- .mockResolvedValueOnce(''); // subdirectory (empty = co-locate)
328
+ .mockResolvedValueOnce('**/*.spec.{ts,tsx}'); // pattern
285
329
  ctx.prompts.select.mockResolvedValueOnce('node').mockResolvedValueOnce('mock-doc').mockResolvedValueOnce('plugin');
286
330
  ctx.prompts.confirm.mockResolvedValueOnce(false);
287
331
  await wizard.init.run(ctx);
@@ -291,24 +335,6 @@ export class MyButton { render() { return <button />; } }
291
335
  expect(spec).toContain("describe('my-button'");
292
336
  expect(spec).toContain('<my-button />');
293
337
  });
294
- it('generates example spec files into a subdirectory for new projects', async () => {
295
- const componentDir = join(tmpDir, 'src', 'components', 'my-button');
296
- mkdirSync(componentDir, { recursive: true });
297
- writeFileSync(join(componentDir, 'my-button.tsx'), `import { Component, h } from '@stencil/core';
298
- @Component({ tag: 'my-button', shadow: true })
299
- export class MyButton { render() { return <button />; } }
300
- `);
301
- const ctx = makeInitCtx(tmpDir, [], true);
302
- ctx.prompts.text
303
- .mockResolvedValueOnce('unit')
304
- .mockResolvedValueOnce('**/*.spec.{ts,tsx}')
305
- .mockResolvedValueOnce('__tests__');
306
- ctx.prompts.select.mockResolvedValueOnce('node').mockResolvedValueOnce('mock-doc').mockResolvedValueOnce('plugin');
307
- ctx.prompts.confirm.mockResolvedValueOnce(false);
308
- await wizard.init.run(ctx);
309
- const specFile = join(componentDir, '__tests__', 'my-button.spec.tsx');
310
- expect(existsSync(specFile)).toBe(true);
311
- });
312
338
  it('skips example test generation when isNewProject is false', async () => {
313
339
  const componentDir = join(tmpDir, 'src', 'components', 'my-button');
314
340
  mkdirSync(componentDir, { recursive: true });
@@ -345,7 +371,8 @@ export class MyButton { render() { return <button />; } }
345
371
  .mockResolvedValueOnce('mock-doc')
346
372
  .mockResolvedValueOnce('plugin')
347
373
  .mockResolvedValueOnce('browser')
348
- .mockResolvedValueOnce('playwright');
374
+ .mockResolvedValueOnce('playwright')
375
+ .mockResolvedValueOnce('full-build');
349
376
  ctx.prompts.confirm
350
377
  .mockResolvedValueOnce(true) // add another
351
378
  .mockResolvedValueOnce(false); // stop
@@ -353,7 +380,7 @@ export class MyButton { render() { return <button />; } }
353
380
  const config = readFileSync(join(tmpDir, 'vitest.config.ts'), 'utf8');
354
381
  expect(config).toContain("name: 'unit'");
355
382
  expect(config).toContain("name: 'browser'");
356
- expect(config).toContain('stencilVitestPlugin()');
383
+ expect(config).toContain('stencilVite()');
357
384
  expect(config).toContain('playwright()');
358
385
  });
359
386
  });
@@ -1 +1 @@
1
- {"version":3,"file":"html-serializer.d.ts","sourceRoot":"","sources":["../../src/testing/html-serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkCH,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qCAAqC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,gBAAgB,GAAG,MAAM,EAC3D,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAWR;AAyID;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuDjD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
1
+ {"version":3,"file":"html-serializer.d.ts","sourceRoot":"","sources":["../../src/testing/html-serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkCH,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qCAAqC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,gBAAgB,GAAG,MAAM,EAC3D,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAWR;AAiJD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuDjD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
@@ -103,6 +103,13 @@ function serializeElementWithShadow(element, excludeStyles, serializeShadowRoot
103
103
  if (shadowRoot.delegatesFocus) {
104
104
  shadowRootTag += ' shadowrootdelegatesfocus';
105
105
  }
106
+ // Add serializable/clonable if true
107
+ if (shadowRoot.serializable) {
108
+ shadowRootTag += ' shadowrootserializable';
109
+ }
110
+ if (shadowRoot.clonable) {
111
+ shadowRootTag += ' shadowrootclonable';
112
+ }
106
113
  shadowRootTag += '>';
107
114
  html += shadowRootTag;
108
115
  // Serialize shadow DOM children
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkC,mBAAmB,EAAiB,MAAM,cAAc,CAAC;AAqcvG,eAAO,MAAM,MAAM,EAAE,mBAkIpB,CAAC"}
1
+ {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkC,mBAAmB,EAAiB,MAAM,cAAc,CAAC;AAycvG,eAAO,MAAM,MAAM,EAAE,mBAmHpB,CAAC"}
package/dist/wizard.js CHANGED
@@ -1,4 +1,4 @@
1
- import { access, mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
1
+ import { access, readdir, readFile, writeFile } from 'node:fs/promises';
2
2
  import { join, relative } from 'node:path';
3
3
  /** Reads the existing vitest.config.ts (if any) and extracts project name/pattern/type metadata. */
4
4
  async function loadVitestProjects(rootDir) {
@@ -17,10 +17,10 @@ async function loadVitestProjects(rootDir) {
17
17
  const pattern = test.include?.[0];
18
18
  if (!name || !pattern)
19
19
  return [];
20
+ const loadMethod = Array.isArray(p.plugins) && p.plugins.length > 0 ? 'plugin' : 'full-build';
20
21
  if (test.browser?.enabled === true) {
21
- return [{ type: 'browser', name, pattern }];
22
+ return [{ type: 'browser', name, pattern, loadMethod }];
22
23
  }
23
- const loadMethod = Array.isArray(p.plugins) && p.plugins.length > 0 ? 'plugin' : 'full-build';
24
24
  return [{ type: 'node', name, pattern, loadMethod }];
25
25
  });
26
26
  }
@@ -76,7 +76,7 @@ function defaultPattern(name) {
76
76
  return `**/*.${name}.spec.{ts,tsx}`;
77
77
  }
78
78
  /** Runs the interactive prompts for a single Vitest project and returns its configuration. */
79
- async function promptProject(prompts, usedPatterns, outputTargets, isFirst, askSubdirectory) {
79
+ async function promptProject(prompts, usedPatterns, outputTargets, isFirst) {
80
80
  const { text, select, isCancel, cancel, log } = prompts;
81
81
  const rawName = await text({
82
82
  message: 'Project name? (label for this group of tests - e.g. unit, browser, jsdom)',
@@ -115,19 +115,6 @@ async function promptProject(prompts, usedPatterns, outputTargets, isFirst, askS
115
115
  log.warn(`"${pattern}" is already claimed by another project - files will run in both.`);
116
116
  }
117
117
  usedPatterns.add(pattern);
118
- let subdirectory;
119
- if (askSubdirectory) {
120
- const rawSubdir = await text({
121
- message: 'Test file subdirectory? (leave blank to co-locate with component)',
122
- placeholder: 'e.g. __tests__',
123
- defaultValue: '',
124
- });
125
- if (isCancel(rawSubdir)) {
126
- cancel('Setup cancelled.');
127
- process.exit(0);
128
- }
129
- subdirectory = rawSubdir.trim() || undefined;
130
- }
131
118
  if (projectType === 'browser') {
132
119
  const provider = await select({
133
120
  message: 'Browser provider?',
@@ -140,7 +127,28 @@ async function promptProject(prompts, usedPatterns, outputTargets, isFirst, askS
140
127
  cancel('Setup cancelled.');
141
128
  process.exit(0);
142
129
  }
143
- return { type: 'browser', name, pattern, subdirectory, provider: provider };
130
+ const browserLoadMethod = await select({
131
+ message: 'How should components be loaded?',
132
+ options: [
133
+ {
134
+ value: 'plugin',
135
+ label: 'Plugin (source)',
136
+ hint: 'compile on-the-fly via @stencil/unplugin - no dist build required',
137
+ },
138
+ { value: 'full-build', label: 'Full build (dist)', hint: 'test the built loader/standalone bundle' },
139
+ ],
140
+ });
141
+ if (isCancel(browserLoadMethod)) {
142
+ cancel('Setup cancelled.');
143
+ process.exit(0);
144
+ }
145
+ return {
146
+ type: 'browser',
147
+ name,
148
+ pattern,
149
+ provider: provider,
150
+ loadMethod: browserLoadMethod,
151
+ };
144
152
  }
145
153
  // Node-based
146
154
  const env = await select({
@@ -158,8 +166,16 @@ async function promptProject(prompts, usedPatterns, outputTargets, isFirst, askS
158
166
  const loadMethod = await select({
159
167
  message: 'How should components be loaded?',
160
168
  options: [
161
- { value: 'plugin', label: 'Plugin (source)', hint: 'compile on-the-fly - module mocking, accurate coverage' },
162
- { value: 'full-build', label: 'Full build (dist)', hint: 'test the actual output - no mocking, no coverage' },
169
+ {
170
+ value: 'plugin',
171
+ label: 'Plugin (source)',
172
+ hint: 'compile on-the-fly via @stencil/unplugin - module mocking, accurate coverage',
173
+ },
174
+ {
175
+ value: 'full-build',
176
+ label: 'Full build (dist)',
177
+ hint: 'test the actual output - no module mocking, no coverage',
178
+ },
163
179
  ],
164
180
  });
165
181
  if (isCancel(loadMethod)) {
@@ -190,7 +206,6 @@ async function promptProject(prompts, usedPatterns, outputTargets, isFirst, askS
190
206
  type: 'node',
191
207
  name,
192
208
  pattern,
193
- subdirectory,
194
209
  env: env,
195
210
  loadMethod: loadMethod,
196
211
  outputTarget,
@@ -200,6 +215,8 @@ async function promptProject(prompts, usedPatterns, outputTargets, isFirst, askS
200
215
  function collectDeps(projects) {
201
216
  const deps = new Set(['vitest']);
202
217
  for (const p of projects) {
218
+ if (p.loadMethod === 'plugin')
219
+ deps.add('@stencil/unplugin');
203
220
  if (p.type === 'node') {
204
221
  if (p.env === 'jsdom')
205
222
  deps.add('jsdom');
@@ -222,13 +239,14 @@ function collectDeps(projects) {
222
239
  /** Renders a single Vitest workspace project block for vitest.config.ts. */
223
240
  function generateProjectBlock(project, excludePatterns) {
224
241
  const excludeLine = excludePatterns.length > 0 ? `\n exclude: [${excludePatterns.map((p) => `'${p}'`).join(', ')}],` : '';
242
+ const pluginsLine = project.loadMethod === 'plugin' ? '\n plugins: [stencilVite()],' : '';
243
+ const setupLine = project.loadMethod === 'full-build' ? `\n setupFiles: ['./vitest-setup.ts'],` : '';
225
244
  if (project.type === 'browser') {
226
245
  const providerExpr = project.provider === 'playwright' ? 'playwright()' : 'webdriverio()';
227
- return ` {
246
+ return ` {${pluginsLine}
228
247
  test: {
229
248
  name: '${project.name}',
230
- include: ['${project.pattern}'],${excludeLine}
231
- setupFiles: ['./vitest-setup.ts'],
249
+ include: ['${project.pattern}'],${excludeLine}${setupLine}
232
250
  browser: {
233
251
  enabled: true,
234
252
  provider: ${providerExpr},
@@ -244,8 +262,6 @@ function generateProjectBlock(project, excludePatterns) {
244
262
  stencil: { domEnvironment: '${project.env}' },
245
263
  },`
246
264
  : '';
247
- const pluginsLine = project.loadMethod === 'plugin' ? '\n plugins: [stencilVitestPlugin()],' : '';
248
- const setupLine = project.loadMethod === 'full-build' ? `\n setupFiles: ['./vitest-setup.ts'],` : '';
249
265
  return ` {${pluginsLine}
250
266
  test: {
251
267
  name: '${project.name}',
@@ -256,12 +272,12 @@ function generateProjectBlock(project, excludePatterns) {
256
272
  }
257
273
  /** Generates the full vitest.config.ts file content for the chosen set of projects. */
258
274
  function generateVitestConfig(projects, hasStencilConfig) {
259
- const needsPlugin = projects.some((p) => p.type === 'node' && p.loadMethod === 'plugin');
275
+ const needsPlugin = projects.some((p) => p.loadMethod === 'plugin');
260
276
  const needsPlaywright = projects.some((p) => p.type === 'browser' && p.provider === 'playwright');
261
277
  const needsWdio = projects.some((p) => p.type === 'browser' && p.provider === 'wdio');
262
278
  const imports = [
263
279
  `import { defineVitestConfig } from '@stencil/vitest/config';`,
264
- needsPlugin ? `import { stencilVitestPlugin } from '@stencil/vitest/plugin';` : null,
280
+ needsPlugin ? `import { stencilVite } from '@stencil/unplugin';` : null,
265
281
  needsPlaywright ? `import { playwright } from '@vitest/browser-playwright';` : null,
266
282
  needsWdio ? `import { webdriverio } from '@vitest/browser-webdriverio';` : null,
267
283
  ]
@@ -294,9 +310,8 @@ ${projectBlocks},
294
310
  });
295
311
  `;
296
312
  }
297
- function specTemplate(tagName, importComponent = false, subdirectory) {
298
- const importPath = subdirectory ? `'../${tagName}'` : `'./${tagName}'`;
299
- const componentImport = importComponent ? `import ${importPath};\n` : '';
313
+ function specTemplate(tagName, importComponent = false) {
314
+ const componentImport = importComponent ? `import './${tagName}';\n` : '';
300
315
  return `import { describe, it, expect, render } from '@stencil/vitest';
301
316
  ${componentImport}
302
317
  describe('${tagName}', () => {
@@ -340,23 +355,16 @@ async function generateExampleTests(rootDir, projects) {
340
355
  const suffix = parsePattern(project.pattern);
341
356
  if (!suffix)
342
357
  continue;
343
- const dir = project.subdirectory
344
- ? join(componentsDir, entry.name, project.subdirectory)
345
- : join(componentsDir, entry.name);
346
- const specFile = join(dir, `${tagName}${suffix}`);
358
+ const specFile = join(componentsDir, entry.name, `${tagName}${suffix}`);
347
359
  if (await fileExists(specFile))
348
360
  continue;
349
- if (project.subdirectory)
350
- await mkdir(dir, { recursive: true });
351
- const content = project.type === 'browser'
352
- ? specTemplate(tagName, false, project.subdirectory)
353
- : specTemplate(tagName, project.loadMethod === 'plugin', project.subdirectory);
361
+ const content = specTemplate(tagName, project.loadMethod === 'plugin');
354
362
  await writeFile(specFile, content, 'utf8');
355
363
  }
356
364
  }
357
365
  }
358
366
  function needsBuild(project) {
359
- return project.type === 'browser' || (project.type === 'node' && project.loadMethod === 'full-build');
367
+ return project.loadMethod === 'full-build';
360
368
  }
361
369
  /** Adds `test` and `test:<name>` scripts to package.json if they don't already exist. */
362
370
  async function updatePackageJsonScripts(rootDir, projects) {
@@ -402,7 +410,7 @@ export const wizard = {
402
410
  let isFirst = true;
403
411
  let keepAdding = true;
404
412
  while (keepAdding) {
405
- const project = await promptProject(prompts, usedPatterns, outputTargets, isFirst, isNewProject);
413
+ const project = await promptProject(prompts, usedPatterns, outputTargets, isFirst);
406
414
  projects.push(project);
407
415
  isFirst = false;
408
416
  const addAnother = await confirm({ message: 'Add another project?', initialValue: false });
@@ -415,7 +423,7 @@ export const wizard = {
415
423
  await nypm.addDependency(deps, { cwd: rootDir, dev: true });
416
424
  s.stop('Dependencies installed');
417
425
  }
418
- const needsSetupFile = projects.some((p) => p.type === 'browser' || (p.type === 'node' && p.loadMethod === 'full-build'));
426
+ const needsSetupFile = projects.some((p) => p.loadMethod === 'full-build');
419
427
  if (needsSetupFile) {
420
428
  const setupPath = join(rootDir, 'vitest-setup.ts');
421
429
  if (!(await fileExists(setupPath))) {
@@ -439,29 +447,21 @@ export const wizard = {
439
447
  },
440
448
  generate: {
441
449
  fileTemplates: async (ctx) => {
442
- const { prompts, config } = ctx;
450
+ const { config } = ctx;
443
451
  const projects = await loadVitestProjects(config.rootDir);
444
- const rawSubdir = await prompts.text({
445
- message: 'Test file subdirectory? (leave blank to co-locate with component)',
446
- placeholder: 'e.g. __tests__',
447
- defaultValue: '',
448
- });
449
- const subdirectory = !prompts.isCancel(rawSubdir) ? rawSubdir.trim() || undefined : undefined;
450
452
  if (projects.length === 0) {
451
453
  return [
452
454
  {
453
455
  label: 'Spec test (.spec.tsx)',
454
456
  extension: 'spec.tsx',
455
- subdirectory,
456
457
  selectedByDefault: true,
457
- template: (tagName) => specTemplate(tagName, true, subdirectory),
458
+ template: (tagName) => specTemplate(tagName, true),
458
459
  },
459
460
  {
460
461
  label: 'Browser test (.browser.spec.ts)',
461
462
  extension: 'browser.spec.ts',
462
- subdirectory,
463
463
  selectedByDefault: false,
464
- template: (tagName) => specTemplate(tagName, false, subdirectory),
464
+ template: (tagName) => specTemplate(tagName, false),
465
465
  },
466
466
  ];
467
467
  }
@@ -475,11 +475,8 @@ export const wizard = {
475
475
  {
476
476
  label,
477
477
  extension: ext,
478
- subdirectory,
479
478
  selectedByDefault: project.type === 'node',
480
- template: project.type === 'browser'
481
- ? (tagName) => specTemplate(tagName, false, subdirectory)
482
- : (tagName) => specTemplate(tagName, project.loadMethod === 'plugin', subdirectory),
479
+ template: (tagName) => specTemplate(tagName, project.loadMethod === 'plugin'),
483
480
  },
484
481
  ];
485
482
  });
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.13.3",
7
+ "version": "1.15.0",
8
8
  "description": "First-class testing utilities for Stencil design systems with Vitest",
9
9
  "license": "MIT",
10
10
  "type": "module",
@@ -76,7 +76,7 @@
76
76
  "access": "public"
77
77
  },
78
78
  "peerDependencies": {
79
- "@stencil/core": "^4.0.0 || ^5.0.0-0",
79
+ "@stencil/core": "^4.0.0 || >=5.0.0-alpha.0 <5.0.0-next.0 || ^5.0.0",
80
80
  "vitest": "^4.0.0 || ^3.0.0 || ^2.0.0"
81
81
  },
82
82
  "peerDependenciesMeta": {
@@ -111,14 +111,14 @@
111
111
  "dependencies": {
112
112
  "jiti": "^2.6.1",
113
113
  "local-pkg": "^1.1.2",
114
- "vitest-environment-stencil": "1.13.3"
114
+ "vitest-environment-stencil": "1.15.0"
115
115
  },
116
116
  "devDependencies": {
117
117
  "@eslint/js": "^9.39.2",
118
118
  "@semantic-release/changelog": "^6.0.3",
119
119
  "@semantic-release/exec": "^6.0.3",
120
120
  "@semantic-release/git": "^10.0.1",
121
- "@stencil/core": "^4.0.0 || ^5.0.0 || >=5.0.0-alpha.0 <5.0.0-next.0",
121
+ "@stencil/core": "^4.0.0 || >=5.0.0-alpha.0 <5.0.0-next.0 || ^5.0.0",
122
122
  "@stencil/cli": "^5.0.0 || >=5.0.0-alpha.0 <5.0.0-next.0",
123
123
  "@types/node": "24.10.4",
124
124
  "@typescript-eslint/eslint-plugin": "^8.50.0",