Skip to main content
Version: 1.x

Architecture Overview

Praman v1.0 ships as a single npm package (playwright-praman) with sub-path exports, organized into a strict 5-layer architecture where lower layers never import from higher layers.

5-Layer Architecture

┌─────────────────────────────────────────────────────────────────────────┐
│ Test Author / AI Agent │
│ import { test, expect } from 'playwright-praman' │
│ import { procurement } from 'playwright-praman/intents' │
└──────────────────────────────────┬──────────────────────────────────────┘

┌──────────────────────────────────▼──────────────────────────────────────┐
│ Layer 5 — Public API (6 sub-path exports) │
│ │
│ playwright-praman /ai /intents /vocabulary /fe /reporters │
└──────────────────────────────────┬──────────────────────────────────────┘

┌──────────────────────────────────▼──────────────────────────────────────┐
│ Layer 4 — Fixtures + Modules │
│ │
│ Fixtures core · auth · nav · stability · ai · fe · intent · flp │
│ Merged via mergeTests() into a single test object │
│ Modules table · dialog · date · navigation · odata · workzone │
│ Auth cloud-saml · office365 · onprem · api-key · cert · tenant │
└──────────────────────────────────┬──────────────────────────────────────┘

┌──────────────────────────────────▼──────────────────────────────────────┐
│ Layer 3 — Control Proxy │
│ │
│ control-proxy.ts · discovery.ts · ui5-object.ts · cache.ts │
│ 3-tier discovery: object cache → stable ID → type + property search │
└──────────────────────────────────┬──────────────────────────────────────┘

┌──────────────────────────────────▼──────────────────────────────────────┐
│ Layer 2 — Bridge │
│ │
│ injection.ts (lazy bridge bootstrap into browser context) │
│ browser-scripts/ inject-ui5 · find-control · execute-method · ... │
│ Interaction strategies: UI5Native · DomFirst · OPA5 │
└──────────────────────────────────┬──────────────────────────────────────┘

┌──────────────────────────────────▼──────────────────────────────────────┐
│ Layer 1 — Core Infrastructure │
│ │
│ config (Zod) · errors (13 subclasses) · logging (pino) │
│ telemetry (OTel) · types (199 interfaces) · utils · compat │
└──────────────────────────────────┬──────────────────────────────────────┘

┌──────────────────────────────────▼──────────────────────────────────────┐
│ @playwright/test (external dependency) │
│ page · browser · context · expect │
└─────────────────────────────────────────────────────────────────────────┘

Layer Dependency Rules

The architecture enforces a strict downward-only dependency rule:

  • Layer 1 (Core) has zero internal dependencies beyond Node.js builtins.
  • Layer 2 (Bridge) imports only from Layer 1.
  • Layer 3 (Proxy) imports from Layers 1 and 2.
  • Layer 4 (Fixtures + Modules) imports from Layers 1, 2, and 3.
  • Layer 5 (Public API) re-exports from Layers 1–4; no higher layer imports from it.

