Skip to content

Test Generation

Gasoline is an open-source MCP server that watches your browser session and generates Playwright tests with real API assertions — not just button clicks. Your AI assistant saw you use the app; now it writes the regression test.

You fixed a bug. You manually verified it works. But without a regression test, it’ll break again next sprint. Writing that test is tedious — you have to remember what you clicked, what API calls fired, and what the responses looked like.

Meanwhile, Gasoline already captured all of it.

Most record-and-replay tools produce fragile scripts that just click buttons. generate_test produces a regression test:

Typical Replay ScriptGasoline generate_test
Clicks buttonsClicks buttons
No network assertionsAsserts API status codes
No response validationValidates response structure
No error checkingAsserts zero console errors
Hardcoded URLsConfigurable base URL
Fragile CSS selectorsMulti-strategy selectors (data-testid > aria > role > CSS)

You log in, submit a form, and see the result. generate_test produces:

import { test, expect } from '@playwright/test';
test('submit-form flow', async ({ page }) => {
// Collect console errors
const consoleErrors = [];
page.on('console', msg => {
if (msg.type() === 'error') consoleErrors.push(msg.text());
});
await page.goto('http://localhost:3000/login');
// Login
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Password').fill('[user-provided]');
const resp1Promise = page.waitForResponse(r => r.url().includes('/api/auth/login'));
await page.getByRole('button', { name: 'Sign In' }).click();
const resp1 = await resp1Promise;
expect(resp1.status()).toBe(200);
const resp1Body = await resp1.json();
expect(resp1Body).toHaveProperty('token');
expect(resp1Body).toHaveProperty('user');
// Navigate to form
await expect(page).toHaveURL(/\/dashboard/);
// Submit
await page.getByTestId('name-input').fill('Test Project');
const resp2Promise = page.waitForResponse(r => r.url().includes('/api/projects'));
await page.getByRole('button', { name: 'Create' }).click();
const resp2 = await resp2Promise;
expect(resp2.status()).toBe(201);
// Assert: no console errors during flow
expect(consoleErrors).toHaveLength(0);
});

Passwords are automatically redacted. Selectors prefer data-testid and ARIA roles over brittle CSS paths.

Gasoline correlates three data sources into a unified timeline:

  • User actions — clicks, inputs, keypresses, navigation, scrolls
  • Network requests — URL, method, status, response body, timing
  • Console events — errors and warnings with messages

Each network request is attributed to the preceding user action that triggered it.

For JSON API responses, Gasoline extracts the structural type signature — field names and types, never values:

Response: {"id": 42, "name": "Project", "tasks": [{"title": "Todo"}]}
Shape: {"id": "number", "name": "string", "tasks": [{"title": "string"}]}

Your test asserts the API contract, not specific data that changes between runs.

SignalAssertion
Click triggers API callwaitForResponse + expect(status).toBe(...)
Navigation occursexpect(page).toHaveURL(/pattern/)
JSON response receivedexpect(body).toHaveProperty('field')
No errors in sessionexpect(consoleErrors).toHaveLength(0)
Errors present in sessionCommented-out assertion + listed known errors

Gasoline computes multiple selector strategies for every interaction and picks the most resilient:

  1. data-testidgetByTestId('submit-btn')
  2. ARIA role + name — getByRole('button', { name: 'Submit' })
  3. ARIA label — getByLabel('Email')
  4. Visible text — getByText('Sign In')
  5. Element ID — locator('#submit')
  6. CSS path — locator('form > button.primary') (last resort)

Generate a full Playwright test from the current session:

ParameterDefaultDescription
test_nameDerived from URLName for the test() block
base_urlCaptured originReplace origin for portability
assert_networktrueAssert API status codes
assert_no_errorstrueAssert zero console errors
assert_response_shapefalseAssert response body structure
last_n_actionsAllScope to recent N actions

Get the correlated timeline without generating a test. Useful for understanding cause-and-effect:

{
"last_n_actions": 5,
"url": "checkout",
"include": ["actions", "network"]
}

Returns a sorted timeline with summary stats (action count, network requests, console errors, duration).

“I just fixed the login timeout issue. Generate a regression test from my session.”

Your AI calls generate_test and produces a test that verifies login works — with the actual API assertions that would catch a regression.

“Generate a test for the checkout flow I just walked through.”

Get a complete Playwright test covering navigation, form fills, API calls, and error checks — no manual test authoring.

“Generate a test with response shape assertions for the user profile flow.”

With assert_response_shape: true, the test validates that API responses maintain their structure — catching breaking changes even when values differ.

“Generate a test using http://localhost:3000 as the base URL.”

The base_url parameter rewrites captured URLs (e.g., from https://staging.example.com) to your local dev server.

  • Passwords are redacted to [user-provided] before test generation
  • Response shapes contain types only, never actual values
  • All processing is local — no data leaves your machine
  • Generated tests never contain auth tokens or secrets