diff --git a/src/generator.ts b/src/generator.ts index f561fbb..134a247 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -20,7 +20,7 @@ import { prompt } from 'enquirer'; import colors from 'ansi-colors'; import { executeCommands, createFiles, executeTemplate, Command, languageToFileExtension, getFileExtensionCT } from './utils'; -import { packageManager } from './packageManager'; +import { type PackageManager, determinePackageManager } from './packageManager'; export type PromptOptions = { testDir: string, @@ -46,9 +46,12 @@ type CliArgumentKey = 'browser' | 'lang'; export class Generator { + private packageManager: PackageManager; + constructor(private readonly rootDir: string, private readonly options: Partial>) { if (!fs.existsSync(rootDir)) fs.mkdirSync(rootDir); + this.packageManager = determinePackageManager(rootDir); } async run() { @@ -124,7 +127,7 @@ export class Generator { { type: 'confirm', name: 'installPlaywrightBrowsers', - message: `Install Playwright browsers (can be done manually via '${packageManager.npx('playwright', 'install')}')?`, + message: `Install Playwright browsers (can be done manually via '${this.packageManager.npx('playwright', 'install')}')?`, initial: true, }, // Avoid installing dependencies on Windows (vast majority does not run create-playwright on Windows) @@ -132,7 +135,7 @@ export class Generator { process.platform === 'linux' && { type: 'confirm', name: 'installPlaywrightDependencies', - message: `Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo ${packageManager.npx('playwright', 'install-deps')}')?`, + message: `Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo ${this.packageManager.npx('playwright', 'install-deps')}')?`, initial: false, }, ]; @@ -168,9 +171,9 @@ export class Generator { if (answers.installGitHubActions) { const githubActionsScript = executeTemplate(this._readAsset('github-actions.yml'), { - installDepsCommand: packageManager.ci(), - installPlaywrightCommand: packageManager.npx('playwright', 'install --with-deps'), - runTestsCommand: answers.framework ? packageManager.run('test-ct') : packageManager.runPlaywrightTest(), + installDepsCommand: this.packageManager.ci(), + installPlaywrightCommand: this.packageManager.npx('playwright', 'install --with-deps'), + runTestsCommand: answers.framework ? this.packageManager.run('test-ct') : this.packageManager.runPlaywrightTest(), }, new Map()); files.set('.github/workflows/playwright.yml', githubActionsScript); } @@ -182,8 +185,8 @@ export class Generator { if (!fs.existsSync(path.join(this.rootDir, 'package.json'))) { commands.push({ - name: `Initializing ${packageManager.name} project`, - command: packageManager.init(), + name: `Initializing ${this.packageManager.name} project`, + command: this.packageManager.init(), }); } @@ -196,14 +199,14 @@ export class Generator { if (!this.options.ct) { commands.push({ name: 'Installing Playwright Test', - command: packageManager.installDevDependency(`@playwright/test${packageTag}`), + command: this.packageManager.installDevDependency(`@playwright/test${packageTag}`), }); } if (this.options.ct) { commands.push({ name: 'Installing Playwright Component Testing', - command: packageManager.installDevDependency(`${ctPackageName}${packageTag}`), + command: this.packageManager.installDevDependency(`${ctPackageName}${packageTag}`), }); const extension = getFileExtensionCT(answers.language, answers.framework); @@ -217,7 +220,7 @@ export class Generator { if (!this._hasDependency('@types/node')) { commands.push({ name: 'Installing Types', - command: packageManager.installDevDependency(`@types/node`), + command: this.packageManager.installDevDependency(`@types/node`), }); } @@ -225,7 +228,7 @@ export class Generator { if (answers.installPlaywrightBrowsers) { commands.push({ name: 'Downloading browsers', - command: packageManager.npx('playwright', 'install') + (answers.installPlaywrightDependencies ? ' --with-deps' : '') + browsersSuffix, + command: this.packageManager.npx('playwright', 'install') + (answers.installPlaywrightDependencies ? ' --with-deps' : '') + browsersSuffix, }); } @@ -285,27 +288,27 @@ export class Generator { console.log(` Inside that directory, you can run several commands: - ${colors.cyan(packageManager.runPlaywrightTest())} + ${colors.cyan(this.packageManager.runPlaywrightTest())} Runs the end-to-end tests. - ${colors.cyan(packageManager.runPlaywrightTest('--ui'))} + ${colors.cyan(this.packageManager.runPlaywrightTest('--ui'))} Starts the interactive UI mode. - ${colors.cyan(packageManager.runPlaywrightTest('--project=chromium'))} + ${colors.cyan(this.packageManager.runPlaywrightTest('--project=chromium'))} Runs the tests only on Desktop Chrome. - ${colors.cyan(packageManager.runPlaywrightTest('example'))} + ${colors.cyan(this.packageManager.runPlaywrightTest('example'))} Runs the tests in a specific file. - ${colors.cyan(packageManager.runPlaywrightTest('--debug'))} + ${colors.cyan(this.packageManager.runPlaywrightTest('--debug'))} Runs the tests in debug mode. - ${colors.cyan(packageManager.npx('playwright', 'codegen'))} + ${colors.cyan(this.packageManager.npx('playwright', 'codegen'))} Auto generate tests with Codegen. We suggest that you begin by typing: - ${colors.cyan(prefix + ' ' + packageManager.runPlaywrightTest())} + ${colors.cyan(prefix + ' ' + this.packageManager.runPlaywrightTest())} And check out the following files: - .${path.sep}${pathToNavigate ? path.join(pathToNavigate, exampleSpecPath) : exampleSpecPath} - Example end-to-end test @@ -322,21 +325,21 @@ Happy hacking! 🎭`); console.log(` Inside that directory, you can run several commands: - ${colors.cyan(`${packageManager.cli} run test-ct`)} + ${colors.cyan(`${this.packageManager.cli} run test-ct`)} Runs the component tests. - ${colors.cyan(`${packageManager.cli} run test-ct -- --project=chromium`)} + ${colors.cyan(`${this.packageManager.cli} run test-ct -- --project=chromium`)} Runs the tests only on Desktop Chrome. - ${colors.cyan(`${packageManager.cli} run test-ct App.test.ts`)} + ${colors.cyan(`${this.packageManager.cli} run test-ct App.test.ts`)} Runs the tests in the specific file. - ${colors.cyan(`${packageManager.cli} run test-ct -- --debug`)} + ${colors.cyan(`${this.packageManager.cli} run test-ct -- --debug`)} Runs the tests in debug mode. We suggest that you begin by typing: - ${colors.cyan(`${packageManager.cli} run test-ct`)} + ${colors.cyan(`${this.packageManager.cli} run test-ct`)} Visit https://playwright.dev/docs/intro for more information. ✨ diff --git a/src/packageManager.ts b/src/packageManager.ts index b766112..6fda2bc 100644 --- a/src/packageManager.ts +++ b/src/packageManager.ts @@ -1,4 +1,7 @@ -interface PackageManager { +import path from 'path'; +import fs from 'fs'; + +export interface PackageManager { cli: string; name: string init(): string @@ -61,7 +64,7 @@ class Yarn implements PackageManager { runPlaywrightTest(args: string): string { return this.npx('playwright', `test${args ? (' ' + args) : ''}`); } - + run(script: string): string { return `yarn ${script}`; } @@ -71,6 +74,9 @@ class PNPM implements PackageManager { name = 'pnpm' cli = 'pnpm' + constructor(private workspace: boolean) { + } + init(): string { return 'pnpm init' } @@ -84,7 +90,7 @@ class PNPM implements PackageManager { } installDevDependency(name: string): string { - return `pnpm add --save-dev ${name}` + return `pnpm add --save-dev ${this.workspace ? '-w ' : ''}${name}` } runPlaywrightTest(args: string): string { @@ -96,15 +102,13 @@ class PNPM implements PackageManager { } } -function determinePackageManager(): PackageManager { +export function determinePackageManager(rootDir: string): PackageManager { if (process.env.npm_config_user_agent) { if (process.env.npm_config_user_agent.includes('yarn')) - return new Yarn() + return new Yarn(); if (process.env.npm_config_user_agent.includes('pnpm')) - return new PNPM() - return new NPM() + return new PNPM(fs.existsSync(path.resolve(rootDir, 'pnpm-workspace.yaml'))); + return new NPM(); } - return new NPM() + return new NPM(); } - -export const packageManager = determinePackageManager(); diff --git a/tests/integration.spec.ts b/tests/integration.spec.ts index 1b0eeb1..059d3bd 100644 --- a/tests/integration.spec.ts +++ b/tests/integration.spec.ts @@ -16,6 +16,7 @@ import { test, expect, packageManagerToNpxCommand, assertLockFilesExist } from './baseFixtures'; import path from 'path'; import fs from 'fs'; +import childProcess from 'child_process'; test('should generate a project in the current directory', async ({ run, dir, packageManager }) => { test.slow(); @@ -84,3 +85,19 @@ test('should generate be able to run JS examples successfully', async ({ run, di await exec(packageManagerToNpxCommand(packageManager), ['playwright', 'test']); }); +test('should generate in the root of pnpm workspace', async ({ run, packageManager }) => { + test.skip(packageManager !== 'pnpm'); + + const dir = test.info().outputDir; + fs.mkdirSync(dir, { recursive: true }); + childProcess.execSync('pnpm init', { cwd: dir }); + fs.writeFileSync(path.join(dir, 'pnpm-workspace.yaml'), `packages:\n - 'packages/*'\n`); + fs.mkdirSync(path.join(dir, 'packages', 'foo'), { recursive: true }); + fs.writeFileSync(path.join(dir, 'packages', 'foo', 'package.json'), `{}`); + + await run([], { installGitHubActions: false, testDir: 'tests', language: 'TypeScript', installPlaywrightDependencies: false, installPlaywrightBrowsers: false }); + assertLockFilesExist(dir, packageManager); + expect(fs.existsSync(path.join(dir, 'tests/example.spec.ts'))).toBeTruthy(); + expect(fs.existsSync(path.join(dir, 'package.json'))).toBeTruthy(); + expect(fs.existsSync(path.join(dir, 'playwright.config.ts'))).toBeTruthy(); +});