How to unit test custom Ember.Inflector rules - ember.js

I'm trying to create a test for the following initializer:
import Ember from 'ember';
const { Inflector } = Ember;
export function initialize() {
Inflector.inflector.uncountable('settings');
Inflector.inflector.uncountable('feedback');
}
export default {
name: 'inflector',
initialize
};
Ember-cli generates the following test for an initializer:
import Ember from 'ember';
import InflectorInitializer from 'redirect/initializers/inflector';
import { module, test } from 'qunit';
let application;
module('Unit | Initializer | inflector', {
beforeEach() {
Ember.run(function() {
application = Ember.Application.create();
application.deferReadiness();
});
}
});
test('it works', function(assert) {
InflectorInitializer.initialize(application);
assert.ok(true);
});
As I understand it, a beforeEach() hook creates an application first, and then pauses it so the initializer test can run.
The test fails because Ember.Inflector in undefined when the initializer is called by the test.
How do I test custom inflector rules?
I'd like to have the following assertions:
assert.equal(inflector.singularize('settings'), 'settings');
assert.equal(inflector.pluralize('settings'), 'settings');
assert.equal(inflector.singularize('feedback'), 'feedback');
assert.equal(inflector.pluralize('feedback'), 'feedback');
assert.equal(inflector.rules.uncountable['settings'], true);
assert.equal(inflector.rules.uncountable['feedback'], true);
I'd be willing to configure inflector rules in a different way if this will make it testable.
I tried to create an application and remove deferReadiness to then see If I can put those assertions in the test. But even though Ember.Inflector is then defined, it doesn't contain my custom rules.

Related

Ember Addon: writing unit tests for files in my addon folder

I am writing an Ember Addon that provides some services that are not exposed through the app/ folder.
// project Foo
// addon/services/foo.js
import Ember from 'ember';
export default Ember.Service.extend({})
The unit test that gets generated by Ember CLI uses moduleFor helper.
// tests/unit/services/foo.js
import { moduleFor, test } from 'ember-qunit';
moduleFor('service:foo', 'Unit | Service | foo', {
// Specify the other units that are required for this test.
// needs: ['service:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let service = this.subject();
assert.ok(service);
});
Problem is that since my FooService is not exposed through the app/ folder, moduleFor helper cannot find it using service:foo name.
What would be the best way to unit test my service here?
I can see three possibilities:
1) add tests/dummy/app/services/foo.js that exports FooService
// tests/dummy/app/services/foo.js
export { default } from 'foo/services/foo.js';
2) create initializers in the dummy app that registers service:foo
// tests/dummy/app/initializers/account-data.js
import FooService from 'foo/services/foo'
export function initialize(application) {
application.register('service:foo', FooService);
}
EDIT
turns out I can't do this. it's not that moduleFor helper is trying to find 'service:foo' but trying to register 'app/services/foo' as 'service:foo'. So registering 'service:foo' ahead of the time does not help.
3) don't use moduleFor helper.
EDIT
By this I meant something like what #Andy Pye's answer. But it would be nice to be able to use moduleFor helper... Especially for models since I need access to store.
EDIT
turns out it gets more complicated for models since I can't create them directly. So if I go with not using moduleFor helper, I need an instead of store object...
I've just had the same (or a very similar) issue. I've found that this seems to work:
// tests/unit/services/foo.js
import { module, test } from 'ember-qunit';
import FooService from 'Foo/services/foo';
module('Unit | Service | foo', {
// Specify the other units that are required for this test.
// needs: ['service:foo']
});
// Replace this with your real tests.
test('it exists', function (assert) {
let service = FooService.create();
assert.ok(service);
});

Ember CLI Simple Auth test helper authenticateSession is not defined

