Skip to content

Commit a0e584f

Browse files
authored
Merge pull request #32844 from storybookjs/yann/vitest-addon-setup-fixes
Addon Vitest: Fix incorrect file modifications during setup
2 parents 7ac43e3 + 0384713 commit a0e584f

File tree

3 files changed

+341
-38
lines changed

3 files changed

+341
-38
lines changed

code/addons/vitest/src/postinstall.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,11 +468,14 @@ export default async function postInstall(options: PostinstallOptions) {
468468
logger.plain(` ${rootConfig}`);
469469

470470
const formattedContent = await formatFileContent(rootConfig, generate(target).code);
471+
// Only add triple slash reference to vite.config files, not vitest.config files
472+
// vitest.config files already have the vitest/config types available
473+
const shouldAddReference = !configFileHasTypeReference && !vitestConfigFile;
471474
await writeFile(
472475
rootConfig,
473-
configFileHasTypeReference
474-
? formattedContent
475-
: '/// <reference types="vitest/config" />\n' + formattedContent
476+
shouldAddReference
477+
? '/// <reference types="vitest/config" />\n' + formattedContent
478+
: formattedContent
476479
);
477480
} else {
478481
logErrors(

code/addons/vitest/src/updateVitestFile.test.ts

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,88 @@ describe('updateConfigFile', () => {
611611
}));"
612612
`);
613613
});
614+
it('supports mergeConfig without defineConfig calls', async () => {
615+
const source = babel.babelParse(
616+
await loadTemplate('vitest.config.template.ts', {
617+
CONFIG_DIR: '.storybook',
618+
BROWSER_CONFIG: "{ provider: 'playwright' }",
619+
SETUP_FILE: '../.storybook/vitest.setup.ts',
620+
})
621+
);
622+
const target = babel.babelParse(`
623+
import { mergeConfig } from 'vite'
624+
import viteConfig from './vite.config'
625+
626+
export default mergeConfig(
627+
viteConfig,
628+
{
629+
plugins: [react()],
630+
test: {
631+
environment: 'jsdom',
632+
}
633+
}
634+
)
635+
`);
636+
637+
const before = babel.generate(target).code;
638+
const updated = updateConfigFile(source, target);
639+
expect(updated).toBe(true);
640+
641+
const after = babel.generate(target).code;
642+
643+
// check if the code was updated at all
644+
expect(after).not.toBe(before);
645+
646+
// check if the code was updated correctly
647+
expect(getDiff(before, after)).toMatchInlineSnapshot(`
648+
" import { mergeConfig } from 'vite';
649+
import viteConfig from './vite.config';
650+
651+
+ import path from 'node:path';
652+
+ import { fileURLToPath } from 'node:url';
653+
+ import { defineConfig } from 'vitest/config';
654+
+ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
655+
+ const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
656+
+
657+
+ // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
658+
+
659+
export default mergeConfig(viteConfig, {
660+
plugins: [react()],
661+
test: {
662+
663+
- environment: 'jsdom'
664+
-
665+
+ workspace: [{
666+
+ extends: true,
667+
+ test: {
668+
+ environment: 'jsdom'
669+
+ }
670+
+ }, {
671+
+ extends: true,
672+
+ plugins: [
673+
+ // The plugin will run tests for the stories defined in your Storybook config
674+
+ // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
675+
+ storybookTest({
676+
+ configDir: path.join(dirname, '.storybook')
677+
+ })],
678+
+ test: {
679+
+ name: 'storybook',
680+
+ browser: {
681+
+ enabled: true,
682+
+ headless: true,
683+
+ provider: 'playwright',
684+
+ instances: [{
685+
+ browser: 'chromium'
686+
+ }]
687+
+ },
688+
+ setupFiles: ['../.storybook/vitest.setup.ts']
689+
+ }
690+
+ }]
691+
+
692+
}
693+
});"
694+
`);
695+
});
614696

615697
it('supports mergeConfig without config containing test property', async () => {
616698
const source = babel.babelParse(
@@ -771,6 +853,204 @@ describe('updateConfigFile', () => {
771853
}));"
772854
`);
773855
});
856+
857+
it('extracts coverage config and keeps it at top level when using workspace', async () => {
858+
const source = babel.babelParse(
859+
await loadTemplate('vitest.config.template.ts', {
860+
CONFIG_DIR: '.storybook',
861+
BROWSER_CONFIG: "{ provider: 'playwright' }",
862+
SETUP_FILE: '../.storybook/vitest.setup.ts',
863+
})
864+
);
865+
const target = babel.babelParse(`
866+
import { mergeConfig, defineConfig } from 'vitest/config'
867+
import viteConfig from './vite.config'
868+
869+
export default mergeConfig(
870+
viteConfig,
871+
defineConfig({
872+
test: {
873+
name: 'node',
874+
environment: 'happy-dom',
875+
include: ['**/*.test.ts'],
876+
coverage: {
877+
exclude: [
878+
'storybook.setup.ts',
879+
'**/*.stories.*',
880+
],
881+
},
882+
},
883+
})
884+
)
885+
`);
886+
887+
const before = babel.generate(target).code;
888+
const updated = updateConfigFile(source, target);
889+
expect(updated).toBe(true);
890+
891+
const after = babel.generate(target).code;
892+
893+
// check if the code was updated at all
894+
expect(after).not.toBe(before);
895+
896+
// check if the code was updated correctly
897+
// Coverage should stay at the top level, not moved into the workspace
898+
expect(getDiff(before, after)).toMatchInlineSnapshot(`
899+
" import { mergeConfig, defineConfig } from 'vitest/config';
900+
import viteConfig from './vite.config';
901+
902+
+ import path from 'node:path';
903+
+ import { fileURLToPath } from 'node:url';
904+
+ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
905+
+ const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
906+
+
907+
+ // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
908+
+
909+
export default mergeConfig(viteConfig, defineConfig({
910+
test: {
911+
912+
- name: 'node',
913+
- environment: 'happy-dom',
914+
- include: ['**/*.test.ts'],
915+
-
916+
coverage: {
917+
exclude: ['storybook.setup.ts', '**/*.stories.*']
918+
919+
- }
920+
-
921+
+ },
922+
+ workspace: [{
923+
+ extends: true,
924+
+ test: {
925+
+ name: 'node',
926+
+ environment: 'happy-dom',
927+
+ include: ['**/*.test.ts']
928+
+ }
929+
+ }, {
930+
+ extends: true,
931+
+ plugins: [
932+
+ // The plugin will run tests for the stories defined in your Storybook config
933+
+ // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
934+
+ storybookTest({
935+
+ configDir: path.join(dirname, '.storybook')
936+
+ })],
937+
+ test: {
938+
+ name: 'storybook',
939+
+ browser: {
940+
+ enabled: true,
941+
+ headless: true,
942+
+ provider: 'playwright',
943+
+ instances: [{
944+
+ browser: 'chromium'
945+
+ }]
946+
+ },
947+
+ setupFiles: ['../.storybook/vitest.setup.ts']
948+
+ }
949+
+ }]
950+
+
951+
}
952+
}));"
953+
`);
954+
});
955+
956+
it('extracts coverage config and keeps it at top level when using projects', async () => {
957+
const source = babel.babelParse(
958+
await loadTemplate('vitest.config.3.2.template.ts', {
959+
CONFIG_DIR: '.storybook',
960+
BROWSER_CONFIG: "{ provider: 'playwright' }",
961+
SETUP_FILE: '../.storybook/vitest.setup.ts',
962+
})
963+
);
964+
const target = babel.babelParse(`
965+
import { mergeConfig, defineConfig } from 'vitest/config'
966+
import viteConfig from './vite.config'
967+
968+
export default mergeConfig(
969+
viteConfig,
970+
defineConfig({
971+
test: {
972+
name: 'node',
973+
environment: 'happy-dom',
974+
include: ['**/*.test.ts'],
975+
coverage: {
976+
exclude: [
977+
'storybook.setup.ts',
978+
'**/*.stories.*',
979+
],
980+
},
981+
},
982+
})
983+
)
984+
`);
985+
986+
const before = babel.generate(target).code;
987+
const updated = updateConfigFile(source, target);
988+
expect(updated).toBe(true);
989+
990+
const after = babel.generate(target).code;
991+
992+
// check if the code was updated at all
993+
expect(after).not.toBe(before);
994+
995+
// check if the code was updated correctly
996+
// Coverage should stay at the top level, not moved into the projects
997+
expect(getDiff(before, after)).toMatchInlineSnapshot(`
998+
" import { mergeConfig, defineConfig } from 'vitest/config';
999+
import viteConfig from './vite.config';
1000+
1001+
+ import path from 'node:path';
1002+
+ import { fileURLToPath } from 'node:url';
1003+
+ import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
1004+
+ const dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url));
1005+
+
1006+
+ // More info at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon
1007+
+
1008+
export default mergeConfig(viteConfig, defineConfig({
1009+
test: {
1010+
1011+
- name: 'node',
1012+
- environment: 'happy-dom',
1013+
- include: ['**/*.test.ts'],
1014+
-
1015+
coverage: {
1016+
exclude: ['storybook.setup.ts', '**/*.stories.*']
1017+
1018+
- }
1019+
-
1020+
+ },
1021+
+ projects: [{
1022+
+ extends: true,
1023+
+ test: {
1024+
+ name: 'node',
1025+
+ environment: 'happy-dom',
1026+
+ include: ['**/*.test.ts']
1027+
+ }
1028+
+ }, {
1029+
+ extends: true,
1030+
+ plugins: [
1031+
+ // The plugin will run tests for the stories defined in your Storybook config
1032+
+ // See options at: https://storybook.js.org/docs/next/writing-tests/integrations/vitest-addon#storybooktest
1033+
+ storybookTest({
1034+
+ configDir: path.join(dirname, '.storybook')
1035+
+ })],
1036+
+ test: {
1037+
+ name: 'storybook',
1038+
+ browser: {
1039+
+ enabled: true,
1040+
+ headless: true,
1041+
+ provider: 'playwright',
1042+
+ instances: [{
1043+
+ browser: 'chromium'
1044+
+ }]
1045+
+ },
1046+
+ setupFiles: ['../.storybook/vitest.setup.ts']
1047+
+ }
1048+
+ }]
1049+
+
1050+
}
1051+
}));"
1052+
`);
1053+
});
7741054
});
7751055

7761056
describe('updateWorkspaceFile', () => {

0 commit comments

Comments
 (0)