@@ -4,13 +4,13 @@ import { execSync } from 'node:child_process';
4
4
import * as vitest from 'vitest' ;
5
5
import { installAddon , type AddonMap , type OptionMap } from 'sv' ;
6
6
import {
7
- addPnpmBuildDependencies ,
8
7
createProject ,
9
8
startPreview ,
9
+ addPnpmBuildDependencies ,
10
10
type CreateProject ,
11
11
type ProjectVariant
12
12
} 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' ;
14
14
import { fileURLToPath } from 'node:url' ;
15
15
16
16
const cwd = vitest . inject ( 'testDir' ) ;
@@ -19,26 +19,52 @@ const variants = vitest.inject('variants');
19
19
20
20
const SETUP_DIR = fileURLToPath ( new URL ( '.' , import . meta. url ) ) ;
21
21
22
- type Fixtures < Addons extends AddonMap > = {
22
+ type Fixtures = {
23
23
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 > } ;
25
30
} ;
26
31
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
+
28
44
let create : CreateProject ;
29
45
let browser : Browser ;
30
46
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
+ }
39
55
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 ) ! ;
42
68
43
69
// constructs a builder for create test projects
44
70
create = createProject ( { cwd, templatesDir, testName } ) ;
@@ -58,61 +84,79 @@ export function setupTest<Addons extends AddonMap>(addons: Addons) {
58
84
private : true
59
85
} )
60
86
) ;
61
- } ) ;
62
87
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 } ) ;
69
90
70
91
// test metadata
71
92
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' ) ;
73
94
74
- // run addon
75
95
const { pnpmBuildDependencies } = await installAddon ( {
76
96
cwd,
77
97
addons,
78
- options,
98
+ options : kind . options ,
79
99
packageManager : 'pnpm'
80
100
} ) ;
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
+ } ) ;
82
106
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 } ` ) ;
84
117
} ;
85
118
86
119
return async ( ) => {
87
- await browserCtx . close ( ) ;
120
+ if ( withBrowser ) {
121
+ await browserCtx . close ( ) ;
122
+ }
88
123
// ...other tear downs
89
124
} ;
90
125
} ) ;
91
126
92
- return {
93
- test,
94
- variants,
95
- prepareServer
96
- } ;
127
+ return { test, addonTestCases, prepareServer } ;
97
128
}
98
129
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 ) {
108
143
// 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 } ) ;
110
148
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 ) ;
113
151
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
+ }
116
160
117
161
return { url, close } ;
118
162
}
0 commit comments