@sun-asterisk/sungen
v2.3.1
Published
Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests
Readme
Sungen v2 — Deterministic E2E Test Compiler
Version: 2.2.3 Gherkin + Selector YAML + Test Data → Playwright .spec.ts
What is Sungen?
Sungen is a deterministic compiler that converts Gherkin features into Playwright tests.
v2 architecture: AI generates the input files (Gherkin + selectors), sungen compiles to tests. No AI inside sungen itself.
AI (Copilot/Claude + MCP Playwright) → visits URL → generates files
sungen generate → compiles .feature + selectors.yaml + data.yaml → .spec.tsQuick Start
# Install
npm install -g @sun-asterisk/sungen@latest
# Initialize project (creates AI rules + directory structure)
sungen init --base-url https://your-app.com
# Use AI slash commands to generate tests
# In GitHub Copilot Chat:
/sungen-add-screen login /auth/login
/sungen-make-tc login
/sungen-make-test loginCLI Commands
| Command | Description |
|---------|-------------|
| sungen init | Scaffold project + generate AI rules |
| sungen add --screen <name> --path <path> | Create screen with empty templates |
| sungen add --screen <name> --feature <name> | Add feature file to existing screen |
| sungen generate --screen <name> | Compile Gherkin → Playwright .spec.ts |
| sungen generate --all | Compile all screens |
| sungen makeauth <role> | Capture browser auth state (SSO support) |
AI Slash Commands
| Action | GitHub Copilot (VS Code) | Claude Code |
|--------|--------------------------|-------------|
| Add screen | /sungen-add-screen login /auth/login | /sungen:add-screen login /auth/login |
| Create test cases | /sungen-make-tc login | /sungen:make-tc login |
| Compile & run tests | /sungen-make-test login | /sungen:make-test login |
make-tc — Create test cases
AI acts as a Senior QA Engineer. Supports 3 input modes:
- Live page — AI visits the page via MCP Playwright, analyzes UI elements
- Figma / screenshots — AI generates tests from static designs
- Update mode — AI detects existing tests and asks: add new, expand, or replace
Output: .feature + test-data.yaml (no selectors — those are generated during make-test)
make-test — Compile & run
AI acts as a Senior Developer:
- Explores live page → generates
selectors.yaml - Compiles:
sungen generate --screen <name> - Runs:
npx playwright test - If fail → auto-fixes selectors/test-data → retry (up to 5 attempts)
Workflow
1. Add a screen
sungen add --screen awards --path /awardsCreates:
qa/screens/awards/
├── features/awards.feature # Gherkin template
├── selectors/awards.yaml # Selector YAML (page entry pre-filled)
└── test-data/awards.yaml # Test data (empty)2. AI generates Gherkin + selectors
Use your AI assistant (GitHub Copilot or Claude Code) with MCP Playwright to:
- Navigate to the page URL
- Take an accessibility snapshot
- Generate
.feature+selectors.yaml+test-data.yaml
The AI rules in .github/prompts/ and .claude/ (created by sungen init) teach the AI the correct syntax.
3. Compile + run
sungen generate --screen awards
npx playwright test4. Fix failures (AI verify loop)
When tests fail → AI reads error → fixes selectors.yaml → recompile → re-run.
| Error | Fix in selectors.yaml |
|---|---|
| strict mode: resolved to N elements | Add exact: true or scope or nth |
| element(s) not found | Fix name, type, or value |
| getByText matched too many | Add match: 'exact' or nth |
Gherkin Syntax
Pattern: [Keyword] User <Action> [Target Name] <Target Type> <with {{Value}}> <is State>
[Target]→ selector reference → lookup inselectors/*.yaml{{Value}}→ test data reference → lookup intest-data/*.yaml
Example
@feature_auth
Feature: Login Screen
Path: /auth/login
@auto @smoke
Scenario: User logs in successfully
Given User is on [Login] page
When User fill [Email] field with {{valid_email}}
And User fill [Password] field with {{valid_password}}
And User click [Login] button
Then User see [Dashboard] page
And User see [Welcome] heading with {{success_message}}
And User see [Logout] button is enabledPattern Shapes (18 categories)
Actions
| Pattern | Example |
|---|---|
| Simple click | User click [Submit] button |
| Click dynamic list | User click [Order] row with {{order_name}} |
| Fill field | User fill [Email] field with {{email}} |
| Fill search | User fill [Global] search with {{keyword}} |
| Check/Uncheck | User check [Remember me] checkbox / User check [Notification] toggle |
| Select dropdown | User select [Country] dropdown with {{country}} |
| Upload file | User upload [Avatar] uploader with {{path}} |
| Double click | User double click [Cell] element |
| Hover | User hover [Info] icon / User hover [Order] row |
| Clear | User clear [Search] field |
click + with rule:
with {{Value}}only for dynamic lists (row,item,card,option). Never for static elements (button,link,icon,tab).
Browser Alert
| Pattern | Example |
|---|---|
| Accept | User click [OK] alert (also: Accept, Yes, Confirm) |
| Dismiss | User click [Cancel] alert (also: Dismiss, No) |
| Fill prompt | User fill [Name] alert with {{value}} |
Alert steps must appear before the triggering action. Generates
page.once('dialog', ...).
Keyboard
| Pattern | Example |
|---|---|
| Global key | User press Escape key |
| Key on element | User press Enter on [Search] field |
Navigation
| Pattern | Example |
|---|---|
| Open page | User is on [Login] page |
| See page (URL) | User see [Dashboard] page |
Wait
| Pattern | Example |
|---|---|
| Wait timeout | User wait for 3 seconds |
| Wait element | User wait for [Modal] dialog |
| Wait hidden | User wait for [Loading] spinner is hidden |
| Wait with data | User wait for [Dialog] dialog with {{title}} |
Assertions (7 verify patterns)
| Pattern | Assertion | Example |
|---|---|---|
| Visibility | toBeVisible() | User see [Success] message |
| Hidden | toBeHidden() | User see [Ads] modal is hidden |
| Text content | toHaveText() | User see [Error] message with {{err_msg}} |
| Input value | toHaveValue() | User see [Email] field with {{user_email}} |
| Partial text | toContainText() | User see [Title] text contains {{partial}} |
| Component state | toBeDisabled() etc. | User see [Submit] button is disabled |
| Page context | toHaveURL() | User see [Dashboard] page |
States: hidden, visible, disabled, enabled, checked, unchecked, focused, empty, loading, selected, sorted ascending, sorted descending
Table
| Pattern | Example |
|---|---|
| Column exists | User see [Email] column in [Users] table |
| Row exists | User see [Users] table row with {{name}} |
| No row | User see [Users] table has no row with {{name}} |
| Row count | User see [Users] table with {{count}} rows |
| Cell by filter | User see [Users] table row with {{name}} has [Status] with {{status}} |
| Cell by index | User see [Users] table row 1 [Name] cell with {{name}} |
| Action in row | User click [Edit] in [Users] table row with {{name}} |
| Empty table | User see [Users] table is empty |
Scope
| Pattern | Example |
|---|---|
| Scroll | User scroll to [Footer] section |
| Frame enter | User switch to [Payment] frame |
| Frame exit | User switch to [main] frame |
Element Types
| Group | Types |
|---|---|
| Context | page dialog modal drawer tab alert overlay step |
| Input | field textarea search dropdown option checkbox radio toggle uploader slider date-picker |
| Trigger | button link icon menuitem tag |
| Data | table row column cell list item card section |
| Feedback | message header label text tooltip badge breadcrumb image |
| System | key frame spinner progressbar |
Selector YAML v2 — NFC Key Format
Sungen v2 uses Unicode NFC normalization for selector keys — not dot notation. Keys use spaces, support Vietnamese, Japanese, and all Unicode characters.
# NFC keys (spaces, not dots)
email address:
type: 'role'
value: 'textbox'
name: 'Email Address'
exact: true
# Japanese
ログイン:
type: 'role'
value: 'button'
name: 'ログイン'
# Page navigation
login:
type: 'page'
value: '/auth/login'
# Scoped element
header login:
type: 'role'
value: 'button'
name: 'Login'
scope: 'main navigation'Locator priority: data-testid > role+name > label > text > CSS
Types: testid, role, text, label, placeholder, locator, page, upload, frame
Tags
| Tag | Level | Description |
|-----|-------|-------------|
| @auto | Scenario | Standard scenario, ready for automation |
| @manual | Scenario | Skip in generation |
| @smoke / @regression | Scenario | Test suite grouping |
| @auth:<role> | Feature/Scenario | Use Playwright auth storage state |
| @no-auth | Scenario | Disable inherited auth |
| @steps:<name> | Scenario | Mark as reusable step block (base scenario) |
| @extend:<name> | Scenario | Prepend Given→When from @steps block (skip Then) |
Auth precedence: Scenario > Feature > None
Reusable Steps
@auth:user @steps:open-dialog
Scenario: Open kudos dialog
Given User is on [kudo] page
When User click [Notifications] button
And User click [Write Kudos] menuitem
Then User see [panel] dialog with {{kudo_title}}
@auth:user @extend:open-dialog
Scenario: User sends a thank you message
Given User is on [panel] dialog with {{kudo_title}}
When User fill [Search] field with {{teammate_name}}
And User click [Send] button
Then User see [panel] dialog with {{kudo_title}} is hiddenProject Structure
qa/screens/<name>/
├── features/ # Gherkin .feature files
├── selectors/ # Element selector YAML mappings
└── test-data/ # Test data YAML values
specs/generated/<name>/
└── <feature>.spec.ts # Generated Playwright testsDocumentation
Full documentation at sungen.sun-asterisk.vn
- Installation Guide — Windows (Git Bash + VS Code + Copilot), macOS, Linux
- Quick Start — From zero to running tests
- Selector YAML Guide — NFC keys, auto-infer, Japanese/Vietnamese support
- Tips & Troubleshooting — When AI gets stuck fixing tests
- Gherkin Dictionary — Full grammar, all 18 patterns, compiler rules, formal BNF
License
MIT License - see LICENSE file for details.
Made with ❤️ by ee team (engineer-excellence) — Sun Asterisk
