Changes within tests are affecting other tests

So we’ve recently updated to Ember 3.4 from 2.0 and I’ve gone back to redo all of our old tests. I’m still trying to dig through all of the changes to QUnit/Ember-QUnit, but I feel like I have a decent grasp of the basics. The issue I’m having right now, on some integration/unit tests, is that changes made inside of a test are affecting the following or previous tests. The components I’ve started with are fairly simple.

Here’s an example of one of the tests that I’m having an issue with.

import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { setProperties } from '@ember/object';

const item = {
      title: 'Title',
      enabledLinks: [
        'link1',
        'link2',
        'link3'
      ]
    };
let isThing = false,
    thisElem;

module('Integration | Component | FirstComp', function(hooks) {
  setupRenderingTest(hooks);

  hooks.beforeEach(function() {
    setProperties(this, {
      item: item,
      isThing: isThing
    });
  });

  test('it renders with correct data', async function(assert) {
    await render(hbs`{{first-comp 
                        item=item 
                        isThing=isThing}}`);
    thisElem = this.element;

    assert.equal(
      thisElem.querySelector('.active').textContent.trim(),
      'link2',
      'selectedLink has .active class, link1 by default'
    );
  });

  test('selecting links functions correctly', async function(assert) {
    await render(hbs`{{first-comp 
                        item=item
                        isThing=isThing}}`);
    thisElem = this.element;

    await thisElem.querySelectorAll('.link')[1].click();

    assert.equal(
      thisElem.querySelector('.active').textContent.trim(),
      'link2',
      'selectedLink has been changed to link2'
    );
  });
});

And here’s the action that the click activates.

changeLink: function(key) {
      this.set('selectedLink', key);
    }

The click action in the second section of tests changes the data being passed in the first one, even though the first set of tests had already finished loading. This happens in another component test, but it is a unit test with no async tests. Am I missing something simple here that needs to be added to the test file to prevent this from happening?

This is just a quick at-a-glance guess but my hunch is that it’s this bit right here:

const item = {
      title: 'Title',
      enabledLinks: [
        'link1',
        'link2',
        'link3'
      ]
    };

The problem is that item is now a const reference to an object defined outside of test scope. When you later do this:

    setProperties(this, {
      item: item,
      isThing: isThing
    });

It’s just saying hey give me the thing called “item” and setting it to the “item” property, but that thing is still pointing to the higher-scope object which is being mutated across tests. I’d recommend you only set the value of const item in the beforeEach hook instead (which may require making it non-const?).

I recently had a similar issue with a test going through the same upgrade process. It’s quite a task to update all your tests but definitely worth it. And it’s a lot easier with the codemods. Good luck!

3 Likes