ObjectStackObjectStack

Testing schema — QA Protocol reference

Testing schemas of the ObjectStack QA Protocol: TestAction, TestActionType and 6 more — each property with its type, default and a TypeScript example.

Source: packages/spec/src/qa/testing.zod.ts

TypeScript Usage

import { TestActionSchema, TestActionTypeSchema, TestAssertionSchema, TestAssertionTypeSchema, TestContextSchema, TestScenarioSchema, TestStepSchema, TestSuiteSchema } from '@objectstack/spec/qa';
import type { TestAction, TestActionType, TestAssertion, TestAssertionType, TestContext, TestScenario, TestStep, TestSuite } from '@objectstack/spec/qa';

// Validate data
const result = TestActionSchema.parse(data);

TestAction

A single test action to execute against the system

Properties

PropertyTypeRequiredDescription
typeEnum<'create_record' | 'update_record' | 'delete_record' | 'read_record' | 'query_records' | 'api_call' | 'run_script' | 'wait'>✅The action type to execute
targetstring✅Target Object, API Endpoint, or Function Name
payloadRecord<string, any>optionalData to send or use
userstringoptionalRun as specific user/role for impersonation testing

TestActionType

Type of test action to perform

Allowed Values

  • create_record
  • update_record
  • delete_record
  • read_record
  • query_records
  • api_call
  • run_script
  • wait

TestAssertion

A test assertion that validates the result of a test action

Properties

PropertyTypeRequiredDescription
fieldstring✅Field path in the result to check, resolved against the parsed response body root — no "body." prefix (e.g. "data.0.status")
operatorEnum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_null' | 'not_null' | 'gt' | 'gte' | 'lt' | 'lte' | 'error'>✅Comparison operator to use
expectedValueany✅Expected value to compare against

TestAssertionType

Comparison operator for test assertions

Allowed Values

  • equals
  • not_equals
  • contains
  • not_contains
  • is_null
  • not_null
  • gt
  • gte
  • lt
  • lte
  • error

TestContext

Initial context or variables for the test

Type: Record<string, any>


TestScenario

A complete test scenario with setup, execution steps, and teardown

Properties

PropertyTypeRequiredDescription
idstring✅Unique scenario identifier
namestring✅Scenario name for test reports
descriptionstringoptionalDetailed description of the test scenario
tagsstring[]optionalTags for filtering and categorization (e.g. "critical", "regression", "crm")
setup{ name: string; description?: string; action: object; assertions?: object[]; … }[]optionalSteps to run before main test (preconditions)
steps{ name: string; description?: string; action: object; assertions?: object[]; … }[]✅Main test sequence to execute
teardown{ name: string; description?: string; action: object; assertions?: object[]; … }[]optionalSteps to cleanup after test execution
requires{ params?: string[]; services?: Enum<'metadata' | 'data' | 'auth' | 'storage' | 'file-storage' | 'search' | 'cache' | …>[] }optionalPreconditions judged before the scenario's first step (setup included). Every entry must hold, or the scenario is SKIPPED with a reason naming each unmet entry — counted separately by os test and never counted as passed

Nested Shape: TestScenario.setup[number]

A single step in a test scenario, consisting of an action and optional assertions

