Testing Engines with ember-qunit >= 3.4

When testing an Ember Engine, we want to run acceptance tests with the dummy app, but unit and integration tests with the engine itself. We found a solution, and I wanted to share it for others and to see if there’s a better way.

We want most tests to use the engine’s resolve so that this.lookup('component:my-button') finds the engine’s component (from the addon/ directory):

// tests/test-helper.js
import { start } from 'ember-qunit';
import { setResolver } from 'ember-test-helpers';
import engineResolverFor from 'ember-engines/test-support/engine-resolver-for';
 
setResolver(engineResolverFor('my-engine-name'));
 
start();

But for acceptance tests, we want to set up the dummy application so that we have a full application to run, like so:

import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { visit, currentURL } from '@ember/test-helpers';

module('basic acceptance test', function(hooks) {
  setupApplicationTest(hooks);

  test('can visit /', async function(assert) {
    await visit('/');
    assert.equal(currentURL(), '/');
  });
});

Because we never called setApplication (as described in the ember-qunit readme), this will fail. But once we call setApplication, it will override the setResolver call and all unit and integration tests will fail. So we came up with a custom “setup” function that uses setupApplicationTest under the hood:

// tests/helpers/dummy.js
import Application from '../../app';
import config from '../../config/environment';
import { setApplication } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
 
export function setupDummyApplicationTest({ beforeEach, afterEach }, options) {
  const hooks = {
    beforeEach(fn) {
      return beforeEach(function(...args) {
        setApplication(Application.create(config.APP));
        return fn.apply(this, args);
      });
    },
 
    afterEach(fn) {
      return afterEach(function(...args) {
        setApplication(null);
        return fn.apply(this, args);
      });
    }
  };
 
  setupApplicationTest(hooks, options);
}

So we can fix the above example by swapping setupApplicationTest with setupDummyApplicationTest. And calling setApplication(null) in afterEach() allows the next test to use the engine’s resolver as specified in tests/test-helper.js.

Are there are any downsides to this approach? Or: is there a better pattern we should be using?

@lennyburdette you don’t need this to write unit, integration and acceptance tests in a engine as addon using dummy app.

You just ensure that your tests/test-helpers.js is like this:

import Application from '../app';
import config from '../config/environment';
import { setApplication } from '@ember/test-helpers';
import { start } from 'ember-qunit';
import preloadAssets from 'ember-asset-loader/test-support/preload-assets';
import manifest from 'dummy/config/asset-manifest';

setApplication(Application.create(config.APP));

preloadAssets(manifest).then(start); // This ensures all engine resources are loaded before the tests

I have examples of all kind of tests here if you need - engine-modal-bug/tests at master · villander/engine-modal-bug · GitHub

@villander thanks for the example repo! Looks like the secret sauce is:

setupRenderingTest(hooks, { resolver: engineResolverFor('ember-blog-engine') });

That’s the key to giving us access to the engine’s dependency injection container (instead of the dummy’s DI container.) :raised_hands:

1 Like

yup @lennyburdette. For now we’re working on new test API for ember engines, to work like a ember normal application like ember guides, adding just setupEngineTest after each setup*Test() - https://github.com/ember-engines/ember-engines/pull/653