Skip to content

Design system registry and contract tests

Maintenance notes for Easy8 developers who change design system component APIs. Customer plugins do not need this page.

The Vue components and the Ruby wrappers are two views of the same component API. Contract tests keep them in sync, so a prop added on one side cannot silently drift from the other.

The contract is mediated by a committed snapshot:

  • app/easy_design/design_system/registry_snapshot.json: generated description of every DS custom element (props with types, prop type hints, model value type, exposed methods, and slots)

The snapshot is derived from the Vue components. Never edit it by hand. Regenerate it with:

yarn ds:registry:export

Three test layers check the contract:

  • A vitest freshness guard (app/frontend/src/tests/tests/design_system/tests/dsRegistrySnapshot.spec.ts) fails when the committed snapshot no longer matches the Vue components
  • A vitest registry contract (dsRegistryContract.spec.ts in the same folder) verifies that the custom elements registry (DS_CUSTOM_ELEMENTS_REGISTRY in app/frontend/src/design_system/shared/constants/customElements.ts) describes real components: every Boolean, Number, and Date prop has a PROP_TYPE_HINT (without one, data-* attributes reach Vue as raw strings and "false" is truthy), exposed methods exist on a mounted instance, and the model value type matches
  • An RSpec contract (spec/easy_design/design_system/registry_contract_spec.rb) renders every Ruby DS component with sentinel values derived from the snapshot and checks the emitted data-* attributes and <script data-prop> props against the Vue runtime props. Every Vue prop must be settable through a Ruby component param, and every component param must be accepted by its ds_* helper

Props that are intentionally not exposed on the Ruby side (for example frontend-only validation rules) are exempted in spec/easy_design/design_system/registry_contract_config.yml. Every exemption needs a documented reason.

Typical workflow when changing a DS component API:

  1. Change the Vue component props, slots, or exposed methods, and update the registry entry in shared/constants/customElements.ts
  2. Run yarn ds:registry:export and commit the regenerated snapshot
  3. If the RSpec contract reports a missing param, update the Ruby wrapper in app/easy_design/design_system/components/ and its ds_* helper, or add a documented exemption to registry_contract_config.yml