PropertyTypeRequiredDescription
namestring✅Step name for identification in test reports
descriptionstringoptionalHuman-readable description of what this step tests
action{ type: Enum<'create_record' | 'update_record' | 'delete_record' | 'read_record' | …>; target: string; payload?: Record<string, any>; user?: string }✅The action to execute in this step
assertions{ field: string; operator: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_null' | 'not_null' | …>; expectedValue: any }[]optionalAssertions to validate after the action completes
captureRecord<string, string>optionalMap result fields to context variables, paths resolved against the response body root (e.g. { "newId": "data.id" })

Nested Shape: TestScenario.steps[number]

A single step in a test scenario, consisting of an action and optional assertions

PropertyTypeRequiredDescription
namestring✅Step name for identification in test reports
descriptionstringoptionalHuman-readable description of what this step tests
action{ type: Enum<'create_record' | 'update_record' | 'delete_record' | 'read_record' | …>; target: string; payload?: Record<string, any>; user?: string }✅The action to execute in this step
assertions{ field: string; operator: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_null' | 'not_null' | …>; expectedValue: any }[]optionalAssertions to validate after the action completes
captureRecord<string, string>optionalMap result fields to context variables, paths resolved against the response body root (e.g. { "newId": "data.id" })

Nested Shape: TestScenario.teardown[number]

A single step in a test scenario, consisting of an action and optional assertions

PropertyTypeRequiredDescription
namestring✅Step name for identification in test reports
descriptionstringoptionalHuman-readable description of what this step tests
action{ type: Enum<'create_record' | 'update_record' | 'delete_record' | 'read_record' | …>; target: string; payload?: Record<string, any>; user?: string }✅The action to execute in this step
assertions{ field: string; operator: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_null' | 'not_null' | …>; expectedValue: any }[]optionalAssertions to validate after the action completes
captureRecord<string, string>optionalMap result fields to context variables, paths resolved against the response body root (e.g. { "newId": "data.id" })

Nested Shape: TestScenario.requires

PropertyTypeRequiredDescription
paramsstring[]optionalEnvironment variables that must be set to a non-empty value in the process running os test — the runner's own environment, not the target server's. An unset or empty variable skips the scenario (SKIPPED, never passed) with a reason naming the variable
servicesEnum<'metadata' | 'data' | 'auth' | 'storage' | 'file-storage' | 'search' | 'cache' | …>[]optionalServices the target must declare in its discovery document as enabled with status available (ADR-0076 D12), read from the discovery document os test already fetches once per run. An entry the target does not declare that way skips the scenario (SKIPPED, never passed) with a reason naming the service and the services the target does declare available
pluginsneveroptional[REMOVED] scenarios[].requires.plugins was removed in @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — nothing ever checked it: os test reaches its target over HTTP and no served surface lists the loaded plugins, so a scenario naming a missing plugin ran anyway. Delete the key and name the service the scenario needs in requires.services, which is judged against the services the target's discovery document declares enabled and available — an unmet entry skips the scenario and says why. Plugin → service: @objectstack/service-analytics → analytics, @objectstack/plugin-auth → auth, @objectstack/service-automation → automation, @objectstack/service-cache → cache, @objectstack/service-queue → queue, @objectstack/service-job → job, @objectstack/service-realtime → realtime, @objectstack/service-storage → storage, @objectstack/service-i18n → i18n, @objectstack/service-messaging → notification, @objectstack/metadata-protocol → ui. A plugin not listed fills no discovery service slot, so there is no service to require for it.

TestStep

A single step in a test scenario, consisting of an action and optional assertions

Properties

PropertyTypeRequiredDescription
namestring✅Step name for identification in test reports
descriptionstringoptionalHuman-readable description of what this step tests
action{ type: Enum<'create_record' | 'update_record' | 'delete_record' | 'read_record' | …>; target: string; payload?: Record<string, any>; user?: string }✅The action to execute in this step
assertions{ field: string; operator: Enum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_null' | 'not_null' | …>; expectedValue: any }[]optionalAssertions to validate after the action completes
captureRecord<string, string>optionalMap result fields to context variables, paths resolved against the response body root (e.g. { "newId": "data.id" })

Nested Shape: TestStep.action

PropertyTypeRequiredDescription
typeEnum<'create_record' | 'update_record' | 'delete_record' | 'read_record' | …>✅The action type to execute
targetstring✅Target Object, API Endpoint, or Function Name
payloadRecord<string, any>optionalData to send or use
userstringoptionalRun as specific user/role for impersonation testing

Nested Shape: TestStep.assertions[number]

A test assertion that validates the result of a test action

PropertyTypeRequiredDescription
fieldstring✅Field path in the result to check, resolved against the parsed response body root — no "body." prefix (e.g. "data.0.status")
operatorEnum<'equals' | 'not_equals' | 'contains' | 'not_contains' | 'is_null' | 'not_null' | …>✅Comparison operator to use
expectedValueany✅Expected value to compare against

TestSuite

A collection of test scenarios grouped into a test suite

Properties

PropertyTypeRequiredDescription
namestring✅Test suite name
scenarios{ id: string; name: string; description?: string; tags?: string[]; … }[]✅List of test scenarios in this suite

Nested Shape: TestSuite.scenarios[number]

A complete test scenario with setup, execution steps, and teardown

PropertyTypeRequiredDescription
idstring✅Unique scenario identifier
namestring✅Scenario name for test reports
descriptionstringoptionalDetailed description of the test scenario
tagsstring[]optionalTags for filtering and categorization (e.g. "critical", "regression", "crm")
setup{ name: string; description?: string; action: object; assertions?: object[]; … }[]optionalSteps to run before main test (preconditions)
steps{ name: string; description?: string; action: object; assertions?: object[]; … }[]✅Main test sequence to execute
teardown{ name: string; description?: string; action: object; assertions?: object[]; … }[]optionalSteps to cleanup after test execution
requires{ params?: string[]; services?: Enum<'metadata' | 'data' | 'auth' | 'storage' | 'file-storage' | 'search' | 'cache' | …>[] }optionalPreconditions judged before the scenario's first step (setup included). Every entry must hold, or the scenario is SKIPPED with a reason naming each unmet entry — counted separately by os test and never counted as passed

On this page