This is enforced at compile time via TypeScript path aliases (#core/*, #bridge/*, #proxy/*, #fixtures/*) and ESLint import rules.

Internal path aliases

The aliases below are internal to Praman's source code and are not available to package consumers. They enforce layer boundaries during development.

// Allowed: Layer 3 importing from Layer 1
import { ErrorCode } from '#core/errors/codes.js';

// Allowed: Layer 3 importing from Layer 2
import { ensureBridgeInjected } from '#bridge/injection.js';

// FORBIDDEN: Layer 1 importing from Layer 3 — compile error
// import { ControlProxy } from '#proxy/control-proxy.js';

Sub-Path Exports

Praman ships 6 sub-path exports, each targeting a specific concern:

Sub-Path ExportPurposeKey Modules
playwright-pramanCore fixtures, expect, testFixtures, selectors, matchers
playwright-praman/aiAI agent integrationCapabilityRegistry, RecipeRegistry, AgenticHandler
playwright-praman/intentsSAP domain intent APIsCore wrappers, 5 domain namespaces
playwright-praman/vocabularyBusiness term resolutionVocabularyService, fuzzy matcher
playwright-praman/feFiori Elements helpersListReport, ObjectPage, FE tables
playwright-praman/reportersCustom Playwright reportersComplianceReporter, ODataTraceReporter

Each export provides both ESM and CJS outputs:

{
"./ai": {
"types": {
"import": "./dist/ai/index.d.ts",
"require": "./dist/ai/index.d.cts"
},
"import": "./dist/ai/index.js",
"require": "./dist/ai/index.cjs"
}
}

All exports are validated by @arethetypeswrong/cli (attw) in CI.

Design Decisions Summary (D1–D29)

The architecture is guided by 29 documented design decisions:

#DecisionCategory
D1Single package with sub-path exports (not monorepo)Packaging
D2Internal fixture composition via extend() chainFixtures
D3Version-negotiated bridge adapters (removed — superseded by D4)Bridge
D4Hybrid typed proxy: 199 typed interfaces + dynamic fallbackProxy
D54-layer observability: Reporter + pino + OTel + AI telemetryObservability
D6Zod validation at external boundaries onlyValidation
D7Zod-validated praman.config.ts with env overridesConfig
D8Unified PramanError hierarchy with 13 subclassesErrors
D9AI Mode A (SKILL.md) + Mode C (agentic fixture)AI
D10Vitest unit tests + Playwright integration testsTesting
D11No plugin API in v1.0Extension
D12Auto-generated SKILL.md + Docusaurus + TypeDocDocs
D13Apache 2.0 licenseLegal
D14Playwright >=1.57.0 <2.0.0 with CI matrixCompat
D15Security: dep scanning, secret redaction, SBOM, provenanceSecurity
D16Single unified proxy (no double-proxy)Proxy
D17Bidirectional proxy conversion (UI5Object <-> UI5ControlProxy)Proxy
D18Integrated discovery factory (removed dead code)Discovery
D19Centralized __praman_getById() (3-tier API resolution)Bridge
D20Browser objectMap with TTL + cleanupMemory
D21Shared interaction logic across strategiesInteractions
D22Auto-generated method signatures (199 interfaces, 4,092 methods)Types
D23skipStabilityWait as global config + per-selector overrideStability
D24exec() with new Function() + security documentationSecurity
D25Visibility preference default (prefer visible controls)Discovery
D26UI5Object AI introspection as first-class capabilityAI
D27Module size <= 300 LOC guideline (with documented exceptions)Quality
D28Auth via Playwright project dependencies (not globalSetup)Auth
D29Enhanced error model + AI response envelopeAI/Errors

Module Decomposition Rationale

The predecessor plugin (v2.5.0) suffered from monolithic files:

FileLOCProblem
ui5-handler.ts2,318God object handling all UI5 operations
plugin-fixtures.ts2,263All 32 fixtures in one file
ui5-control-proxy.ts1,829Double-proxy with redundant interception

Praman v1.0 decomposes these into focused modules following SRP (Single Responsibility Principle):

Fixtures are split by domain:

  • core-fixtures.ts — UI5 control operations
  • auth-fixtures.ts — Authentication strategies
  • nav-fixtures.ts — Navigation and routing
  • stability-fixtures.ts — Wait conditions and stability checks
  • ai-fixtures.ts — AI agent fixtures
  • fe-fixtures.ts — Fiori Elements fixtures
  • intent-fixtures.ts — Intent API fixtures
  • shell-footer-fixtures.ts, flp-locks-fixtures.ts, flp-settings-fixtures.ts — FLP-specific fixtures

Modules handle domain operations independently of fixtures:

  • table.ts + table-operations.ts + table-filter-sort.ts — Grid and SmartTable
  • dialog.ts — Dialog detection and interaction
  • date.ts — DatePicker and range fields
  • navigation.ts — UI5 routing and hash navigation
  • odata.ts + odata-http.ts — OData model access and CRUD
  • workzone.ts — BTP WorkZone helpers

UI5Handler was decomposed from a 2,318 LOC god object into:

  • ui5-handler.ts (588 LOC) — 16 core methods
  • shell-handler.ts (102 LOC) — FLP shell operations
  • footer-handler.ts (119 LOC) — Footer bar operations
  • navigation.ts (201 LOC) — Route and hash navigation

Control proxy was simplified from a double-proxy pattern (1,829 LOC) into:

  • control-proxy.ts (653 LOC) — Unified single proxy handler
  • ui5-object.ts (383 LOC) — Non-control object proxy
  • discovery.ts (111 LOC) — 3-tier control discovery
  • cache.ts (104 LOC) — Proxy cache with RegExp keys

Every module targets <= 300 LOC. Exceptions are documented with justification comments.

Codebase Metrics

MetricValue
Source files~150
Source LOC~29,000
Public functions208
Test files109
Unit tests~2,000 passing
Typed control interfaces199 (4,092 methods)
Error subclasses13
Coverage>98% (per-file enforcement)
Lint errors0
Type errors0
ESM + CJS dual buildValidated by attw