ember-simple-auth, acceptance tests and waiting for async actions - testing

Struggling with acceptance tests. Started with basic login test:
import { test } from 'qunit';
import moduleForAcceptance from 'static/tests/helpers/module-for-acceptance';
moduleForAcceptance('Acceptance | authentication');
test('login', function(assert) {
visit('/');
click('.nav-bar__login-link');
andThen(function() {
assert.notOk(find('.login-form__submit-button').attr('disabled'));
});
fillIn('.login-form__email-block input', "ruz#email.com");
fillIn('.login-form__password-block input', "qwe");
click('.login-form__submit-button');
andThen(function() {
console.log("ftw");
assert.equal(find('.nav-bar__profile-link').text(), "some");
});
});
The problem is that andThen callback is called before authentication completes. It's jQuery ajax request and a few promises after. From what I can see ember waits for ajax query to complete, but doesn't wait for promises to get resolved/rejected. Should this test work out of the box? Do I have to write a custom waiter?

It sounds like your promises may not be setup right? But no, you should be able to write tests using the acceptance test helpers and not need to worry about async calls settling (or promises resolving) yourself

Related

How to run multiple tests under same fixture with same browser session

I am trying to test multiple features in one test.js file with each feature implemented as a test. All these tests can be run only after login to the portal. Testcafe closes the browser after the first test which fails the subsequent tests. I used Role and .beforeEach so that the tests can log in to the portal and proceed as usual but is there any easy way to just continue all the tests in the same browser session without really closing them after each test?
I used Role feature and .beforeEach which looks like a workaround to me. Is there any other way to run all tests one after another without really closing the browser session. This will save us the login operation and the instability that might cause for each test.
import { Selector , ClientFunction, Role } from 'testcafe';
import loginpage from '../../features/blah/login/page-model'
const appPortalUser2 = Role('https://test.com', async t => {
await loginpage.signInToPortal()
await loginpage.login('test-userm', 'Password123')
}, { preserveUrl: true });
fixture `portal - settings`
.page `https://test.com/apps`
.beforeEach (async t => {
await t`enter code here`
.useRole(appPortalUser2)
});
test('settings', async t => {
//test1
await loginpage.foo1()
});
test('backup', async t => {
//test2
await loginpage.foo2()
});
Actual behavior: after test1 browser exits and login page appears which fails test2 without using .beforeEach.
Expected: browser session should continue for test2 after test1 without .beforeEach. Provide such an option where tests can continue without creating new browser sessions each time.
At the moment, there is no such option in the public API.
The idea is that one test should not affect another test in any way. If all tests had run in one browser session, every test would have influenced all preceding tests as it could have had a page with an invalid state.

Make Mocha Wait for UI to Update

I'm using Mocha and Chai as part of the web-component-tester tool to write my tests. As part of those tests, I need to wait for a part of the UI to update before doing an assertion.
The only way I've been able to figure out how to do this successfully is by using a timeout:
test("should update image", function(done) {
setTimeout(function() {
assert.equal(document.querySelector(".tp-revslider-mainul .tp-revslider-slidesli:nth-child(1) .tp-bgimg").getAttribute("src"), "https://someurl/image.jpg");
done();
}, 5000);
});
Is there a better way? CasperJS has a waitFor function that is great in situations like these, but I'm not sure how to do the same in Mocha.
Thx.

Ember acceptance test - timeouts

I have a reasonably special use-case:
I have an input field which issues a search when the user has stopped typing for 500ms. This is developed as a reusable add-on.
I would like to write an acceptance test for this but I cannot make the tests pass properly. The first passes, the second doesn't.
Now, the Ember runloop has a nice description but it's behaviour is really "something else".
This is my helper to timeout the runloop:
import Ember from 'ember';
export default Ember.Test.registerAsyncHelper('pauseFor', function (time) {
return Ember.Test.promise(function (resolve) {
Ember.run.later(resolve, time);
});
});
And this is how I use it
it('should do something after 500ms', function () {
visit('/');
fillIn('.search-input', 'a');
pauseFor(500);
andThen(function () {
// do my assertions/expectations here...
});
});
This is the error I get:
The weird thing is that I have 2 test cases and the first passes happily.
I guess my question is:
How to do this properly? What am I missing here or what am I doing wrong? How can I just simply timeout the test case?
Thanks for the halp!

Qunit beforeEach, afterEach - async

