1

I'm trying to test if my Http Request method throw an error, but I always got: Unhandled promise rejection.

This is my test:

    it('it should get the first page of all offers with limit 20 without a cache system', (done) => {
        const httpRequestConnector = new HttpRequestConnector(apiConfigs);
        const queryArgs: any = {
            page: 1,
            limit: 20,
        };

        const functionThatThrows = () => {
            httpRequestConnector.offersFindAll(queryArgs, 'admin').then((res) => {
                res.should.have.property('status');
                res.status.should.equal(200);
                res.should.have.property('body');

                res.body.should.have.property('request');
                res.body.request.should.have.property('page');
                res.body.request.page.should.equal('1');
                res.body.request.should.have.property('limit');
                res.body.request.limit.should.equal('20');

                res.body.should.have.property('response');
                res.body.response.should.have.property('data');
                res.body.response.data.should.have.property('data');

                Object.keys(res.body.response.data.data).length.should.equal(20);
            }).catch((err) => {
                throw err;
            });
        };

        expect(functionThatThrows).to.throw();
        done();
    });

This is my methods (where the "Offeree" will cause an error):

...
private query(url: string, send: any): Promise<any> {
    const httpRequestService: HttpRequestInterface = new HttpRequestService();

    return httpRequestService.post({
        url,
        send,
    });
}

offersFindAll(args: any, apiDefinition: string): Promise<any> {
    (new GuardAgainstNullValues())
        .guard(apiDefinition);

    const queryArgs = args || {};
    const target: string = (apiDefinition === 'admin') ? 'Offeree' : 'Affiliate_Offer';
    const method: string = 'findAll';
    const apiInfos: any = this.getApiInfos(apiDefinition);
    const url: string = apiInfos.api + '?api_key=' + apiInfos.api_key + '&Target=' + target + '&Method=' + method;

    if (queryArgs && 'limit' in queryArgs) {
        queryArgs.limit = args.limit;
    } else {
        queryArgs.limit = 1000;
    }

    return new Promise((fulfill, reject) => {
        return this.query(url, queryArgs)
            .then((res) => {
                if (res.body.response.status === -1) {
                    throw new RequestStatusException('Cannot get offers');
                }

                fulfill(res);
            })
            .catch((err) => {
                reject(err);
            });
    });
}
...

And this is my POST method from my HttpRequestService:

class HttpRequestService implements HttpRequestInterface{
    private engine: SuperAgentStatic;

    constructor() {
        this.engine = request; // Superagent
    }

    get({ url, query }: { url: string, query?: any }): Promise<any>{
        return new Promise((fulfill: any, reject: any) => {
            this.engine
                .get(url)
                .query(query)
                .end((err: ResponseError, res: Response) => {
                    if (err) {
                        reject(err);
                    }

                    fulfill(res);
                });
        });
    }

    post({ url, send }: { url: string, send?: any }): Promise<any>{
        return new Promise((fulfill: any, reject: any) => {
            this.engine
                .post(url)
                .send(qs.stringify(send))
                .end((err: ResponseError, res: Response) => {
                    if (err) {
                        reject(err);
                    }

                    fulfill(res);
                });
        });
    }
};

I wrapped my offersFindAll request with a promise to handle if (res.body.response.status === -1) { to throw an error instead of throwing it anywhere i use this method.

I'm trying to expect the function to throw here in my mocha test: expect(functionThatThrows).to.throw();

But i always got a (node:7485) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): RequestStatusException: Cannot get offers which is the good exception, but I can't handle the promise correctly.

I try to only return this.query without wrapping it in a promise, but does the same.

How can I structure this correctly to test if it throws?

Thank you very much for your help

Mike Boutin
  • 5,297
  • 12
  • 38
  • 65
  • Hi Mike, I think that you can simply listen *unhandledRejection* and write your test while listening to that event. Please let me know if you have any other questions. https://nodejs.org/api/process.html#process_event_unhandledrejection – tagkiller Oct 05 '17 at 13:22
  • Is it a good practice? It's seems weird – Mike Boutin Oct 05 '17 at 13:28

1 Answers1

0

In your method offersFindAll():

    return new Promise((fulfill, reject) => {
    return this.query(url, queryArgs)
        .then((res) => {
            if (res.body.response.status === -1) {
                throw new RequestStatusException('Cannot get offers');
            }

            fulfill(res);
        })
        .catch((err) => {
            reject(err);
        });
});

the exception cannot be caught by the catch clause. It's better to write so:

    return new Promise((fulfill, reject) => {
    return this.query(url, queryArgs)
        .then((res) => {
            if (res.body.response.status === -1) {
                reject('Cannot get offers');
            }

            fulfill(res);
        })
        .catch((err) => {
            reject(err);
        });
});

Meanwhile, the stacktrace of the errors can be found using:

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at:', p, 'reason:', reason);
  // application specific logging, throwing an error, or other logic here
});
motou
  • 726
  • 4
  • 12
  • Thank you for your quick answer! It handles it better, but in my test it gave me `(node:7644) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Cannot get offers` again. – Mike Boutin Oct 05 '17 at 13:27
  • 1
    Try to use the code to get stacktrace: process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at:', p, 'reason:', reason); // application specific logging, throwing an error, or other logic here }); – motou Oct 05 '17 at 14:33