I am using ember-cli 0.2.6 and ember-cli-simple-auth 0.8.0-beta.2.
Starting from scratch I do the following:
ember create project1
//inside project1
ember install ember-cli-simple-auth
now i am adding the following line to tests/helpers/start-app:
import 'simple-auth-testing/test-helpers';
and in environment.js only add this:
if (environment === 'test') {
ENV['simple-auth'] = {
store: 'simple-auth-session-store:ephemeral'
};
...
}
Also I created an acceptance test named "login"
ember generate acceptance-test login
Which i adjusted to make use of the authenticateSession(); helper:
import Ember from 'ember';
import {
module,
test
} from 'qunit';
import startApp from 'project1/tests/helpers/start-app';
var application;
module('Acceptance: Login', {
beforeEach: function() {
application = startApp();
},
afterEach: function() {
Ember.run(application, 'destroy');
}
});
test('visiting /login', function(assert) {
authenticateSession();
ok('yes');
});
Now however, whenever i run ember test I get the same error message:
acceptance/login-test.js: line 22, col 3, 'authenticateSession' is not defined.
What did I miss to be not able to access the simple-auth helpers inside my acceptance test? I also tried with the simple-auth 0.7.3 release,... In another try I set up a custom authorizer, but got the same error.
You need to import the testing helpers like this:
import initializeTestHelpers from 'simple-auth-testing/test-helpers';
initializeTestHelpers();

Ember-CLI tests can't include modules from 'app' directory

I am trying to include a module in my app from one of the tests. Is it even possible to do that? I am only able to include a module in the 'tests' directory.
I keep getting the infamous "Could not find module" error.
http://localhost:4200/assets/test-support.js:5578:16: Could not find module d3graph/app/controllers/index imported from d3graph/tests/unit/utils/graph-helper-test
This is my test code:
import { moduleFor, test } from 'ember-qunit';
import Ember from 'ember';
import helper from '../../../app/anything/anywhere'; // <- THIS LINE FAILS
moduleFor('util:graph-helper', 'Graph Helper', {
beforeEach: () => initialize()
});
function initialize() { /* something */ };
test('test desc', function(assert) {
var testObj = this.subject();
// test logic follows
});
I did try various modifications of the path to the module, including absolute path from root, I even tried including via 'require()', but alas without success.
Please help.
Shouldn't be a problem. You will need a needs line inside your moduleFor call:
import { moduleFor, test } from 'ember-qunit';
import Ember from 'ember';
moduleFor('util:graph-helper', 'Graph Helper', {
needs: ['controller:index'],
beforeEach: () => initialize()
});
function initialize() { /* something */ };
test('test desc', function(assert) {
var testObj = this.subject();
// test logic follows
});
See http://guides.emberjs.com/v1.10.0/testing/testing-controllers/#toc_testing-controller-needs for more details about needs.
Edit
Disregard the above information... that's for Ember modules which resolve the standard way. To include modules off the beaten Ember path, a simple ES6 import will suffice (this example demonstrates pulling in some-util for the controller:index unit tests):
import { moduleFor, test } from 'ember-qunit';
import Ember from 'ember';
import SomeUsefulUtil from '<application-name>/utils/some-useful-util';
moduleFor('controller:index', 'Graph Helper', {
beforeEach: () => initialize()
});
function initialize() { /* something */ };
test('test desc', function(assert) {
var testObj = this.subject();
// Create utility class instance
var someUsefulUtilInstance = new SomeUsefulUtil();
// test logic follows
});
The potentially non-intuitive part of this is that you have to prefix the import with your application's name instead of the standard app directory.

installing an Ember helper through add on then using it in a component breaks the tests

