elaich
elaich

Reputation: 941

Mocha may be deferring Chai expectations

I'm doing some test driven development with mocha, selenium and chai, i'm a beginner on these libraries, I'm asking if I'm doing things right already ? Here is a piece of my functional_tests.js

test.it('Hamid visits the first page of tests', function(){
    // Hamid visits the home page of the test plateform he heard about
    driver.get('file:///home/marouane/Projects/iframe_test/test_template.html') ;

    // he noticed the title and the header of the page mention Test Template
    driver.getTitle().then(function(title){
        expect(title).to.contain('Test Template');
    });

    driver.findElement(webdriver.By.tagName('h1')).then(function(element){
        expect(element).to.contain('Test Template');
    });
    // he is invited to enter a URL for the page he wants to test
    driver.findElement(webdriver.By.id('input-url'), function(element){
         expect(element).to.equal('Enter a url');
    });

Here is the html page I test:

<!DOCTYPE html>
<html>
<head>
    <title>Test Template</title>
</head>
<body>
<h1></h1>
</body>
</html>

I was expecting to get an assertion error on the second chai expectation, but I ended with this error:

NoSuchElementError: Unable to locate element: {"method":"id","selector":"input-url"}.

May be I'm doing something wrong, and that the callback functions are deferred.

Upvotes: 0

Views: 657

Answers (1)

Louis
Louis

Reputation: 151401

I am not organized here to run your code, but through examining your code I believe there are two problems:

  1. The code in your it callback is asynchronous but you do not use the done callback to indicate that the test is finished. Although the promise style of using WebDriverJS makes it look more like synchronous code, and the "control flows" (that's WebDriverJS's terminology) also makes asynchronous code look synchronous, the fact remains that using WebDriverJS is inherently asynchronous.

  2. You mix two different styles of calling WebDriverJS functions. Namely, you mix promises and continuations. Your calls to driver.get, driver.getTitle, and the first call to driver.findElement are all using promises (explicitly or implicitly). However, the last call to driver.findElement uses a continuation rather than a promise. So the first calls use the control flows facility but the last one does not. The last one cannot use the control flows facility because this facility only manages promises and your lass call uses a continuation rather than a promise. So your expect calls are not executed in the order you think they are.

Something like this should solve the problems I've mentioned above:

test.it('Hamid visits the first page of tests', function(done){
    // Hamid visits the home page of the test plateform he heard about
    driver.get('file:///home/marouane/Projects/iframe_test/test_template.html') ;

    // he noticed the title and the header of the page mention Test Template
    driver.getTitle().then(function(title){
        expect(title).to.contain('Test Template');
    });

    driver.findElement(webdriver.By.tagName('h1')).then(function(element){
        expect(element).to.contain('Test Template');
    });

    // he is invited to enter a URL for the page he wants to test
    driver.findElement(webdriver.By.id('input-url')).then(function(element){
         expect(element).to.equal('Enter a url');
         done();
    });
});

There are only two changes:

  1. I've added the done parameter to the callback to it (first line) and I've added a call to done() in the callback that contains your last expect.

  2. I've changed the last call to driver.findElement to the kind of call that uses a promise rather than a continuation.

Upvotes: 0

Related Questions