Skip to main content

Writing E2E Scenarios

This guide walks through adding a new end-to-end test scenario using Gherkin syntax and godog step definitions.

Where Feature Files Live

Feature files are in category folders under:

crawbl-backend/test-features/
├── auth/ (auth.feature, logout.feature, cleanup.feature, error_cases.feature)
├── chat/ (chat.feature, conversations_crud.feature, mentions.feature, agent_*.feature, error_cases.feature)
├── core/ (health.feature, legal.feature, models.feature, edge_cases.feature, uploads_contract.feature)
├── integrations/ (integrations.feature)
├── multi_user/ (multi_user.feature, error_cases.feature)
├── profile/ (profile.feature, error_cases.feature)
├── tools/ (memory.feature, web_search.feature)
└── workspaces/ (workspaces.feature, mobile_first_launch.feature, error_cases.feature)

Add new scenarios to the existing file that matches your domain, or create a new feature file inside the matching category folder.

Gherkin Syntax Basics

Feature: Integrations
Scenarios for creating and managing integrations.

Scenario: Create an integration
Given the user "primary" is authenticated
When I send a POST request to "/v1/integrations" with body:
"""
{
"workspace_id": "{primary_workspace_id}",
"provider": "slack"
}
"""
Then the response status should be 201
And the response body should contain "slack"

Use {key} for value interpolation (e.g. {primary_workspace_id}, {last_response_id}).

Step Definition Files

Step definitions live in internal/testsuite/e2e/ and are registered per file:

FilePurpose
steps_http.goHTTP request steps
steps_auth.goAuthentication and session steps
steps_assert.goResponse assertion steps
steps_db.goDatabase assertion steps
steps_state.goValue interpolation and stored state
steps_chat.goChat and conversation steps
steps_agent.goAgent interaction steps
steps_health.goHealth check steps
steps_workspace.goWorkspace lifecycle steps
steps_user.goUser lifecycle steps
steps_isolation.goTest isolation helpers
steps_integrations.goIntegration-specific steps
steps_redis.goRedis state assertions
steps_spaces.goSpaces steps

Registration follows this pattern in each file:

func registerXxxSteps(sc *godog.ScenarioContext, tc *testContext) {
sc.Step(`^step pattern$`, tc.stepHandler)
}

Adding a New Scenario

1
Step 1

Choose the feature file

Add the scenario to the existing category file that matches your domain:

test-features/integrations/integrations.feature
2
Step 2

Write the Gherkin

Start with the scenario in plain Gherkin. Use {key} for interpolated values.

Scenario: Create a Slack integration
Given the user "primary" is authenticated
And the user "primary" has a workspace
When I send a POST request to "/v1/workspaces/{primary_workspace_id}/integrations" with body:
"""
{
"provider": "slack"
}
"""
Then the response status should be 201
And the response JSON at "provider" should equal "slack"
3
Step 3

Reuse existing step definitions

Most scenarios fit the existing Given, When, and Then helpers across the 14 step files.

Given the user "primary" is authenticated
When I send a GET request to "/v1/users/profile"
Then the response status should be 200
And I store the response JSON at "id" as "integration_id"
4
Step 4

Add new steps only if needed

If a step does not exist, add it to the matching steps_*.go file and register it.

func registerIntegrationSteps(sc *godog.ScenarioContext, tc *testContext) {
sc.Step(`^the response JSON array should be empty$`, tc.theResponseJSONArrayShouldBeEmpty)
}
5
Step 5

Run the scenario

Target a single category to iterate quickly, then widen once it passes.

crawbl test e2e --port-forward --category integrations -v

Tips

  • Use the 3 fixed test users (primary, frank, grace) — do not create new users per scenario.
  • Use {key} interpolation to reference IDs from previous steps.
  • Keep scenarios independent — each scenario should work regardless of execution order within the same user context.
  • Test error cases — include 400, 401, 403, and 404 scenarios alongside happy paths; each category has an error_cases.feature for this.

What's next: Test Architecture