My app stores some information about the current session in localStorage. Therefore I need my tests to clear localStorage before or after each single test throughout all test files. Is there a way to define a beforeEach or afterEach callback globally instead of on each test file?
We had wrapped ember-qunit's module, moduleFor and moduleForComponent for a nearly the same reason. And we are importing those wrappers instead of ember-qunit.
Another suggestion is to wrap localStorage with a service. Never access to localStorage except this service. So you can use a mock implementation of it in tests.
Updated:
How it is realised:
import { moduleFor, moduleForModel, test, only, setResolver } from 'ember-qunit';
import { moduleForComponent as qunitModuleForComponent } from 'ember-qunit';
function moduleForComponent(name, description, callbacks) {
//our implementation that wraps "qunitModuleForComponent"
//eg. init commonly used services vs.
}
export {
moduleFor,
moduleForComponent,
moduleForModel,
test,
only,
setResolver
};
Pros:
Prevents code duplication
Centralize unit test management
Easy to add new methods for custom needs, such as: moduleForValidatableComponent, moduleForLocalStorage
Cons:
ember-cli generates tests those are importing ember-qunit. Developers must change the import statements to these wrappers. It was sometimes forgotten. (When a test fails, developers remember that they need to change import statements.)
For some tests, wrapping is unnecessary.
Related
I'm reading through the Vue Testing Cookbook and Vue Test Utils's docs, where they touch on testing components with Vuex. Both sources advise using createLocalVue, but I don't fully understand why. We already have a couple of tests that use Vuex but don't use createLocalVue, and they work. So why do these sources suggest using createLocalVue?
Here's the test that appears to be a bad practice according to those sources. Is this code going to break something down the road? Is it causing unwanted side-effects we're not aware of?
import { mount } from '#vue/test-utils';
import Vuex from 'vuex';
import Component from 'somewhere';
// We don't use this and yet the code seems to work
// const localVue = createLocalVue()
// localVue.use(Vuex)
describe('Foo Component', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(Component, {
// localVue, <-- We don't use this
store: new Vuex.Store({
modules: {
app: {
namespaced: true,
// ... more store stuff
}
}
})
})
});
it('should contain foo', () => {
expect(wrapper.contains('.foo')).toBe(true);
});
});
From docs:
localVue: A local copy of Vue created by createLocalVue to use when mounting the component. Installing plugins on this copy of Vue prevents polluting the original Vue copy.
In your tests, you might want to make particular changes and install plugins on the tested Vue instance. Using localVue ensures those changes are reset for every test.
An obvious advantage is you don't have to install all plugins for all tests. So your tests will be faster.
Also, when your tests get a bit more complex, if you don't use localVue you'll experience tests failing erratically based on their order, because the previously ran test, even though it passed, modified the Vue instance in a way that breaks your next test. But the next test passes when ran in isolation.
The type of errors which typically imply hair loss.
Using localVue provides a type of certainty most developers welcome when running tests. If you feel adventurous, don't use it.
It's a recommendation, not an imposition.
I'm on Ember 1.13 (not 2.x yet), and I need to be able to run a helper unit test. My helper has a line:
const i18n = Frontend.__container__.lookup('service:i18n');
which injects a service the ugly way, since before Ember 2.x helpers are not "real" objects and cannot do something like:
i18n: Ember.inject.service('i18n')
When I try to run simple unit tests for the helper, I get:
Can't find variable: Frontend
How do I import/inject/mock the global app namespace in this case? Or is there another way to get past this?
I have an Ember util that I want to unit test. It uses another util.
// utils/util-1.js
import util2 from './util-2';
export default util1() {
util2();
}
I want to somehow mock the referenced util. Since it's not an Ember.Object, I can't take advantage of the service injecting system. I'm familiar with node require mocking, but I don't think I can use that here. The best I can come up with is:
// utils/util-1.js
export default util1(util2) {
util2();
}
Anyone have anything better to share?
I am using Ember with formatjs to internationalize my application, and ember-cli to build it all.
When I generate a component with
ember g component some-component
Ember also creates a test that checks that the component renders. However, if I use the intl-get helper from formatjs in the component template, the unit test fails.
So how can I register the custom helpers that formatjs creates for a unit test?
I first tried to add the intl-get helper:
moduleForComponent('some-component', {
needs: ['helper:intl-get']
});
However, this just fails inside intl-get when it tries to access "intl:main". I would like for the intl initializer to run, but I am not sure if there is even application setup. Or is it some way to just mock those methods using sinon?
My current workaround is to just delete the 'it renders' tests. But I would like for these tests to pass as well, so I can further test rendering later if I want.
Try:
moduleForComponent('some-component', {
integration: true
});
TLDR
I'm trying to unit test a very simple component. However, it appears some very common test helpers aren't being defined. This is something specific about unit-testing a component, as I'm using these in integration tests without issue.
Now just jump straight to the Questions at the end.
Details
The errors are generic:
click is not defined
andThen is not defined
Stack trace for context:
Died on test #4 at Object.test (http://localhost:7357/assets/test-support.js:110:11)
at http://localhost:7357/assets/skylab.js:14977:15
at mod.state (http://localhost:7357/assets/vendor.js:150:29)
at tryFinally (http://localhost:7357/assets/vendor.js:30:14)
at requireModule (http://localhost:7357/assets/vendor.js:148:5)
at Object.TestLoader.require (http://localhost:7357/assets/test-loader.js:29:9)
at Object.TestLoader.loadModules (http://localhost:7357/assets/test-loader.js:21:18): click is not defined
The component and the tests are very basic. The component:
import Ember from 'ember';
export default Ember.TextField.extend({
classNames: ['input-span']
});
The Test:
import Ember from 'ember';
import {
moduleForComponent,
test
} from 'ember-qunit';
moduleForComponent('custom-input');
test('focus on click', function(assert) {
assert.expect(1);
var component = this.subject();
this.render();
click('input')
assert.ok(component.$('input').is(':focus'));
});
Best Guess
My best guess is that these helpers work in the acceptance tests because the startApp helper creates the click and andThen helper functions. I don't have setup & teardown code in my moduleForComponent call, but it doesn't look like I should need it. And I don't want to test the whole app here -- just an isolated component.
Questions
Is there another way to inject these test helpers that I'm unaware of?
Am I writing these tests wrong? Should I never use click in a component test? Is the documentation simply outdated?
Should this be supported as-written, and is this a framework bug I should report?
acceptance level helpers currently depend on an app being spun up, as such they are not available for unit level tests. As those do not have an app.