Liondancer
Liondancer

Reputation: 16479

testing promises causing undefined values

I am getting this error when I am testing my code:

1) Sourcerer Testing:  getStatusCode :
     Error: Expected undefined to equal 200

I'm not sure why I am getting undefined in my tests but when I run the code I get 200. It might be from not handling promises properly

Test code:

import expect from 'expect';
import rp from 'request-promise';
import Sourcerer from './sourcerer';


describe("Sourcerer Testing: ", () => {
    let sourcerer = new Sourcerer(null);
    const testCases = {
        "https://www.google.com": 200,
        // "www.google.com":
    };

    describe("getStatusCode", () => {
        it("", () => {
            for (let testCase in testCases) {
                sourcerer.setSourcererUrl(testCase);
                expect(sourcerer.url).toEqual(testCase);
                expect(sourcerer.getStatusCode()).toEqual(testCases[testCase]);
            }
        });
    });
});

code:

import rp from 'request-promise';

export default class Sourcerer {
    constructor(url) {
        this.options = {
            method: 'GET',
            url,
            resolveWithFullResponse: true
        };
        this.payload = {};
    }

    setSourcererUrl(url) {
        this.url = url;
    }

    getSourcererUrl() {
        return this.url;
    }

    analyzeSourcePage() {
        rp(this.options).then((res) => {
            console.log(res);
        }).catch((err) => {
            console.log("ERROR");
            throw(err);
        });

    }

    getStatusCode() {
        rp(this.options).then((res) => {
            console.log(res.statusCode);
            return res.statusCode;
        }).catch((err) => {
            console.log("STATUS CODE ERROR");
            return 0;
        });
    }
}

Upvotes: 0

Views: 49

Answers (2)

Estus Flask
Estus Flask

Reputation: 222989

getStatusCode doesn't return anything. And it should return a promise:

getStatusCode() {
    return rp(this.options)...
}

The spec will fail in this case, because it expects promise object to equal 200.

It is even more complicated because the spec is async and there are several promises that should be waited before the spec will be completed. It should be something like

    it("", () => {
        let promises = [];
        for (let testCase in testCases) {
            sourcerer.setSourcererUrl(testCase);
            let statusCodePromise = sourcerer.getStatusCode()
            .then((statusCode) => {
                expect(sourcerer.url).toEqual(testCase);
                expect(statusCode).toEqual(testCases[testCase]);
            })
            .catch((err) => {
                throw err;
            });
            promises.push(statusCodePromise);
        }

        return promises;
    });

co offers an awesome alternative to Promise.all for flow control:

    it("", co.wrap(function* () {
        for (let testCase in testCases) {
            sourcerer.setSourcererUrl(testCase);
            expect(sourcerer.url).toEqual(testCase);
            let statusCode = yield sourcerer.getStatusCode();
            expect(statusCode).toEqual(testCases[testCase]);
        }
    });

Upvotes: 1

Reza
Reza

Reputation: 867

Disclaimer: I wouldn't run a for-loop in a single it(), since I want to know which iteration failed. granted that there are ways to achieve that, but that is another story. Also, this very much depends on you test runner, but here is some rules of thumb I find useful.

But for what you have asked, the test should not evaluate until the promise is resolved. sometimes (e.g. in mocha), that means returning the promise from the it() internal function. sometimes, it means getting a done function and calling it when you are ready for the test to evaluate. If you provide more info on your test framework, I may be able to help (others certainly would be)

Upvotes: 1

Related Questions