@@ -24,7 +24,8 @@ import { executeCommands, createFiles, determinePackageManager, executeTemplate,
2424export type PromptOptions = {
2525 testDir : string ,
2626 installGitHubActions : boolean ,
27- language : 'JavaScript' | 'TypeScript'
27+ language : 'JavaScript' | 'TypeScript' ,
28+ framework : 'react' | 'vue' | 'svelte' | undefined ,
2829 installPlaywrightDependencies : boolean ,
2930} ;
3031
@@ -63,10 +64,14 @@ export class Generator {
6364 language : this . options . lang ?. [ 0 ] === 'js' ? 'JavaScript' : 'TypeScript' ,
6465 installPlaywrightDependencies : ! ! this . options [ 'install-deps' ] ,
6566 testDir : fs . existsSync ( path . join ( this . rootDir , 'tests' ) ) ? 'e2e' : 'tests' ,
67+ framework : undefined ,
6668 } ;
6769 }
68- return await prompt < PromptOptions > ( [
69- {
70+
71+ const isDefinitelyTS = fs . existsSync ( path . join ( this . rootDir , 'tsconfig.json' ) ) ;
72+
73+ const questions = [
74+ ! isDefinitelyTS && {
7075 type : 'select' ,
7176 name : 'language' ,
7277 message : 'Do you want to use TypeScript or JavaScript?' ,
@@ -75,27 +80,41 @@ export class Generator {
7580 { name : 'JavaScript' } ,
7681 ] ,
7782 } ,
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 && {
7994 type : 'text' ,
8095 name : 'testDir' ,
8196 message : 'Where to put your end-to-end tests?' ,
8297 initial : fs . existsSync ( path . join ( this . rootDir , 'tests' ) ) ? 'e2e' : 'tests' ,
8398 } ,
84- {
99+ ! this . options . ct && {
85100 type : 'confirm' ,
86101 name : 'installGitHubActions' ,
87102 message : 'Add a GitHub Actions workflow?' ,
88- initial : true ,
103+ initial : false ,
89104 } ,
90105 // Avoid installing dependencies on Windows (vast majority does not run create-playwright on Windows)
91106 // Avoid installing dependencies on Mac (there are no dependencies)
92- ... ( process . platform === 'linux' ? [ {
107+ process . platform === 'linux' && {
93108 type : 'confirm' ,
94109 name : 'installPlaywrightDependencies' ,
95110 message : 'Install Playwright operating system dependencies (requires sudo / root - can be done manually via \sudo npx playwright install-deps\')?' ,
96111 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 ;
99118 }
100119
101120 private async _identifyChanges ( answers : PromptOptions ) {
@@ -107,8 +126,17 @@ export class Generator {
107126 for ( const browserName of [ 'chromium' , 'firefox' , 'webkit' ] )
108127 sections . set ( browserName , ! this . options . browser || this . options . browser . includes ( browserName ) ? 'show' : 'comment' ) ;
109128
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+
110137 files . set ( `playwright.config.${ fileExtension } ` , executeTemplate ( this . _readAsset ( `playwright.config.${ fileExtension } ` ) , {
111- testDir : answers . testDir ,
138+ testDir : answers . testDir || '' ,
139+ ctPackageName,
112140 } , sections ) ) ;
113141
114142 if ( answers . installGitHubActions ) {
@@ -119,7 +147,8 @@ export class Generator {
119147 files . set ( '.github/workflows/playwright.yml' , githubActionsScript ) ;
120148 }
121149
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 } ` ) ) ;
123152
124153 if ( ! fs . existsSync ( path . join ( this . rootDir , 'package.json' ) ) ) {
125154 commands . push ( {
@@ -138,6 +167,25 @@ export class Generator {
138167 command : this . packageManager === 'yarn' ? `yarn add --dev ${ packageName } ` : `npm install --save-dev ${ packageName } ` ,
139168 } ) ;
140169
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+
141189 const browsersSuffix = this . options . browser ? ' ' + this . options . browser . join ( ' ' ) : '' ;
142190 commands . push ( {
143191 name : 'Downloading browsers' ,
@@ -154,8 +202,9 @@ export class Generator {
154202 gitIgnore = fs . readFileSync ( gitIgnorePath , 'utf-8' ) . trimEnd ( ) + '\n' ;
155203 if ( ! gitIgnore . includes ( 'node_modules' ) )
156204 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' ;
159208 fs . writeFileSync ( gitIgnorePath , gitIgnore ) ;
160209 }
161210
@@ -175,11 +224,25 @@ export class Generator {
175224 await createFiles ( this . rootDir , files , true ) ;
176225 }
177226
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+
178241 private _printEpilogue ( answers : PromptOptions ) {
179242 console . log ( colors . green ( '✔ Success!' ) + ' ' + colors . bold ( `Created a Playwright Test project at ${ this . rootDir } ` ) ) ;
180243 const pathToNavigate = path . relative ( process . cwd ( ) , this . rootDir ) ;
181244 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 ) } ` ;
183246 const playwrightConfigPath = `playwright.config.${ languageToFileExtension ( answers . language ) } ` ;
184247 console . log ( `Inside that directory, you can run several commands:
185248
0 commit comments