cucumber

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package cucumber provides a godog-based BDD test framework with HTTP API testing support.

Variables are scoped to the scenario. HTTP response state is stored in the user's session. Switching users switches the session. Scenarios are executed concurrently.

Variable resolution supports:

  • ${variableName} → scenario variable lookup
  • ${response.body} → full HTTP response body (Java feature file compat)
  • ${response.body.field} → response body field via gojq (Java feature file compat)
  • ${response.field} → response body field via gojq
  • ${variable.field} → nested field access
  • ${variable | pipe} → pipe transformations (json, json_escape, string)

Index

Constants

This section is empty.

Variables

View Source
var JSONEncoding = Encoding{
	Name: "json",
	Marshal: func(a any) ([]byte, error) {
		return json.MarshalIndent(a, "", "  ")
	},
	Unmarshal: json.Unmarshal,
}
View Source
var PipeFunctions = map[string]func(any, error) (any, error){
	"json": func(value any, err error) (any, error) {
		if err != nil {
			return value, err
		}
		buf := bytes.NewBuffer(nil)
		encoder := json.NewEncoder(buf)
		encoder.SetIndent("", "  ")
		err = encoder.Encode(value)
		if err != nil {
			return value, err
		}
		return buf.String(), err
	},
	"json_escape": func(value any, err error) (any, error) {
		if err != nil {
			return value, err
		}
		data, err := json.Marshal(fmt.Sprintf("%v", value))
		if err != nil {
			return value, err
		}
		return strings.TrimSuffix(strings.TrimPrefix(string(data), `"`), `"`), nil
	},
	"string": func(value any, err error) (any, error) {
		if err != nil {
			return value, err
		}
		return fmt.Sprintf("%v", value), nil
	},
	"uuid_to_hex_string": func(value any, err error) (any, error) {
		if err != nil {
			return value, err
		}
		s := fmt.Sprintf("%v", value)
		id, err := uuid.Parse(s)
		if err != nil {
			return nil, fmt.Errorf("uuid_to_hex_string: invalid UUID %q: %w", s, err)
		}
		var sb strings.Builder
		for _, b := range id[:] {
			fmt.Fprintf(&sb, "\\x%02x", b)
		}
		return sb.String(), nil
	},
	"base64_to_hex_string": func(value any, err error) (any, error) {
		if err != nil {
			return value, err
		}
		s := fmt.Sprintf("%v", value)
		decoded, decodeErr := base64.StdEncoding.DecodeString(s)
		if decodeErr != nil {

			if id, parseErr := uuid.Parse(s); parseErr == nil {
				decoded = id[:]
			} else {
				return nil, fmt.Errorf("base64_to_hex_string: invalid base64 %q: %w", s, decodeErr)
			}
		}
		var sb strings.Builder
		for _, b := range decoded {
			fmt.Fprintf(&sb, "\\x%02x", b)
		}
		return sb.String(), nil
	},
}
View Source
var StepModules []func(ctx *godog.ScenarioContext, s *TestScenario)

StepModules is the list of functions used to register steps with a godog.ScenarioContext.

Functions

func ApplyReportOptions

func ApplyReportOptions(opts *godog.Options, testName string) func()

ApplyReportOptions configures report output when GODOG_REPORT_DIR is set. GODOG_REPORT_FORMAT selects the report format (default: junit). When set to "cucumber", reports are written as JSON. Pass t.Name() as testName; slashes are replaced with dashes to form the filename. Returns a cleanup function that must be called (or deferred) after the test runs.

func DefaultOptions

func DefaultOptions() godog.Options

func ToString

func ToString(value interface{}, name string, encoding Encoding) (string, error)

Types

type Encoding

type Encoding struct {
	Name      string
	Marshal   func(any) ([]byte, error)
	Unmarshal func([]byte, any) error
}

Encoding wraps marshal/unmarshal for a specific format.

type ScenarioSetupFunc

