Core Test Module Architecture
This document describes how module authors can verify module correctness using declarative, metadata-native tests. The emphasis is purity and determinism: tests should use the same expression language and object model as runtime modules, not imperative side scripts.
Author-Centric Principles
- Test with the same primitives used in production modules.
- Keep assertions declarative and side-effect aware.
- Prefer pure expression evaluation over imperative code.
- Validate behavior at lifecycle boundaries, not only at API endpoints.
- Treat test modules as contracts for module author intent.
What Module Authors Should Assert
- Installation lifecycle
- Required resource types/predicates/templates are installed.
- Referential links are resolvable after install.
- Default configuration is applied as expected.
- Template invocation lifecycle
- Inputs are validated and mapped correctly.
- Exported objects are present and structurally correct.
- Invocation remains deterministic for identical inputs.
- Upgrade and rollback lifecycle
- Canonical version transitions preserve required invariants.
- No unexpected object shape drift.
- Deprecation/rename semantics are explicit and queryable.
- Runtime contract surface
- Expected procedures/routes are present.
- Expected operation groups (for example get/list/put/del) are available where the module declares support.
- Missing operations are explicit and asserted as known gaps.
Recommended Structure
- Feature module local test templates
- Each feature module exports a small set of author-facing test templates.
- Suggested naming:
- assert-install-invariants
- assert-template-invocation
- assert-lifecycle-transition
- seed-minimal-fixture
- Optional shared core.test module
- Introduce only when cross-module composition repeats.
- Role: compose module-exported assertions and seed templates into reusable suites.
- Do not encode product business logic in core.test.
- Module profile boot helper
- Keep profile composition centralized and declarative.
- Current helper location: integration-tests/fixtures/module-profiles.ts.
Declarative Assertion Model
Assertions should be represented as module/test objects evaluated by the same expression language used by templates and reducers.
Example shape (illustrative):
type: test.assert
with:
name: install-registers-required-types
when:
phase: postInstall
given:
modules: [feature-x]
expect:
all:
- expr: { $exists: { $resourceType: feature_x.item } }
- expr: { $exists: { $predicate: feature_x.relates_to } }
Template invocation assertion (illustrative):
type: test.assert
with:
name: template-produces-exported-root
when:
phase: templateInvoke
invoke:
template: feature-x-seed
with:
key: sample-1
expect:
all:
- expr: { $exists: { $ref: invoke.exports.root } }
- expr: { $eq: [{ $ref: invoke.exports.root.data.status }, active] }
Rules for purity:
- Assertions must not rely on wall-clock time unless explicitly fixed in test input.
- Expression evaluation should be deterministic for equal input state.
- Randomness must be seeded and declared.
- Assertions should not mutate global state beyond declared setup/teardown scopes.
Lifecycle Hook Coverage Matrix
Each module should maintain a minimal matrix:
- preInstall: guardrails and preconditions.
- postInstall: registration and wiring invariants.
- templateInvoke: input/output contract checks.
- preUpgrade/postUpgrade: compatibility and migration checks.
- preUninstall/postUninstall: dependency and cleanup checks.
Not every module needs every hook, but unsupported hooks should be explicit.
Integration with Existing Suites
- Router/API contracts remain in integration tests.
- Declarative module assertions should complement, not replace, API tests.
- Prefer parameterized profile tests for broad coverage.
- Keep component/visual tests focused on metadata-to-UI mapping and behavior outcomes.
Current related files:
- integration-tests/entities-crud.profile.workflow.test.ts
- integration-tests/fixtures/module-profiles.ts
Adoption Path
- Start local: add one install assertion template and one template-invocation assertion template per module.
- Add lifecycle assertions for upgrade/uninstall where module lifecycle complexity exists.
- Promote repeated cross-module assertions into core.test.
- Keep assertion templates versioned with modules to prevent drift.