Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
9 changes: 6 additions & 3 deletions code/addons/vitest/src/postinstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,11 +468,14 @@ export default async function postInstall(options: PostinstallOptions) {
logger.plain(` ${rootConfig}`);

const formattedContent = await formatFileContent(rootConfig, generate(target).code);
// Only add triple slash reference to vite.config files, not vitest.config files
// vitest.config files already have the vitest/config types available
const shouldAddReference = !configFileHasTypeReference && !vitestConfigFile;
await writeFile(
rootConfig,
configFileHasTypeReference
? formattedContent
: '/// <reference types="vitest/config" />\n' + formattedContent
shouldAddReference
? '/// <reference types="vitest/config" />\n' + formattedContent
: formattedContent
);
} else {
logErrors(
Expand Down
188 changes: 188 additions & 0 deletions code/addons/vitest/src/updateVitestFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,194 @@ describe('updateConfigFile', () => {
}));"
`);
});

it('extracts coverage config and keeps it at top level when using workspace', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.template.ts', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
})
);
const target = babel.babelParse(`
import { mergeConfig, defineConfig } from 'vitest/config'
import viteConfig from './vite.config'

export default mergeConfig(
viteConfig,
defineConfig({
test: {
name: 'node',
environment: 'happy-dom',
include: ['**/*.test.ts'],
coverage: {
exclude: [
'storybook.setup.ts',
'**/*.stories.*',
],
},
},
})
)
`);

const before = babel.generate(target).code;
const updated = updateConfigFile(source, target);
expect(updated).toBe(true);

const after = babel.generate(target).code;

// check if the code was updated at all
expect(after).not.toBe(before);

// check if the code was updated correctly
// Coverage should stay at the top level, not moved into the workspace
expect(getDiff(before, after)).toMatchInlineSnapshot(`
" import { mergeConfig, defineConfig } from 'vitest/config';
import viteConfig from './vite.config';

+ import path from 'node:path';
+ import { fileURLToPath } from 'node:url';
+ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
+ const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
+
+ // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
+
export default mergeConfig(viteConfig, defineConfig({
test: {

- name: 'node',
- environment: 'happy-dom',
- include: ['**/*.test.ts'],
-
coverage: {
exclude: ['storybook.setup.ts', '**/*.stories.*']

- }
-
+ },
+ workspace: [{
+ extends: true,
+ test: {
+ name: 'node',
+ environment: 'happy-dom',
+ include: ['**/*.test.ts']
+ }
+ }, {
+ extends: true,
+ plugins: [
+ // The plugin will run tests for the stories defined in your Storybook config
+ // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
+ storybookTest({
+ configDir: path.join(dirname, '.storybook')
+ })],
+ test: {
+ name: 'storybook',
+ browser: {
+ provider: 'playwright'
+ },
+ setupFiles: ['../.storybook/vitest.setup.ts']
+ }
+ }]
+
}
}));"
`);
});

it('extracts coverage config and keeps it at top level when using projects', async () => {
const source = babel.babelParse(
await loadTemplate('vitest.config.3.2.template.ts', {
CONFIG_DIR: '.storybook',
BROWSER_CONFIG: "{ provider: 'playwright' }",
SETUP_FILE: '../.storybook/vitest.setup.ts',
})
);
const target = babel.babelParse(`
import { mergeConfig, defineConfig } from 'vitest/config'
import viteConfig from './vite.config'

export default mergeConfig(
viteConfig,
defineConfig({
test: {
name: 'node',
environment: 'happy-dom',
include: ['**/*.test.ts'],
coverage: {
exclude: [
'storybook.setup.ts',
'**/*.stories.*',
],
},
},
})
)
`);

const before = babel.generate(target).code;
const updated = updateConfigFile(source, target);
expect(updated).toBe(true);

const after = babel.generate(target).code;

// check if the code was updated at all
expect(after).not.toBe(before);

// check if the code was updated correctly
// Coverage should stay at the top level, not moved into the projects
expect(getDiff(before, after)).toMatchInlineSnapshot(`
" import { mergeConfig, defineConfig } from 'vitest/config';
import viteConfig from './vite.config';

+ import path from 'node:path';
+ import { fileURLToPath } from 'node:url';
+ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
+ const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
+
+ // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
+
export default mergeConfig(viteConfig, defineConfig({
test: {

- name: 'node',
- environment: 'happy-dom',
- include: ['**/*.test.ts'],
-
coverage: {
exclude: ['storybook.setup.ts', '**/*.stories.*']

- }
-
+ },
+ projects: [{
+ extends: true,
+ test: {
+ name: 'node',
+ environment: 'happy-dom',
+ include: ['**/*.test.ts']
+ }
+ }, {
+ extends: true,
+ plugins: [
+ // The plugin will run tests for the stories defined in your Storybook config
+ // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
+ storybookTest({
+ configDir: path.join(dirname, '.storybook')
+ })],
+ test: {
+ name: 'storybook',
+ browser: {
+ provider: 'playwright'
+ },
+ setupFiles: ['../.storybook/vitest.setup.ts']
+ }
+ }]
+
}
}));"
`);
});
});

describe('updateWorkspaceFile', () => {
Expand Down
26 changes: 25 additions & 1 deletion code/addons/vitest/src/updateVitestFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,24 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as
workspaceOrProjectsProp &&
workspaceOrProjectsProp.value.type === 'ArrayExpression'
) {
// Extract coverage config before creating the test project
const coverageProp = existingTestProp.value.properties.find(
(p) =>
p.type === 'ObjectProperty' &&
p.key.type === 'Identifier' &&
p.key.name === 'coverage'
) as t.ObjectProperty | undefined;

// Create a new test config without the coverage property
const testPropsWithoutCoverage = existingTestProp.value.properties.filter(
(p) => p !== coverageProp
);

const testConfigForProject: t.ObjectExpression = {
type: 'ObjectExpression',
properties: testPropsWithoutCoverage,
};

// Create the existing test project
const existingTestProject: t.ObjectExpression = {
type: 'ObjectExpression',
Expand All @@ -263,7 +281,7 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as
{
type: 'ObjectProperty',
key: { type: 'Identifier', name: 'test' },
value: existingTestProp.value,
value: testConfigForProject,
computed: false,
shorthand: false,
},
Expand All @@ -278,6 +296,12 @@ export const updateConfigFile = (source: BabelFile['ast'], target: BabelFile['as
(p) => p !== existingTestProp
);

// If there was a coverage config, add it to the template's test config (at the top level of the test object)
// Insert it at the beginning so it appears before workspace/projects
if (coverageProp && templateTestProp.value.type === 'ObjectExpression') {
templateTestProp.value.properties.unshift(coverageProp);
}

// Merge the template properties (which now include our existing test project in the array)
mergeProperties(properties, defineConfigProps.properties);
} else {
Expand Down
Loading