type ScenarioSetupFunc func(ctx context.Context, s *TestScenario, sc *godog.Scenario) (func(context.Context) error, error)

ScenarioSetupFunc provisions scenario-local runtime state and returns an optional cleanup callback.

type TaskRow

type TaskRow struct {
	ID         string
	TaskType   string
	TaskBody   string
	RetryAt    time.Time
	RetryCount int
	LastError  *string
}

TaskRow represents a row from the tasks table/collection.

type TestDB

type TestDB interface {
	// ClearAll wipes all data (called before each scenario).
	ClearAll(ctx context.Context) error
	// ResolveGroupID returns the conversation_group_id for a given conversation ID.
	ResolveGroupID(ctx context.Context, conversationID string) (string, error)
	// SetConversationEntriesCreatedAt forces all entries in a conversation group to the same created_at timestamp.
	SetConversationEntriesCreatedAt(ctx context.Context, conversationID string, createdAt time.Time) error
	// ExecSQL runs a raw SQL query and returns rows as maps. Non-SQL backends return (nil, nil) to skip assertions.
	ExecSQL(ctx context.Context, query string) ([]map[string]interface{}, error)
	// ExecMongoQuery runs a MongoDB query spec (JSON payload) and returns rows as maps.
	// Non-Mongo backends return (nil, nil) to skip assertions.
	ExecMongoQuery(ctx context.Context, query string) ([]map[string]interface{}, error)
	// ArchiveConversation sets archived_at on the conversation and its group to `days` ago.
	ArchiveConversation(ctx context.Context, conversationID string, days int) error
	// ArchiveConversationOnly sets archived_at on the conversation only, without touching the group.
	ArchiveConversationOnly(ctx context.Context, conversationID string, days int) error
	// Task queue operations for task-queue BDD feature.
	DeleteAllTasks(ctx context.Context) error
	CreateTask(ctx context.Context, id, taskType, body string) error
	CreateFailedTask(ctx context.Context, id, taskType, body string) error
	ClaimReadyTasks(ctx context.Context, limit int) ([]TaskRow, error)
	DeleteTask(ctx context.Context, id string) error
	FailTask(ctx context.Context, id, errMsg string) error
	GetTask(ctx context.Context, id string) (*TaskRow, error)
	CountTasks(ctx context.Context) (int, error)
}

TestDB abstracts direct database operations needed by BDD steps, so different backends (Postgres, MongoDB) can be injected by the test runner.

type TestScenario

type TestScenario struct {
	Suite       *TestSuite
	ScenarioUID string
	CurrentUser string
	PathPrefix  string
	APIURL      string
	DB          TestDB
	Extra       map[string]interface{}

	Variables map[string]interface{}
	Users     map[string]*TestUser
	// contains filtered or unexported fields
}

TestScenario holds state for a single scenario. Not accessed concurrently.

func (*TestScenario) APIBaseURL

func (s *TestScenario) APIBaseURL() string

func (*TestScenario) EncodingMustMatch

func (s *TestScenario) EncodingMustMatch(encoding Encoding, actual, expected string, expandExpected bool) error

func (*TestScenario) Expand

func (s *TestScenario) Expand(value string, skippedVars ...string) (result string, rerr error)

Expand replaces ${var} in the string based on scenario variables.

func (*TestScenario) FilterQueryRows

func (s *TestScenario) FilterQueryRows(rows []map[string]interface{}) []map[string]interface{}

func (*TestScenario) IsolatedClientID

func (s *TestScenario) IsolatedClientID(clientID string) string

func (*TestScenario) IsolatedUser

func (s *TestScenario) IsolatedUser(name string) string

func (*TestScenario) JSONMustContain

func (s *TestScenario) JSONMustContain(actual, expected string, expand bool) error

func (*TestScenario) JSONMustMatch

func (s *TestScenario) JSONMustMatch(actual, expected string, expandExpected bool) error

func (*TestScenario) NormalizeResponseBody

