@@ -4,13 +4,13 @@ import { execSync } from 'node:child_process';
44import * as vitest from 'vitest' ;
55import { installAddon , type AddonMap , type OptionMap } from 'sv' ;
66import {
7- addPnpmBuildDependencies ,
87 createProject ,
98 startPreview ,
9+ addPnpmBuildDependencies ,
1010 type CreateProject ,
1111 type ProjectVariant
1212} from 'sv/testing' ;
13- import { chromium , type Browser , type Page } from '@playwright/test' ;
13+ import { chromium , type Browser , type BrowserContext , type Page } from '@playwright/test' ;
1414import { fileURLToPath } from 'node:url' ;
1515
1616const cwd = vitest . inject ( 'testDir' ) ;
@@ -19,26 +19,52 @@ const variants = vitest.inject('variants');
1919
2020const SETUP_DIR = fileURLToPath ( new URL ( '.' , import . meta. url ) ) ;
2121
22- type Fixtures < Addons extends AddonMap > = {
22+ type Fixtures = {
2323 page : Page ;
24- run ( variant : ProjectVariant , options : OptionMap < Addons > ) : Promise < string > ;
24+ cwd ( addonTestCase : AddonTestCase < any > ) : string ;
25+ } ;
26+
27+ type AddonTestCase < Addons extends AddonMap > = {
28+ variant : ProjectVariant ;
29+ kind : { type : string ; options : OptionMap < Addons > } ;
2530} ;
2631
27- export function setupTest < Addons extends AddonMap > ( addons : Addons ) {
32+ export function setupTest < Addons extends AddonMap > (
33+ addons : Addons ,
34+ options ?: {
35+ kinds : Array < AddonTestCase < Addons > [ 'kind' ] > ;
36+ filter ?: ( addonTestCase : AddonTestCase < Addons > ) => boolean ;
37+ browser ?: boolean ;
38+ }
39+ ) {
40+ const test = vitest . test . extend < Fixtures > ( { } as any ) ;
41+
42+ const withBrowser = options ?. browser ?? true ;
43+
2844 let create : CreateProject ;
2945 let browser : Browser ;
3046
31- const test = vitest . test . extend < Fixtures < Addons > > ( { } as any ) ;
32-
33- vitest . beforeAll ( async ( ) => {
34- browser = await chromium . launch ( ) ;
35- return async ( ) => {
36- await browser . close ( ) ;
37- } ;
38- } ) ;
47+ if ( withBrowser ) {
48+ vitest . beforeAll ( async ( ) => {
49+ browser = await chromium . launch ( ) ;
50+ return async ( ) => {
51+ await browser . close ( ) ;
52+ } ;
53+ } ) ;
54+ }
3955
40- vitest . beforeAll ( ( { name } ) => {
41- const testName = path . parse ( name ) . name . replace ( '.test' , '' ) ;
56+ const addonTestCases : Array < AddonTestCase < Addons > > = [ ] ;
57+ for ( const kind of options ?. kinds ?? [ ] ) {
58+ for ( const variant of variants ) {
59+ const addonTestCase = { variant, kind } ;
60+ if ( ! options ?. filter || options ?. filter ?.( addonTestCase ) ) {
61+ addonTestCases . push ( addonTestCase ) ;
62+ }
63+ }
64+ }
65+ let testName : string ;
66+ vitest . beforeAll ( async ( { name } ) => {
67+ testName = path . dirname ( name ) . split ( '/' ) . at ( - 1 ) ! ;
4268
4369 // constructs a builder for create test projects
4470 create = createProject ( { cwd, templatesDir, testName } ) ;
@@ -58,61 +84,79 @@ export function setupTest<Addons extends AddonMap>(addons: Addons) {
5884 private : true
5985 } )
6086 ) ;
61- } ) ;
6287
63- // runs before each test case
64- vitest . beforeEach < Fixtures < Addons > > ( async ( ctx ) => {
65- const browserCtx = await browser . newContext ( ) ;
66- ctx . page = await browserCtx . newPage ( ) ;
67- ctx . run = async ( variant , options ) => {
68- const cwd = create ( { testId : ctx . task . id , variant } ) ;
88+ for ( const { variant, kind } of addonTestCases ) {
89+ const cwd = create ( { testId : `${ kind . type } -${ variant } ` , variant } ) ;
6990
7091 // test metadata
7192 const metaPath = path . resolve ( cwd , 'meta.json' ) ;
72- fs . writeFileSync ( metaPath , JSON . stringify ( { variant, options } , null , '\t' ) , 'utf8' ) ;
93+ fs . writeFileSync ( metaPath , JSON . stringify ( { variant, kind } , null , '\t' ) , 'utf8' ) ;
7394
74- // run addon
7595 const { pnpmBuildDependencies } = await installAddon ( {
7696 cwd,
7797 addons,
78- options,
98+ options : kind . options ,
7999 packageManager : 'pnpm'
80100 } ) ;
81- addPnpmBuildDependencies ( cwd , 'pnpm' , [ 'esbuild' , ...pnpmBuildDependencies ] ) ;
101+ await addPnpmBuildDependencies ( cwd , 'pnpm' , [ 'esbuild' , ...pnpmBuildDependencies ] ) ;
102+ }
103+
104+ execSync ( 'pnpm install' , { cwd : path . resolve ( cwd , testName ) , stdio : 'pipe' } ) ;
105+ } ) ;
82106
83- return cwd ;
107+ // runs before each test case
108+ vitest . beforeEach < Fixtures > ( async ( ctx ) => {
109+ let browserCtx : BrowserContext ;
110+ if ( withBrowser ) {
111+ browserCtx = await browser . newContext ( ) ;
112+ ctx . page = await browserCtx . newPage ( ) ;
113+ }
114+
115+ ctx . cwd = ( addonTestCase ) => {
116+ return path . join ( cwd , testName , `${ addonTestCase . kind . type } -${ addonTestCase . variant } ` ) ;
84117 } ;
85118
86119 return async ( ) => {
87- await browserCtx . close ( ) ;
120+ if ( withBrowser ) {
121+ await browserCtx . close ( ) ;
122+ }
88123 // ...other tear downs
89124 } ;
90125 } ) ;
91126
92- return {
93- test,
94- variants,
95- prepareServer
96- } ;
127+ return { test, addonTestCases, prepareServer } ;
97128}
98129
99- /**
100- * Installs dependencies, builds the project, and spins up the preview server
101- */
102- async function prepareServer ( { cwd, page } : { cwd : string ; page : Page } ) {
103- // install deps
104- execSync ( 'pnpm install --no-frozen-lockfile' , { cwd, stdio : 'pipe' } ) ;
105-
106- // ...do commands and any other extra stuff
107-
130+ type PrepareServerOptions = {
131+ cwd : string ;
132+ page : Page ;
133+ buildCommand ?: string ;
134+ previewCommand ?: string ;
135+ } ;
136+ // installs dependencies, builds the project, and spins up the preview server
137+ async function prepareServer ( {
138+ cwd,
139+ page,
140+ buildCommand = 'pnpm build' ,
141+ previewCommand = 'pnpm preview'
142+ } : PrepareServerOptions ) {
108143 // build project
109- execSync ( 'npm run build' , { cwd, stdio : 'pipe' } ) ;
144+ if ( buildCommand ) execSync ( buildCommand , { cwd, stdio : 'pipe' } ) ;
145+
146+ // start preview server
147+ const { url, close } = await startPreview ( { cwd, command : previewCommand } ) ;
110148
111- // start preview server `vite preview`
112- const { url , close } = await startPreview ( { cwd } ) ;
149+ // increases timeout as 30s is not always enough when running the full suite
150+ page . setDefaultNavigationTimeout ( 60_000 ) ;
113151
114- // navigate to the page
115- await page . goto ( url ) ;
152+ try {
153+ // navigate to the page
154+ await page . goto ( url ) ;
155+ } catch ( e ) {
156+ // cleanup in the instance of a timeout
157+ await close ( ) ;
158+ throw e ;
159+ }
116160
117161 return { url, close } ;
118162}
0 commit comments