Since start(), stop() will be removed in Qunit 2.0, what is the alternative for async setups and teardowns via the beforeEach, afterEach methods? For instance, if I want the beforeEach to wait for a promise to be finished?
QUnit basically wants people to stop using the global methods (not just start() and stop(), but also test(), expect(), etc). So, as of version 1.16.0, you should always use either the global namespace (QUnit) or the assert API argument passed into the test() functions. This includes the new async control:
QUnit.test( "testing async action", function( assert ) { // <-- note the `assert` argument here
var done = assert.async(); // tell QUnit we're doing async actions and
// hold onto the function it returns for later
setTimeout(function() { // do some async stuff
assert.ok( true, "This happened 100 ms later!" );
done(); // using the function returned from `assert.async()` we
// tell QUnit we're don with async actions
}, 100);
});
If you are familiar with the old start() and stop() way of doing things, you should see that this is extremely similar, but more compartmentalized and extensible.
Because the async() method call is on the assert argument into the test, it cannot be used in the beforeEach() function. If you have an example of how you were doing that before, please post it and we can try to figure out how to git it into the new way.
UPDATE
My mistake previously, the assert object is being passed into the beforeEach and afterEach callbacks on modules, so you should be able to do the same logic that you would do for a test:
QUnit.module('set of tests', {
beforeEach: function(assert) {
var done = assert.async();
doSomethingAsync(function() {
done(); // tell QUnit you're good to go.
});
}
});
(tested in QUnit 1.17.1)
Seeing that nobody has answered the beforeEach/afterEach part: a test suite is supposed to run as soon as the page loads. When that is not immediately possible, then resort to configuring QUnit:
QUnit.config.autostart = false;
and continue with setting up your test suite (initializing tests, feeding them to QUnit, asynchronously waiting for some components to load, be it AJAX or anything else), your site, and finally, when it's ready, just run:
QUnit.start();
QUnit's docsite has it covered.
Ember Qunit, has once exists beforeEach/setup, afterEach/teardown co-exist for a little while.
See PR: https://github.com/emberjs/ember-qunit/pull/125

How to set jasmine for karma e2e for testing angular app?

I try to create e2e tests with karma and jasmine with yeoman. In my karma-e2e.conf.js I add jasmine:
files = [
JASMINE,
JASMINE_ADAPTER,
ANGULAR_SCENARIO,
ANGULAR_SCENARIO_ADAPTER,
'test/e2e/**/*.js'
];
A need async testing so I need to use runs, waits, waitsFor (https://github.com/pivotal/jasmine/wiki/Asynchronous-specs)
But if I try to use it:
it('test', function () {
runs(function () {
...
});
});
Scenatio test runner returns this:
TypeError: Cannot call method 'runs' of null
at runs (http://localhost:8080/adapter/lib/jasmine.js:562:32)
at Object.<anonymous> (http://localhost:8080/base/test/e2e/eduUser.js:42:3)
at Object.angular.scenario.SpecRunner.run (http://localhost:8080/adapter/lib/angular-scenario.js:27057:15)
at Object.run (http://localhost:8080/adapter/lib/angular-scenario.js:10169:18)
I don't know where the problem is. Can you help me please?
Angular e2e tests with Karma don't and can't use the JASMINE adapter. Instead you have the ANGULAR_SCENARIO_ADAPTER which has a similar feel to writing Jasmine tests.
All commands in the adapter's API are asynchronous anyway. For example element('#nav-items').count() doesn't return a number, it returns a Future object. Future objects are placed in a queue and executed asynchronously as the runner progresses. To quote the API docs:
expect(future).{matcher}:
[...] All API statements return a future object, which get a value assigned after they are executed.
If you need to run your own asynchronous test code, you can extend the adapter's DSL, this is easier than it might sound. The idea is that you return your own Future which can be evaluated by a matcher such as toBe(). There are some examples on how to do this in the e2e-tests.js Gist from Vojta. Just remember to call done(null, myRetrunValue); when your test code is successful (myRetrunValue is the value evaluated by your matcher). Or done('Your own error message'); if you want the test to fail.
UPDATE: In response to question below. To simulate a login, first add a function called login to the dsl:
angular.scenario.dsl('login', function() {
return function(selector) {
// #param {DOMWindow} appWindow The window object of the iframe (the application)
// #param {jQuery} $document jQuery wrapped document of the application
// #param {function(error, value)} done Callback that should be called when done
// (will basically call the next item in the queuue)
return this.addFutureAction('Logging in', function(appWindow, $document, done) {
// You can do normal jQuery/jqLite stuff here on $document, just call done() when your asynchronous tasks have completed
// Create some kind of listener to handle when your login is complete
$document.one('loginComplete', function(e){
done(null, true);
}).one('loginError', function(e){
done('Login error', false);
});
// Simulate the button click
var loginButton = $document.find(selector || 'button.login');
loginButton.click();
})
};
});
And then call:
beforeEach( function()
{
expect( login('button.login') ).toBeTruthy();
});