Writing a unit test for a Glimmer component

Last reviewed on June 12, 2024

In Ember, in order to test the logic in our Glimmer components, we write integration tests. We can test the value returned from a getter by writing an assertion against the DOM to verify it was rendered correctly. We can also simulate user events and write assertions against the DOM.

Recently I found myself in a situation where I couldn't test some new component logic via an integration test because of constraints that were out of my control. I considered refactoring the code and moving it to make it easier to test, but ultimately I wanted to minimize the amount of changed code while having some test coverage, so I resorted to a component unit test. This isn't something I would generally recommend, but if you find yourself in a similar sitation, here is an example.

For our example, let's say we have a Foo component that we'd invoke as such:

<Foo @a={{1}} @b={{2}} />

To generate a unit test, not an integration test, for our Glimmer component, we can run the following:

ember g component-test foo --unit

At the time of this writing, Ember CLI (5.9.0) will generate a component unit test that fails:

tests/unit/components/foo-test.js
import { module, test } from 'qunit';
import { setupTest } from 'component-unit-tests/tests/helpers';

module('Unit | Component | foo', function (hooks) {
  setupTest(hooks);

  test('it exists', function (assert) {
    let component = this.owner.factoryFor('component:foo').create();
    assert.ok(component);
  });
});

Failing Glimmer component unit test

Let's update our component to have some getter:

app/components/foo.js
import Component from '@glimmer/component';

export default class FooComponent extends Component {
  get bar() {
    const { a, b } = this.args;

    return a + b;
  }
}

We can test that getter directly with the following:

tests/unit/components/foo-test.js
import { module, test } from "qunit";
import { setupTest } from "ember-qunit";

module("Unit | Component | foo", function (hooks) {
  setupTest(hooks);

  test("the bar getter", function (assert) {
    const { class: FooComponentClass } = this.owner.factoryFor("component:foo");

    const componentManager = this.owner.lookup("component-manager:glimmer");

    const fooComponent = componentManager.createComponent(FooComponentClass, {
      named: {
        a: 1,
        b: 2,
      },
    });

    assert.strictEqual(fooComponent.bar, 3);
  });
});

Passing Glimmer component unit test