How to solve promise() is not a function - jestjs

I have React code that makes API call to a backend server. I am trying to test it using Jest.
Let's assume I have a class 'User' with a single method listResources.
User user = new User(credentials);
user.listResources()
.promise()
.then(res => console.log(res))
.catch(err => console.log(err))
I am mocking it in my Jest tests like this:
User.prototype.listResources = jest.fn().mockImplementation(
() => {
return new Promise((resolve, reject) => {
resolve('resourceA');
reject('error');
})
}
)
The test returns
TypeError: user.listResources(...).promise is not a function
Any ideas on how to approach this?

listResources is expected to return an object that has a promise function, so you need to mock it like this:
User.prototype.listResources = jest.fn(() => ({
promise: () => Promise.resolve(), // or Promise.reject()
}));

Related

Resolution method is overspecified when testing with Mocha and Supertest for Node.js [duplicate]

After the upgrade, Mocha can not even run a simple test here is the code
const assert = require('assert');
it('should complete this test', function (done) {
return new Promise(function (resolve) {
assert.ok(true);
resolve();
})
.then(done);
});
I took this code from here
I understood that it now throws an exception Error: Resolution method is overspecified. Specify a callback * or * return a Promise; not both.
But how to make it work? I did not understand. I have
node -v 6.9.4
mocha -v 3.2.0
How to run this code are now in a new and correct format?
Just drop
.then(done); and replace function(done) with function()
You are returning a Promise so calling done is redundant as it said in error message
In the elder versions you had to use callback in case of async methods like that
it ('returns async', function(done) {
callAsync()
.then(function(result) {
assert.ok(result);
done();
});
})
Now you have an alternative of returning a Promise
it ('returns async', function() {
return new Promise(function (resolve) {
callAsync()
.then(function(result) {
assert.ok(result);
resolve();
});
});
})
But using both is misleading
(see for example here https://github.com/mochajs/mocha/issues/2407)
Mocha allows to either use a callback:
it('should complete this test', function (done) {
new Promise(function (resolve) {
assert.ok(true);
resolve();
})
.then(done);
});
OR return a promise:
it('should complete this test', function () {
return new Promise(function (resolve) {
assert.ok(true);
resolve();
});
});
// Or in the async manner
it('should complete this test', async () => {
await Promise.resolve();
assert.ok(true);
});
You can't do both.
I had to removed the done from the function parameter and the done() of the function call
Before
before(async function (done) {
user = new User({ ...});
await user.save();
done()
});
After
before(async function () {
user = new User({ ...});
await user.save();
});
These works for me
I had this same issue. A lot of times Mocha is paired with another library called Chai. Chai has a package called "chai-as-promised". It gives you the super simple ability to write less code and test promises. In your case of just testing if a promise resolves, it seems perfect.
const chai = require('chai');
const chaiAsPromised = require("chai-as-promised");
const should = require("chai").should();
chai.use(chaiAsPromised);
describe("Testing with correct syntax and non repeated names", () => {
it("Should give us a positive response", () => {
graphQL.sendToGQL(model,"specialEndpoint").should.eventually.be.an("Object");
})
})
An example of async functions with done breaking.
Failure Case
it('If the credentials exists in the system it should return the token generated against it.', async (done) => {
let aObj = await admin.createAdmin();
chai.request(server)
.post("/authenticate")
.set("Content-Type", "application/x-www-form-urlencoded")
.send({username: aObj.login,password:aObj.password})
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a("string");
done();
});
});
Success Case
it('If the credentials exists in the system it should return the token generated against it.', async () => {
let adminObj = await admin.createAdmin();
chai.request(server)
.post("/auth/login")
.set("Content-Type", "application/x-www-form-urlencoded")
.send({username: adminObj.login,password:adminObj.password})
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a("string");
// done();
});
});
If you don't have callbacks, prior answers (which suggest deleting the done) is correct.
If need to both await some external promise, and then exercise a callback/errback-based implementation in your test, that solution doesn't help you.
You can use a library like pify to convert the callback API to use promises.
Alternatively, you can use a Latch in your callback:
it("test", async () => {
const l = new Latch()
const v = await promiseValue()
s.methodThatTakesCallback((err, result) => {
expect(result).to.eql(expected)
l.resolve() // < notifies mocha your test is done
})
return l.promise
})
In TypeScript, here's a very stripped-down Latch implementation:
/**
* Simple one-count concurrent barrier
*/
export class Latch {
readonly promise: Promise<void>
resolve!: () => void
constructor() {
this.promise = new Promise<void>(resolve => (this.resolve = resolve))
}
}
Just emit done callback completely and use async instead.
(This implementation is based on an express api running on firebase functions, using a custom jsonwebtoken)
const { FIREBASE_UID } = require('dotenv').config()?.parsed
const chai = require('chai');
const chaiHttp = require('chai-http');
const server = require('../lib/api').API;
const should = chai.should();
const expect = chai.expect
chai.use(chaiHttp)
const test = chai.request(server).keepOpen()
// get your token with an earlier mock request and store to a var
describe('Just checking a token', () => {
let some_token
it('should print custom jwt for testing, status: 200'), async () => {
try {
const res = await test.get(`/createCustomFirebaseToken/${FIREBASE_UID}`).send()
res.should.exist
res.should.have.status(200);
res.should.have.json
some_token = (JSON.parse(res.text)).token
} catch (error) {
throw error
}
}
it('should print details:PING, status:200'), async () => {
try {
const res = await test.get('/').set('Authorization',`Bearer ${some_token}`)
.send()
res.should.exist
res.should.have.status(200);
res.should.have.json
const { details, status } = JSON.parse(res.text)
expect(details).to.equal('PING')
expect(status).to.equal(200)
} catch (error) {
throw error
}
}
after(() => test.close())
})

