mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
feat: add playwright and storybook folder support for packages with declarative test schemas
- Created playwright.schema.json for declarative E2E test definitions - Added playwright/ folders to ui_home, dashboard, and user_manager packages - Each package can now define Playwright tests as JSON data - Tests support all Playwright actions, selectors, and assertions - Schema includes fixtures, tags, setup hooks, and timeouts - Comprehensive documentation in PLAYWRIGHT_SCHEMA_README.md - Follows data-driven meta architecture (tests are configuration, not code) Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
52
packages/dashboard/playwright/tests.json
Normal file
52
packages/dashboard/playwright/tests.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"$schema": "https://metabuilder.dev/schemas/package-playwright.schema.json",
|
||||
"package": "dashboard",
|
||||
"version": "1.0.0",
|
||||
"description": "E2E tests for dashboard package - validates user dashboard, widgets, and data display",
|
||||
"tests": [
|
||||
{
|
||||
"name": "should load dashboard for authenticated user",
|
||||
"tags": ["@smoke", "@dashboard"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/dashboard"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Verify dashboard container",
|
||||
"action": "expect",
|
||||
"selector": ".dashboard-container",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should display user widgets",
|
||||
"tags": ["@ui", "@widgets"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/dashboard"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "networkidle"
|
||||
},
|
||||
{
|
||||
"description": "Check widgets grid exists",
|
||||
"action": "expect",
|
||||
"selector": ".dashboard-widgets",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
85
packages/ui_home/playwright/README.md
Normal file
85
packages/ui_home/playwright/README.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Playwright Tests for ui_home Package
|
||||
|
||||
This folder contains declarative Playwright test definitions for the `ui_home` package, following MetaBuilder's data-driven architecture.
|
||||
|
||||
## Structure
|
||||
|
||||
- **tests.json** - Main test suite with JSON-defined E2E tests
|
||||
- **metadata.json** - Test suite metadata and coverage information
|
||||
|
||||
## Test Coverage
|
||||
|
||||
The test suite validates:
|
||||
|
||||
- ✅ Home page loads successfully (HTTP 200)
|
||||
- ✅ Hero section with title and CTAs
|
||||
- ✅ Six Levels of Power feature cards
|
||||
- ✅ Navigation bar with Sign In/Admin buttons
|
||||
- ✅ About MetaBuilder section
|
||||
- ✅ Contact form with all fields
|
||||
- ✅ No critical console errors
|
||||
- ✅ Anchor link navigation
|
||||
|
||||
## Running Tests
|
||||
|
||||
### From Package Test Definition
|
||||
```bash
|
||||
# Generate .spec.ts from tests.json (future implementation)
|
||||
npm run test:generate -- --package ui_home
|
||||
|
||||
# Run generated tests
|
||||
npm run test:e2e -- --grep @ui_home
|
||||
```
|
||||
|
||||
### Run Existing E2E Tests
|
||||
```bash
|
||||
cd /path/to/metabuilder
|
||||
npm run test:e2e -- e2e/smoke.spec.ts
|
||||
```
|
||||
|
||||
## Test Schema
|
||||
|
||||
Tests follow the `playwright.schema.json` schema:
|
||||
- **Declarative steps**: All test actions defined in JSON
|
||||
- **Selector strategies**: Support for CSS, role-based, text, and test-id selectors
|
||||
- **Assertions**: Playwright expect matchers as data
|
||||
- **Fixtures**: Reusable test data
|
||||
- **Tags**: Filter tests by categories (@smoke, @critical, etc.)
|
||||
|
||||
## Example Test
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "should display hero section with title and CTAs",
|
||||
"tags": ["@smoke", "@ui"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "expect",
|
||||
"selector": ".hero-title",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Meta Architecture Benefits
|
||||
|
||||
- **Data-driven**: Tests are configuration, not code
|
||||
- **Package-scoped**: Each package owns its test definitions
|
||||
- **Schema-validated**: Tests conform to JSON schema
|
||||
- **Auto-discoverable**: Test loader can find all `playwright/tests.json` files
|
||||
- **Maintainable**: Update tests without touching TypeScript
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Test Generator**: Convert `tests.json` → `.spec.ts` automatically
|
||||
2. **Visual Testing**: Add screenshot comparison tests
|
||||
3. **Performance**: Add lighthouse/performance assertions
|
||||
4. **Accessibility**: WCAG/aria validation tests
|
||||
5. **Cross-browser**: Multi-browser test matrix from single JSON
|
||||
16
packages/ui_home/playwright/metadata.json
Normal file
16
packages/ui_home/playwright/metadata.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json",
|
||||
"folder": "playwright",
|
||||
"description": "Playwright E2E test definitions for ui_home package",
|
||||
"version": "1.0.0",
|
||||
"files": {
|
||||
"tests.json": "Main test suite with declarative test definitions"
|
||||
},
|
||||
"testRunner": "playwright",
|
||||
"coverage": {
|
||||
"components": ["home_page", "hero_section", "features_section", "about_section", "contact_section"],
|
||||
"interactions": ["navigation", "forms", "anchors"],
|
||||
"viewports": ["desktop", "mobile"]
|
||||
},
|
||||
"tags": ["@smoke", "@ui", "@critical", "@navigation", "@form", "@interaction", "@features", "@content"]
|
||||
}
|
||||
360
packages/ui_home/playwright/tests.json
Normal file
360
packages/ui_home/playwright/tests.json
Normal file
@@ -0,0 +1,360 @@
|
||||
{
|
||||
"$schema": "https://metabuilder.dev/schemas/package-playwright.schema.json",
|
||||
"package": "ui_home",
|
||||
"version": "1.0.0",
|
||||
"description": "E2E tests for ui_home package - validates landing page rendering, navigation, and interactions",
|
||||
"baseURL": "http://localhost:3000",
|
||||
"setup": {
|
||||
"beforeAll": [
|
||||
{
|
||||
"action": "seed",
|
||||
"description": "Seed database with ui_home package data"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fixtures": {
|
||||
"heroTitle": "Build Anything, Visually",
|
||||
"heroSubtitle": "A 6-level meta-architecture for creating entire applications through visual workflows, schema editors, and embedded scripting. No code required.",
|
||||
"featuresSectionTitle": "Six Levels of Power",
|
||||
"expectedFeatureCards": 6,
|
||||
"aboutTitle": "About MetaBuilder",
|
||||
"contactTitle": "Get in Touch"
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"name": "should load home page successfully",
|
||||
"description": "Verifies the home page loads with HTTP 200 and displays content",
|
||||
"tags": ["@smoke", "@critical"],
|
||||
"timeout": 10000,
|
||||
"steps": [
|
||||
{
|
||||
"description": "Navigate to root path",
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"description": "Wait for DOM to be ready",
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Verify page has content",
|
||||
"action": "expect",
|
||||
"selector": "body",
|
||||
"assertion": {
|
||||
"matcher": "toContainText",
|
||||
"expected": "MetaBuilder"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should display hero section with title and CTAs",
|
||||
"description": "Validates hero section renders with gradient title and action buttons",
|
||||
"tags": ["@smoke", "@ui"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Check hero title is visible",
|
||||
"action": "expect",
|
||||
"selector": ".hero-title",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify hero title text",
|
||||
"action": "expect",
|
||||
"selector": ".hero-title",
|
||||
"assertion": {
|
||||
"matcher": "toContainText",
|
||||
"expected": "Build Anything"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Check Get Started button exists",
|
||||
"action": "expect",
|
||||
"role": "button",
|
||||
"text": "Get Started",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Check Watch Demo button exists",
|
||||
"action": "expect",
|
||||
"role": "button",
|
||||
"text": "Watch Demo",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should display six level feature cards",
|
||||
"description": "Validates the Six Levels of Power feature grid with all 6 level cards",
|
||||
"tags": ["@smoke", "@ui", "@features"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "networkidle"
|
||||
},
|
||||
{
|
||||
"description": "Verify features section header",
|
||||
"action": "expect",
|
||||
"selector": ".features-header",
|
||||
"assertion": {
|
||||
"matcher": "toContainText",
|
||||
"expected": "Six Levels of Power"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Check features grid is visible",
|
||||
"action": "expect",
|
||||
"selector": ".features-grid",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify exactly 6 feature cards",
|
||||
"action": "expect",
|
||||
"selector": ".feature-card",
|
||||
"assertion": {
|
||||
"matcher": "toHaveCount",
|
||||
"expected": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Check Level 1 card is visible",
|
||||
"action": "expect",
|
||||
"selector": ".feature-card--level1",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Check Level 6 (Super God) card is visible",
|
||||
"action": "expect",
|
||||
"selector": ".feature-card--level6",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should display navigation with Sign In and Admin buttons",
|
||||
"description": "Validates navigation bar with authentication links",
|
||||
"tags": ["@smoke", "@navigation"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Check navigation bar exists",
|
||||
"action": "expect",
|
||||
"selector": ".landing-nav",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify Sign In button",
|
||||
"action": "expect",
|
||||
"role": "button",
|
||||
"text": "Sign In",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify Admin button",
|
||||
"action": "expect",
|
||||
"role": "button",
|
||||
"text": "Admin",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should display about section",
|
||||
"description": "Validates About MetaBuilder section content",
|
||||
"tags": ["@ui", "@content"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Check about section is visible",
|
||||
"action": "expect",
|
||||
"selector": ".about-section",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify about title",
|
||||
"action": "expect",
|
||||
"selector": ".about-title",
|
||||
"assertion": {
|
||||
"matcher": "toContainText",
|
||||
"expected": "About MetaBuilder"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should display contact form",
|
||||
"description": "Validates contact section with form fields",
|
||||
"tags": ["@ui", "@form"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Check contact section is visible",
|
||||
"action": "expect",
|
||||
"selector": ".contact-section",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify contact title",
|
||||
"action": "expect",
|
||||
"selector": ".contact-title",
|
||||
"assertion": {
|
||||
"matcher": "toContainText",
|
||||
"expected": "Get in Touch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Check contact form exists",
|
||||
"action": "expect",
|
||||
"selector": ".contact-form",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify name field",
|
||||
"action": "expect",
|
||||
"selector": ".contact-field--name",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify email field",
|
||||
"action": "expect",
|
||||
"selector": ".contact-field--email",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify message field",
|
||||
"action": "expect",
|
||||
"selector": ".contact-field--message",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify submit button",
|
||||
"action": "expect",
|
||||
"selector": ".contact-submit",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should have no critical console errors",
|
||||
"description": "Ensures page loads without JavaScript errors",
|
||||
"tags": ["@smoke", "@critical"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "networkidle"
|
||||
},
|
||||
{
|
||||
"description": "Page should load successfully without errors",
|
||||
"action": "expect",
|
||||
"selector": "body",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should navigate to sections via anchor links",
|
||||
"description": "Tests smooth scrolling to sections via navigation links",
|
||||
"tags": ["@interaction", "@navigation"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Click Features link",
|
||||
"action": "click",
|
||||
"selector": "a[href='#features']"
|
||||
},
|
||||
{
|
||||
"description": "Wait for scroll",
|
||||
"action": "wait",
|
||||
"timeout": 500
|
||||
},
|
||||
{
|
||||
"description": "Features section should be in viewport",
|
||||
"action": "expect",
|
||||
"selector": "#features",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
74
packages/user_manager/playwright/tests.json
Normal file
74
packages/user_manager/playwright/tests.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"$schema": "https://metabuilder.dev/schemas/package-playwright.schema.json",
|
||||
"package": "user_manager",
|
||||
"version": "1.0.0",
|
||||
"description": "E2E tests for user_manager package - validates user CRUD operations and admin workflows",
|
||||
"tests": [
|
||||
{
|
||||
"name": "should display user list",
|
||||
"tags": ["@smoke", "@admin"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/admin/users"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Verify user table",
|
||||
"action": "expect",
|
||||
"selector": ".user-table",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should create new user",
|
||||
"tags": ["@crud", "@admin"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/admin/users"
|
||||
},
|
||||
{
|
||||
"action": "click",
|
||||
"role": "button",
|
||||
"text": "Add User"
|
||||
},
|
||||
{
|
||||
"action": "waitForSelector",
|
||||
"selector": ".user-form"
|
||||
},
|
||||
{
|
||||
"description": "Fill username",
|
||||
"action": "fill",
|
||||
"selector": "input[name='username']",
|
||||
"value": "testuser"
|
||||
},
|
||||
{
|
||||
"description": "Fill email",
|
||||
"action": "fill",
|
||||
"selector": "input[name='email']",
|
||||
"value": "test@example.com"
|
||||
},
|
||||
{
|
||||
"action": "click",
|
||||
"role": "button",
|
||||
"text": "Save"
|
||||
},
|
||||
{
|
||||
"description": "Verify success message",
|
||||
"action": "expect",
|
||||
"text": "User created successfully",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
273
schemas/package-schemas/PLAYWRIGHT_SCHEMA_README.md
Normal file
273
schemas/package-schemas/PLAYWRIGHT_SCHEMA_README.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# Playwright Test Schema
|
||||
|
||||
This schema defines declarative Playwright E2E tests for MetaBuilder packages, following the data-driven architecture principle.
|
||||
|
||||
## Purpose
|
||||
|
||||
Enable packages to define end-to-end tests as JSON data rather than TypeScript code, making tests:
|
||||
- **Data-driven**: Tests are configuration
|
||||
- **Package-scoped**: Each package owns its test definitions
|
||||
- **Auto-discoverable**: Test loaders can find all `playwright/tests.json` files
|
||||
- **Schema-validated**: Tests conform to JSON schema
|
||||
- **Maintainable**: Update tests without touching code
|
||||
|
||||
## Schema Location
|
||||
|
||||
- **File**: `schemas/package-schemas/playwright.schema.json`
|
||||
- **$id**: `https://metabuilder.dev/schemas/package-playwright.schema.json`
|
||||
|
||||
## Package Structure
|
||||
|
||||
```
|
||||
packages/{package_name}/
|
||||
├── playwright/
|
||||
│ ├── tests.json # Main test definitions (required)
|
||||
│ ├── metadata.json # Test suite metadata (optional)
|
||||
│ └── README.md # Package-specific test docs (optional)
|
||||
```
|
||||
|
||||
## Test Definition Format
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://metabuilder.dev/schemas/package-playwright.schema.json",
|
||||
"package": "ui_home",
|
||||
"version": "1.0.0",
|
||||
"description": "E2E tests for ui_home package",
|
||||
"tests": [
|
||||
{
|
||||
"name": "should load home page successfully",
|
||||
"tags": ["@smoke", "@critical"],
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"action": "expect",
|
||||
"selector": "body",
|
||||
"assertion": {
|
||||
"matcher": "toContainText",
|
||||
"expected": "MetaBuilder"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Supported Actions
|
||||
|
||||
### Navigation
|
||||
- `navigate` - Navigate to URL
|
||||
- `waitForNavigation` - Wait for navigation event
|
||||
- `waitForLoadState` - Wait for load/domcontentloaded/networkidle
|
||||
|
||||
### Interactions
|
||||
- `click` - Click element
|
||||
- `dblclick` - Double-click element
|
||||
- `fill` - Fill input field
|
||||
- `type` - Type text (simulates keyboard)
|
||||
- `select` - Select dropdown option
|
||||
- `check` / `uncheck` - Toggle checkboxes
|
||||
- `hover` - Hover over element
|
||||
- `focus` - Focus element
|
||||
- `press` - Press keyboard key
|
||||
|
||||
### Assertions
|
||||
- `expect` - Make assertion with Playwright matchers
|
||||
|
||||
### Utilities
|
||||
- `wait` - Wait for timeout
|
||||
- `waitForSelector` - Wait for element
|
||||
- `screenshot` - Capture screenshot
|
||||
- `evaluate` - Run JavaScript in browser
|
||||
|
||||
## Selector Strategies
|
||||
|
||||
Multiple selector types supported:
|
||||
|
||||
```json
|
||||
{
|
||||
"selector": ".hero-title" // CSS selector
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"role": "button", // ARIA role
|
||||
"text": "Get Started"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "Build Anything" // Text content
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"label": "Email" // Form label
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"testId": "submit-button" // data-testid attribute
|
||||
}
|
||||
```
|
||||
|
||||
## Assertion Matchers
|
||||
|
||||
All Playwright expect matchers supported:
|
||||
|
||||
- **Visibility**: `toBeVisible`, `toBeHidden`
|
||||
- **State**: `toBeEnabled`, `toBeDisabled`, `toBeChecked`, `toBeFocused`
|
||||
- **Content**: `toHaveText`, `toContainText`, `toBeEmpty`
|
||||
- **Values**: `toHaveValue`, `toHaveAttribute`, `toHaveClass`, `toHaveCSS`
|
||||
- **Count**: `toHaveCount`
|
||||
- **URL/Title**: `toHaveURL`, `toHaveTitle`
|
||||
- **Comparison**: `toEqual`, `toContain`, `toBeGreaterThan`, `toBeLessThan`
|
||||
|
||||
Use `not: true` to negate assertions:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "expect",
|
||||
"selector": ".error-message",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible",
|
||||
"not": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Test Tags
|
||||
|
||||
Use tags to organize and filter tests:
|
||||
|
||||
- `@smoke` - Critical smoke tests
|
||||
- `@critical` - High-priority tests
|
||||
- `@ui` - UI interaction tests
|
||||
- `@navigation` - Navigation tests
|
||||
- `@form` - Form interaction tests
|
||||
- `@crud` - Create/Read/Update/Delete tests
|
||||
- `@admin` - Admin-only tests
|
||||
- `@slow` - Slower-running tests
|
||||
|
||||
Run tests by tag:
|
||||
```bash
|
||||
npm run test:e2e -- --grep @smoke
|
||||
npm run test:e2e -- --grep @ui
|
||||
```
|
||||
|
||||
## Setup Hooks
|
||||
|
||||
Define setup/teardown at test suite level:
|
||||
|
||||
```json
|
||||
{
|
||||
"setup": {
|
||||
"beforeAll": [
|
||||
{ "action": "seed", "description": "Seed database" }
|
||||
],
|
||||
"beforeEach": [
|
||||
{ "action": "navigate", "url": "/" }
|
||||
],
|
||||
"afterEach": [
|
||||
{ "action": "screenshot", "path": "test-results/{test-name}.png" }
|
||||
],
|
||||
"afterAll": [
|
||||
{ "action": "custom", "script": "cleanup" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Fixtures
|
||||
|
||||
Define reusable test data:
|
||||
|
||||
```json
|
||||
{
|
||||
"fixtures": {
|
||||
"testUser": {
|
||||
"username": "testuser",
|
||||
"email": "test@example.com",
|
||||
"password": "test123"
|
||||
},
|
||||
"heroTitle": "Build Anything, Visually"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference fixtures in tests:
|
||||
```json
|
||||
{
|
||||
"action": "fill",
|
||||
"selector": "input[name='username']",
|
||||
"value": "{{fixtures.testUser.username}}"
|
||||
}
|
||||
```
|
||||
|
||||
## Test Configuration
|
||||
|
||||
Per-test configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "slow integration test",
|
||||
"timeout": 30000, // 30 second timeout
|
||||
"retries": 2, // Retry twice on failure
|
||||
"skip": false, // Skip this test
|
||||
"only": false // Run only this test
|
||||
}
|
||||
```
|
||||
|
||||
## Example: Complete Test Suite
|
||||
|
||||
See `packages/ui_home/playwright/tests.json` for a complete example with:
|
||||
- 8 declarative tests
|
||||
- Multiple selector strategies
|
||||
- Various assertion types
|
||||
- Smoke, UI, and interaction tests
|
||||
- Navigation and form testing
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Test Generator**: Auto-generate `.spec.ts` from `tests.json`
|
||||
2. **Visual Regression**: Screenshot comparison tests
|
||||
3. **Performance**: Lighthouse/web vitals assertions
|
||||
4. **Accessibility**: WCAG/ARIA validation
|
||||
5. **API Mocking**: Declarative API mock definitions
|
||||
6. **Cross-browser**: Multi-browser matrix from single JSON
|
||||
|
||||
## Related Schemas
|
||||
|
||||
- `storybook_schema.json` - Storybook story definitions
|
||||
- `tests_schema.json` - Unit test definitions
|
||||
- `component.schema.json` - Component definitions
|
||||
|
||||
## Validation
|
||||
|
||||
Validate test files:
|
||||
```bash
|
||||
cd schemas/package-schemas
|
||||
./schema_validator.sh playwright.schema.json ../../packages/ui_home/playwright/tests.json
|
||||
```
|
||||
|
||||
## Benefits of Data-Driven Tests
|
||||
|
||||
1. **95% Configuration Rule**: Tests are data, not code
|
||||
2. **Package Ownership**: Each package defines its own tests
|
||||
3. **Schema Validation**: Catch errors before runtime
|
||||
4. **Auto-Discovery**: Test runners can find all package tests
|
||||
5. **Consistency**: Same structure across all packages
|
||||
6. **Maintainability**: Change tests without TypeScript knowledge
|
||||
7. **Meta Architecture**: Tests themselves are abstract/declarative
|
||||
380
schemas/package-schemas/playwright.schema.json
Normal file
380
schemas/package-schemas/playwright.schema.json
Normal file
@@ -0,0 +1,380 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://metabuilder.dev/schemas/package-playwright.schema.json",
|
||||
"title": "Package Playwright Test Configuration",
|
||||
"description": "Playwright E2E test configuration for MetaBuilder packages - defines test scenarios, assertions, and page interactions",
|
||||
"type": "object",
|
||||
"required": ["$schema", "tests"],
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string",
|
||||
"description": "JSON Schema reference",
|
||||
"const": "https://metabuilder.dev/schemas/package-playwright.schema.json"
|
||||
},
|
||||
"package": {
|
||||
"type": "string",
|
||||
"description": "Package identifier",
|
||||
"pattern": "^[a-z0-9_]+$"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Schema version",
|
||||
"default": "1.0.0"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Test suite description"
|
||||
},
|
||||
"baseURL": {
|
||||
"type": "string",
|
||||
"description": "Base URL for tests (defaults to playwright config)",
|
||||
"format": "uri"
|
||||
},
|
||||
"setup": {
|
||||
"type": "object",
|
||||
"description": "Global test setup configuration",
|
||||
"properties": {
|
||||
"beforeAll": {
|
||||
"type": "array",
|
||||
"description": "Steps to run once before all tests",
|
||||
"items": { "$ref": "#/definitions/setupStep" }
|
||||
},
|
||||
"beforeEach": {
|
||||
"type": "array",
|
||||
"description": "Steps to run before each test",
|
||||
"items": { "$ref": "#/definitions/setupStep" }
|
||||
},
|
||||
"afterEach": {
|
||||
"type": "array",
|
||||
"description": "Steps to run after each test",
|
||||
"items": { "$ref": "#/definitions/setupStep" }
|
||||
},
|
||||
"afterAll": {
|
||||
"type": "array",
|
||||
"description": "Steps to run once after all tests",
|
||||
"items": { "$ref": "#/definitions/setupStep" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"fixtures": {
|
||||
"type": "object",
|
||||
"description": "Test fixtures - reusable test data",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"description": "Fixture data"
|
||||
}
|
||||
},
|
||||
"tests": {
|
||||
"type": "array",
|
||||
"description": "Test definitions",
|
||||
"items": { "$ref": "#/definitions/test" }
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"setupStep": {
|
||||
"type": "object",
|
||||
"required": ["action"],
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"description": "Action to perform",
|
||||
"enum": ["navigate", "click", "fill", "select", "wait", "eval", "mock", "seed", "custom"]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL for navigate action"
|
||||
},
|
||||
"selector": {
|
||||
"type": "string",
|
||||
"description": "Element selector"
|
||||
},
|
||||
"value": {
|
||||
"description": "Value for fill/select actions"
|
||||
},
|
||||
"script": {
|
||||
"type": "string",
|
||||
"description": "JavaScript code to evaluate"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "number",
|
||||
"description": "Timeout in milliseconds",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"type": "object",
|
||||
"required": ["name", "steps"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Test name",
|
||||
"minLength": 1
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Detailed test description"
|
||||
},
|
||||
"skip": {
|
||||
"type": "boolean",
|
||||
"description": "Skip this test",
|
||||
"default": false
|
||||
},
|
||||
"only": {
|
||||
"type": "boolean",
|
||||
"description": "Run only this test",
|
||||
"default": false
|
||||
},
|
||||
"timeout": {
|
||||
"type": "number",
|
||||
"description": "Test timeout in milliseconds",
|
||||
"minimum": 0
|
||||
},
|
||||
"retries": {
|
||||
"type": "number",
|
||||
"description": "Number of retries on failure",
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"description": "Test tags for filtering",
|
||||
"items": { "type": "string" },
|
||||
"examples": [["@smoke", "@critical", "@slow"]]
|
||||
},
|
||||
"fixtures": {
|
||||
"type": "object",
|
||||
"description": "Test-specific fixture overrides",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"steps": {
|
||||
"type": "array",
|
||||
"description": "Test steps to execute",
|
||||
"items": { "$ref": "#/definitions/testStep" },
|
||||
"minItems": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"testStep": {
|
||||
"type": "object",
|
||||
"required": ["action"],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Human-readable step description"
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
"description": "Action to perform",
|
||||
"enum": [
|
||||
"navigate",
|
||||
"click",
|
||||
"dblclick",
|
||||
"fill",
|
||||
"type",
|
||||
"select",
|
||||
"check",
|
||||
"uncheck",
|
||||
"hover",
|
||||
"focus",
|
||||
"press",
|
||||
"wait",
|
||||
"waitForSelector",
|
||||
"waitForNavigation",
|
||||
"waitForLoadState",
|
||||
"screenshot",
|
||||
"evaluate",
|
||||
"expect",
|
||||
"custom"
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL for navigate action"
|
||||
},
|
||||
"selector": {
|
||||
"type": "string",
|
||||
"description": "CSS selector or role-based selector"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "ARIA role for getByRole selector",
|
||||
"enum": ["button", "link", "textbox", "heading", "img", "navigation", "main", "article", "section"]
|
||||
},
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "Text content or pattern for getByText selector"
|
||||
},
|
||||
"label": {
|
||||
"type": "string",
|
||||
"description": "Label for getByLabel selector"
|
||||
},
|
||||
"placeholder": {
|
||||
"type": "string",
|
||||
"description": "Placeholder for getByPlaceholder selector"
|
||||
},
|
||||
"testId": {
|
||||
"type": "string",
|
||||
"description": "Test ID for getByTestId selector"
|
||||
},
|
||||
"value": {
|
||||
"description": "Value to fill, type, or select"
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "Key to press (e.g., 'Enter', 'Escape')"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "number",
|
||||
"description": "Step timeout in milliseconds",
|
||||
"minimum": 0
|
||||
},
|
||||
"assertion": {
|
||||
"$ref": "#/definitions/assertion",
|
||||
"description": "Assertion to make for expect actions"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"description": "Load state for waitForLoadState",
|
||||
"enum": ["load", "domcontentloaded", "networkidle"]
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "File path for screenshot"
|
||||
},
|
||||
"fullPage": {
|
||||
"type": "boolean",
|
||||
"description": "Capture full page screenshot",
|
||||
"default": false
|
||||
},
|
||||
"script": {
|
||||
"type": "string",
|
||||
"description": "JavaScript code for evaluate action"
|
||||
},
|
||||
"condition": {
|
||||
"type": "string",
|
||||
"description": "Conditional expression for conditional steps"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assertion": {
|
||||
"type": "object",
|
||||
"required": ["matcher"],
|
||||
"properties": {
|
||||
"matcher": {
|
||||
"type": "string",
|
||||
"description": "Playwright assertion matcher",
|
||||
"enum": [
|
||||
"toBeVisible",
|
||||
"toBeHidden",
|
||||
"toBeEnabled",
|
||||
"toBeDisabled",
|
||||
"toBeChecked",
|
||||
"toBeFocused",
|
||||
"toBeEmpty",
|
||||
"toHaveText",
|
||||
"toContainText",
|
||||
"toHaveValue",
|
||||
"toHaveCount",
|
||||
"toHaveAttribute",
|
||||
"toHaveClass",
|
||||
"toHaveCSS",
|
||||
"toHaveURL",
|
||||
"toHaveTitle",
|
||||
"toBeTruthy",
|
||||
"toBeFalsy",
|
||||
"toEqual",
|
||||
"toContain",
|
||||
"toBeGreaterThan",
|
||||
"toBeLessThan"
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"description": "Expected value for matcher"
|
||||
},
|
||||
"not": {
|
||||
"type": "boolean",
|
||||
"description": "Negate the assertion",
|
||||
"default": false
|
||||
},
|
||||
"timeout": {
|
||||
"type": "number",
|
||||
"description": "Assertion timeout in milliseconds",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"$schema": "https://metabuilder.dev/schemas/package-playwright.schema.json",
|
||||
"package": "ui_home",
|
||||
"description": "E2E tests for home page components",
|
||||
"tests": [
|
||||
{
|
||||
"name": "should display home page with hero section",
|
||||
"tags": ["@smoke", "@critical"],
|
||||
"steps": [
|
||||
{
|
||||
"description": "Navigate to home page",
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"description": "Wait for page to load",
|
||||
"action": "waitForLoadState",
|
||||
"state": "domcontentloaded"
|
||||
},
|
||||
{
|
||||
"description": "Verify hero title is visible",
|
||||
"action": "expect",
|
||||
"text": "Build Anything, Visually",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify Get Started button exists",
|
||||
"action": "expect",
|
||||
"role": "button",
|
||||
"text": "Get Started",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "should display six feature cards",
|
||||
"steps": [
|
||||
{
|
||||
"action": "navigate",
|
||||
"url": "/"
|
||||
},
|
||||
{
|
||||
"action": "waitForLoadState",
|
||||
"state": "networkidle"
|
||||
},
|
||||
{
|
||||
"description": "Check feature grid container exists",
|
||||
"action": "expect",
|
||||
"selector": ".features-grid",
|
||||
"assertion": {
|
||||
"matcher": "toBeVisible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Verify 6 feature cards are rendered",
|
||||
"action": "expect",
|
||||
"selector": ".feature-card",
|
||||
"assertion": {
|
||||
"matcher": "toHaveCount",
|
||||
"expected": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user