From a sentence to a scheduled Playwright test
One real test, recorded on the open-source demo shop: the whole loop in 30 seconds.
The whole loop in 30 seconds
Step through it yourself
Press a tab, or pick another real generation.
Checkout with 2FA sign-in, on the Fieldmark demo shop
You describe the flow
- Sign in as the 2FA shopper: username and password, then the 6-digit authenticator code.
- Open the Waterproof Notebook and add one to the cart.
- Check out: fill in a shipping address and pay with the test card 4242 4242 4242 4242, any future expiry date and CVC 123.
- Check the order confirmation says the order was placed and the total is $21.00 (the $16.00 notebook plus $5.00 shipping).
TestWatch writes a Playwright test
checkout-with-2fa-sign-in.spec.ts
import { test, expect, otp } from '../fixtures';
test('Checkout with 2FA sign-in', async ({ page }) => {
await test.step('Sign in as the 2FA shopper', async () => {
await page.getByRole('link', { name: 'Sign in' }).click();
await page.getByRole('textbox', { name: 'Username' }).fill(process.env.TARGET_EMAIL!);
await page.getByRole('textbox', { name: 'Password' }).fill(process.env.TARGET_PASSWORD!);
await page.getByRole('button', { name: 'Sign in' }).click();
await page.getByRole('textbox', { name: 'Authentication code' }).fill(otp());
await page.getByRole('button', { name: 'Verify' }).click();
await expect(page.getByRole('button', { name: 'Sign out' })).toBeVisible();
});
await test.step('Open the Waterproof Notebook and add one to the cart', async () => {
await page.getByRole('link', { name: 'Waterproof Notebook' }).click();
await page.getByTestId('add-to-cart').click();
await expect(page.getByRole('link', { name: 'Check out' })).toBeVisible();
});
await test.step('Check out and pay with test card', async () => {
await page.getByRole('link', { name: 'Check out' }).click();
await page.getByRole('textbox', { name: 'Street address' }).fill('123 Main St');
await page.getByRole('textbox', { name: 'City' }).fill('Anytown');
await page.getByRole('textbox', { name: 'Postcode' }).fill('12345');
const paymentFrame = page.locator('iframe[title="Secure card payment input frame"]').contentFrame();
await paymentFrame.getByRole('textbox', { name: 'Card number' }).fill('4242 4242 4242 4242');
await paymentFrame.getByRole('textbox', { name: 'Expiration (MM / YY)' }).fill('12/28');
await paymentFrame.getByRole('textbox', { name: 'CVC' }).fill('123');
await page.getByTestId('place-order').click();
});
await test.step('Verify order confirmation and total', async () => {
await expect(page.getByText('Thanks! Your order has been placed.')).toBeVisible();
await expect(page.getByTestId('order-total')).toHaveText('$21.00');
});
});
It runs on a schedule
- PassedSign in as the 2FA shopper310 ms
- PassedOpen the Waterproof Notebook and add one to the cart130 ms
- PassedCheck out and pay with test card185 ms
- PassedVerify order confirmation and total65 ms
0AI calls on this passing run
The page changed. You approve the fix
Proposed fixThe page changed, not the app’s behaviour.
await page.getByRole('link', { name: 'Waterproof Notebook' }).click();
Removed: await page.getByTestId('add-to-cart').click();
Added: await page.getByTestId('add-to-bag').click();
A real run from 3 October 2026, exported from TestWatch unedited.
Step by step
- You describe the flow
Write what a user does and what should be true at the end, in plain English. If something is unclear (which account, which product), TestWatch asks before it starts.
- It explores your app and writes the test
An AI agent opens your live app in a real browser, follows the flow, checks each step works, and writes a Playwright test with named steps. Then it runs the test against your app before calling it ready.

Recorded 19 October 2026 on the Fieldmark demo shop. Unedited dashboard screenshot. - It runs on a schedule or from CI, without AI
Runs are plain Playwright on our browsers, on up to 4 browser profiles. They start on a preset or cron schedule, by hand, or (Starter and up) from CI through the GitHub Action, the CLI, the API or a deploy hook. A passing run makes no AI calls, which is why every plan includes the runs.

Recorded 19 October 2026 on the Fieldmark demo shop. Unedited dashboard screenshot. - A failure gets a reason
When a run fails, TestWatch looks at the evidence and says what happened: the page changed, a real bug, the app is down, a CAPTCHA blocked it, or the login no longer works. When it isn’t a page change, it asks you instead of changing the test.

Recorded 19 October 2026 on the Fieldmark demo shop. Unedited dashboard screenshot. - You approve the fix
For a page change it proposes a new locator or wait as a diff. Assertions in your main tests are never touched, and nothing changes until you approve it. A fix you accept on a pull-request preview may also update a check’s expected text; it is applied to the main test once it passes there twice, with a notice and Undo.

Recorded 19 October 2026 on the Fieldmark demo shop. Unedited dashboard screenshot.
What it won’t do
- No
Log in with SMS codes, or through Google, GitHub or SSO in your app. It tells you instead.
- No
Get past a CAPTCHA or bot wall. It tells you the flow is blocked instead.
- No
Change what a test checks. Fixes touch locators and waits only.
- No
Test native mobile apps. Mobile means mobile browsers, emulated.
Try it on your own app.
Free: 5 tests, 500 runs a month, 2 apps and one daily schedule. Unlimited teammates, no card.
The story above is Fieldmark demo shop data, exported from TestWatch unedited.