diff --git a/src/cli.ts b/src/cli.ts index e01225f..5cb8f27 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -32,6 +32,7 @@ program .option('--beta', 'install @beta version of Playwright') .option('--quiet', 'do not ask for interactive input prompts') .option('--gha', 'install GitHub Actions') + .option('--no-gha', 'do not install GitHub Actions') .option('--lang ', 'language to use (js, TypeScript)') .option('--test-dir ', 'directory for test files (default: "tests" if it does not exist, otherwise "e2e")') .action(async (rootDir, options) => { @@ -43,7 +44,8 @@ program installDeps: options.installDeps, next: options.next, beta: options.beta, - quiet: options.quiet, + // Prompts cannot be answered without a TTY, fall back to the --quiet defaults. + quiet: options.quiet || !process.stdin.isTTY, gha: options.gha, lang: options.lang, testDir: options.testDir, diff --git a/src/generator.ts b/src/generator.ts index 7679d26..52e2d8b 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -97,7 +97,7 @@ export class Generator { const isDefinitelyTS = fs.existsSync(path.join(this.rootDir, 'tsconfig.json')); const questions = [ - !isDefinitelyTS && { + !isDefinitelyTS && !this.options.lang && { type: 'select', name: 'language', message: 'Do you want to use TypeScript or JavaScript?', @@ -105,8 +105,6 @@ export class Generator { { name: 'TypeScript' }, { name: 'JavaScript' }, ], - initial: this.options.lang === 'js' ? 'JavaScript' : 'TypeScript', - skip: !!this.options.lang, }, { type: 'text', @@ -119,8 +117,8 @@ export class Generator { type: 'confirm', name: 'installGitHubActions', message: 'Add a GitHub Actions workflow?', - initial: true, - skip: !!this.options.gha, + initial: this.options.gha ?? true, + skip: this.options.gha !== undefined, }, { type: 'confirm', @@ -147,6 +145,8 @@ export class Generator { ); if (isDefinitelyTS) result.language = 'TypeScript'; + else if (this.options.lang) + result.language = this.options.lang === 'js' ? 'JavaScript' : 'TypeScript'; return result; } diff --git a/tests/baseFixtures.ts b/tests/baseFixtures.ts index 23c4843..64a0ce2 100644 --- a/tests/baseFixtures.ts +++ b/tests/baseFixtures.ts @@ -33,7 +33,7 @@ const userAgents: Record = { export type TestFixtures = { packageManager: PackageManager; dir: string; - run: (parameters: string[], options: PromptOptions) => Promise, + run: (parameters: string[], options?: PromptOptions) => Promise, exec: typeof spawnAsync, }; @@ -86,13 +86,13 @@ export const test = base.extend({ }); }, run: async ({ packageManager, exec, dir }, use) => { - await use(async (parameters: string[], options: PromptOptions): Promise => { + await use(async (parameters: string[], options?: PromptOptions): Promise => { return await exec('node', [path.join(__dirname, '..'), ...parameters], { cwd: dir, env: { ...process.env, npm_config_user_agent: userAgents[packageManager], - 'TEST_OPTIONS': JSON.stringify(options), + ...(options ? { TEST_OPTIONS: JSON.stringify(options) } : {}), }, }); }); diff --git a/tests/generator.spec.ts b/tests/generator.spec.ts new file mode 100644 index 0000000..2dd4079 --- /dev/null +++ b/tests/generator.spec.ts @@ -0,0 +1,40 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { expect, test } from './baseFixtures'; +import { Generator } from '../src/generator'; + +// The CLI falls back to --quiet without a TTY, so the interactive path is exercised in-process. +// A question that is not skipped would wait for input and time out the test. + +test('should not prompt for --lang js and --no-gha', async ({ dir }) => { + const generator = new Generator(dir, { lang: 'js', gha: false, testDir: 'specs', noBrowsers: true, installDeps: true }); + expect(await generator['_askQuestions']()).toMatchObject({ + language: 'JavaScript', + installGitHubActions: false, + testDir: 'specs', + installPlaywrightBrowsers: false, + }); +}); + +test('should not prompt for --lang ts and --gha', async ({ dir }) => { + const generator = new Generator(dir, { lang: 'ts', gha: true, testDir: 'specs', noBrowsers: true, installDeps: true }); + expect(await generator['_askQuestions']()).toMatchObject({ + language: 'TypeScript', + installGitHubActions: true, + testDir: 'specs', + installPlaywrightBrowsers: false, + }); +}); diff --git a/tests/integration.spec.ts b/tests/integration.spec.ts index db28a28..9e019b2 100644 --- a/tests/integration.spec.ts +++ b/tests/integration.spec.ts @@ -231,6 +231,37 @@ test('should not prompt and skip existing files in --quiet mode', async ({ run, expect(fs.readFileSync(path.join(dir, 'playwright.config.ts'), 'utf8')).toBe(originalConfig); }); +test('should install GHA workflow when --gha is passed', async ({ run, dir }) => { + await run(['--quiet', '--gha', '--lang', 'js', '--test-dir', 'specs', '--no-browsers']); + + expect(fs.existsSync(path.join(dir, '.github/workflows/playwright.yml'))).toBeTruthy(); + expect(fs.existsSync(path.join(dir, 'specs/example.spec.js'))).toBeTruthy(); + expect(fs.readFileSync(path.join(dir, 'playwright.config.js'), 'utf8')).toContain('specs'); +}); + +test('should not install GHA workflow when --no-gha is passed', async ({ run, dir }) => { + await run(['--quiet', '--no-gha', '--lang', 'js', '--test-dir', 'specs', '--no-browsers']); + + expect(fs.existsSync(path.join(dir, '.github/workflows/playwright.yml'))).toBeFalsy(); + expect(fs.existsSync(path.join(dir, 'specs/example.spec.js'))).toBeTruthy(); + expect(fs.readFileSync(path.join(dir, 'playwright.config.js'), 'utf8')).toContain('specs'); +}); + +test('should not prompt in non-interactive terminals without --quiet', async ({ run, dir }) => { + await run(['--lang', 'js', '--test-dir', 'specs', '--no-browsers']); + + expect(fs.existsSync(path.join(dir, '.github/workflows/playwright.yml'))).toBeFalsy(); + expect(fs.existsSync(path.join(dir, 'specs/example.spec.js'))).toBeTruthy(); + expect(fs.readFileSync(path.join(dir, 'playwright.config.js'), 'utf8')).toContain('specs'); +}); + +test('should not overwrite existing files in non-interactive terminals without --quiet', async ({ run, dir }) => { + fs.writeFileSync(path.join(dir, 'playwright.config.js'), '// existing'); + + await expect(run(['--lang', 'js', '--no-browsers'])).rejects.toThrowError('run again with --force'); + expect(fs.readFileSync(path.join(dir, 'playwright.config.js'), 'utf8')).toBe('// existing'); +}); + test('is proper yarn classic', async ({ packageManager, exec }) => { test.skip(packageManager !== 'yarn-classic'); const result = await exec('yarn --version', [], { cwd: test.info().outputDir, shell: true }); @@ -241,4 +272,4 @@ test('is proper yarn berry', async ({ packageManager, exec }) => { test.skip(packageManager !== 'yarn-berry'); const result = await exec('yarn --version', [], { cwd: test.info().outputDir, shell: true }); expect(result.stdout).toMatch(/^4\./); -}); \ No newline at end of file +});