undefined async handler using sinon.stub()

I know it's something obvious that I'm missing but I'm trying to write unit tests using mocha, chai and sinon for an async handler that's referencing another async service. Here's the code for what I'm dealing with:
authenticateService.js
module.exports = (() => {
...
async authenticate(username, password) {
const isValid = await validCreds(username)
if (!isValid) {
throw Error(`invalid_credentials`)
}
return isValid
}
}
authenticateHandler.js
module.export.handler = {
async (event) => {
const auth = await authenticate(username, password)
if (auth) {
// do things
}
return {statusCodes.OK}
}
}
unit test
describe(`Admin Module`, () => {
beforeEach(() => {
sinon.stub(authenticateService.prototype, "authenticate")
.callsFake(() => Promise.resolve({status:200}))
})
afterEach(() => {
authenticationService.restore()
})
describe(`test auth`, () => {
it(`Receives GET event expects statusCode 200`, async () => {
const event = {
httpMethod: `POST`,
resourcePath: `/admin/authentications`,
body: {
username: `fizz#email.com`,
password: `buzz`,
recaptchaToken: `some_token`
},
}
expect(response.statusCode).to.equal(200)
})
})
I tried setting the following:
setting it in a sandbox
using yields, resolve, return and could not figure out how to stub it correctly
tried mocking the nested authenticateService, mocking the handler and mocking both
I keep getting Error: Trying to stub property 'authenticate' of undefined so I know it must not be instantiating the service correctly. Frankly it seems like a simple thing but I just cannot figure out what I am missing.

Training on promise and await / async with fetch in another function

I go on with praticing in JS.
This time, I try to do quite the same thing using async / await or promise :
const url = 'https://jsonplaceholder.typicode.com/todos/1';
Async / await version :
async function getData() {
const response = await fetch(url);
const data = await response.json();
return data;
}
const callGetData = async () => {
try {
const data = await getData()
console.log(data);
} catch (error) {
console.log("Something gone wrong")
}
}
Promise version
function getData() {
return new Promise((resolve, reject) => {
fetch(url)
.then(res => res.json())
.then(data => resolve(data))
.catch(error => reject(error));
});
}
const callGetData = () => {
getData()
.then(data => console.log(data))
.catch(error => console.log("Something gone wrong"));
}
and finally :
callGetData();
Both snippets seem to work. It's easier to me to write the async / await version.
Questions :
do I use promise properly in this case ?
is there some possible improvements ?
Thank you for your help.
fectch is also a promise and you are trying to wrap a promise inside a new Promise
more on the Promise version you can simply return it from the function as
getData(url){
return fetch(url)
.then(response => response.json()).then(jsonResponse=>jsonResponse)
.catch(err=>err)
}
now getData returns a promise. we can simply do as :
getData().then(data=>console.log(data))

chained promises in nodejs is executing only the first promise but not chained promises

I have below code in nodejs. I have two promises chained and then by console message done at the end.
const myPromisedFunction = () => {
console.log('my promised function');
return new Promise((resolve, reject) => {
setTimeout(() => resolve, 1000);
});
};
myPromisedFunction().then(() => myPromisedFunction()).then(() => console.log('done'));
when I run the program I get output as my promised function only once.
But I expect twice followed by done message.
node version I'm using is v.8.15.0
Any idea what is wrong in my code?
resolve() instead of resolve in the setTimeoutFn
Or you can do it even simplier
const myPromisedFunction = () => {
console.log('my promised function');
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
};
myPromisedFunction().then(myPromisedFunction).then(() => console.log('done'));
Use resolve instead of () => resolve and myPromisedFunction instead of () => myPromisedFunction

How To Spy On An Exported and Mocked Function In Jest

I am trying to mock a module (which has an exported function[and this is also mocked]).
I would like to spy on the exported function to check that it was called with something.
This is my code...
import { addNewPaymentMethod } from '../src/service'
jest.mock('../src/service', () => ({
addNewPaymentMethod : (paymentMethodInfoModel) => {
let responseFromApi = {responseStatus:{name:'blah'}};
return Promise.resolve(responseFromApi);
}
}))
import { createNewPaymentMethod } from '../src/actions/paymentMethod'
test('test expect', () => {
createNewPaymentMethod({owNickName:'nName',id:22})();
//this is the bit I don't know how to do
//...
jest.spyOn(addNewPaymentMethod);
expect(addNewPaymentMethod).toBeCalledWith({some:object});
});
You can define the mock using jest.fn().mockResolvedValue(value)
jest.mock('../src/service', () => ({
addNewPaymentMethod : jest.fn().mockResolvedValue({
responseStatus: {
name:'blah'
}
})
}))
and then since it's a jest.fn() you don't need to spyOn it :)
but note that since it's async (uses promises) you either have to chain then to the method (and use return):
it('should have been called with data', () => {
const data = {};
return service.methodWhichCallsDependencysaddNewPaymentMethod(data).then(() => {
return expect(addNewPaymentMethod).toHaveBeenCalledWith(data);
});
});
or use async/await:
it('should have been called with data', async () => {
const data = {};
await service.methodWhichCallsDependencysaddNewPaymentMethod(data);
expect(addNewPaymentMethod).toHaveBeenCalledWith(data);
});
I've set up a working example

Resources