Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/shy-pillows-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@yamatomo/playwright": minor
---

feat: Allow fixture settings to be configured via defineConfig
31 changes: 12 additions & 19 deletions packages/playwright/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ Fixture configuration to `playwright.config.ts`

```typescript
// playwright.config.ts
import { defineConfig } from '@playwright/test'

import { spawn } from 'node:child_process'
import { type AppEnv, fixtureConfig, getPort } from '@yamatomo/playwright'
import { type AppEnv, defineConfig, devices, getPort } from '@yamatomo/playwright'

declare module '@yamatomo/playwright' {
interface AppEnv {
Expand All @@ -23,30 +21,25 @@ declare module '@yamatomo/playwright' {
}
}

fixtureConfig({
startApp: async (appPort) => {
const appEnv: AppEnv = {
export default defineConfig({
// ...
use: {
baseURL: `http://localhost:${await getPort()}`, // Setting the baseURL is also required
// ...
},
startApp: async (baseUrlPort) => {
const env = {
...process.env,
BACKEND_API_HOST: `http://backend-api.localhost:${await getPort()}`,
}
} satisfies AppEnv

return [
spawn('/your/app/start/command', ['...options'], { env: { ...process.env, ...appEnv } }),
appEnv,
]
return [spawn('/your/app/start/command', ['...options'], { env }), env]
},
resolveMswParams: (appEnv) => ({
port: new URL(appEnv.BACKEND_API_HOST).port,
api: (path) => new URL(path, appEnv.BACKEND_API_HOST).toString(),
}),
})

export default defineConfig({
// ...
use: {
baseURL: `http://localhost:${await getPort()}`, // Setting the baseURL is also required
// ...
},
})
```

Write tests using the `msw` fixture.
Expand Down
32 changes: 13 additions & 19 deletions packages/playwright/example/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { spawn } from 'node:child_process'

import { defineConfig, devices } from '@playwright/test'
import { type AppEnv, fixtureConfig, getPort } from '@yamatomo/playwright'
import { type AppEnv, defineConfig, devices, getPort } from '@yamatomo/playwright'

declare module '@yamatomo/playwright' {
interface AppEnv {
Expand All @@ -13,23 +12,6 @@ declare module '@yamatomo/playwright' {
}
}

fixtureConfig({
startApp: async (appPort) => {
const appEnv: AppEnv = {
BACKEND_API_HOST: `http://backend-api.localhost:${await getPort()}`,
}

return [
spawn('pnpm', ['dev', `--port=${appPort}`], { env: { ...process.env, ...appEnv } }),
appEnv,
]
},
resolveMswParams: (appEnv) => ({
port: new URL(appEnv.BACKEND_API_HOST).port,
api: (path) => new URL(path, appEnv.BACKEND_API_HOST).toString(),
}),
})

export default defineConfig({
testDir: './tests',
fullyParallel: true,
Expand All @@ -46,4 +28,16 @@ export default defineConfig({
use: { ...devices['Desktop Chrome'] },
},
],
startApp: async (baseUrlPort) => {
const env = {
...process.env,
BACKEND_API_HOST: `http://backend-api.localhost:${await getPort()}`,
} satisfies AppEnv

return [spawn('pnpm', ['dev', `--port=${baseUrlPort}`], { env }), env]
},
resolveMswParams: (appEnv) => ({
port: new URL(appEnv.BACKEND_API_HOST).port,
api: (path) => new URL(path, appEnv.BACKEND_API_HOST).toString(),
}),
})
5 changes: 3 additions & 2 deletions packages/playwright/src/fixtureConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ interface MswParams {
}

type Store = {
startApp?: (appServerPort: number) => Promise<[ChildProcess, AppEnv]>
startApp?: (baseUrlPort: number) => Promise<[ChildProcess, AppEnv]>
resolveMswParams?: (env: AppEnv) => MswParams
isFixtureConfigured?: boolean
}

export const store: Store = {}

export const fixtureConfig = (params: Store) => {
/** @deprecated Use `defineConfig` instead. */
export const fixtureConfig = (params: Omit<Store, 'isFixtureConfigured'>) => {
store.startApp = params.startApp
store.resolveMswParams = params.resolveMswParams
store.isFixtureConfigured = true
Expand Down
24 changes: 18 additions & 6 deletions packages/playwright/src/playwrightTestHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import type { ChildProcess } from 'node:child_process'

import { test as base } from '@playwright/test'
import {
test as base,
defineConfig as baseDefineConfig,
type PlaywrightTestConfig,
} from '@playwright/test'
import { waitPort } from '@yamatomo/internal-utils'
import { createServer } from '@yamatomo/msw-server'
import { setupServer } from 'msw/node'

import { type AppEnv, type MswParams, store } from './fixtureConfig'
import { type AppEnv, fixtureConfig, type MswParams, store } from './fixtureConfig'
import { getDescendantPids } from './getDescendantPids.ts'

const startApp = async (baseURL: string) => {
if (!store.startApp) throw new Error('startApp is not defined.')

const appPort = Number(new URL(baseURL).port)
const [process, env] = await store.startApp(appPort)
await waitPort(appPort)
const baseUrlPort = Number(new URL(baseURL).port)
const [process, env] = await store.startApp(baseUrlPort)
await waitPort(baseUrlPort)

return { process, env }
}
Expand Down Expand Up @@ -69,5 +73,13 @@ const test = base.extend<TestFixtureType, WorkerFixtureType>({
],
})

type FixtureConfigParams = Parameters<typeof fixtureConfig>[0]
const defineConfig = (config: PlaywrightTestConfig & FixtureConfigParams) => {
const { startApp, resolveMswParams, ...playwrightConfig } = config

fixtureConfig({ startApp, resolveMswParams })
return baseDefineConfig(playwrightConfig)
}

export * from '@playwright/test'
export { test }
export { test, defineConfig }