CR

create-page-object

Automates the creation of Playwright page objects by inspecting the target UI.

Install

mkdir -p .claude/skills/create-page-object && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/10499" && unzip -o skill.zip -d .claude/skills/create-page-object && rm skill.zip

Installs to .claude/skills/create-page-object

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Erstellt ein neues Playwright Page-Object für eine Admin-Seite im Schulportal. Nutzt Playwright MCP zur Live-Inspektion der Zielseite (data-testid-Attribute, interaktive Elemente) und generiert danach die TypeScript-Datei nach den Projektkonventionen. Use when asked to create a new page object, add a page class, or implement a new page for the schulportal test automation project.
382 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

Key capabilities

  • Inspect pages via MCP
  • Generate TypeScript classes
  • Implement page objects
  • Capture testIds

How it works

Uses Playwright MCP to inspect the DOM and generate a TypeScript class following project conventions.

Inputs & outputs

You give it
Page URL and requirements
You get back
TypeScript page object

When to use create-page-object

  • Create a new page object
  • Automate a new admin page
  • Capture data-testid for tests

About this skill

Create Page Object

Dieses Skill erstellt ein neues Playwright Page-Object für eine Admin-Seite des Schulportals. Es inspiziert die Zielseite per Playwright MCP live und generiert dann die TypeScript-Klasse nach den Projektkonventionen.

Use When

  • Ein neues Page-Object für eine Admin-Seite erstellt werden soll
  • Eine neue Seite in den Test-Automatisierungsworkflow eingebunden werden soll
  • Die data-testid-Attribute einer Seite unbekannt sind und per MCP ermittelt werden müssen

Do Not Use When

  • Nur eine bestehende Klasse erweitert oder umbenannt werden soll → verwende stattdessen extend-page-object
  • Kein Login-Zugang zur Zielseite vorhanden ist

See Also

  • extend-page-object — Erweitert eine bestehende Page-Klasse um neue Locators und Methoden

Projektkonventionen

Dateinamenskonvention

TypMusterBeispiel
Konvention<Name>.page.tsPersonDetailsView.page.ts
Standalone (kein extend)<Name>.ts oder <Name>.page.tsSchulischeAngebotsverwaltungView.ts

Ablageorte

pages/admin/personen/          ← Personen-Views
pages/admin/organisationen/    ← Schulen, Klassen
pages/admin/rollen/            ← Rollen-Views
pages/admin/service-provider/  ← Angebote / Service-Provider
pages/components/              ← Wiederverwendbare UI-Komponenten

Klassenstruktur — mit AbstractAdminPage (Standard)

import { expect, Page } from '@playwright/test';
import { AbstractAdminPage } from '../AbstractAdmin.page';
import { MenuBarPage } from '../../components/MenuBar.page';
// ... weitere Imports

export class MyViewPage extends AbstractAdminPage {
  private readonly someLocator: Locator;
  public readonly menu: MenuBarPage;

  constructor(protected readonly page: Page) {
    super(page);
    this.someLocator = this.page.getByTestId('some-test-id');
    this.menu = new MenuBarPage(this.page);
  }

  /* actions */
  public async waitForPageLoad(): Promise<MyViewPage> {
    await expect(this.page.getByTestId('layout-card-headline')).toHaveText('...');
    return this;
  }

  /* assertions */
  public async assertSomething(): Promise<void> {
    await expect(this.someLocator).toBeVisible();
  }
}

Klassenstruktur — Standalone (kein extends)

import { expect, Locator, Page } from '@playwright/test';
import { MenuBarPage } from '../../components/MenuBar.page';

export class MyViewPage {
  private readonly headline: Locator;
  public readonly menu: MenuBarPage;

  constructor(protected readonly page: Page) {
    this.headline = this.page.getByTestId('layout-card-headline');
    this.menu = new MenuBarPage(this.page);
  }

  /* actions */
  public async waitForPageLoad(): Promise<MyViewPage> {
    await expect(this.headline).toHaveText('...');
    return this;
  }
}

Verfügbare Hilfsklassen

KlasseImportVerwendung
DataTable../../components/DataTable.pageTabellen mit Sortierung, Paginierung, Zeilenauswahl
Autocomplete../../components/AutocompleteSuch-/Filter-Dropdowns
SearchFilter../../components/SearchFilterFreitext-Suche
MenuBarPage../../components/MenuBar.pageNavigationsmenü
AbstractAdminPage../AbstractAdmin.pageBasisklasse für Admin-Views

