ワンクリックで
spec-from-test
Convert an existing Playwright or Cypress E2E test file into a demo-machine YAML spec. Reuses test coverage as demo scripts.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Convert an existing Playwright or Cypress E2E test file into a demo-machine YAML spec. Reuses test coverage as demo scripts.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Generate a polished product demo video from a YAML spec using demo-machine. Use when the user wants to create, run, or update a demo video for their app.
Generate a complete demo-machine YAML spec by crawling a live web app. Give it a URL and description, get a ready-to-run spec.
Automatically fix a broken demo-machine spec by analyzing failure artifacts (screenshots, DOM, error logs). Use when a demo fails after a UI change.
Generate compelling AI narration for every step in a demo-machine spec. Use when a spec has no narration or needs better narration text.
AI quality review of a completed demo run. Analyzes event log, timing, and narration to flag issues and suggest improvements.
Translate all narration text in a demo-machine spec to another language, producing a localized copy.
| name | spec-from-test |
| description | Convert an existing Playwright or Cypress E2E test file into a demo-machine YAML spec. Reuses test coverage as demo scripts. |
| argument-hint | <test-file> |
| allowed-tools | Read, Write, Edit, Glob, Grep, Bash(node *), Bash(pnpm *) |
Parse existing Playwright or Cypress test files and generate demo-machine YAML specs from them. Reuses engineering test coverage as polished product demos.
$ARGUMENTS should be a path to a Playwright (.spec.ts, .test.ts) or Cypress (.cy.ts, .cy.js) test file.tests/, e2e/, cypress/, or playwright/ directories.| Playwright | Demo-Machine | Notes |
|---|---|---|
page.goto(url) | action: navigate, url: ... | |
page.click(sel) | action: click, selector: ... | |
locator.click() | action: click, target: ... | Convert locator strategy |
page.fill(sel, text) | action: type, selector: ..., text: ... | |
locator.fill(text) | action: type, target: ..., text: ... | |
page.hover(sel) | action: hover, selector: ... | |
locator.hover() | action: hover, target: ... | |
page.press(sel, key) | action: press, key: ... | |
locator.press(key) | action: press, key: ... | |
locator.check() | action: check, target: ... | |
locator.uncheck() | action: uncheck, target: ... | |
locator.selectOption(val) | action: select, target: ..., option: ... | |
page.waitForSelector(sel) | action: wait, timeout: 5000 + assert | |
expect(...).toBeVisible() | action: assert, target: ..., visible: true | |
expect(...).toContainText(txt) | action: assert, target: ..., text: ... | |
page.screenshot() | action: screenshot, name: ... | Optional for demos |
| Cypress | Demo-Machine | Notes |
|---|---|---|
cy.visit(url) | action: navigate, url: ... | |
cy.get(sel).click() | action: click, selector: ... | |
cy.get(sel).type(text) | action: type, selector: ..., text: ... | |
cy.get(sel).check() | action: check, selector: ... | |
cy.get(sel).uncheck() | action: uncheck, selector: ... | |
cy.get(sel).select(val) | action: select, selector: ..., option: ... | |
cy.contains(text).click() | action: click, target: {by: text, text: ...} | |
cy.get(sel).should('be.visible') | action: assert, selector: ..., visible: true | |
cy.get(sel).should('contain', text) | action: assert, selector: ..., text: ... | |
cy.screenshot() | action: screenshot, name: ... | Optional |
Convert Playwright locators to target:
// page.getByRole('button', { name: 'Click me' })
target: by: role;
role: button;
name: "Click me";
// page.getByTestId('submit-btn')
target: by: testId;
testId: "submit-btn";
// page.getByLabel('Email')
target: by: label;
label: "Email";
// page.getByText('Hello')
target: by: text;
text: "Hello";
describe, it, and test blocksdescribe → chapter; each it → sequence of stepsbeforeAll, beforeEach for runner configpage.goto() and form submissions, add wait stepsexpect(...) into assert steps/narrate-spec afterwardnode dist/cli.js validate <spec.yaml>Before (Playwright test):
describe("Task Management", () => {
it("should create and complete a task", async ({ page }) => {
await page.goto("http://localhost:3000");
await page.click('[data-testid="new-task"]');
await page.fill('[data-testid="task-input"]', "Buy milk");
await page.click('[data-testid="add-btn"]');
await page.waitForSelector('[data-testid="task-item"]');
await expect(page.locator('[data-testid="task-item"]')).toContainText("Buy milk");
await page.click('[data-testid="task-item"] input[type="checkbox"]');
await expect(page.locator('[data-testid="task-item"]')).toHaveClass("completed");
});
});
After (Demo spec):
meta:
title: "Task Management"
resolution:
width: 1920
height: 1080
runner:
command: "npm run dev"
url: "http://localhost:3000"
timeout: 10000
chapters:
- title: "Creating and Completing a Task"
steps:
- action: navigate
url: "http://localhost:3000"
- action: wait
timeout: 1000
- action: click
target:
by: testId
testId: "new-task"
- action: type
target:
by: testId
testId: "task-input"
text: "Buy milk"
- action: click
target:
by: testId
testId: "add-btn"
- action: wait
timeout: 500
- action: assert
target:
by: testId
testId: "task-item"
text: "Buy milk"
- action: click
target:
by: role
role: checkbox
- action: assert
target:
by: testId
testId: "task-item"
visible: true
beforeEach setup if it only logs in; add as demo steps insteadbaseURL from test config → runner.urlexpect chains to separate assert stepswait steps after navigations (add ~1000ms) and form submissions (~500ms)by: testId whenever available (most stable)narration fields empty; user runs /narrate-spec afterAfter conversion:
# Validate structure
node dist/cli.js validate <spec.yaml>
# Dry-run (don't capture)
node dist/cli.js run <spec.yaml> --no-record
# Full capture
node dist/cli.js run <spec.yaml> --output ./output
Arguments: $ARGUMENTS