I'm installing the 'ember-moment' helper and then I'm using it in components. As soon as I do that, those components' tests break saying pretty much nothing:
not ok 120 PhantomJS 1.9 - StatusCardComponent: it renders
---
actual: >
null
message: >
Died on test #2 at http://localhost:7357/assets/test-support.js:2779
at test (http://localhost:7357/assets/test-support.js:1796)
at http://localhost:7357/assets/client.js:11190
at http://localhost:7357/assets/vendor.js:150
at tryFinally (http://localhost:7357/assets/vendor.js:30)
at http://localhost:7357/assets/vendor.js:156
at http://localhost:7357/assets/test-loader.js:29
at http://localhost:7357/assets/test-loader.js:21
at http://localhost:7357/assets/test-loader.js:40
at http://localhost:7357/assets/test-support.js:5545: Assertion Failed: A helper named 'moment' could not be found
Log: >
...
And here is the code of the test itself, it's just the auto generation:
import {
moduleForComponent,
test
} from 'ember-qunit';
moduleForComponent('event-card', {
// Specify the other units that are required for this test
// needs: ['component:foo', 'helper:bar']
});
test('it renders', function(assert) {
assert.expect(2);
// Creates the component instance
var component = this.subject();
assert.equal(component._state, 'preRender');
// Renders the component to the page
this.render();
assert.equal(component._state, 'inDOM');
});
I tried a bunch of ways of adding this helper to the test as a dependency like needs: ['helper:moment'] and adding its initializer signature to the moduleForComponent function's params, but nothing worked and I can't find any information about it. Help is much appreciated.
Edit: According to this PR, you should be able to specify { integration: true } to turn your existing unit test into an integration test, which eliminates the need for needs:.
moduleForComponent('post', { integration: true });
More background can be found here: https://github.com/rwjblue/ember-qunit/issues/108. Essentially, the integration flag disables the isolated container for the test, so that it has access to the app's resolver.
Note: Requires ember-qunit#0.2.11.
Old Answer: Take a look at this PR: https://github.com/switchfly/ember-test-helpers/pull/21 which adds moduleForIntegration. Here's the relavant bit:
This adds a new kind of test module that fills a gap in the current
set of possible tests. So far we have:
• unit tests that are good for testing algorithmic correctness in isolation.
• acceptance tests that are good for testing within a complete
application.
But we're missing the ability to integration test a unit smaller than
whole-application. This PR adds a new TestModuleForIntegration that
lets you drive an integration test with a template. I think this is
often a more appropriate way to test Ember Components than a unit
test, because interesting components tend to have rich dependence on
other components.
You can see it in use in liquid-fire tests:
/* global sinon */
import Ember from "ember";
import moduleForIntegration from "../../helpers/module-for-integration";
import { test } from "ember-qunit";
moduleForIntegration('Integration: liquid-if');
test('it should render', function(assert) {
this.set('person', 'Tom');
this.render(`
{{#liquid-if isReady}}
{{person}} is ready
{{else}}
{{person}} is not ready
{{/liquid-if}}
`); // }}`)
assert.equal(this.$().text().trim(), 'Tom is not ready');
this.set('person', 'Yehuda');
assert.equal(this.$().text().trim(), 'Yehuda is not ready');
this.set('isReady', true);
assert.equal(this.$().text().trim(), 'Yehuda is ready');
});
So this is what ended up working:
import {
moduleForComponent,
test
} from 'ember-qunit';
import Ember from 'ember';
import { initialize } from '../../../../../initializers/ember-moment';
moduleForComponent('event-card', {
// Specify the other units that are required for this test
// needs: ['helper:moment'],
setup: function (container) {
Ember.run(function () {
// these two arguments are not used
// but probably still good to pass them in
// in the event we leverage them in the future
initialize(container);
});
}
});
test('it renders', function (assert) {
assert.expect(2);
// Creates the component instance
var component = this.subject();
assert.equal(component._state, 'preRender');
// Renders the component to the page
this.render();
assert.equal(component._state, 'inDOM');
});
Do you see that line that is commented out that reads:
// needs: ['component:foo', 'helper:bar']
You need to uncomment it out and make it read:
needs: ['helper:moment']
That should help, if your moment helper is registered correctly

Using an initializer in an unit test?

I have a stdlib initializer. In that initializer, i reopen some of built-in Ember classes and add some custom methods. For example, i added reverseEach to Ember.Enumerable and Array.
They work fine in the app, but in tests i receive "reverseEach: undefined is not a function".
How do i indicate that the test should use the initializer?
I tried needs: [..., 'initializer:stdlib']. It does not stumble upon that, but i still receive the "undefined" error.
Here's an example test:
`import { test, moduleForModel } from 'ember-qunit'`
moduleForModel 'foo', 'foo',
needs: [
'model:bar'
'initializer:stdlib'
]
test 'deleteLastNItems', ->
model = #subject()
model.set '', ['foo', 'bar', 'baz', 'quux']
model.deleteLastNItems 2 # This should not die with "reverseEach: undefined is not a function"
deepEquals model.get('someProperty'), ['foo', 'bar']
You can use ember g initializer stdlib, it will generate sample code for you, including test.
import Ember from 'ember';
import { initialize } from '../../../initializers/stdlib';
import { module, test } from 'qunit';
var registry, application;
module('Unit | Initializer | stdlib', {
beforeEach: function() {
Ember.run(function() {
application = Ember.Application.create();
registry = application.registry;
application.deferReadiness();
});
}
});
// Replace this with your real tests.
test('it works', function(assert) {
initialize(registry, application);
// you would normally confirm the results of the initializer here
assert.ok(true);
});
Refer: Ember blueprints