I'm using Pikaday to create an Ember Datepicker Component within an Ember CLI project. It seems to be impossible to test user interactions within the component test. Does anyone know how to do this?
For example I'm trying to test that the Pikaday widget is displayed when the input of the component is clicked. The test looks like this:
import { test, moduleForComponent } from 'ember-qunit';
moduleForComponent('datepicker-input');
test('is an input tag', function() {
equal('INPUT', this.$().prop('tagName'));
});
test('clicking the input opens the pikaday dialog', function() {
ok($('.pika-single').hasClass('is-hidden'));
click(this.$().find('input'));
ok(!$('.pika-single').hasClass('is-hidden'));
});
The second tests fails due to ReferenceError: click is not defined. I don't know what I'm doing wrong, as far as I can tell my tests do the same as the example on the Ember.js website: http://emberjs.com/guides/testing/testing-components/#toc_interacting-with-components-in-the-dom
So I'm guessing the problem could be also with Ember CLI. Any help is welcome, I'm open to suggestions how to test the user interactions of an component.
You need to add the component to the DOM.
test('clicking the input opens the pikaday dialog', function() {
$input = this.append();
ok($('.pika-single').hasClass('is-hidden'));
click('#your-input').then(function() {
ok(!$('.pika-single').hasClass('is-hidden'));
});
});
I ended up starting and destroying the app by hand. In addition I also teardown the component after every test by hand. This is necessary until a few upstream changes from the QUnit addon land in Ember CLI.
You can look at the complete test file on GitHub: https://github.com/edgycircle/ember-pikaday/blob/master/tests/unit/components/pikaday-input-test.js
I think you need to call App.setupForTesting, and in older versions of ember, additionally App.injectTestHelpers before the tests are run.
http://emberjs.com/guides/testing/integration/#toc_setup
You also need to call this.append to make the component show up in the DOM.
In what version of Ember was this problem? I've tested with the auto-generated component test almost identically on how I tested on an ember App on an Ember AddOn (ember 2.4.3).
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('image-item', 'Integration | Component | image item', {
integration: true
});
test('it renders an image with alt', function(assert) {
this.set('src', 'image.png');
this.set('alt', 'grandmother');
this.render(hbs`{{image-item src=src alt=alt}}`);
assert.equal(this.$('img').attr('src'), 'image.png');
assert.equal(this.$('img').attr('alt'), 'grandmother');
});
Related
I'm writing an integration test for one of my addon components. I've also linked it to a sibling project using npm link:
.. projects/
.... my-project/
.... my-linked-project/
I use one of the my-linked-project mixins in the my-project component in question.
//my-project/addon/components/my-component/component.js
import Ember from 'ember';
import ExternalMixin from 'my-linked-project/mixins/foo'
export default Ember.Component.extend(ExternalMixin, {
...
}
This runs fine with the application running, but seems to hit some issues when I render it in my integration test.
//my-project/tests/integration/components/my-component-test.js
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('my-component', 'Integration description', {
integration: true
}
test('should render', function() {
this.render(hbs`{{my-component}}`);
}
However I get Error: Could not find module 'my-linked-project/mixins/foo'.
Where can I read more about what happens when render / hbs are called?
Could the issue be the location of the test file, which can't find the external linked project?
It's worth removing the npm link from tech equation temporarily to see if that's causing your problems. What you have there looks fine ...
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);
});
I'm building a relatively straight-foward comment-list component. I want to pass in the commentable model (say a Post) and have the component take care of creating, editing, deleting comments. Right now I pass around all the various actions and it's been extremely brittle.
How do I create a true instance of an Ember Data model in a component integration test?
My immediate thought was to import the model then .create({}) it but that errors with use this.store.createRecord() instead
/* jshint expr:true */
import { assert } from 'chai';
import { describeComponent, it } from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile';
import Post from 'ownersup-client/post/model';
describeComponent( 'comment-list', 'Integration: CommentListComponent', {
integration: true
},
function() {
it('renders all of the comments', function() {
const model = Post.create({ title: 'title' });
model.get('comments').createRecord({ body: 'One Comment' })
this.render(hbs`{{comment-list model=model}}`);
assert.lengthOf(this.$('.comment-list-item'), 1);
});
}
);
Anyone have any thoughts?
Among all Ember test helpers, the store is only available from moduleForModel.
Here's how this test helper does it (source):
var container = this.container;
var store = container.lookup('service:store') || container.lookup('store:main');
You can do the same inside your test. You can also put it into a helper so that you don't have to copy-paste a lot.
Note that it will only work for an integration test. You can turn any test into integration one by starting the app using the startApp test helper that is bundled with your Ember CLI boilerplate.
The new ember mocha release 0.8.4 contains a new, public way to inject services such as the store. There's a guides section coming soon with an example (see https://github.com/emberjs/guides/blob/master/source/testing/testing-components.md)
essentially, in your beforeEach you want add the following line: this.inject.service('store');, making the store accessible as this.get('store') in your tests.
Here's a link to the pull request for the new change: https://github.com/switchfly/ember-test-helpers/pull/105
General answer for people who are struggled with similar things related to injecting in integration tests.
Everything depends on which version and solutions you have in your project.
When you have an integration test with module
(import { module } from 'ember-qunit';)
you can use this.owner.lookup('service:store') inside your test
for more information, there is a great article from Dockyard
https://dockyard.com/blog/2018/01/11/modern-ember-testing
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
Here's a simplified version of my PuzzleController:
// app/controllers/puzzle.js
export default Em.ObjectController.extend({
needs: ['application']
});
And here's my controller test:
// tests/unit/controllers/puzzle-test.js
import {
moduleFor,
test
} from 'ember-qunit';
moduleFor('controller:puzzle', 'PuzzleController', {
needs: ['controller:application']
});
test('it exists', function() {
var controller = this.subject();
ok(controller);
});
I get this error when running ember test:
Attempting to register an unknown factory: `controller:application`
I'm using Ember 1.7.0, ember-cli 0.1.1. It seems like Ember should definitely recognize the controller:application selector. Am I using the wrong syntax here?
I believe you'll need to create the application controller.
Run ember g controller application and then try again.
I don't think ember-testing will work with an automagically generated controller. You need to define it.