BDD-to-Code Pipeline
A contract-driven frontend production system that ensures behavioral intent is preserved through the entire development lifecycle, from specification to deployment. This pattern implements a rigorous relay model—Spec → Gherkin → Tests → Generated Code → Pipeline—where executable specifications define truth, code generation enforces structure, and automated testing arbitrates reality. Unlike traditional development models that optimize for developer speed, this system optimizes for truth, repeatability, and auditability.
Core Philosophy
This is not “BDD + tooling.” It is a behavior-first frontend factory based on the operating model:
Behavior → Structure → Verification → Enforcement
Most teams stop at “tests exist.” This pattern explicitly states that behavior defines structure, and structure is continuously enforced. That’s the difference between a demo stack and an industrial one.
Truth Claims vs Implementation
The architecture separates intent from implementation:
- Gherkin defines truth claims about the system
- Angular/React/Vue is merely a realization of those claims
- Robot Framework is the arbiter of whether reality matches intent
This separation rejects:
- UI-driven tests as primary truth
- Unit tests as behavior proof
- Developer interpretation as authoritative
Code Generation as Governance
Code generation is treated as structural constraint, not convenience:
- Plop = tactical consistency (“Every component looks like this”)
- Yellicode = architectural intent (“This system is shaped like this”)
The Four Layers
1. Specification Layer: Executable Truth (Gherkin)
Gherkin is a human-readable, plain-text language that serves as the Single Source of Truth and a living contract between stakeholders and developers.
Purpose: Bridge the gap between non-technical stakeholders (product owners) and developers.
Key Insight: Gherkin files are not “comments”—they are executable code. Because feature files are executed as specifications, they prevent “requirement drift,” ensuring documentation always reflects actual behavior.
Syntax Structure: Given, When, Then, And, But
Example:
Feature: User Login
Scenario: Successful Login
Given the user is on the login page
When the user enters valid credentials
Then the dashboard should be displayedRelationship to OpenAPI Specification: When building RESTful APIs, an OpenAPI spec provides a wealth of details easily transformed to Gherkin. The spec defines URL paths, operations (HTTP verbs), and responses. Each (path, operation, response) combination becomes a Gherkin scenario.
2. Generation Layer: Code as Governance (PlopJS & Yellicode)
Rather than using generators for mere convenience, this system treats code generation as architectural governance.
PlopJS (Tactical Consistency)
Role: Micro-generator framework for developer experience (DX)
Purpose: Prevents copy-pasting, enforces coding standards, speeds up development
Use Case: Developer needs a new Button component. Instead of manually creating button.component.ts, button.component.html, and button.component.scss, they run npm run generate button.
Result: Instant, consistent file structure adhering to team linting rules immediately.
Templates: Uses Handlebars templates
Strategic Impact: Handles the “micro” level—boilerplate, file naming, directory structure. Makes the “right way” to build a component the only available way.
Yellicode (Strategic Architecture)
Role: Code generation for complex, modular structures based on models
Purpose: Model-driven development at higher abstraction level than Plop
Use Case: You have a data model (UML diagram or JSON definition of an API). Yellicode ingests that model and generates entire Angular modules, services, and TypeScript interfaces at once.
Result: If the API model changes, simply regenerate the code, reducing refactoring errors.
Angular Integration: Provides @yellicode/angular package to generate Angular 2+ components, services, and models
Templates: Uses TypeScript-based templates, operates on .ymn model files
Strategic Impact: Handles the “macro” level—ensuring large-scale architectural decisions are propagated programmatically, not manually. This drastically reduces technical debt.
3. Verification Layer: Behavioral Arbitration (Robot Framework)
Role: Test automation and acceptance testing
Technology: Open-source, Python-based automation framework, keyword-driven
Mechanism: Robot Framework serves as the arbiter, verifying that built reality matches original intent. It utilizes Python as “glue code” to bridge high-level Gherkin steps with low-level browser interactions or DOM assertions.
Critical Nuance: Robot Framework does not natively execute Gherkin. More precisely:
- Gherkin feature files are parsed or mapped
- Steps are bound to Robot keywords, often via:
robotframework-gherkin- Custom glue code
- Preprocessing layers
Maintenance Risk: Step binding strategy becomes a maintenance risk. Poor step hygiene leads to brittle tests. The mapping layer (glue code) requires disciplined maintenance.
Browser Interaction: Likely via Selenium or Playwright libraries to interact with Angular/React DOM
Output: Generates detailed HTML reports and logs automatically, providing an auditable trail of compliance for every build
Focus: Black-box behavioral verification based on observable outcomes, not internal implementation
Example Step Definitions (using Behave/Python):
from behave import *
@given('a test microservice')
def create_client(context):
# Test client setup
pass
@given("umpires ['Tinker', 'Evers', 'Chance']")
def set_database(context):
# Database setup
pass
@when('request is "/umpires"')
def make_get_umpires_request(context):
# RESTful API request
pass
@then("response body includes ['Tinker', 'Evers', 'Chance']")
def assert_response(context):
# Check the response
pass4. Orchestration Layer: Pipeline Enforcement (CI/CD)
Role: Automated enforcement that ensures “what is promised is what is built”
Philosophy: Pipeline enforces reality, not optimism. No manual gates. No “QA phase.” No vibes.
Causal Order:
- Promise (Gherkin)
- Shape (generation)
- Proof (Robot Framework)
- Permission to ship (CI/CD)
Pipeline Stages:
| Stage | Action | Tooling |
|---|---|---|
| 1. Define | Write user stories in .feature files | Gherkin |
| 2. Scaffolding | Generate boilerplate Angular code | PlopJS |
| 3. Architecture | Generate complex models/services from specs | Yellicode |
| 4. Build | Compile the Angular application | Angular CLI (ng build) |
| 5. Verify | Run Gherkin scenarios against built app | Robot Framework |
| 6. Report | Generate HTML logs of pass/fail status | Robot Framework |
| 7. Deploy | If tests pass, deploy | Azure DevOps / GitLab / GitHub Actions |
Trigger: Code committed to Git
Result: Only code that fulfills its behavioral contract is deployed
The Relay Model: Spec to Gherkin to Code
The through-line is a relay play (borrowing baseball metaphor) from specification to working, tested code:
Spec → Gherkin → Tests → Generated Code → Pipeline
OpenAPI Specification to Gherkin Transformation
When building RESTful APIs, start with an OpenAPI specification (OAS). The nested structure:
path:
operation:
… (request details)
responses:
code: … (response details)
Each (path, operation, response) combination becomes a Gherkin scenario.
Gherkin Template:
Scenario: {operation summary} leading to {response description}
Given {context}
And some context tied to the response
When {operation} on {path}
And some reason for the response
Then validate expected {response}Most placeholders come directly from OAS. The exceptions are “context tied to the response” and “reason for the response”—these are implied but not stated in the spec.
Example OpenAPI Spec:
swagger: '2.0'
info:
title: A Quick Demo
version: '1.0'
paths:
/umpires:
get:
summary: The umpires
responses:
200:
description: The umpire list
schema:
type: object
properties:
status:
type: string
example: "OK"
data:
type: array
items:
type: string
example: ["Tinker", "Evers", "Chance"]Generated Gherkin Scenario:
Scenario: Get list of Umpires
Given a test app and client
And a valid Authorization token is 'dizzy'
And a test database
And umpire names of ["Tinker", "Evers", "Chance"]
When headers include {"x-Auth-Token": "dizzy", "Accept": "application/json"}
And request operation is 'Get'
And request path is '/umpires'
Then response status is 200
And response body is {"status": "OK", "data": ["Tinker", "Evers", "Chance"]}Technical Gherkin: Parameterized Steps
The general shape has Given-When-Then structure, but details have changed from abstract view to specific technical details describing RESTful API implementation.
Steps are parameterized using boilerplate text followed by parameter values. The idea: create step definitions based on parsing step strings. One general Python step implementation can work with variety of parameter values.
Parameterized Step Definition:
@when('Response status is {status:int}')
def check_status(context, status):
assert context['status'] == statusThis @when definition can be reused by all Gherkin scenarios generated from the OpenAPI specification.
OpenAPI-to-Gherkin Transformation Script
A two-step transformation pipeline:
- OpenAPI In: Builds scenario definitions from OAS. Customizations and extensions handled when ingesting source.
- Gherkin Out: Writes Gherkin feature files from scenario definitions. Careful orchestration between step definitions and Gherkin text.
Internal Representation (Python dictionary):
Path- The path (goes into When step)Operation- The operation (goes into When step)Request- Details of request/parameters (populates scenario name and When steps)Status- Overall final status for scenarioResponse- Expected response example document
Top-level Function:
def make_gherkin(oaspec: Dict, file: OptFile=sys.stdout):
common = get_common_features(oaspec)
emit_feature_header(oaspec, file)
for scenario in scenario_iter(oaspec):
emit_scenario(make_scenario(common, scenario), file)Scenario Iterator:
def scenario_iter(oaspec: Dict) -> Iterable[Dict]:
for path in oaspec['paths']:
for operation in oaspec['paths'][path]:
request = oaspec['paths'][path][operation].copy()
responses = request.pop('responses')
for response_status in responses:
response = responses[response_status].copy()
yield {
'path': path,
'operation': operation,
'request': request,
'status': response_status,
'response': response}Extension Properties for Error Scenarios:
OpenAPI examples typically cover only the “happy path.” For error scenarios, add extension properties:
404:
description: Unknown umpire
x-given: Umpires are ["Tinker"]
x-when: request is for "Evers"However, it’s often better to handle error scenarios in Gherkin only, rather than cluttering the OpenAPI spec.
Development Workflow
The Complete Cycle
- Requirement Definition: Non-technical users write features (
.feature) in Gherkin to define user stories - Code Generation: Developers use Plop or Yellicode to generate code structures (
.ts,.html,.css) based on templates - Local Testing: Developers run Robot Framework tests against the app to verify behavior defined in Gherkin
- Commit: Code pushed to Git
- CI/CD Pipeline Trigger: Automatically runs:
- Generate: Pipeline triggers Plop/Yellicode to ensure code adheres to standards
- Build: Angular app built (
ng build) - Test: Robot Framework runs Gherkin scenarios to validate behavior
- Deploy: If tests pass, app is deployed
Development Loop Example
- Product Owner writes a Gherkin feature:
"Given a user has a premium account..." - Developer uses Plop to spin up UI components and Yellicode to generate services for “premium accounts”
- Developer runs Robot Framework locally. Test fails (logic not written yet)
- Developer writes Angular logic to make test pass
- Code pushed. CI pipeline rebuilds app and re-runs Robot Framework suite to ensure no regressions
Living Documentation
Because Gherkin files are executed as tests, the documentation always matches the software’s actual behavior. Unlike PDF specs that get outdated the moment coding starts, Gherkin represents living documentation.
Framework Agnosticism
While this pattern currently targets Angular, the architectural spine is framework-agnostic above the generation layer:
- Angular is replaceable
- The pipeline is framework-agnostic above generation layer
This makes it a behavior-first frontend factory that currently targets Angular, rather than “Angular tooling.”
If you switch frontend frameworks (e.g., to React), your Gherkin tests (the business logic) remain valid; only the Robot Framework glue code needs updating.
Observable State Verification
Mature pipelines add:
- DOM assertions
- API contract checks
- Visual regression (optional)
Conceptually: “Verification is based on observable outcomes, not internal implementation.”
This aligns with the black-box behavioral verification philosophy and avoids confusion when internal implementation details change.
Pattern Naming
To communicate this approach effectively, frame it as:
- “Behavior-Locked Frontend Pipeline”
- “Contract-Driven UI Development”
- “Executable UX Contracts”
This helps defend against objections like “Isn’t this overkill for frontend?”
(It isn’t. It’s overkill for toy apps. For production systems requiring auditability and repeatability, it’s essential.)
Summary Table
| Tool | Role | Focus |
|---|---|---|
| Gherkin | Specification | What the system should do (Behavior) |
| Robot Framework | Testing | Verifying the behavior (Automation) |
| PlopJS | Generation | Consistency in boilerplate (Efficiency) |
| Yellicode | Generation | Complex structure generation (Architecture) |
| Angular/React | Framework | The technology being built |
| Pipeline | Automation | Orchestration of all steps |
Complicating Factors
When building OpenAPI-to-Gherkin transformation tools, several issues arise:
-
Naming: Organizations establish different conventions for summaries vs descriptions. Tool must reflect organizational naming conventions.
-
Optional Features: Spec may define many optional parameters. Enumerating scenarios can be difficult to automate. Beware of combinatoric explosion: the powerset of n optional parameters is 2^n.
-
Local Standards: Established microservice families might have standard features assumed rather than defined. May be better to handle these outside OpenAPI spec.
-
External Dependencies: Simple microservices allow database state described with
x-givenextensions. Complex external dependencies may require manually-created step definitions. -
Unhappy Path Scenarios: Rather than clutter API description with error-processing details, better for OpenAPI-to-Gherkin tool to inject error-processing scenarios.
Umpire Metaphor: Tests as Truth
Without automated tests, there is no usable code. This parallels the three baseball umpires struggling to be fair:
- Umpire #1: “There are balls and there are strikes, and I call them as they are.”
- Umpire #2: “I’m only human, the very best I can do is to call them as I see them.”
- Umpire #3: “You’re both wrong: they’re nothing until you call them.”
Umpire #3’s view parallels Acceptance Test Driven Development (ATDD). Code doesn’t work until automated tests confirm subjective impression of correct behavior. Without test results, there is no usable code.
Test cases may be the single most important artifact—potentially the only meaningful definition of correct behavior.
Comparison to Traditional Stacks
Traditional frontend stacks optimize for:
- Speed
- Developer happiness
- Local reasoning
This stack optimizes for:
- Truth
- Repeatability
- Auditability
This is “Ops-Core thinking applied to frontend.” That’s why this reads “serious,” not trendy.
Why This Specific Combination?
Angular + Yellicode: Powerful pairing because Angular is highly opinionated and structured. Yellicode thrives on structure, making generated code clean and “Angular-compliant.”
Gherkin + Robot Framework: Decouples test logic from test implementation. If you switch frameworks in the future, your Gherkin tests (business logic) remain valid; only Robot Framework glue code needs updating.
Related Patterns
For deeper understanding of this pattern, see:
- gherkin-testing-frameworks - Detailed comparison of Cucumber, Behave, pytest-bdd
- tdd-workflow - Test-driven development practices and how they integrate with BDD
Next Steps
Logical progression from this pattern:
- Tighten this into a one-page architecture brief
- Turn it into a reference pipeline diagram
- Stress-test against real failure modes:
- Ambiguous Gherkin
- Generator drift
- Flaky UI tests
- Step binding maintenance
The spine is built. Now it’s about hardening the joints.
Source Files
This document synthesizes content from the following notebook outputs:
/Users/gordie/dev/ap/library/knowledge-vault/research-lab-materials/logs/notebook outputs/BDD Frontend Production System.txt/Users/gordie/dev/ap/library/knowledge-vault/research-lab-materials/logs/notebook outputs/BDD, Generation, and Angular Pipeline.txt/Users/gordie/dev/ap/library/knowledge-vault/research-lab-materials/logs/notebook outputs/BDD.txt/Users/gordie/dev/ap/library/knowledge-vault/research-lab-materials/logs/notebook outputs/Spec to Gherkin to Code.txt/Users/gordie/dev/ap/library/knowledge-vault/research-lab-materials/logs/notebook outputs/The Behavior-First Frontend Factory.txt/Users/gordie/dev/ap/library/knowledge-vault/research-lab-materials/logs/notebook outputs/The Behavior-Locked Frontend Pipeline.txt