func (s *TestScenario) NormalizeResponseBody(requestURL, contentType string, body []byte) ([]byte, error)

func (*TestScenario) NormalizeUsers

func (s *TestScenario) NormalizeUsers(text string) string

func (*TestScenario) NormalizeValue

func (s *TestScenario) NormalizeValue(value interface{}) interface{}

func (*TestScenario) RegisterCanonicalUsers

func (s *TestScenario) RegisterCanonicalUsers(names ...string)

func (*TestScenario) Resolve

func (s *TestScenario) Resolve(name string) (interface{}, error)

func (*TestScenario) ResolveString

func (s *TestScenario) ResolveString(name string) (string, error)

func (*TestScenario) RewriteQuotedUsers

func (s *TestScenario) RewriteQuotedUsers(text string) string

func (*TestScenario) RewriteRequestBody

func (s *TestScenario) RewriteRequestBody(body string) string

func (*TestScenario) RewriteRequestPath

func (s *TestScenario) RewriteRequestPath(path string) string

func (*TestScenario) SelectChild

func (s *TestScenario) SelectChild(value any, path string) (any, error)

func (*TestScenario) SendHTTPRequestWithJSONBody

func (s *TestScenario) SendHTTPRequestWithJSONBody(method, path string, jsonTxt *godog.DocString) error

func (*TestScenario) SendHTTPRequestWithJSONBodyAndStyle

func (s *TestScenario) SendHTTPRequestWithJSONBodyAndStyle(method, path string, jsonTxt *godog.DocString, eventStream bool, expandJSON bool) (err error)

func (*TestScenario) SendHTTPRequestWithJSONBodyAsEventStream

func (s *TestScenario) SendHTTPRequestWithJSONBodyAsEventStream(method, path string, jsonTxt *godog.DocString) error

func (*TestScenario) Session

func (s *TestScenario) Session() *TestSession

func (*TestScenario) TestDB

func (s *TestScenario) TestDB() TestDB

func (*TestScenario) TheResponseShouldContainJSONDoc

func (s *TestScenario) TheResponseShouldContainJSONDoc(expected *godog.DocString) error

func (*TestScenario) TheResponseShouldMatchJSONDoc

func (s *TestScenario) TheResponseShouldMatchJSONDoc(expected *godog.DocString) error

func (*TestScenario) User

func (s *TestScenario) User() *TestUser

type TestSession

type TestSession struct {
	TestUser  *TestUser
	Client    *http.Client
	Resp      *http.Response
	RespBytes []byte

	Header            http.Header
	EventStream       bool
	EventStreamEvents chan interface{}
	// contains filtered or unexported fields
}

TestSession holds the HTTP context for a user, like a browser.

func (*TestSession) RespJSON

func (s *TestSession) RespJSON() (interface{}, error)

RespJSON returns the last HTTP response body as parsed JSON.

func (*TestSession) SetRespBytes

func (s *TestSession) SetRespBytes(bytes []byte)

type TestSuite

type TestSuite struct {
	Context  interface{} // opaque application context
	APIURL   string
	Mu       sync.Mutex
	TestingT *testing.T
	Extra    map[string]interface{} // additional test-scoped objects (e.g. mock servers)
	DB       TestDB                 // injected by test runner for store-specific operations
	// ScenarioSetup optionally provisions per-scenario runtime state such as
	// dedicated servers, datastore handles, and extra values.
	ScenarioSetup ScenarioSetupFunc
}

TestSuite holds state global to all test scenarios. Accessed concurrently from all test scenarios.

func NewTestSuite

func NewTestSuite() *TestSuite

func (*TestSuite) InitializeScenario

func (suite *TestSuite) InitializeScenario(ctx *godog.ScenarioContext)

type TestUser

type TestUser struct {
	Name    string
	Subject string // Bearer token value
	Mu      sync.Mutex
}

TestUser represents a user that can interact with the API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL