Scaffolding Tests

3 min read

ork e2e init reads the Katalog in the current directory and generates an e2e.yaml skeleton pre-filled with the operator name, CRD kind, and best-practice expect blocks. No cluster is needed — it reads only the Katalog.


Basic usage

# katalog.yaml in the current directory
ork e2e init

# Explicit path
ork e2e init -f my-operator.yaml

# Overwrite an existing e2e.yaml
ork e2e init --force

# Preview without writing
ork e2e init --dry-run

Output:

✓ Generated e2e.yaml
  1 CRD(s): Website

  Edit the placeholders, then run ork e2e.

What it generates

ork e2e init produces a skeleton with three expect blocks that cover the standard test contract:

# Schema reference: https://orkestra.sh/docs/reference/schema/e2e/
apiVersion: orkestra.orkspace.io/v1
kind: E2E
metadata:
  name: hello-website-e2e
  description: "Generated by ork e2e init — edit to refine"

spec:
  katalog: ./katalog.yaml
  crd: ./crd.yaml
  cr: ./cr.yaml

  cluster:
    provider: kind
    name: hello-website-e2e
    reuse: false

  expect:
    - name: CR created
      after: cr-applied
      timeout: 60s
      resources:
        - kind: Website
          name: <name>
          namespace: <namespace>

    # - name: Resources created
    #   after: cr-applied
    #   timeout: 60s
    #   resources:
    #     - kind: Deployment
    #       name: <resource-name>
    #       namespace: <namespace>
    #       ready: true

    - name: Cleanup verified
      after: cr-deleted
      timeout: 30s
      resources:
        - kind: Website
          name: <name>
          namespace: <namespace>
          count: 0
        # - kind: Deployment
        #   name: <resource-name>
        #   namespace: <namespace>
        #   count: 0

CR created — confirms the CRD is registered and the CR was accepted by the API server.

Resources created — commented out by default. Uncomment and fill in the kinds your operator actually creates. This is the block that catches real operator failures.

Cleanup verified — confirms the operator’s delete path works. count: 0 on the CR asserts it is fully removed. Uncomment the Deployment entry (and add others) to assert that child resources were also cleaned up — not just the CR.

The CRD kind is populated from the Katalog. All other values are placeholders — replace <name> and <namespace> with the values from your cr.yaml.


Multi-CRD Katalogs

When the Katalog defines more than one CRD, ork e2e init adds a setup.apply block pointing to the remaining CRDs and CRs, and lists the additional kinds as comments:

  setup:
    apply:
      - ./other-crds.yaml   # CRD definitions for the remaining kinds
      - ./other-crs.yaml    # CR instances for the remaining kinds
      # Additional CRDs in this Katalog:
      # - Cache
      # - Queue

  expect:
    - name: CR created        # Database (primary CRD)
      ...
    - name: Cleanup verified  # Database (primary CRD)
      ...
    # Add expect blocks for Cache and Queue as needed.

The scaffold covers only the first CRD. Add expect blocks for the others once you know what each produces.


Scaffolding a suite

--suite discovers all e2e.yaml leaf files under the given directory and writes a pure aggregator:

ork e2e init --suite               # discover under .
ork e2e init --suite ./examples/   # scoped discovery
ork e2e init --suite --force       # overwrite existing e2e.yaml
ork e2e init --suite --dry-run     # preview without writing

Output:

# Schema reference: https://orkestra.sh/docs/reference/schema/e2e/imports/
apiVersion: orkestra.orkspace.io/v1
kind: E2E
metadata:
  name: suite
  description: "Generated by ork e2e init --suite — 4 file(s) discovered"
imports:
  - path: ./examples/01-hello-website/e2e.yaml
  - path: ./examples/02-with-serviceaccount/e2e.yaml
    wait: 5s
  - path: ./examples/03-secret-copy/e2e.yaml
    wait: 5s
  - path: ./examples/04-configmap-copy/e2e.yaml
    wait: 5s

--wait injects a pause between each import (first excluded). Default: 5s.

ork e2e init --suite --wait 10s

Use --skip to exclude directories or patterns:

ork e2e init --suite --skip vendor,testdata,external

Pure aggregators (files with imports: but no spec:) are excluded automatically — the generated suite will not import itself on the next run.


Flags

FlagDefaultDescription
-fkatalog.yamlPath to the Katalog file
--forcefalseOverwrite an existing e2e.yaml
--dry-runfalsePrint to stdout instead of writing the file
--suitefalseAggregate all e2e.yaml files under the given dir
--wait5sPause injected between suite imports (first excluded)
--skipComma-separated path patterns to exclude from discovery

→ See also: Suites and imports