npm package: @sun-asterisk/sungen
Description: Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests
Author: ee team
Latest version: 2.4.1

# 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.ts
```

---

## Quick Start

```bash
# 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 login
```

---

## CLI 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**:
1. Explores live page → generates `selectors.yaml`
2. Compiles: `sungen generate --screen <name>`
3. Runs: `npx playwright test`
4. If fail → auto-fixes selectors/test-data → retry (up to 5 attempts)

---

## Workflow

### 1. Add a screen

```bash
sungen add --screen awards --path /awards
```

Creates:
```
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:
1. Navigate to the page URL
2. Take an accessibility snapshot
3. 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

```bash
sungen generate --screen awards
npx playwright test
```

### 4. 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 in `selectors/*.yaml`
- `{{Value}}` → test data reference → lookup in `test-data/*.yaml`

### Example

```gherkin
@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 enabled
```

---

## Pattern 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 [Username] row in [Users] table with {{name}}` |
| Row hidden | `User see [Username] row in [Users] table with {{name}} is hidden` |
| Row count | `User see [Users] table with {{count}}` |
| Empty table | `User see [Users] table is empty` |
| Cell value | `User see [Status] column with {{status}}` (row scoped) |
| Action in row | `User click [Edit] button in [Users] table with {{name}}` |

### 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.

```yaml
# 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

```gherkin
@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 hidden
```

---

## Project 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 tests
```

---

## Documentation

Full documentation at **[sungen.sun-asterisk.vn](https://sungen.sun-asterisk.vn)**

- **[Installation Guide](https://sun-asterisk.github.io/sungen/docs/guides/installation)** — Windows (Git Bash + VS Code + Copilot), macOS, Linux
- **[Quick Start](https://sun-asterisk.github.io/sungen/docs/guides/quick-start)** — From zero to running tests
- **[Selector YAML Guide](https://sun-asterisk.github.io/sungen/docs/guides/selector-override)** — NFC keys, auto-infer, Japanese/Vietnamese support
- **[Tips & Troubleshooting](https://sun-asterisk.github.io/sungen/docs/guides/tips)** — When AI gets stuck fixing tests
- **[Gherkin Patterns](https://sun-asterisk.github.io/sungen/docs/gherkin/patterns)** — Full grammar, all patterns, compiler rules

---

## License

MIT License - see LICENSE file for details.

**Made with ❤️ by ee team (engineer-excellence) — Sun Asterisk**