2

I am trying to work out how to return a value from a block that uses a promise to retrieve the value when using WebDriverJs + Mocha.

I have this example code to try to show where I face the problem, the mocha test 1) fails as it doesn't use the value in a nested test.it block, whereas test 2) passes.

import assert from 'assert';
import test from 'selenium-webdriver/testing';
import webdriver from 'selenium-webdriver';

test.describe( 'Capture value from promise', function() {
    this.timeout( 20000 );

    let title, driver;

    test.before( 'Start Browser', function() {
        driver = new webdriver.Builder().forBrowser( 'chrome' ).build();
    } );

    test.describe( '1) Capture page title without block', function() {
        test.it( 'Get and use page title', function() {
            driver.get( 'https://WordPress.com' );
            title = driver.getTitle().then( ( innerTitle ) => {
                return innerTitle;
            } );
            console.log( title ); //promise
            return assert.equal( title, 'WordPress.com: Create a free website or blog' );
        } );
    } );

    test.describe( '2) Capture page title with block', function() {
        test.it( 'Get page title', function() {
            driver.get( 'https://WordPress.com' );
            return driver.getTitle().then( ( innerTitle ) => {
                title = innerTitle;
            } );
        } );

        test.it( 'Use page title', function() {
            console.log( title ); // actual title
            return assert.equal( title, 'WordPress.com: Create a free website or blog' );
        } );
    } );
} );

If I want to use the returned value without nesting another test.it block is there a way to wait for the promise to be resolved?

Alister Scott
  • 3,675
  • 24
  • 41
  • exact duplicate of [How do I return the response from an asynchronous call?](http://stackoverflow.com/q/14220321/1048572). It's not possible. – Bergi Aug 31 '16 at 08:52
  • You'll probably find a solution fitting your exact case in [How do I properly test promises with mocha and chai?](http://stackoverflow.com/q/26571328/1048572) or [How to test promises with Mocha](http://stackoverflow.com/q/15058847/1048572) – Bergi Aug 31 '16 at 08:58
  • Once you asked a coherent question, and got answers, it is not okay to invalidate the answers by changing the question. – Louis Aug 31 '16 at 23:59

3 Answers3

1

In your second test you are doing something that is not supported by Mocha: nesting calls to it. When I run your code here, test 2 passes, but the test title 'Use page title' is not output to the console, and console.log is not executed.

Mocha flat out does not support such nesting. What this means in practice is that if you nest calls to it, you'll get undefined behavior. When I've previously tried to nest it calls, I actually was able to get the nested test to run. It was just running in an unexpected order. But undefined behavior means that what worked way back when may not work anymore.

So you must get the 1st test to work. To do this, you just move the assertion inside the .then call. When the assertion fails, the promise will become rejected and the test will fail.

test.it( '1) Capture page title without block', function() {
    driver.get( 'https://WordPress.com' );
    driver.getTitle().then( ( innerTitle ) => {
        assert.equal(innerTitle, 'WordPress.com: Create a free website or blog');
    } );
} );

If this were "stock" Mocha (Mocha not used through Selenium), then you'd have to chain the calls to driver.get and driver.getTitle and you'd have to return from the test the resulting promise. However, what you get through selenium-webdriver/testing is a modified Mocha that hooks into Selenium's "control flow" mechanism. So you do not have to chain the calls or return the promise. (A good explanation of what "control flow" does can be found in the Selenium documentation on promises.)

Louis
  • 146,715
  • 28
  • 274
  • 320
  • Thanks for the info about nested 'it' blocks - I have updated the example to have these within describe blocks which makes the problem clearer, and if I want to use a value in a subsequent block, there seems two ways: use another it block (example 2), or use two flow.execute blocks which @Hoverduck has suggested below. – Alister Scott Sep 01 '16 at 00:05
1

To take Louis's answer a step further, you can use the Control Flow mechanism directly to guarantee that steps will be executed in the given order:

test.it( '3) Capture page title with controlFLow', function() {
  let flow = driver.controlFlow();
  driver.get( 'https://WordPress.com' );
  let title = "";
  flow.execute( function() {
    return driver.getTitle().then( ( innerTitle ) => {
      title = innerTitle;
      } );
  } );

  flow.execute( function() {
    console.log( title ); // actual title
    assert.equal( title, 'WordPress.com: Create a free website or blog' );
  } );
} );
Hoverduck
  • 134
  • 2
-1

Mocha lets you return a promise which has to be resolved for a test to pass. If the promise is rejected, it will fail. If it timeouts, it will fail. If the assert is false, it will fail.

  test.describe("1) Capture page title without block", function() {
    test.it("Get and use page title", function(){
      driver.get("https://WordPress.com");
      return driver.getTitle().then(function(title) {
        assert.equal(title, "WordPress.com: Create a free website or blog");
      });
    });
  });
Linus Oleander
  • 17,746
  • 15
  • 69
  • 102