Skip to content

Testing values

Stimulus values are the source of truth for a controller's state. The harness makes them trivial to set up, observe, and mutate.

Default values

Declare a default in the controller:

js
static values = { count: { type: Number, default: 0 } }

Omit the attribute in the fixture and the default applies:

ts
const { controller } = await render(CounterController, {
  html: `<div data-controller="counter"></div>`,
})

expect(controller.countValue).toBe(0)

Overriding from the fixture

ts
const { controller } = await render(CounterController, {
  html: `<div ${attr.controller('counter', { count: 42 })}></div>`,
})

expect(controller.countValue).toBe(42)

Object and array values

Non-scalar values are JSON-serialized by the attr.controller helper, matching Stimulus' own semantics:

ts
const { controller } = await render(UserCardController, {
  html: `<div ${attr.controller('user-card', {
    user: { name: 'Ada', age: 36 },
    tags: ['a', 'b'],
  })}></div>`,
})

expect(controller.userValue).toEqual({ name: 'Ada', age: 36 })
expect(controller.tagsValue).toEqual(['a', 'b'])

Asserting programmatic changes

Mutating a value from the controller triggers the usual Stimulus xxxValueChanged() callback. Assert on the visible outcome:

ts
const { controller, getByRole, user } = await render(CounterController, {
  html: `
    <div data-controller="counter" data-counter-count-value="0">
      <span data-counter-target="display"></span>
      <button data-action="click->counter#increment">+</button>
    </div>
  `,
})

await user.click(getByRole('button', { name: '+' }))

expect(controller.countValue).toBe(1)
expect(controller.displayTarget.textContent).toBe('1')

Mutating the value attribute from the test

If you want to verify that the controller reacts to an external attribute change (as Turbo Frames might do):

ts
controller.element.setAttribute('data-counter-count-value', '99')
await nextTick()   // let MutationObserver run

expect(controller.countValue).toBe(99)

Released under the MIT License.