Workflow

Phase 1 — Eingaben sammeln

Folgende Informationen sind erforderlich, bevor mit der Implementierung begonnen wird:

InformationPflichtQuelle
Klassenname der neuen PageBenutzer
Dateiname (*.page.ts)Benutzer
Ablageort im ProjektBenutzer
URL der ZielseiteBenutzer
Welche Aktionen sollen abgebildet werden (read / edit / delete)Benutzer
Login-Credentials oder Test-UserBenutzer / global-setup.ts

Warte auf alle Pflicht-Informationen, bevor du mit Phase 2 beginnst.

Pflichtfrage — Klassentyp

Stelle diese Frage explizit, bevor du mit dem Implement beginnst — auch wenn der Nutzer sie nicht von sich aus beantwortet hat:

„Soll die Klasse extends AbstractAdminPage verwenden (Standard für Admin-Views mit Header/Menu-Basisfunktionalität) oder soll sie eine Standalone-Klasse ohne Vererbung sein?"

Warte auf die Antwort. Fahre erst dann mit Phase 2 fort.

AntwortKlassendeklarationsuper(page) im KonstruktorAbstractAdminPage-Import
extends AbstractAdminPageexport class XPage extends AbstractAdminPage✅ ja✅ ja
Standaloneexport class XPage❌ nein❌ nein

Phase 2 — MCP-Inspektion der Zielseite

Nutze Playwright MCP um die Live-Seite zu inspizieren.

  1. Browser öffnen — Zur Login-Seite der Anwendung navigieren
  2. Einloggen — Login-Workflow durchführen (Credentials aus global-setup.ts oder vom Benutzer)
  3. Zur Zielseite navigieren — Die vom Benutzer angegebene URL aufrufen
  4. Snapshot erstellenbrowser_snapshot ausführen, um den DOM-Zustand zu erfassen
  5. data-testid-Attribute dokumentieren — Alle relevanten testIds auflisten:
    • Headlines / Überschriften
    • Formularfelder und Labels
    • Buttons (Speichern, Abbrechen, Bearbeiten, Löschen)
    • Tabellen
    • Dropdowns / Autocomplete-Felder
    • Dialoge / Modals
  6. Interaktive Elemente bestimmen — Unterscheiden zwischen:
    • Nur lesend (display-only)
    • Editierbar (Input, Select, Checkbox)
    • Aktionen auslösend (Button, Link)

Erwartetes Ergebnis: Eine Liste aller gefundenen data-testid-Werte mit ihrer Bedeutung.


Phase 3 — Page-Object implementieren

Erstelle die TypeScript-Datei am angegebenen Ablageort.

3.1 — Imports auswählen

Nur die tatsächlich benötigten Imports einfügen (kein Dead Code):

  • Page, Locator, expect aus @playwright/test
  • Hilfsklassen (DataTable, Autocomplete, etc.) nur wenn genutzt
  • AbstractAdminPage nur bei extends-Variante

3.2 — Klassendeklaration

export class <Name>Page {                   // Standalone
export class <Name>Page extends AbstractAdminPage {   // mit extends

3.3 — Konstruktor

  • Alle Locators als private readonly-Felder deklarieren
  • getByTestId(...) für alle gefundenen testIds verwenden
  • MenuBarPage als public readonly menu hinzufügen
  • Bei Autocomplete-Feldern: new Autocomplete(this.page, this.page.getByTestId('...'))
  • Bei Tabellen: new DataTable(this.page, this.page.getByTestId('...'))

3.4 — Methoden implementieren

Pflichtmethoden:

public async waitForPageLoad(): Promise<MyViewPage> {
  // Warte auf mindestens eine charakteristische Headline oder ein Element
  // Best Practice: mindestens eine eindeutige Headline mit toHaveText() prüfen
  await expect(this.page.getByTestId('admin-headline')).toHaveText('Administrationsbereich');
  await expect(this.someCard).toBeVisible();
  await expect(this.headline).toContainText('...');
  return this;
}

Read-Methoden (wenn Daten nur angezeigt werden):

public async getFieldValue(): Promise<string> {
  return await this.someLocator.innerText();
}

Edit-Methoden (wenn Felder bearbeitbar sind):

public async editField(value: string): Promise<void> {
  await this.someInput.fill(value);
}
public async saveChanges(): Promise<void> {
  await this.saveButton.click();
}

Assertion-Methoden (assert-Präfix — gemäß best-practices.md):

public async assertPageIsVisible(): Promise<void> {
  await expect(this.headline).toBeVisible();
}
public async assertFieldValue(expected: string): Promise<void> {
  await expect(this.someLocator).toHaveText(expected);
}

3.5 — Methodenblöcke kommentieren

/* actions */
// read- und edit-Methoden

/* assertions */
// assert-Methoden

Phase 4 — Validierung

