From 299a55c562776263bbdf8add6974911ca01969e3 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Tue, 14 Sep 2021 13:14:43 +0200 Subject: [PATCH] chore(create-playwright): UX follow-ups (#8897) --- .../assets/playwright.config.js | 8 +- .../assets/playwright.config.ts | 8 +- packages/create-playwright/package.json | 2 +- packages/create-playwright/src/index.ts | 98 +++++++++++++------ packages/create-playwright/src/utils.ts | 14 ++- .../tests/integration.spec.ts | 11 ++- 6 files changed, 94 insertions(+), 47 deletions(-) diff --git a/packages/create-playwright/assets/playwright.config.js b/packages/create-playwright/assets/playwright.config.js index 07799d8bce..670ea8d943 100644 --- a/packages/create-playwright/assets/playwright.config.js +++ b/packages/create-playwright/assets/playwright.config.js @@ -19,11 +19,9 @@ const config = { projects: [ { - name: 'Desktop Chromium', + name: 'Desktop Chrome', use: { - browserName: 'chromium', - // Test against Chrome Beta channel. - channel: 'chrome-beta', + ...devices['Desktop Chrome'], }, }, { @@ -52,4 +50,4 @@ const config = { ], }; -module.exports = config; \ No newline at end of file +module.exports = config; diff --git a/packages/create-playwright/assets/playwright.config.ts b/packages/create-playwright/assets/playwright.config.ts index 0136b93275..d6c4004694 100644 --- a/packages/create-playwright/assets/playwright.config.ts +++ b/packages/create-playwright/assets/playwright.config.ts @@ -15,11 +15,9 @@ const config: PlaywrightTestConfig = { projects: [ { - name: 'Chrome Stable', + name: 'Desktop Chrome', use: { - browserName: 'chromium', - // Test against Chrome Stable channel. - channel: 'chrome', + ...devices['Desktop Chrome'], }, }, { @@ -47,4 +45,4 @@ const config: PlaywrightTestConfig = { }, ], }; -export default config; \ No newline at end of file +export default config; diff --git a/packages/create-playwright/package.json b/packages/create-playwright/package.json index 0edd091ca8..9e7940c696 100644 --- a/packages/create-playwright/package.json +++ b/packages/create-playwright/package.json @@ -1,6 +1,6 @@ { "name": "create-playwright", - "version": "0.1.5", + "version": "0.1.6", "description": "Getting started with writing end-to-end tests with Playwright.", "repository": "github:Microsoft/playwright", "homepage": "https://playwright.dev", diff --git a/packages/create-playwright/src/index.ts b/packages/create-playwright/src/index.ts index 923c305597..0c9f13e8c7 100755 --- a/packages/create-playwright/src/index.ts +++ b/packages/create-playwright/src/index.ts @@ -19,7 +19,7 @@ import fs from 'fs'; import { prompt } from 'enquirer'; import colors from 'ansi-colors'; -import { executeCommands, createFiles, determinePackageManager, executeTemplate, determineRootDir } from './utils'; +import { executeCommands, createFiles, determinePackageManager, executeTemplate, determineRootDir, Command, languagetoFileExtension } from './utils'; export type PromptOptions = { testDir: string, @@ -27,6 +27,8 @@ export type PromptOptions = { language: 'JavaScript' | 'TypeScript' }; +const PACKAGE_JSON_TEST_SCRIPT_CMD = 'test:e2e'; + class Generator { packageManager: 'npm' | 'yarn'; constructor(private readonly rootDir: string) { @@ -37,12 +39,12 @@ class Generator { async run() { this._printIntro(); - const questions = await this._askQuestions(); - const { files, commands } = await this._identifyChanges(questions); + const answers = await this._askQuestions(); + const { files, commands } = await this._identifyChanges(answers); executeCommands(this.rootDir, commands); await createFiles(this.rootDir, files); await this._patchPackageJSON(); - this._printOutro(); + this._printOutro(answers); } private _printIntro() { @@ -66,28 +68,28 @@ class Generator { { type: 'text', name: 'testDir', - message: 'Where to put your integration tests?', + message: 'Where to put your end-to-end tests?', initial: 'e2e' }, { type: 'confirm', name: 'installGitHubActions', - message: 'Add GitHub Actions workflow?', + message: 'Add a GitHub Actions workflow?', initial: true, }, ]); } - private async _identifyChanges(options: PromptOptions) { - const commands: string[] = []; + private async _identifyChanges(answers: PromptOptions) { + const commands: Command[] = []; const files = new Map(); - const fileExtension = options.language === 'JavaScript' ? 'js' : 'ts'; + const fileExtension = languagetoFileExtension(answers.language); files.set(`playwright.config.${fileExtension}`, executeTemplate(this._readAsset(`playwright.config.${fileExtension}`), { - testDir: options.testDir, + testDir: answers.testDir, })); - if (options.installGitHubActions) { + if (answers.installGitHubActions) { const githubActionsScript = executeTemplate(this._readAsset('github-actions.yml'), { installDepsCommand: this.packageManager === 'npm' ? 'npm ci' : 'yarn', runTestsCommand: commandToRunTests(this.packageManager), @@ -95,21 +97,40 @@ class Generator { files.set('.github/workflows/playwright.yml', githubActionsScript); } - files.set(path.join(options.testDir, `example.spec.${fileExtension}`), this._readAsset(`example.spec.${fileExtension}`)); + files.set(path.join(answers.testDir, `example.spec.${fileExtension}`), this._readAsset(`example.spec.${fileExtension}`)); - if (!fs.existsSync(path.join(this.rootDir, 'package.json'))) - commands.push(this.packageManager === 'yarn' ? 'yarn init -y' : 'npm init -y'); + if (!fs.existsSync(path.join(this.rootDir, 'package.json'))) { + commands.push({ + name: `Initializing ${this.packageManager === 'yarn' ? 'Yarn' : 'NPM'} project`, + command: this.packageManager === 'yarn' ? 'yarn init -y' : 'npm init -y', + }); + } - if (this.packageManager === 'yarn') - commands.push('yarn add --dev @playwright/test'); - else - commands.push('npm install --save-dev @playwright/test'); + commands.push({ + name: 'Installing Playwright Test', + command: this.packageManager === 'yarn' ? 'yarn add --dev @playwright/test' : 'npm install --save-dev @playwright/test', + }); - commands.push('npx playwright install --with-deps'); + commands.push({ + name: 'Downloading browsers', + command: 'npx playwright install --with-deps', + }); + + files.set('.gitignore', this._buildGitIgnore()); return { files, commands }; } + private _buildGitIgnore(): string { + let gitIgnore = ''; + if (fs.existsSync(path.join(this.rootDir, '.gitignore'))) + gitIgnore = fs.readFileSync(path.join(this.rootDir, '.gitignore'), 'utf-8').trimEnd() + '\n'; + if (!gitIgnore.includes('node_modules')) + gitIgnore += 'node_modules/\n'; + gitIgnore += 'test-results/\n'; + return gitIgnore; + } + private _readAsset(asset: string): string { const assetsDir = path.join(__dirname, '..', 'assets'); return fs.readFileSync(path.join(assetsDir, asset), 'utf-8'); @@ -119,26 +140,47 @@ class Generator { const packageJSON = JSON.parse(fs.readFileSync(path.join(this.rootDir, 'package.json'), 'utf-8')); if (!packageJSON.scripts) packageJSON.scripts = {}; - packageJSON.scripts['playwright-tests'] = `playwright test`; + if (packageJSON.scripts['test']?.includes('no test specified')) + delete packageJSON.scripts['test']; + packageJSON.scripts[PACKAGE_JSON_TEST_SCRIPT_CMD] = `playwright test`; const files = new Map(); - files.set('package.json', JSON.stringify(packageJSON, null, 2)); + files.set('package.json', JSON.stringify(packageJSON, null, 2) + '\n'); // NPM keeps a trailing new-line await createFiles(this.rootDir, files, true); } - private _printOutro() { - console.log(colors.green('✔'), colors.bold('Successfully initialized your Playwright Test project!')); + private _printOutro(answers: PromptOptions) { + console.log(colors.green('✔ Success!') + ' ' + colors.bold(`Created a Playwright Test project at ${this.rootDir}`)); const pathToNavigate = path.relative(process.cwd(), this.rootDir); - const prefix = pathToNavigate !== '' ? `- cd ${pathToNavigate}\n` : ''; - console.log(colors.bold('🎭 Try it out with:\n') + colors.greenBright(prefix + '- ' + commandToRunTests(this.packageManager))); - console.log('Visit https://playwright.dev/docs/intro for more information'); + const prefix = pathToNavigate !== '' ? ` cd ${pathToNavigate}\n` : ''; + console.log(`Inside that directory, you can run several commands: + + ${colors.cyan(commandToRunTests(this.packageManager))} + Runs the end-to-end tests. + + ${colors.cyan(commandToRunTests(this.packageManager) + ' -- --project=Desktop Chrome')} + Runs the tests only on Desktop Chrome. + + ${colors.cyan(commandToRunTests(this.packageManager) + ` -- ${answers.testDir}${path.sep}example.spec.${languagetoFileExtension(answers.language)}`)} + Runs the tests of a specific file. + + ${colors.cyan((this.packageManager === 'npm' ? 'npx' : 'yarn') + ' playwright debug ' + commandToRunTests(this.packageManager))} + Runs the tests in debug mode. + +We suggest that you begin by typing: + +${colors.cyan(prefix + ' ' + commandToRunTests(this.packageManager))} + +Visit https://playwright.dev/docs/intro for more information. ✨ + +Happy hacking! 🎭`); } } export function commandToRunTests(packageManager: 'npm' | 'yarn') { if (packageManager === 'yarn') - return 'yarn playwright-tests'; - return 'npm run playwright-tests'; + return `yarn ${PACKAGE_JSON_TEST_SCRIPT_CMD}`; + return `npm run ${PACKAGE_JSON_TEST_SCRIPT_CMD}`; } (async () => { diff --git a/packages/create-playwright/src/utils.ts b/packages/create-playwright/src/utils.ts index fa7b975e45..dc7842d9a7 100644 --- a/packages/create-playwright/src/utils.ts +++ b/packages/create-playwright/src/utils.ts @@ -21,10 +21,14 @@ import path from 'path'; import { prompt } from 'enquirer'; import colors from 'ansi-colors'; +export type Command = { + command: string; + name: string; +}; -export function executeCommands(cwd: string, commands: string[]) { - for (const command of commands) { - console.log('Running:', command); +export function executeCommands(cwd: string, commands: Command[]) { + for (const { command, name } of commands) { + console.log(`${name} (${command})…`); execSync(command, { stdio: 'inherit', cwd, @@ -72,3 +76,7 @@ export function executeTemplate(input: string, args: Record): st input = input.replace(`{{${key}}}`, args[key]); return input; } + +export function languagetoFileExtension(language: 'JavaScript' | 'TypeScript'): 'js' | 'ts' { + return language === 'JavaScript' ? 'js' : 'ts'; +} diff --git a/packages/create-playwright/tests/integration.spec.ts b/packages/create-playwright/tests/integration.spec.ts index d680ccd4c4..7f965a5a35 100644 --- a/packages/create-playwright/tests/integration.spec.ts +++ b/packages/create-playwright/tests/integration.spec.ts @@ -84,14 +84,15 @@ for (const packageManager of ['npm', 'yarn'] as ('npm'|'yarn')[]) { const playwrightConfigContent = fs.readFileSync(path.join(dir, 'playwright.config.ts'), 'utf8'); expect(playwrightConfigContent).toContain('e2e'); expect(fs.existsSync(path.join(dir, '.github/workflows/playwright.yml'))).toBeTruthy(); + expect(fs.existsSync(path.join(dir, '.gitignore'))).toBeTruthy(); if (packageManager === 'npm') { - expect(stdout).toContain('Running: npm init -y'); - expect(stdout).toContain('Running: npm install --save-dev @playwright/test'); + expect(stdout).toContain('Initializing NPM project (npm init -y)…'); + expect(stdout).toContain('Installing Playwright Test (npm install --save-dev @playwright/test)…'); } else { - expect(stdout).toContain('Running: yarn init -y'); - expect(stdout).toContain('Running: yarn add --dev @playwright/test'); + expect(stdout).toContain('Initializing Yarn project (yarn init -y)…'); + expect(stdout).toContain('Installing Playwright Test (yarn add --dev @playwright/test)…'); } - expect(stdout).toContain('Running: npx playwright install --with-deps'); + expect(stdout).toContain('npx playwright install --with-deps'); }); test('should generate a project in a given directory', async ({ run }) => {