Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Microsoft Playwright GenerateCode

From Leeroopedia
Knowledge Sources
Domains Testing, Code_Generation, Multi_Language_Support
Last Updated 2026-02-11 00:00 GMT

Overview

Concrete tool for transforming recorded actions into idiomatic test code across multiple programming languages, provided by the Playwright library.

Description

The generateCode function is the core code generation engine that takes a list of recorded actions and produces syntactically correct, language-specific test code. It works in conjunction with the LanguageGenerator interface, which provides pluggable language backends for each supported output format.

The generation process follows these steps:

  1. Action collapsing: Before generation, the raw action list is preprocessed by collapseActions() (defined at recorderUtils.ts:L102-116). This step merges consecutive redundant actions, such as multiple navigations to the same URL, sequential fills on the same input element, or immediate openPage/closePage pairs.
  2. Header generation: The language generator produces the file header, which includes imports, test function declarations, browser/context setup code, and any necessary boilerplate. The header is parameterized by LanguageGeneratorOptions which carries the browser name, launch options, context options, and device name.
  3. Action translation: Each collapsed action is passed through generator.generateAction(), which produces one or more lines of code for that action. The translation handles action-specific concerns like selector quoting, value escaping, modifier keys, and signal handling (e.g., wrapping click-with-navigation in Promise.all).
  4. Footer generation: The language generator produces the closing boilerplate (closing braces, teardown, etc.).
  5. Assembly: The header, action texts, and footer are joined into a complete source file.

The generated code is output through two channels simultaneously:

  • Inspector UI: All 11 registered generators produce output in parallel, and each is displayed as a tab in the inspector window via _pushAllSources().
  • Output file: If --output was specified, the selected language's output is written to disk via ThrottledFile, which batches writes to avoid excessive I/O during rapid recording.

The system ships with 11 language generators:

Generator ID Language Framework Group
playwright-test TypeScript Playwright Test Test Runner
javascript JavaScript Playwright Library Library
python-pytest Python Pytest Test Runner
python Python Playwright Library (sync) Library
python-async Python Playwright Library (async) Library
csharp-mstest C# MSTest Test Runner
csharp-nunit C# NUnit Test Runner
csharp C# Playwright Library Library
java-junit Java JUnit Test Runner
java Java Playwright Library Library
jsonl JSON Lines Machine-readable Data

Usage

Use this function when you need to:

  • Generate test code from a list of recorded actions in any supported language.
  • Build custom code generation pipelines that consume Playwright's action format.
  • Extend the code generation system with new language backends.
  • Implement language-specific post-processing or formatting on generated output.

Code Reference

Source Location

  • Repository: playwright
  • File: packages/playwright-core/src/server/codegen/language.ts (L22-28 for generateCode)
  • File: packages/playwright-core/src/server/codegen/types.ts (L31-39 for types)
  • Related: packages/playwright-core/src/server/recorder/recorderUtils.ts (L102-116 for collapseActions)

Signature

function generateCode(
  actions: ActionInContext[],
  languageGenerator: LanguageGenerator,
  options: LanguageGeneratorOptions
): {
  header: string;
  footer: string;
  actionTexts: string[];
  text: string;
}

LanguageGenerator Interface

interface LanguageGenerator {
  id: string;           // e.g., 'playwright-test'
  groupName: string;    // e.g., 'Test Runner'
  name: string;         // e.g., 'Playwright Test'
  highlighter: string;  // e.g., 'javascript'

  generateHeader(options: LanguageGeneratorOptions): string;
  generateAction(actionInContext: ActionInContext): string;
  generateFooter(): string;
}

LanguageGeneratorOptions Type

interface LanguageGeneratorOptions {
  browserName: string;
  launchOptions: LaunchOptions;
  contextOptions: BrowserContextOptions;
  deviceName?: string;
  saveStorage?: string;
  generateAutoExpect?: boolean;
}

Import

// Internal function - not a public API import
// Defined in packages/playwright-core/src/server/codegen/language.ts
// Used by the Recorder class to generate code for all language tabs

I/O Contract

Inputs

Name Type Required Description
actions ActionInContext[] Yes Array of recorded actions, typically pre-processed by collapseActions(). Each action contains the frame description, action details (name, selector, value, signals), and timing information.
languageGenerator LanguageGenerator Yes The language-specific generator that produces code strings. One of the 11 registered generators or a custom implementation.
options LanguageGeneratorOptions Yes Generation options including browser name, launch options, context options, device name, and flags controlling output behavior.

Outputs

Name Type Description
header string Generated file header: imports, test function declaration, browser/context setup.
footer string Generated file footer: teardown, closing braces, end of test.
actionTexts string[] Array of generated code strings, one per action. Useful for incremental display in the inspector UI.
text string Complete generated source code: header + all action texts + footer, joined with newlines. Ready to write to a file or display.

Usage Examples

Basic Example

import { generateCode } from './codegen/language';
import { PlaywrightTestGenerator } from './codegen/javascript';

const actions: ActionInContext[] = [
  {
    frame: { pageAlias: 'page', framePath: [] },
    action: { name: 'navigate', url: 'https://example.com', signals: [] },
  },
  {
    frame: { pageAlias: 'page', framePath: [] },
    action: {
      name: 'click',
      selector: 'getByRole("link", { name: "About" })',
      signals: [{ name: 'navigation', url: 'https://example.com/about' }],
      button: 'left',
      modifiers: 0,
      clickCount: 1,
    },
  },
  {
    frame: { pageAlias: 'page', framePath: [] },
    action: {
      name: 'assertText',
      selector: 'getByRole("heading", { name: "About Us" })',
      text: 'About Us',
      substring: false,
      signals: [],
    },
  },
];

const result = generateCode(actions, new PlaywrightTestGenerator(), {
  browserName: 'chromium',
  launchOptions: {},
  contextOptions: {},
});

console.log(result.text);

Generated Output (Playwright Test)

import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
  await page.goto('https://example.com');
  await page.getByRole('link', { name: 'About' }).click();
  await expect(page.getByRole('heading', { name: 'About Us' })).toHaveText('About Us');
});

Generated Output (Python Pytest)

from playwright.sync_api import Page, expect

def test_example(page: Page) -> None:
    page.goto("https://example.com")
    page.get_by_role("link", name="About").click()
    expect(page.get_by_role("heading", name="About Us")).to_have_text("About Us")

Generated Output (C# NUnit)

using Microsoft.Playwright.NUnit;
using Microsoft.Playwright;

[TestFixture]
public class Tests : PageTest
{
    [Test]
    public async Task Test()
    {
        await Page.GotoAsync("https://example.com");
        await Page.GetByRole(AriaRole.Link, new() { Name = "About" }).ClickAsync();
        await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "About Us" })).ToHaveTextAsync("About Us");
    }
}

Generated Output (Java JUnit)

import com.microsoft.playwright.*;
import com.microsoft.playwright.options.*;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import org.junit.jupiter.api.*;

public class TestExample {
    @Test
    void test() {
        page.navigate("https://example.com");
        page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("About")).click();
        assertThat(page.getByRole(AriaRole.HEADING, new Page.GetByRoleOptions().setName("About Us"))).hasText("About Us");
    }
}

Related Pages

Implements Principle

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment