@@ -24,7 +24,8 @@ import { executeCommands, createFiles, determinePackageManager, executeTemplate,
24
24
export type PromptOptions = {
25
25
testDir : string ,
26
26
installGitHubActions : boolean ,
27
- language : 'JavaScript' | 'TypeScript'
27
+ language : 'JavaScript' | 'TypeScript' ,
28
+ framework : 'react' | 'vue' | 'svelte' | undefined ,
28
29
installPlaywrightDependencies : boolean ,
29
30
} ;
30
31
@@ -63,10 +64,14 @@ export class Generator {
63
64
language : this . options . lang ?. [ 0 ] === 'js' ? 'JavaScript' : 'TypeScript' ,
64
65
installPlaywrightDependencies : ! ! this . options [ 'install-deps' ] ,
65
66
testDir : fs . existsSync ( path . join ( this . rootDir , 'tests' ) ) ? 'e2e' : 'tests' ,
67
+ framework : undefined ,
66
68
} ;
67
69
}
68
- return await prompt < PromptOptions > ( [
69
- {
70
+
71
+ const isDefinitelyTS = fs . existsSync ( path . join ( this . rootDir , 'tsconfig.json' ) ) ;
72
+
73
+ const questions = [
74
+ ! isDefinitelyTS && {
70
75
type : 'select' ,
71
76
name : 'language' ,
72
77
message : 'Do you want to use TypeScript or JavaScript?' ,
@@ -75,27 +80,41 @@ export class Generator {
75
80
{ name : 'JavaScript' } ,
76
81
] ,
77
82
} ,
78
- {
83
+ this . options . ct && {
84
+ type : 'select' ,
85
+ name : 'framework' ,
86
+ message : 'Which framework do you use? (experimental)' ,
87
+ choices : [
88
+ { name : 'react' } ,
89
+ { name : 'vue' } ,
90
+ { name : 'svelte' } ,
91
+ ] ,
92
+ } ,
93
+ ! this . options . ct && {
79
94
type : 'text' ,
80
95
name : 'testDir' ,
81
96
message : 'Where to put your end-to-end tests?' ,
82
97
initial : fs . existsSync ( path . join ( this . rootDir , 'tests' ) ) ? 'e2e' : 'tests' ,
83
98
} ,
84
- {
99
+ ! this . options . ct && {
85
100
type : 'confirm' ,
86
101
name : 'installGitHubActions' ,
87
102
message : 'Add a GitHub Actions workflow?' ,
88
- initial : true ,
103
+ initial : false ,
89
104
} ,
90
105
// Avoid installing dependencies on Windows (vast majority does not run create-playwright on Windows)
91
106
// Avoid installing dependencies on Mac (there are no dependencies)
92
- ... ( process . platform === 'linux' ? [ {
107
+ process . platform === 'linux' && {
93
108
type : 'confirm' ,
94
109
name : 'installPlaywrightDependencies' ,
95
110
message : 'Install Playwright operating system dependencies (requires sudo / root - can be done manually via \sudo npx playwright install-deps\')?' ,
96
111
initial : false ,
97
- } ] : [ ] ) ,
98
- ] ) ;
112
+ } ,
113
+ ] ;
114
+ const result = await prompt < PromptOptions > ( questions . filter ( Boolean ) as any ) ;
115
+ if ( isDefinitelyTS )
116
+ result . language = 'TypeScript' ;
117
+ return result ;
99
118
}
100
119
101
120
private async _identifyChanges ( answers : PromptOptions ) {
@@ -107,8 +126,17 @@ export class Generator {
107
126
for ( const browserName of [ 'chromium' , 'firefox' , 'webkit' ] )
108
127
sections . set ( browserName , ! this . options . browser || this . options . browser . includes ( browserName ) ? 'show' : 'comment' ) ;
109
128
129
+ let installExamples = true ;
130
+ let ctPackageName = '' ;
131
+ if ( answers . framework ) {
132
+ ctPackageName = `@playwright/experimental-ct-${ answers . framework } ` ;
133
+ sections . set ( 'ct' , 'show' ) ;
134
+ installExamples = false ;
135
+ }
136
+
110
137
files . set ( `playwright.config.${ fileExtension } ` , executeTemplate ( this . _readAsset ( `playwright.config.${ fileExtension } ` ) , {
111
- testDir : answers . testDir ,
138
+ testDir : answers . testDir || '' ,
139
+ ctPackageName,
112
140
} , sections ) ) ;
113
141
114
142
if ( answers . installGitHubActions ) {
@@ -119,7 +147,8 @@ export class Generator {
119
147
files . set ( '.github/workflows/playwright.yml' , githubActionsScript ) ;
120
148
}
121
149
122
- files . set ( path . join ( answers . testDir , `example.spec.${ fileExtension } ` ) , this . _readAsset ( `example.spec.${ fileExtension } ` ) ) ;
150
+ if ( installExamples )
151
+ files . set ( path . join ( answers . testDir , `example.spec.${ fileExtension } ` ) , this . _readAsset ( `example.spec.${ fileExtension } ` ) ) ;
123
152
124
153
if ( ! fs . existsSync ( path . join ( this . rootDir , 'package.json' ) ) ) {
125
154
commands . push ( {
@@ -138,6 +167,25 @@ export class Generator {
138
167
command : this . packageManager === 'yarn' ? `yarn add --dev ${ packageName } ` : `npm install --save-dev ${ packageName } ` ,
139
168
} ) ;
140
169
170
+ if ( ctPackageName ) {
171
+ commands . push ( {
172
+ name : 'Installing Playwright Component Testing' ,
173
+ command : this . packageManager === 'yarn' ? `yarn add --dev ${ ctPackageName } @latest` : `npm install --save-dev ${ ctPackageName } @latest` ,
174
+ } ) ;
175
+
176
+ const extension = languageToFileExtension ( answers . language ) ;
177
+ const htmlTemplate = executeTemplate ( this . _readAsset ( path . join ( 'playwright' , 'index.html' ) ) , { extension } , new Map ( ) ) ;
178
+ files . set ( 'playwright/index.html' , htmlTemplate ) ;
179
+
180
+ const jsTemplate = this . _readAsset ( path . join ( 'playwright' , 'index.js' ) ) ;
181
+ files . set ( `playwright/index.${ extension } ` , jsTemplate ) ;
182
+
183
+ if ( answers . language === 'TypeScript' ) {
184
+ files . set ( `playwright/types.d.ts` , `import '${ ctPackageName } ';\n` ) ;
185
+ this . _patchTsconfigJSON ( ) ;
186
+ }
187
+ }
188
+
141
189
const browsersSuffix = this . options . browser ? ' ' + this . options . browser . join ( ' ' ) : '' ;
142
190
commands . push ( {
143
191
name : 'Downloading browsers' ,
@@ -154,8 +202,9 @@ export class Generator {
154
202
gitIgnore = fs . readFileSync ( gitIgnorePath , 'utf-8' ) . trimEnd ( ) + '\n' ;
155
203
if ( ! gitIgnore . includes ( 'node_modules' ) )
156
204
gitIgnore += 'node_modules/\n' ;
157
- gitIgnore += 'test-results/\n' ;
158
- gitIgnore += 'playwright-report/\n' ;
205
+ gitIgnore += '/test-results/\n' ;
206
+ gitIgnore += '/playwright-report/\n' ;
207
+ gitIgnore += '/dist-pw/\n' ;
159
208
fs . writeFileSync ( gitIgnorePath , gitIgnore ) ;
160
209
}
161
210
@@ -175,11 +224,25 @@ export class Generator {
175
224
await createFiles ( this . rootDir , files , true ) ;
176
225
}
177
226
227
+ private async _patchTsconfigJSON ( ) {
228
+ const tsconfigFile = path . join ( this . rootDir , 'tsconfig.json' ) ;
229
+ const files = new Map < string , string > ( ) ;
230
+ if ( ! fs . existsSync ( tsconfigFile ) ) {
231
+ files . set ( `tsconfig.json` , this . _readAsset ( path . join ( 'tsconfig.json' ) ) ) ;
232
+ } else {
233
+ const tsconfigJSON = fs . readFileSync ( path . join ( this . rootDir , 'tsconfig.json' ) , 'utf-8' ) ;
234
+ const newJSON = tsconfigJSON . replace ( / ( " i n c l u d e " [ \s \S ] * : [ \s \S ] \[ [ \s \S ] * " s r c " ) / m, '$1, "playwright/types.d.ts"' ) ;
235
+ if ( ! tsconfigJSON . includes ( 'playwright' ) && tsconfigJSON !== newJSON )
236
+ files . set ( 'tsconfig.json' , newJSON ) ;
237
+ }
238
+ await createFiles ( this . rootDir , files , true ) ;
239
+ }
240
+
178
241
private _printEpilogue ( answers : PromptOptions ) {
179
242
console . log ( colors . green ( '✔ Success!' ) + ' ' + colors . bold ( `Created a Playwright Test project at ${ this . rootDir } ` ) ) ;
180
243
const pathToNavigate = path . relative ( process . cwd ( ) , this . rootDir ) ;
181
244
const prefix = pathToNavigate !== '' ? ` cd ${ pathToNavigate } \n` : '' ;
182
- const exampleSpecPath = `${ answers . testDir } ${ path . sep } example.spec.${ languageToFileExtension ( answers . language ) } ` ;
245
+ const exampleSpecPath = `example.spec.${ languageToFileExtension ( answers . language ) } ` ;
183
246
const playwrightConfigPath = `playwright.config.${ languageToFileExtension ( answers . language ) } ` ;
184
247
console . log ( `Inside that directory, you can run several commands:
185
248
0 commit comments