AvantiC
AvantiC

Reputation: 377

Testcafe+Nightmare: Why is element not in DOM?

I have the following test:

fixture('Minimal reproduction')
  .page('http://www.sport-conrad.com/');


test('Navigate to item-details', async t => {
  await t
    .click('.dropdown-toggle')
    .click('.productData:first-of-type a')
  });

When I run this with testcafe chrome test.js it works as expect.

If I do testcafe nightmare test.js I get the error The element that matches the specified selector is not visible..

I tracked this one down to the fact that apparently the Electron-browser nightmare uses opens up the page with a viewport that causes the desktop-nav to disappear and so .dropdown-toggle is not visible anymore. So I worked around this by adding a manual resize:

fixture('Minimal reproduction')
  .page('http://www.sport-conrad.com/');


test('Navigate to item-details', async t => {
  await t
    .resizeWindow(1024, 900)
    .click('.dropdown-toggle')
    .click('.productData:first-of-type a')
  });

So my first question: While this works, is there another way to provide the dimension that testcafe opens up the browser in nightmare-mode?

...but: Now that .dropdown-toggle is back, I expected the test to pass again, just like before.

Unfortunately now I get another error: The specified selector does not match any element in the DOM tree. ...which seems to relate to the second selector. I'm not sure why though.

So my second question: What is the nightmare browser here doing differently? I tried a similar test-case on another page and it seemed to load the page fine just as chrome did.

I also tried a couple of workaround like forcing the browser to wait for some time but nothing worked.

Maybe someone can point me in the right direction here? :)

Upvotes: 3

Views: 2108

Answers (2)

AvantiC
AvantiC

Reputation: 377

So, with Alexander's help (thank you very much!) I was able to track down the root of this error to jQuery.

The following lines seem to cause this behaviour:

    // Determine handlers
    handlerQueue = jQuery.event.handlers.call( this, event, handlers );

    // Run delegates first; they may want to stop propagation beneath us
    i = 0;
    while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
        event.currentTarget = matched.elem;

        j = 0;
        while ( ( handleObj = matched.handlers[ j++ ] ) &&
            !event.isImmediatePropagationStopped() ) {

            // Triggered event must either 1) have no namespace, or 2) have namespace(s)
            // a subset or equal to those in the bound event (both can have no namespace).
            if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {

                event.handleObj = handleObj;
                event.data = handleObj.data;

                ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
                    handleObj.handler ).apply( matched.elem, args );

                if ( ret !== undefined ) {
                    if ( ( event.result = ret ) === false ) {
                        event.preventDefault();
                        event.stopPropagation();
                    }
                }
            }
        }
    }

    // Call the postDispatch hook for the mapped type
    if ( special.postDispatch ) {
        special.postDispatch.call( this, event );
    }

I'm not really sure why this happens though. And especially why it only happens when the test is run with nightmare while other browsers seem to do just fine...

Upvotes: 1

Alexander Moskovkin
Alexander Moskovkin

Reputation: 1861

1) For now the only way to set the browser size in your case is using the t.resizeWindow command. To avoid code duplication you can do it in the fixture.beforeEach hook (see testcafe documentation).

Meanwhile, Nightmare allows to set the browser size via its constructor options. But it's necessary to add API for this in the testcafe-browser-provider-nightmare plugin.

2) I've opened your site in nightmare in visual mode (without TestCafe) and have tried to click on the .dropdown-toggle link. But redirect to a new page doesn't occur. After some debug I see that the event.preventDefault() is called in the script for the click event. (In chrome this is not called and redirect occurs). Scripts are minified so it's hard to determine the real reason why preventDefault is called. I think it's something specific for electron browser, and it's necessary to investigate why it happens. Here is the script how I run it:

var Nightmare = require('nightmare');       
var nightmare = Nightmare({
    show: true,
    width: 1024,
    height: 600,
    webPreferences: { devTools: true },
    executionTimeout: 1000000,
    waitTimeout: 1000000
});

nightmare
  .goto('http://www.sport-conrad.com/')
  .wait(1000000)
  .end();

Upvotes: 3

Related Questions