I have just begun adding ember-intl into an application for which I had working tests. My acceptance tests are still working, but my integration tests on components whose templates are using ember-intl for string translation are failing with:
"No locale defined. Unable to resolve translation:..."
In the ember-intl docs there is a section on Integration Testing, which seems to be out of date:
import hbs from 'htmlbars-inline-precompile';
import wait from 'ember-test-helpers/wait';
import { moduleForComponent, test } from 'ember-qunit';
let service;
moduleForComponent('x-product', 'XProductComponent', {
integration: true,
setup() {
service = this.container.lookup('service:intl');
service.setLocale('en-us');
}
});
test('it renders', function(assert) {
assert.expect(1);
this.render(hbs`{{x-product price=price deadline=deadline}}`);
this.set('price', 1000);
this.set('deadline', new Date());
let output = this.$().text();
assert.ok(output);
});
test('it translates', function(assert) {
assert.expect(1);
/* waits for async behavior (loading translations on app boot) to settle */
return wait().then(() => {
assert.equal(service.t('some.key'), 'Hello world');
});
});
I've looked in the Ember docs and I can see how to stub a service for testing, but not how to just load the service in a test and then work with it.
Instead of using this.container, we now need to use this.owner in the new format tests. Here's a snippet of code showing how to use it in context:
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { find, render } from '#ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | login-form', function(hooks) {
setupRenderingTest(hooks);
let service;
hooks.beforeEach(function() {
service = this.owner.lookup('service:intl');
service.setLocale('en-us');
});
test('it renders', async function(assert) {
await render(hbs`{{login-form}}`);
assert.equal(find('[data-test-login-title]').textContent.trim(), 'Login');
});
});
A PR has been submitted to ember-intl, so hopefully the docs will reflect the latest best-practice soon.
Related
I'm running into some issues with the before all hook in ember-mocha (version 0.14.0). Here's an example from the docs that's been slightly modified to include a beforeEach hook:
import { expect } from 'chai';
import { describe, it } from 'mocha';
import { setupApplicationTest } from 'ember-mocha';
import { visit, currentURL } from '#ember/test-helpers';
describe('basic acceptance test', function() {
setupApplicationTest();
beforeEach(async function() {
await visit('index');
});
it('can visit /', async function() {
await visit('/');
expect(currentURL()).to.equal('/');
});
});
The above test runs as expected with no issues. However, when I substitute before for beforeEach I encounter an error:
import { expect } from 'chai';
import { describe, it } from 'mocha';
import { setupApplicationTest } from 'ember-mocha';
import { visit, currentURL } from '#ember/test-helpers';
describe('basic acceptance test', function() {
setupApplicationTest();
before(async function() {
await visit('index');
});
it('can visit /', async function() {
await visit('/');
expect(currentURL()).to.equal('/');
});
});
TypeError: Cannot destructure property `owner` of 'undefined' or 'null'.
at visit (assets/test-support.js:24931:9)
at Context.<anonymous> (assets/tests.js:339:36)
at invoke (assets/test-support.js:22801:21)
at Context.asyncFn (assets/test-support.js:22786:11)
at callFnAsync (assets/test-support.js:14070:8)
at Hook.Runnable.run (assets/test-support.js:14022:7)
at next (assets/test-support.js:14386:10)
at assets/test-support.js:14408:5
at timeslice (assets/test-support.js:9651:27)
Please let me know if any clarification is needed. Thanks in advance for your help!
Thats expected!
before only runs once for all tests.
That means before all beforeEach hooks
However setupApplicationTest utilizes beforeEach to setup the app (and the container), and afterEach to tear it down again.
This means you get a fresh app for all tests.
However you can not really visit anything without an app.
This means for every test you get a new app instance.
This means there is no app for all tests so there is no app that could visit a route.
The same question was asked in the ember discord channel. This answer tries to take the essence of the discussion to archive it on SO.
I've been struggling with mirage for the past few days, and still haven't come up with a solution.
Even with a very simplified configuration (see below), mirage responds with a 404 error code whenever it is called within acceptance tests.
The calls do work perfectly when I serve my app and look at the browser console
(Mirage responds with a 200 status, and the data is here with the hello#world.com that I setup bellow).
Here's my mirage/config.js file
// mirage/config.js
export default function() {
this.get('/users', function() {
return {
data: [{
type: 'user',
id: 'first',
attributes: {
email: 'hello#world.com'
}
}]
};
});
}
Here's my app/routes/home.js
// app/routes/home.js
import Route from '#ember/routing/route';
export default Route.extend({
model() { return this.store.findAll('user'); }
});
Here's the failing test
import { module, test } from 'qunit';
import { visit, currentURL } from '#ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
module('Acceptance | home', function(hooks) {
setupApplicationTest(hooks);
test('visiting /home', async function(assert) {
await visit('/home');
assert.equal(currentURL(), '/home');
});
});
With this message:
Promise rejected during "visiting /home": Ember Data Request GET /users
returned a 404
Payload (Empty Content-Type)
Not found: /users# 152 ms
Source:
Error: Ember Data Request GET /users returned a 404
Payload (Empty Content-Type)
Not found: /users
at ErrorClass.EmberError
(http://localhost:7357/assets/vendor.js:24125:25)
at ErrorClass.AdapterError
(http://localhost:7357/assets/vendor.js:157167:15)
at new ErrorClass (http://localhost:7357/assets/vendor.js:157185:22)
at Class.handleResponse
(http://localhost:7357/assets/vendor.js:169227:18)
at ajaxError (http://localhost:7357/assets/vendor.js:169720:25)
at Class.hash.error
(http://localhost:7357/assets/vendor.js:169308:23)
at fire (http://localhost:7357/assets/vendor.js:3607:31)
at Object.fireWith [as rejectWith]
(http://localhost:7357/assets/vendor.js:3737:7)
at done (http://localhost:7357/assets/vendor.js:9646:14)
at XMLHttpRequest.<anonymous>
(http://localhost:7357/assets/vendor.js:9887:9)
Thank you
Are you sure Mirage is even running during your test?
If you're on a recent version of Ember, Mirage's default initializer may not be running. (This needs to be fixed.)
You might want to give the latest release notes a read, and make sure you're on version 0.4.2+.
In the new style of tests, you'll need to do something like
import { module, test } from 'qunit';
import { visit, currentURL } from '#ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
+ import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
module('Acceptance | login', function(hooks) {
setupApplicationTest(hooks);
+ setupMirage(hooks);
test('visiting /login', async function(assert) {
await visit('/login');
assert.equal(currentURL(), '/login');
});
});
I have a component that calls something like:
this.get('store')
.findAll('calendar-event')
.then((data) => {
// do stuff
});
However, when I replace findAll() with query() it breaks my integration testing.
this.get('store')
.query('calendar-event', { some_stuff: [596] })
.then((data) => {
// do stuff
});
The application in the web browser via ember server continues to function correctly. However: no luck with integration testing. Error I get is: TypeError: Cannot read property 'setObjects' of null
Integration test looks like:
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import moment from 'moment';
import startMirage from '../../helpers/setup-mirage-for-integration';
moduleForComponent('main-calendar', 'Integration | Component | main calendar', {
integration: true,
beforeEach() {
startMirage(this.container);
},
afterEach() {
window.server.shutdown();
}
});
test('it renders', function (assert) {
this.render(hbs`{{main-calendar}}`);
assert.equal(this.$('.col-sm.text-center').text().trim(), moment().format('MMMM YYYY'));
});
Any ideas why it would render with the server but not on the integration testing side of things.
I am trying to integrate ember-cli-mirage fixtures into some tests. I followed the documentation here: ember fixtures
Problem: The server is not defined. error message:
ReferenceError: server is not defined
model-test.js:
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('network', 'Unit | Model | network', {
needs: []
});
test('it exists', function(assert) {
server.loadFixtures('networks'); //no defined
andThen(function() {
let net1 = networks.first();
});
assert.ok(true);
});
I have also verified that the config is set to true.
ENV['ember-cli-mirage'] = {
enabled: true
}
Mirage starts up in an initializer. Since initializers only run when a full Ember app boots up, by default the Mirage server is only available in an acceptance test.
To use Mirage in an integration or unit test, follow the docs on manually starting your Mirage server. Currently the docs say this:
To run your Mirage server during a unit or integration test, first create a helper:
// tests/helpers/start-mirage.js
import mirageInitializer from '../../initializers/ember-cli-mirage';
export default function startMirage(container) {
mirageInitializer.initialize(container);
}
Then, add the following to any test where you want Mirage to initialize:
// tests/integration/components/your-test.js
import startMirage from '../../../helpers/start-mirage';
moduleForComponent('your-component', 'Integration | Component | your component', {
integration: true,
setup: function() {
startMirage(this.container);
}
});
I've got ESA working nicely with Ember 2.0.1 but stumbled on an interesting case whilst testing:
Given the following test:
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'notifier/tests/helpers/start-app';
import Pretender from 'pretender';
import { authenticateSession } from '../../helpers/ember-simple-auth';
let server;
let application;
module('Acceptance | signout', {
beforeEach: function() {
application = startApp();
},
afterEach: function() {
Ember.run(application, 'destroy');
server.shutdown();
}
});
test('successfully sign out and get redirected', function(assert) {
server = new Pretender(function() {
this.post('/oauth/revoke', function() {
return [200, {"Content-Type": "application/json"}];
});
});
authenticateSession(application);
visit('/admin');
click('#sign-out');
andThen(() => {
assert.equal(currentRouteName(), 'users.sign-in');
});
});
The test result is the route never changes. It remains on /admin. This only occurs in testing, it works fine if I manually interact with the app.
The reason this happens is the page never gets reloaded (window.location.reload()) after the session gets invalidated as per https://github.com/simplabs/ember-simple-auth/blob/jj-abrams/addon/mixins/application-route-mixin.js#L99-L101.
Therefore the beforeModel hook in AuthenticatedRouteMixin never get triggered so the test never redirects out of /admin to /users/sign-in.
I get that this happens because you can't run window.location.reload() in testing but I'm not sure what alternative to use. I could override sessionInvalidated() in my application route and just have the app redirect to /users/sign-in when testing but that's no longer actually testing the app I suppose.
Any suggestions?
You cannot actually reload the location in testing mode as that would restart the test suite, thus leading to an infinite loop. You could maybe stub it with sinon and assert that the stub gets called.