Skip to content

Commit 0686b4f

Browse files
pavel-lensPavel Svitek
andauthored
feat: add pnpm package manager support (#36)
Co-authored-by: Pavel Svitek <[email protected]>
1 parent 0575c73 commit 0686b4f

File tree

6 files changed

+69
-21
lines changed

6 files changed

+69
-21
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
cache: 'npm'
2222
- run: npm i -g npm@8
2323
- run: npm i -g yarn@1
24+
- run: npm i -g pnpm@7
2425
- run: npm ci
2526
- run: npx playwright install-deps
2627
- run: npm run build

src/generator.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { prompt } from 'enquirer';
2020
import colors from 'ansi-colors';
2121

2222
import { executeCommands, createFiles, determinePackageManager, executeTemplate, Command, languageToFileExtension } from './utils';
23+
import { PackageManager } from './types';
2324

2425
export type PromptOptions = {
2526
testDir: string,
@@ -32,7 +33,7 @@ export type PromptOptions = {
3233
const assetsDir = path.join(__dirname, '..', 'assets');
3334

3435
export class Generator {
35-
packageManager: 'npm' | 'yarn';
36+
packageManager: PackageManager;
3637
constructor(private readonly rootDir: string, private readonly options: { [key: string]: string[] }) {
3738
if (!fs.existsSync(rootDir))
3839
fs.mkdirSync(rootDir);
@@ -145,8 +146,13 @@ export class Generator {
145146
}
146147

147148
if (answers.installGitHubActions) {
149+
const pmInstallCommand: Record<PackageManager, string> = {
150+
npm: 'npm ci',
151+
pnpm: 'pnpm install',
152+
yarn: 'yarn',
153+
}
148154
const githubActionsScript = executeTemplate(this._readAsset('github-actions.yml'), {
149-
installDepsCommand: this.packageManager === 'npm' ? 'npm ci' : 'yarn',
155+
installDepsCommand: pmInstallCommand[this.packageManager],
150156
runTestsCommand: commandToRunTests(this.packageManager),
151157
}, new Map());
152158
files.set('.github/workflows/playwright.yml', githubActionsScript);
@@ -158,9 +164,19 @@ export class Generator {
158164
}
159165

160166
if (!fs.existsSync(path.join(this.rootDir, 'package.json'))) {
167+
const pmInitializeCommand: Record<PackageManager, string> = {
168+
npm: 'npm init -y',
169+
pnpm: 'pnpm init',
170+
yarn: 'yarn init -y'
171+
}
172+
const pmOfficialName: Record<PackageManager, string> = {
173+
npm: 'NPM',
174+
pnpm: 'Pnpm',
175+
yarn: 'Yarn',
176+
}
161177
commands.push({
162-
name: `Initializing ${this.packageManager === 'yarn' ? 'Yarn' : 'NPM'} project`,
163-
command: this.packageManager === 'yarn' ? 'yarn init -y' : 'npm init -y',
178+
name: `Initializing ${pmOfficialName[this.packageManager]} project`,
179+
command: pmInitializeCommand[this.packageManager],
164180
});
165181
}
166182

@@ -171,17 +187,22 @@ export class Generator {
171187
if (this.options.next)
172188
packageLine = '@next';
173189

190+
const pmInstallDevDepCommand: Record<PackageManager, string> = {
191+
npm: 'npm install --save-dev',
192+
pnpm: 'pnpm add --save-dev',
193+
yarn: 'yarn add --dev'
194+
}
174195
if (!this.options.ct) {
175196
commands.push({
176197
name: 'Installing Playwright Test',
177-
command: this.packageManager === 'yarn' ? `yarn add --dev ${packageName}${packageLine}` : `npm install --save-dev ${packageName}${packageLine}`,
198+
command: `${pmInstallDevDepCommand[this.packageManager]} ${packageName}${packageLine}`,
178199
});
179200
}
180201

181202
if (this.options.ct) {
182203
commands.push({
183204
name: 'Installing Playwright Component Testing',
184-
command: this.packageManager === 'yarn' ? `yarn add --dev ${ctPackageName}${packageLine}` : `npm install --save-dev ${ctPackageName}${packageLine}`,
205+
command: `${pmInstallDevDepCommand[this.packageManager]} ${ctPackageName}${packageLine}`,
185206
});
186207

187208
const extension = languageToFileExtension(answers.language);
@@ -300,13 +321,17 @@ Happy hacking! 🎭`);
300321
}
301322
}
302323

303-
export function commandToRunTests(packageManager: 'npm' | 'yarn', args?: string) {
324+
export function commandToRunTests(packageManager: PackageManager, args?: string) {
325+
if (packageManager === 'pnpm')
326+
return `pnpm playwright test${args ? (' ' + args) : ''}`;
304327
if (packageManager === 'yarn')
305328
return `yarn playwright test${args ? (' ' + args) : ''}`;
306329
return `npx playwright test${args ? (' ' + args) : ''}`;
307330
}
308331

309-
export function commandToRunCodegen(packageManager: 'npm' | 'yarn') {
332+
export function commandToRunCodegen(packageManager: PackageManager) {
333+
if (packageManager === 'pnpm')
334+
return `pnpm playwright codegen`;
310335
if (packageManager === 'yarn')
311336
return `yarn playwright codegen`;
312337
return `npx playwright codegen`;

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type PackageManager = 'npm' | 'pnpm' | 'yarn'

src/utils.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import path from 'path';
2020

2121
import { prompt } from 'enquirer';
2222
import colors from 'ansi-colors';
23+
import { PackageManager } from './types';
2324

2425
export type Command = {
2526
command: string;
@@ -55,11 +56,18 @@ export async function createFiles(rootDir: string, files: Map<string, string>, f
5556
}
5657
}
5758

58-
export function determinePackageManager(rootDir: string): 'yarn' | 'npm' {
59+
export function determinePackageManager(rootDir: string): PackageManager {
5960
if (fs.existsSync(path.join(rootDir, 'yarn.lock')))
6061
return 'yarn';
61-
if (process.env.npm_config_user_agent)
62-
return process.env.npm_config_user_agent.includes('yarn') ? 'yarn' : 'npm';
62+
if (fs.existsSync(path.join(rootDir, 'pnpm-lock.yaml')))
63+
return 'pnpm';
64+
if (process.env.npm_config_user_agent) {
65+
if (process.env.npm_config_user_agent.includes('yarn'))
66+
return 'yarn'
67+
if (process.env.npm_config_user_agent.includes('pnpm'))
68+
return 'pnpm'
69+
return 'npm';
70+
}
6371
return 'npm';
6472
}
6573

tests/baseFixtures.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ import { spawn, SpawnOptionsWithoutStdio } from 'child_process';
1919
import path from 'path';
2020
import fs from 'fs';
2121
import { PromptOptions } from '../src/generator';
22+
import { PackageManager } from '../src/types';
2223

2324
type TestFixtures = {
24-
packageManager: 'npm' | 'yarn';
25+
packageManager: PackageManager;
2526
run: (parameters: string[], options: PromptOptions) => Promise<RunResult>,
2627
};
2728

@@ -58,6 +59,8 @@ export const test = base.extend<TestFixtures>({
5859
fs.mkdirSync(testInfo.outputDir, { recursive: true });
5960
const env = packageManager === 'yarn' ? {
6061
'npm_config_user_agent': 'yarn'
62+
} : packageManager === 'pnpm' ? {
63+
'npm_config_user_agent': 'pnpm/0.0.0'
6164
} : undefined;
6265
const result = await spawnAsync('node', [path.join(__dirname, '..'), ...parameters], {
6366
shell: true,

tests/integration.spec.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
import { test, expect } from './baseFixtures';
1717
import path from 'path';
1818
import fs from 'fs';
19+
import { PackageManager } from '../src/types';
1920

20-
for (const packageManager of ['npm', 'yarn'] as ('npm' | 'yarn')[]) {
21+
for (const packageManager of ['npm', 'pnpm', 'yarn'] as PackageManager[]) {
2122
test.describe(`Package manager: ${packageManager}`, () => {
2223
test.use({ packageManager });
2324

@@ -29,8 +30,10 @@ for (const packageManager of ['npm', 'yarn'] as ('npm' | 'yarn')[]) {
2930
expect(fs.existsSync(path.join(dir, 'package.json'))).toBeTruthy();
3031
if (packageManager === 'npm')
3132
expect(fs.existsSync(path.join(dir, 'package-lock.json'))).toBeTruthy();
32-
else
33+
else if (packageManager === 'yarn')
3334
expect(fs.existsSync(path.join(dir, 'yarn.lock'))).toBeTruthy();
35+
else if (packageManager === 'pnpm')
36+
expect(fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))).toBeTruthy();
3437
expect(fs.existsSync(path.join(dir, 'playwright.config.ts'))).toBeTruthy();
3538
const playwrightConfigContent = fs.readFileSync(path.join(dir, 'playwright.config.ts'), 'utf8');
3639
expect(playwrightConfigContent).toContain('tests');
@@ -39,9 +42,12 @@ for (const packageManager of ['npm', 'yarn'] as ('npm' | 'yarn')[]) {
3942
if (packageManager === 'npm') {
4043
expect(stdout).toContain('Initializing NPM project (npm init -y)…');
4144
expect(stdout).toContain('Installing Playwright Test (npm install --save-dev @playwright/test)…');
42-
} else {
45+
} else if (packageManager === 'yarn') {
4346
expect(stdout).toContain('Initializing Yarn project (yarn init -y)…');
4447
expect(stdout).toContain('Installing Playwright Test (yarn add --dev @playwright/test)…');
48+
} else if (packageManager === 'pnpm') {
49+
expect(stdout).toContain('pnpm init'); // pnpm command outputs name in different case, hence we are not testing the whole string
50+
expect(stdout).toContain('Installing Playwright Test (pnpm add --save-dev @playwright/test)…');
4551
}
4652
expect(stdout).toContain('npx playwright install' + process.platform === 'linux' ? ' --with-deps' : '');
4753
});
@@ -53,8 +59,10 @@ for (const packageManager of ['npm', 'yarn'] as ('npm' | 'yarn')[]) {
5359
expect(fs.existsSync(path.join(dir, 'foobar/package.json'))).toBeTruthy();
5460
if (packageManager === 'npm')
5561
expect(fs.existsSync(path.join(dir, 'foobar/package-lock.json'))).toBeTruthy();
56-
else
62+
else if (packageManager === 'yarn')
5763
expect(fs.existsSync(path.join(dir, 'foobar/yarn.lock'))).toBeTruthy();
64+
else if (packageManager === 'pnpm')
65+
expect(fs.existsSync(path.join(dir, 'foobar/pnpm-lock.yaml'))).toBeTruthy();
5866
expect(fs.existsSync(path.join(dir, 'foobar/playwright.config.ts'))).toBeTruthy();
5967
expect(fs.existsSync(path.join(dir, 'foobar/.github/workflows/playwright.yml'))).toBeTruthy();
6068
});
@@ -66,8 +74,10 @@ for (const packageManager of ['npm', 'yarn'] as ('npm' | 'yarn')[]) {
6674
expect(fs.existsSync(path.join(dir, 'package.json'))).toBeTruthy();
6775
if (packageManager === 'npm')
6876
expect(fs.existsSync(path.join(dir, 'package-lock.json'))).toBeTruthy();
69-
else
77+
else if (packageManager === 'yarn')
7078
expect(fs.existsSync(path.join(dir, 'yarn.lock'))).toBeTruthy();
79+
else if (packageManager === 'pnpm')
80+
expect(fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))).toBeTruthy();
7181
expect(fs.existsSync(path.join(dir, 'playwright.config.js'))).toBeTruthy();
7282
expect(fs.existsSync(path.join(dir, '.github/workflows/playwright.yml'))).toBeFalsy();
7383
});
@@ -81,11 +91,11 @@ for (const packageManager of ['npm', 'yarn'] as ('npm' | 'yarn')[]) {
8191
expect(fs.existsSync(path.join(dir, 'playwright.config.ts'))).toBeTruthy();
8292

8393
{
84-
const { code } = await exec(packageManager === 'npm' ? 'npx' : 'yarn', ['playwright', 'install-deps']);
94+
const { code } = await exec(packageManager === 'npm' ? 'npx' : packageManager === 'pnpm' ? 'pnpm dlx' : 'yarn', ['playwright', 'install-deps']);
8595
expect(code).toBe(0);
8696
}
8797

88-
const { code } = await exec(packageManager === 'npm' ? 'npx' : 'yarn', ['playwright', 'test']);
98+
const { code } = await exec(packageManager === 'npm' ? 'npx' : packageManager === 'pnpm' ? 'pnpm dlx' : 'yarn', ['playwright', 'test']);
8999
expect(code).toBe(0);
90100
});
91101

@@ -98,11 +108,11 @@ for (const packageManager of ['npm', 'yarn'] as ('npm' | 'yarn')[]) {
98108
expect(fs.existsSync(path.join(dir, 'playwright.config.js'))).toBeTruthy();
99109

100110
{
101-
const { code } = await exec(packageManager === 'npm' ? 'npx' : 'yarn', ['playwright', 'install-deps']);
111+
const { code } = await exec(packageManager === 'npm' ? 'npx' : packageManager === 'pnpm' ? 'pnpm dlx' : 'yarn', ['playwright', 'install-deps']);
102112
expect(code).toBe(0);
103113
}
104114

105-
const { code } = await exec(packageManager === 'npm' ? 'npx' : 'yarn', ['playwright', 'test']);
115+
const { code } = await exec(packageManager === 'npm' ? 'npx' : packageManager === 'pnpm' ? 'pnpm dlx' : 'yarn', ['playwright', 'test']);
106116
expect(code).toBe(0);
107117
});
108118
});

0 commit comments

Comments
 (0)