3

I'm trying to create an acceptance test for the login page of a webapp. Everything is almost working, except the await click(element) promise never resolves:

import { module, test } from 'qunit';
import { visit, currentURL, fillIn, click, waitFor, getSettledState } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import { invalidateSession } from 'ember-simple-auth/test-support';
import { setupMirage } from 'ember-cli-mirage/test-support';

module('Acceptance | login', function(hooks) {
  setupApplicationTest(hooks);
  setupMirage(hooks);

  test('login page | login success', async function(assert) {
    assert.timeout(5000);

    console.log('start', getSettledState());

    await visit('/login');
    assert.equal(currentURL(), '/login');

    await waitFor('.btn-primary:disabled');

    await fillIn('input[type="text"]', 'mirage');
    await fillIn('input[type="password"]', 'password1234');

    await waitFor('.btn-primary:not([disabled])', 2000);
    console.log('btn enabled');

    let btnSubmit = document.querySelector('.btn-primary');
    assert.equal(btnSubmit.disabled, false);

    await click(btnSubmit);
    console.log('await btn click');

    await waitFor('.nav-tabs', 4000);
    console.log('nav complete');

    assert.equal(currentURL(), '/login-success');
    console.log('finished', getSettledState());
  });
});

If I run this test as-is, "await btn click" doesn't log in the console, until it times-out. I also get the qunit error "Uncaught (in promise) Error: pushFailure() assertion outside test context, in ___ at internalStart" (underscores added by me)

HOWEVER, if I remove the await part of the click(btnSubmit) call, the test completes successfully BUT, the last check of getSettledState() returns this:

hasPendingRequests: true
hasPendingTimers: true
hasPendingWaiters: false
hasRunLoop: true
pendingRequestCount: 1

Since there are pending requests and timers, the test still times-out, even though all the assert() calls were successful.

So it looks like if I run the test correctly with await click(btnSubmit), the test times out on the click(), but if I just call click(btnSubmit), the tests complete successfully, although testem or qunit doesn't know all the tests completed. What am I doing wrong?

mirage login endpoint:

this.post('/login', function(db, request) {
    let formData = JSON.parse(request.requestBody);
    let auth = this.serialize(db.profiles.all());
    if (formData.identification !== auth.data[0].attributes.loginid || formData.password !== auth.data[0].attributes.password) {
      return new Response(401, {some: 'header', 'Content-Type': 'application/json'}, {
        error_code: "err_loginAuthenticationFail"
      });
    }
    let profile = this.serialize(db.profiles.all());
    profile.data[0].attributes.id = profile.data[0].attributes.localid
    delete profile.data[0].attributes.localid;
    return { ...longAccessTokenObject }
});

The mirage endpoint is functioning correctly, it authenticates the one user/pw combo I setup, whether in tests or manually using the /login page in Chrome.

ChrisN
  • 302
  • 2
  • 9
  • Also, when I view the tests in Chrome, everything works. Whether I use await `click(btnSubmit)` or just `click(btnSubmit)`. I can see that Chrome navigates to the expected page, after login success. – ChrisN Jun 21 '19 at 20:38
  • what ember version are you using? also, are you using ember concurrency anywhere? websockets? any `while(true)`s? how have you mocked the authentication endpoint? ( i see you're using mirage). can you add more code, or a minimal reproduction? thanks! :) – NullVoxPopuli Jun 23 '19 at 20:09
  • 1
    also, do you have any errors in the console when the test-driven click happens? my hunch is that there is a request that isn't finishing, or isn't captured by mirage. (`pendingRequestCount: 1`) – NullVoxPopuli Jun 23 '19 at 20:12
  • Ember 3.10. ember-concurrency is used, but not in the login process. No websockets at all, no while() statements in the login. – ChrisN Jun 23 '19 at 22:03
  • No errors are logged when the click() event happens. The code execution stops, however, because no further console.log()s happen. BEFORE the click() event getSettledState() returns: `hasPendingRequests: false hasPendingTimers: true hasPendingWaiters: false hasRunLoop: true pendingRequestCount: 0` AFTER the button click(), there is a long delay, then getSettledState() returns: `hasPendingRequests: false hasPendingTimers: true hasPendingWaiters: false hasRunLoop: true pendingRequestCount: 0` Also, other calls to click(someBtn) work fine in other acceptance tests. – ChrisN Jun 23 '19 at 22:06
  • Hey, what do you mean a "request that isn't finishing, or isn't captured by mirage"? How does mirage "capture" a request? Just like it normally intercepts an API call and responds to it locally? Everything on the API is in mirage, I think. – ChrisN Jun 23 '19 at 22:33

1 Answers1

3

NullVoxPopuli was 100% correct. I followed up on your suspicions, and there was an ember-concurrency task in the codebase I wasn't aware of that was not resolving.

ChrisN
  • 302
  • 2
  • 9