mirror of
https://github.com/screenci/screenci.git
synced 2026-09-19 08:57:46 +08:00
refactor(screenci): remove dev command and no-container mode
This commit is contained in:
@@ -69,7 +69,7 @@ All standard `page` methods (`goto`, `waitForURL`, `waitForLoadState`, `waitForT
|
||||
|
||||
```bash
|
||||
# Dry-run: opens Playwright UI so you can verify selectors and pacing
|
||||
npx screenci dev
|
||||
npx screenci test --ui
|
||||
|
||||
# Record: captures the screen and writes .screenci/<name>/recording.mp4
|
||||
npx screenci record
|
||||
@@ -78,7 +78,7 @@ npx screenci record
|
||||
Or via the package scripts scaffolded by `init`:
|
||||
|
||||
```bash
|
||||
npm run dev # → npx screenci dev
|
||||
npm run test # → npx screenci test
|
||||
npm run record # → npx screenci record
|
||||
```
|
||||
|
||||
|
||||
+11
-316
@@ -349,80 +349,6 @@ describe('CLI', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('record command with --no-container', () => {
|
||||
beforeEach(() => {
|
||||
process.env.SCREENCI_SECRET = 'test-secret'
|
||||
})
|
||||
|
||||
it('should spawn playwright directly when --no-container is provided', async () => {
|
||||
process.argv = ['node', 'cli.js', 'record', '--no-container']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(mockSpawn).toHaveBeenCalled()
|
||||
})
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledWith(
|
||||
'npx',
|
||||
expect.arrayContaining([
|
||||
'playwright',
|
||||
'test',
|
||||
'--config',
|
||||
expect.stringContaining('screenci.config.ts'),
|
||||
]),
|
||||
expect.objectContaining({
|
||||
stdio: 'inherit',
|
||||
env: expect.objectContaining({
|
||||
SCREENCI_RECORD: 'true',
|
||||
}),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('should not include --no-container in playwright args', async () => {
|
||||
process.argv = ['node', 'cli.js', 'record', '--no-container']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(mockSpawn).toHaveBeenCalled()
|
||||
})
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
const spawnCall = mockSpawn.mock.calls[0]
|
||||
const args = spawnCall[1] as string[]
|
||||
expect(args).not.toContain('--no-container')
|
||||
})
|
||||
|
||||
it('should pass other args alongside --no-container', async () => {
|
||||
process.argv = ['node', 'cli.js', 'record', '--no-container', '--headed']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(mockSpawn).toHaveBeenCalled()
|
||||
})
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledWith(
|
||||
'npx',
|
||||
expect.arrayContaining(['--headed']),
|
||||
expect.objectContaining({ stdio: 'inherit' })
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('container workflow', () => {
|
||||
let mockBuildProcess: EventEmitter
|
||||
let mockRecordingBuildProcess: EventEmitter
|
||||
@@ -889,6 +815,17 @@ describe('CLI', () => {
|
||||
expect(processExitSpy).toHaveBeenCalledWith(1)
|
||||
})
|
||||
|
||||
it('should reject the removed dev command', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
|
||||
await expect(main()).rejects.toThrow('process.exit called')
|
||||
|
||||
expect(loggerErrorSpy).toHaveBeenCalledWith('Unknown command: dev')
|
||||
expect(processExitSpy).toHaveBeenCalledWith(1)
|
||||
})
|
||||
|
||||
it('should show global help with --help', async () => {
|
||||
process.argv = ['node', 'cli.js', '--help']
|
||||
const stdoutSpy = vi
|
||||
@@ -1067,248 +1004,6 @@ describe('CLI', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('dev command', () => {
|
||||
it('should spawn playwright with --ui flag and default config path', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledWith(
|
||||
'npx',
|
||||
expect.arrayContaining([
|
||||
'playwright',
|
||||
'test',
|
||||
'--config',
|
||||
expect.stringContaining('screenci.config.ts'),
|
||||
'--ui',
|
||||
]),
|
||||
expect.objectContaining({ stdio: 'inherit' })
|
||||
)
|
||||
})
|
||||
|
||||
it('should support --config flag with custom path', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev', '--config', 'custom.config.ts']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.arrayContaining([
|
||||
'playwright',
|
||||
'test',
|
||||
'--config',
|
||||
expect.stringContaining('custom.config.ts'),
|
||||
'--ui',
|
||||
]),
|
||||
expect.objectContaining({ stdio: 'inherit' })
|
||||
)
|
||||
})
|
||||
|
||||
it('should support -c flag with custom path', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev', '-c', 'custom.config.ts']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.arrayContaining([
|
||||
'playwright',
|
||||
'test',
|
||||
'--config',
|
||||
expect.stringContaining('custom.config.ts'),
|
||||
'--ui',
|
||||
]),
|
||||
expect.objectContaining({ stdio: 'inherit' })
|
||||
)
|
||||
})
|
||||
|
||||
it('should pass additional arguments to playwright', async () => {
|
||||
process.argv = [
|
||||
'node',
|
||||
'cli.js',
|
||||
'dev',
|
||||
'--project=chromium',
|
||||
'--timeout=5000',
|
||||
]
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.arrayContaining([
|
||||
'playwright',
|
||||
'test',
|
||||
'--config',
|
||||
expect.stringContaining('screenci.config.ts'),
|
||||
'--ui',
|
||||
'--project=chromium',
|
||||
'--timeout=5000',
|
||||
]),
|
||||
expect.objectContaining({ stdio: 'inherit' })
|
||||
)
|
||||
})
|
||||
|
||||
it('should allow parallel execution flags', async () => {
|
||||
process.argv = [
|
||||
'node',
|
||||
'cli.js',
|
||||
'dev',
|
||||
'--workers=4',
|
||||
'--fully-parallel',
|
||||
]
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.arrayContaining([
|
||||
'playwright',
|
||||
'test',
|
||||
'--ui',
|
||||
'--workers=4',
|
||||
'--fully-parallel',
|
||||
]),
|
||||
expect.objectContaining({ stdio: 'inherit' })
|
||||
)
|
||||
})
|
||||
|
||||
it('should log UI mode when running dev command', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
expect(loggerInfoSpy).toHaveBeenCalledWith(
|
||||
'Running ScreenCI UI mode with npx...'
|
||||
)
|
||||
expect(loggerInfoSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Using config:')
|
||||
)
|
||||
})
|
||||
|
||||
it('should run in headed mode when --headed flag is provided', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev', '--headed']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
const spawnCall = mockSpawn.mock.calls[0]
|
||||
const args = spawnCall[1]
|
||||
|
||||
// Should NOT include --ui when --headed is present
|
||||
expect(args).not.toContain('--ui')
|
||||
expect(args).toContain('--headed')
|
||||
expect(loggerInfoSpy).toHaveBeenCalledWith(
|
||||
'Running ScreenCI headed mode with npx...'
|
||||
)
|
||||
})
|
||||
|
||||
it('should run in headed mode with additional flags', async () => {
|
||||
process.argv = [
|
||||
'node',
|
||||
'cli.js',
|
||||
'dev',
|
||||
'--headed',
|
||||
'--project=chromium',
|
||||
'--workers=2',
|
||||
]
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 0)
|
||||
|
||||
await mainPromise
|
||||
|
||||
const spawnCall = mockSpawn.mock.calls[0]
|
||||
const args = spawnCall[1]
|
||||
|
||||
expect(args).not.toContain('--ui')
|
||||
expect(args).toContain('--headed')
|
||||
expect(args).toContain('--project=chromium')
|
||||
expect(args).toContain('--workers=2')
|
||||
})
|
||||
|
||||
it('should handle playwright exit with error code', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('close', 1)
|
||||
|
||||
await expect(mainPromise).rejects.toThrow('Playwright exited with code 1')
|
||||
})
|
||||
|
||||
it('should handle playwright error event', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev']
|
||||
|
||||
const { main } = await import('./cli')
|
||||
const mainPromise = main()
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
mockChildProcess.emit('error', new Error('spawn failed'))
|
||||
|
||||
await expect(mainPromise).rejects.toThrow('spawn failed')
|
||||
})
|
||||
|
||||
it('should exit if config not found', async () => {
|
||||
process.argv = ['node', 'cli.js', 'dev']
|
||||
mockExistsSync.mockReturnValue(false)
|
||||
|
||||
const { main } = await import('./cli')
|
||||
|
||||
await expect(main()).rejects.toThrow('process.exit called')
|
||||
|
||||
expect(loggerErrorSpy).toHaveBeenCalledWith(
|
||||
'Error: screenci.config.ts not found in current directory'
|
||||
)
|
||||
expect(processExitSpy).toHaveBeenCalledWith(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test command', () => {
|
||||
it('should spawn playwright test with default config path', async () => {
|
||||
process.argv = ['node', 'cli.js', 'test', '--project=chromium']
|
||||
|
||||
@@ -1306,7 +1306,7 @@ function generatePackageJson(
|
||||
scripts: {
|
||||
record: 'screenci record',
|
||||
retry: 'screenci retry',
|
||||
dev: 'screenci dev',
|
||||
test: 'screenci test',
|
||||
},
|
||||
dependencies: {
|
||||
screenci: 'latest',
|
||||
@@ -1330,7 +1330,7 @@ Write video scripts in \`videos/*.video.ts\`. Each \`video(...)\` scenario opens
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Run tests in UI/dev mode:
|
||||
1. Run tests in UI mode:
|
||||
|
||||
\`npx screenci test\`
|
||||
|
||||
@@ -1663,7 +1663,7 @@ export async function main() {
|
||||
if (process.argv.length <= 2) {
|
||||
logger.error('Error: No command provided')
|
||||
logger.error(
|
||||
'Available commands: record, dev, test, info, make-public, make-private, retry, init'
|
||||
'Available commands: record, test, info, make-public, make-private, retry, init'
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
@@ -1685,8 +1685,7 @@ export async function main() {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const useContainer =
|
||||
!parsed.noContainer && process.env.SCREENCI_IN_CONTAINER !== 'true'
|
||||
const useContainer = process.env.SCREENCI_IN_CONTAINER !== 'true'
|
||||
|
||||
// Validate early so we don't build the container unnecessarily
|
||||
if (useContainer) {
|
||||
@@ -1789,22 +1788,12 @@ export async function main() {
|
||||
}
|
||||
})
|
||||
|
||||
// dev command — playwright args pass through as-is
|
||||
program
|
||||
.command('dev [playwrightArgs...]')
|
||||
.description('Run Playwright in dev/UI mode')
|
||||
.allowUnknownOption(true)
|
||||
.action(async () => {
|
||||
const parsed = parseDevCliArgs(getSubcommandArgv('dev'))
|
||||
await run('dev', parsed.otherArgs, parsed.configPath)
|
||||
})
|
||||
|
||||
program
|
||||
.command('test [playwrightArgs...]')
|
||||
.description('Run Playwright test with screenci.config.ts')
|
||||
.allowUnknownOption(true)
|
||||
.action(async () => {
|
||||
const parsed = parseDevCliArgs(getSubcommandArgv('test'))
|
||||
const parsed = parseConfigCliArgs(getSubcommandArgv('test'))
|
||||
await run('test', parsed.otherArgs, parsed.configPath)
|
||||
})
|
||||
|
||||
@@ -1918,14 +1907,12 @@ function getSubcommandArgv(command: string): string[] {
|
||||
|
||||
function parseRecordCliArgs(args: string[]): {
|
||||
configPath: string | undefined
|
||||
noContainer: boolean
|
||||
imageTag: string | undefined
|
||||
verbose: boolean
|
||||
forcedRuntime: ContainerRuntimeName | 'both' | undefined
|
||||
otherArgs: string[]
|
||||
} {
|
||||
let configPath: string | undefined
|
||||
let noContainer = false
|
||||
let imageTag: string | undefined
|
||||
let verbose = false
|
||||
let forcedRuntime: ContainerRuntimeName | 'both' | undefined
|
||||
@@ -1942,8 +1929,6 @@ function parseRecordCliArgs(args: string[]): {
|
||||
}
|
||||
configPath = nextArg
|
||||
i++
|
||||
} else if (arg === '--no-container') {
|
||||
noContainer = true
|
||||
} else if (arg === '--verbose' || arg === '-v') {
|
||||
verbose = true
|
||||
} else if (arg === '--podman') {
|
||||
@@ -1965,7 +1950,6 @@ function parseRecordCliArgs(args: string[]): {
|
||||
|
||||
return {
|
||||
configPath,
|
||||
noContainer,
|
||||
imageTag,
|
||||
verbose,
|
||||
forcedRuntime,
|
||||
@@ -1973,7 +1957,7 @@ function parseRecordCliArgs(args: string[]): {
|
||||
}
|
||||
}
|
||||
|
||||
function parseDevCliArgs(args: string[]): {
|
||||
function parseConfigCliArgs(args: string[]): {
|
||||
configPath: string | undefined
|
||||
otherArgs: string[]
|
||||
} {
|
||||
@@ -2282,7 +2266,7 @@ async function runWithContainer(
|
||||
}
|
||||
|
||||
async function run(
|
||||
command: string,
|
||||
command: 'record' | 'test',
|
||||
additionalArgs: string[],
|
||||
customConfigPath?: string
|
||||
) {
|
||||
@@ -2296,25 +2280,14 @@ async function run(
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Only validate args for record command (dev allows parallel execution)
|
||||
// Only validate args for record command
|
||||
if (command === 'record') {
|
||||
validateArgs(additionalArgs)
|
||||
const screenciDir = resolve(dirname(configPath), '.screenci')
|
||||
clearDirectory(screenciDir)
|
||||
}
|
||||
|
||||
// For dev command: use --ui unless --headed is specified
|
||||
const isHeaded = additionalArgs.includes('--headed')
|
||||
const shouldUseUI = command === 'dev' && !isHeaded
|
||||
|
||||
const mode =
|
||||
command === 'dev'
|
||||
? isHeaded
|
||||
? 'headed mode'
|
||||
: 'UI mode'
|
||||
: command === 'test'
|
||||
? 'tests'
|
||||
: 'recorder'
|
||||
const mode = command === 'test' ? 'tests' : 'recorder'
|
||||
if (process.env.SCREENCI_IN_CONTAINER !== 'true') {
|
||||
logger.info(`Running ScreenCI ${mode} with npx...`)
|
||||
logger.info(`Using config: ${configPath}`)
|
||||
@@ -2325,7 +2298,6 @@ async function run(
|
||||
'test',
|
||||
'--config',
|
||||
configPath,
|
||||
...(shouldUseUI ? ['--ui'] : []),
|
||||
...additionalArgs,
|
||||
]
|
||||
|
||||
|
||||
+1
-20
@@ -14,7 +14,6 @@ Most commands look for `screenci.config.ts` in the current directory. Use `--con
|
||||
| Command | What it does |
|
||||
| --------------------------------- | ---------------------------------------------------------------- |
|
||||
| `screenci init [name]` | Scaffold a new ScreenCI project |
|
||||
| `screenci dev [args...]` | Run Playwright in UI mode for fast iteration |
|
||||
| `screenci test [args...]` | Forward directly to `playwright test` using your ScreenCI config |
|
||||
| `screenci record [args...]` | Record videos, usually in a container |
|
||||
| `screenci retry` | Upload the newest local recording in `.screenci/` |
|
||||
@@ -35,21 +34,6 @@ Options:
|
||||
|
||||
- `-v, --verbose` prints underlying command output instead of spinners
|
||||
|
||||
## `screenci dev [playwrightArgs...]`
|
||||
|
||||
Runs Playwright against your ScreenCI config in local development mode. By default this starts Playwright UI mode.
|
||||
|
||||
```bash
|
||||
npx screenci dev
|
||||
npx screenci dev --project=chromium
|
||||
npx screenci dev --headed
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `--headed` disables Playwright UI mode and runs headed instead
|
||||
- any additional args are forwarded to `playwright test`
|
||||
|
||||
## `screenci test [playwrightArgs...]`
|
||||
|
||||
Forwards directly to `playwright test` while still resolving `screenci.config.ts`.
|
||||
@@ -60,7 +44,7 @@ npx screenci test --grep "checkout"
|
||||
npx screenci test --project=chromium
|
||||
```
|
||||
|
||||
Use this when you want normal Playwright execution without recording and without the Playwright UI shortcut from `screenci dev`.
|
||||
Use this when you want normal Playwright execution without recording.
|
||||
|
||||
## `screenci record [playwrightArgs...]`
|
||||
|
||||
@@ -69,13 +53,11 @@ Records videos with ScreenCI. On the host this normally builds and runs the proj
|
||||
```bash
|
||||
npx screenci record
|
||||
npx screenci record --project=chromium
|
||||
npx screenci record --no-container --headed
|
||||
```
|
||||
|
||||
Options:
|
||||
|
||||
- `-c, --config <path>` use a custom config path
|
||||
- `--no-container` run locally instead of in Podman or Docker
|
||||
- `--podman` force Podman
|
||||
- `--docker` force Docker
|
||||
- `--tag <tag>` pull and use a specific `ghcr.io/screenci/record:<tag>` image
|
||||
@@ -167,7 +149,6 @@ Requirements:
|
||||
|
||||
These commands support `--config <path>`:
|
||||
|
||||
- `dev`
|
||||
- `test`
|
||||
- `record`
|
||||
- `retry`
|
||||
|
||||
@@ -65,7 +65,7 @@ All of these are composable with normal [Playwright](https://playwright.dev/docs
|
||||
## Develop without recording
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
npm run test -- --ui
|
||||
```
|
||||
|
||||
Opens the Playwright UI. Run your scripts, verify selectors work, iterate fast. No screen capture, no Docker, no FFmpeg. Just Playwright.
|
||||
|
||||
+1
-2
@@ -57,8 +57,7 @@ That's Playwright. screenci extends it — it does not replace it.
|
||||
### 4. Develop without recording
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or: npx screenci dev
|
||||
npx screenci test --ui
|
||||
```
|
||||
|
||||
Opens the Playwright UI. Run your scripts, verify they work, fix selectors — no screen capture, no container, no FFmpeg. Just normal Playwright test execution.
|
||||
|
||||
@@ -31,7 +31,7 @@ If you are creating new videos, remove the starter `videos/example.video.ts` fil
|
||||
|
||||
```bash
|
||||
# iterate locally without recording
|
||||
npx screenci dev
|
||||
npx screenci test --ui
|
||||
|
||||
# verify repeatedly until green
|
||||
npx screenci test
|
||||
@@ -60,8 +60,8 @@ ScreenCI uses Playwright-style `.video.ts` files and adds recording-specific hel
|
||||
|
||||
## Command Notes
|
||||
|
||||
- `screenci record` runs the recording flow. By default it uses Podman or Docker unless `--no-container` is used.
|
||||
- `screenci dev` runs Playwright in UI mode for fast iteration without screen capture.
|
||||
- `screenci record` runs the recording flow in Podman or Docker.
|
||||
- `screenci test --ui` runs Playwright in UI mode for fast iteration without screen capture.
|
||||
- `screenci retry` uploads the latest `.screenci` output when API configuration is available.
|
||||
|
||||
## Recording Workflow
|
||||
@@ -70,7 +70,7 @@ ScreenCI uses Playwright-style `.video.ts` files and adds recording-specific hel
|
||||
2. Add or edit `.video.ts` files in `videos/`.
|
||||
Remove `videos/example.video.ts` if you are creating new videos and do not need the starter video.
|
||||
For narration, define `const narration = createNarration({ ... })` near the top of the file and trigger lines with `await narration.someKey` inside the test body.
|
||||
3. Run `npx screenci dev` to validate selectors and flow.
|
||||
3. Run `npx screenci test --ui` to validate selectors and flow.
|
||||
4. Run `npx screenci test` until it passes.
|
||||
5. Run `npx screenci record` to produce `.screenci/<video-name>/recording.mp4` and `data.json`.
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ If you are creating new videos, remove the starter `videos/example.video.ts` fil
|
||||
|
||||
```bash
|
||||
npx screenci record
|
||||
npx screenci record --no-container
|
||||
npx screenci record -c screenci.config.ts
|
||||
```
|
||||
|
||||
@@ -23,7 +22,6 @@ npx screenci record -c screenci.config.ts
|
||||
## Runtime Behavior
|
||||
|
||||
- By default, recording runs in Podman or Docker.
|
||||
- `--no-container` runs directly on the host.
|
||||
- Playwright arguments can be passed through after the command.
|
||||
- When API configuration and `SCREENCI_SECRET` are available, uploads may run after recording.
|
||||
|
||||
@@ -31,7 +29,7 @@ npx screenci record -c screenci.config.ts
|
||||
|
||||
```bash
|
||||
# first verify the flow
|
||||
npx screenci dev
|
||||
npx screenci test --ui
|
||||
|
||||
# then record
|
||||
npx screenci record
|
||||
|
||||
Reference in New Issue
Block a user