5

I have the following scenario:

  • Load page
  • Expect spinner is hidden
  • Type username Click search
  • Expect spinner display
  • After a few seconds delay, expect spinner to hide
  • Assert the right user details are displayed

Here is the working demo enter image description here

I have mocked the network request in my test spec, but I am unable to understand how to assert spinner is visible after I click the search button

Here is my test spec:

    import {Selector, RequestMock} from "testcafe";
   import mockUser from "../mocks/mockUser.json";

var apiMocks = RequestMock()
  .onRequestTo(/\/api\/users/)
  .respond(mockUser, 200, {
    'access-control-allow-credentials': "*",
    'access-control-allow-origin': "*"
  })
fixture `When a user is searched`
  .page(`http://localhost:3000/`)
  .requestHooks(apiMocks);

test("Should fetch user details", async t => {
  const spinnerEl = Selector("[data-test-id='spinner']");

  await t.expect(spinnerEl.exists).notOk();

  await t
    .typeText("[data-test-id='txt-search']", "foo")
    .click("[data-test-id='btn-search']");
   // This line does not work
  // await t.expect(spinnerEl.exists).ok();
  await t.expect(Selector("[data-test-id='username']").innerText).eql("Foo Bar");
  await t.expect(Selector("[data-test-id='userid']").innerText).eql("foo");
})

I am new to TestCafe, could someone help me with this.

Thanks!

Alex Skorkin
  • 4,264
  • 3
  • 25
  • 47
Nikhil
  • 905
  • 7
  • 9
  • Could you please provide an example of the application with which I can run the provided test code? – mlosev Nov 11 '19 at 15:36
  • @mlosev Thanks for responding. I've put up this code pen demo to illustrate the functionality I want to test: https://codepen.io/niki4810/pen/eYYLBmN You can type in any valid github userid in the search box and hit the Get User button to see the loading spinner. Thanks for your help. Please let me know if anything else is needed from my end. – Nikhil Nov 12 '19 at 15:55
  • @Nikhil - That url doesn't allow automation, as it requires a captcha.... Could you also supply the '../mocks/mockUser.json' file? Or edit the code above to allow mockUser to be defined? – TallKU Nov 13 '19 at 20:08
  • @TallKU my apologies. Here is a GitHub repo with the demo app and the sample scripts files: https://github.com/niki4810/testcafe-demo-app#steps-to-run-tests Please let me know if anything else is needed from my side. – Nikhil Nov 15 '19 at 02:57

1 Answers1

4

It is difficult to check whether the described spinner element is shown due to the following:

  1. It is displayed only during a short period of time. This does not allow TestCafe to check it in time. Using mocks makes the spinner appear only for milliseconds.
  2. TestCafe waits for all requests and does not perform any actions until XHR requests are completed. This means that assertions will not start until your request is finished.

However, it's still possible to work around the issue. You can use MutationObserver and TestCafe ClientFunctions mechanism.

You can create your element observer using the ClientFunction. The observer will watch for the app element changes. If the spinner element appears the observer will be notified and set the window.spinnerWasShown variable to true.

After the button is clicked, you can check that the windows.spinnerWasShown variable is set to true.

Here is the full example:

import { Selector, RequestMock, ClientFunction } from "testcafe";
import mockUser from "../mocks/mockUser.json";

var apiMocks = RequestMock()
    .onRequestTo(/\/api.github.com\/users/)
    .respond(mockUser, 200, {
        'access-control-allow-credentials': "*",
        'access-control-allow-origin':      "*"
    });

fixture`When a user is searched`
    .page(`http://localhost:3000/`)
    .requestHooks(apiMocks);


const spinnerWasShown = ClientFunction(() => window.spinnerWasShown);


const observeSpinner = ClientFunction(() => {
    var appEl = document.querySelector('.app');

    const config = { attributes: true, childList: true };

    const callback = function(mutationsList) {
        for(let mutation of mutationsList) {
            if (mutation.type === 'childList') {
                for (var i =0; i < mutation.addedNodes.length; i++ )
                    window.spinnerWasShown = window.spinnerWasShown || mutation.addedNodes[i].className.indexOf('spinner') > -1;
            }
        }
    };

    const observer = new MutationObserver(callback);

    observer.observe(appEl, config);
});

test("Should fetch user details", async t => {
    const spinnerEl = Selector("[data-test-id='spinner']");

    await t.expect(spinnerEl.exists).notOk();

    await t.typeText("[data-test-id='txt-search']", "foo");

    await observeSpinner();

    await t.click("[data-test-id='btn-search']");

    await t.expect(spinnerWasShown()).eql(true);

    await t.expect(spinnerEl.exists).notOk();

    await t.expect(Selector("[data-test-id='username']").innerText).eql("Foo Bar");
    await t.expect(Selector("[data-test-id='userid']").innerText).eql("foo");
});
Alex Kamaev
  • 6,198
  • 1
  • 14
  • 29