  1. TypeScript-Kompilierung prüfen:
    npx tsc --noEmit
    
  2. Import-Pfade verifizieren — Relative Pfade müssen korrekt sein
  3. Nochmal MCP-Check (optional)waitForPageLoad() auf der echten Seite ausführen und bestätigen, dass sie nicht wirft

Referenz-Dateien im Projekt

DateiPattern
pages/admin/service-provider/ServiceProviderManagementBySchuleView.page.tsStandalone-Klasse mit Filter-Autocomplete
pages/admin/service-provider/ServiceProviderManagementView.page.tsextends AbstractAdminPage, DataTable
pages/admin/personen/PersonManagementView.page.tsKomplexes Beispiel: DataTable, Filter, Dialoge, Navigation zur Detailseite
pages/admin/rollen/RolleDetailsView.page.tsDetailseite mit Edit- und Delete-Aktionen

Beispiel-Output

Für die URL https://main.dev.spsh.dbildungsplattform.de/admin/angebote/schulspezifisch/{id}?orga={orgaId}:

Datei: pages/admin/service-provider/ServiceProviderDetailsBySchuleView.page.ts

import { expect, Locator, Page } from '@playwright/test';
import { MenuBarPage } from '../../components/MenuBar.page';

export class ServiceProviderDetailsBySchuleViewPage {
  // TODO: testIds per MCP-Inspektion ermitteln und hier einsetzen
  private readonly card: Locator;
  private readonly headline: Locator;
  public readonly menu: MenuBarPage;

  constructor(protected readonly page: Page) {
    this.card = this.page.getByTestId('service-provider-details-by-schule-card');
    this.headline = this.page.getByTestId('layout-card-headline');
    this.menu = new MenuBarPage(this.page);
  }

  /* actions */
  public async waitForPageLoad(): Promise<ServiceProviderDetailsBySchuleViewPage> {
    // Mindestens eine eindeutige Headline mit toHave

---

*Content truncated.*

When not to use it

  • When extending existing page objects
  • When no login access is available

Prerequisites

PlaywrightPlaywright MCP

Limitations

  • Requires login access to the target page
  • Requires manual verification of generated testIds

How it compares

Automates the creation of page objects by live-inspecting the target page rather than manual coding.

Compared to similar skills

create-page-object side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
create-page-object (this skill)02moReviewIntermediate
ui-ux-expert-skill919moReviewAdvanced
playwright-browser-automation297moReviewIntermediate
frontend-testing113moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

ui-ux-expert-skill

fercracix33

Technical workflow for implementing accessible React user interfaces with shadcn/ui, Tailwind CSS, and TanStack Query. Includes 6-phase process with mandatory Style Guide compliance, Context7 best practices consultation, Chrome DevTools validation, and WCAG 2.1 AA accessibility standards. Use after Test Agent, Implementer, and Supabase agents complete their work.

91244

playwright-browser-automation

lackeyjb

Complete browser automation with Playwright. Auto-detects dev servers, writes clean test scripts to /tmp. Test pages, fill forms, take screenshots, check responsive design, validate UX, test login flows, check links, automate any browser task. Use when user wants to test websites, automate browser interactions, validate web functionality, or perform any browser-based testing.

29146

frontend-testing

langgenius

Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities. Triggers on testing, spec files, coverage, Vitest, RTL, unit tests, integration tests, or write/review test requests.

1152

flutter

alinaqi

Flutter development with Riverpod state management, Freezed, go_router, and mocktail testing

1343

feature-flags

facebook

Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React.

642

vue-testing-best-practices

vuejs-ai

Use for Vue.js testing. Covers Vitest, Vue Test Utils, component testing, mocking, testing patterns, and Playwright for E2E testing.

534

Search skills

Search the agent skills registry