I'm trying to run the tests on this promises but I get this error:
"Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure" done () "is called; if returning to Promise, ensure it resolves. (C:\Users\Ranieri\Documents\Projetos\Node Js\testestest\test\libs\registerUser.test.js)"
I have already increased the timeout time but it still does not solve the problem.
I searched for asynchronous test here on stackoverflow and found nothing or anyone with something similar
my test code https://github.com/ran-j/teste
Already tried :
expect(Promise.resolve( userPromesie.selectUser(rUser) ) ).to.be.null
return expect(Promise.resolve( userPromesie.selectUser(rUser) ) ).to.be.null
userPromesie.selectUser(rUser).then((result) => result.to.be.null
selectUser returns a Promise and you need to wait for this to resolve in order to be able to assert against it. This can achieved two ways:
Using then on the returning promise, calling the done() function within that block.
Using async/await, you declare your function async and you await the Promise
Below is an example of an async/await method:
it('should do something with the user', async () => {
const user = await userPromise.selectUser(rUser);
expect(user).to.be.null;
});
I'd highly recommend reading up on Promises for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
EDIT Here's an example using the done method:
it('should do something with the user', (done) => {
userPromise.selectUser(rUser).then((user) => {
expect(user).to.be.null;
done();
});
});
Related
I know that to implement promises in redis you have to use a promise. But how would I use those promise functions in a promise.all to work in order. At the moment the promises seem to all be working at the same time.
At the moment here is what my code looks like:
const promiseget=promise(client.mget).bind(client);
promiseget(['............']).then(res=>{
.......
........
....
const promiselrange=promise(client.lrange).bind(client);
promiselrange('.......',0,-1).then(res=>{
......
......
.....
})
Promise.all([promiselrange,promiseget]).then((values)=>{
Well, the truth is that Promise.all will wait for all of the promises that are executing concurrently. If you need to have a specific order you need to wait for a promise of a first operation and then perform the next operation e.g.
call1()
.then(() => {
console.log("First operation done!");
return call2();
})
.then(() => console.log("Second operation done!"));
It can look even nicer with async/await syntax.
I was trying to mock rejected value and got this error. It's weird that this construction works in the case of "success" addUser.mockImplementation(value => jest.fn().mockResolvedValue(value)), but when I'm trying to do the same trick with rejecting, it doesn't work and says 'Cannot read property 'createEvent' of null'
Here is my test case
it('receives invalid value and throws an error', async () => {
addUser.mockImplementation(() =>
jest.fn().mockRejectedValue(new Error('Sample error'))
)
const enqueueSnackbar = jest.fn()
useSnackbar.mockReturnValue({ enqueueSnackbar })
const { emailInput, form, submitButton } = setup()
await act(async () => {
fillIn(emailInput, 'sample#mail.com')
})
expect(emailInput.value).toBe('sample#mail.com')
expect(submitButton).toHaveProperty('disabled', false)
await act(async () => {
fireEvent.submit(form)
})
expect(enqueueSnackbar).toHaveBeenCalledTimes(1)
expect(enqueueSnackbar).toHaveBeenCalledWith(`Sample error`, {
variant: 'error'
})})
Does anyone know how to make it work?
This seems to be the #1 question that is found when someone Googles "Cannot read property 'createEvent' of null", so leaving this answer here for those readers:
For me this error came in the midst of a test.
When executing a series of tests, some test or the other used to fail with this error, with no indication of where things went wrong. But the answer turned out to be not the test but the component itself:
It was an unmocked API call.
There was an API call being made in a hook and that hook was used in the component with the failing tests. Obviously Jest cleaned up everything after completing its test, and when the call returned, it found nothing so it errored out.
Mocking the hook solved the issue.
If someone comes across such an error, make sure to mock any asynchronous logic you have, especially if it interacts with the DOM when it returns.
Similar to what #alexandre_anicio stated. I was getting this error when using the findAllByText query.
expect(screen.findAllByText('word'))...
When I switched to the getAllByText the error went away and the test passed.
expect(screen.getAllByText('word'))...
If I used expect(await screen.findAllByText('word'))... I noticed the test passed as well.
Digging deeper, this is because findBy tests return a promise so the await is needed. https://testing-library.com/docs/guide-disappearance/#1-using-findby-queries
It would have been nice for the library to throw a better error however.
This seems to work for me but I can't explain it. Try removing your act() wrapper, and use await immediately after calling the fireEvent function.
fireEvent.submit(form);
await wait();
When I encountered this same error message, I discovered I had forgotten to declare my test function as async after I updated the expectation to include await.
waitFor already uses act under the hood so there's no need to use the act blocks there.
I recognize the error you mentioned but the way I replicate it is using waitFor without await, something like this:
it('works', async() => {
render(<SomeComponent />);
// (some setup here)
waitFor(() => { // notice that we are not awaiting this promise
expect(someChange).toBeInTheDocument();
});
});
Could you try
it('receives invalid value and throws an error', async () => {
addUser.mockImplementation(() =>
jest.fn().mockRejectedValue(new Error('Sample error'))
)
const enqueueSnackbar = jest.fn()
useSnackbar.mockReturnValue({ enqueueSnackbar })
const { emailInput, form, submitButton } = setup()
fillIn(emailInput, 'sample#mail.com') // This is using some fireEvent under the hood right?
await waitFor(() => {
expect(emailInput.value).toBe('sample#mail.com')
expect(submitButton).toHaveProperty('disabled', false)
});
fireEvent.submit(form)
await waitFor(() => {
expect(enqueueSnackbar).toHaveBeenCalledTimes(1)
expect(enqueueSnackbar).toHaveBeenCalledWith(`Sample error`, {
variant: 'error'
})
});
})
Similar issue and error messages, adding await before userEvent did the trick
Before
userEvent.upload(screen.getByRole('button'), ...)
userEvent.upload(screen.getByLabelText('Upload'), FILE)
After
await userEvent.upload(screen.getByRole('button'), ...)
await userEvent.upload(screen.getByLabelText('Upload'), FILE)
I had some problems using mockImplementation(() => Promise) (returning some promise) and the await waitFor(()=> ...) at the same time.
If you are using react-testing-library, you can work around this problem using findBy query, that are a combination of getBy queries and waitFor. The only downside is that you have to find something visual (a text, data-test-id, label, etc...) that can tell you that the mock function have been called. On your code you can try something like this:
it('receives invalid value and throws an error', async () => {
addUser.mockImplementation(() =>
jest.fn().mockRejectedValue(new Error('Sample error'))
)
await screen.findByText('Sample Error message reflected in your component')
... rest of your tests ...
})
1. await waitFor(() => expect(history.location.pathname).toBe('/auth'))
2. await waitFor(() => expect(history.location.pathname)).toBe('/auth')
It's about something else but the same error. Spent 2 hours so you don't have to :)
The second one with the parenthesis in the wrong place was the culprit
I was getting
/…/node_modules/.pnpm/react-dom#17.0.2_react#17.0.2/node_modules/react-dom/cjs/react-dom.development.js:3905
var evt = document.createEvent('Event');
^
TypeError: Cannot read property 'createEvent' of null
at Object.invokeGuardedCallbackDev (/…/node_modules/.pnpm/react-dom#17.0.2_react#17.0.2/node_modules/react-dom/cjs/react-dom.development.js:3905:26)
at invokeGuardedCallback (/…/node_modules/.pnpm/react-dom#17.0.2_react#17.0.2/node_modules/react-dom/cjs/react-dom.development.js:4056:31)
at flushPassiveEffectsImpl (/…/node_modules/.pnpm/react-dom#17.0.2_react#17.0.2/node_modules/react-dom/cjs/react-dom.development.js:23543:11)
at unstable_runWithPriority (/…/node_modules/.pnpm/scheduler#0.20.2/node_modules/scheduler/cjs/scheduler.development.js:468:12)
at runWithPriority$1 (/…/node_modules/.pnpm/react-dom#17.0.2_react#17.0.2/node_modules/react-dom/cjs/react-dom.development.js:11276:10)
at flushPassiveEffects (/…/node_modules/.pnpm/react-dom#17.0.2_react#17.0.2/node_modules/react-dom/cjs/react-dom.development.js:23447:14)
at Object.<anonymous>.flushWork (/…/node_modules/.pnpm/react-dom#17.0.2_react#17.0.2/node_modules/react-dom/cjs/react-dom-test-utils.development.js:992:10)
at Immediate.<anonymous> (/…/node_modules/.pnpm/react-dom#17.0.2_react#17.0.2/node_modules/react-dom/cjs/react-dom-test-utils.development.js:1003:11)
at processImmediate (internal/timers.js:461:21)
Tracked down to an import statement.
I was able to "fix" it by changing:
import { AddCircle, RemoveCircle } from '#mui/icons-material';
to
import AddCircle from '#mui/icons-material/AddCircle';
import RemoveCircle from '#mui/icons-material/RemoveCircle';
Crazy.
If the error is because of wrong usage of jest's findBy* instead of async/await you can also return promise:
it('test', () => {
expect.assertions(1);
return screen
.findByTestId('iiError')
.then(elem =>
expect(elem).toHaveTextContent(
"This is error message"
)
);
});
Do not forget about expect.assertions and return!
Ref: https://jestjs.io/docs/tutorial-async
I had the same issue, the culprit in my case was that the rendered React component was unmounted with .unmount(). A running API call triggered a callback and React tried to update the DOM, that was already unmounted.
Since this is the top result on Google for this issue, I'll add my own answer. For me, this issue was happening on Circle CI when my tests were running. The Circle CI server ran the tests more slowly because it's CPU is limited, so a long-running test with lots of userEvent.types in it was exceeding the default timeout of 5 seconds.
I don't know why it didn't give an error about exceeding the timeout, but this thread helped me track it down.
All I had to do was increase the timeout on the long-running test.
Error occurred for me because I had work scheduled from useEffect that resolved after the rest was torn down.
The solution is to await Promise.sleep() after each test.
I was facing the same issue
It had to something with the async function not completing before the test case completes
I solved this using await flushMicrotasksQueue()
in my code
Let's say I have a function:
const someAction = async(): Promise<string> => {
/* do stuff */
};
And I have some code that just needs to run this action, ignoring the result. But I have a bug - I don't want for action to complete:
someAction();
Which, instead, should've been looked like this:
await someAction();
Now, I can check that this action was ran:
const actionStub = sinon.stub(someAction);
expect(actionStub).to.have.been.calledWith();
But what's the most concise way to check that this promise have been waited on?
I understand how to implement this myself, but I suspect it must have already been implemented in sinon or sinon-chai, I just can't find anything.
I can certainly say that nothing like this exists in sinon or sinon-chai.
This is a difficulty inherent to testing any promise-based function where the result isn't used. If the result is used, you know the promise has to be resolved before proceeding with said result. If it is not, things get more complex and kind of outside of the scope of what sinon can do for you with a simple stub.
A naive approach is to stub the action with a fake that sets some variable (local to your test) to track the status. Like so:
let actionComplete = false;
const actionStub = sinon.stub(someAction).callsFake(() => {
return new Promise((resolve) => {
setImmediate(() => {
actionComplete = true;
resolve();
});
});
});
expect(actionStub).to.have.been.calledWith();
expect(actionComplete).to.be.true;
Of course, the problem here is that awaiting any promise, not necessarily this particular one, will pass this test, since the variable will get set on the next step of the event loop, regardless of what caused you to wait for that next step.
For example, you could make this pass with something like this in your code under test:
someAction();
await new Promise((resolve) => {
setImmediate(() => resolve());
});
A more robust approach will be to create two separate tests. One where the promise resolves, and one where the promise rejects. You can test to make sure the rejection causes the containing function to reject with the same error, which would not be possible if that specific promise was not awaited.
const actionStub = sinon.stub(someAction).resolves();
// In one test
expect(actionStub).to.have.been.calledWith();
// In another test
const actionError = new Error('omg bad error');
actionStub.rejects(actionError);
// Assuming your test framework supports returning promises from tests.
return functionUnderTest()
.then(() => {
throw new Error('Promise should have rejected');
}, (err) => {
expect(err).to.equal(actionError);
});
Some assertion libraries and extensions (maybe chai-as-promised) may have a way of cleaning up that use of de-sugared promises there. I didn't want to assume too much about the tools you're using and just tried to make sure the idea gets across.
I have some async functions that I need to test via Intern. Each uses ES6 promises.
In the Intern docs, it says that test functions that return a promise pass as soon as that promise is resolved. However, I not only care about whether the async function I am testing is resolved/rejected, I also want to check to make sure the resolved value is correct.
Example: I have my function:
function getSomething() {
return new Promise((resolve, reject) => {
// do some async stuff and resolve when done
setTimeout(function() {
resolve('the value');
}, 1000);
});
}
Then I have the test method:
tdd.test('getSomething', function() {
return new Promise((resolve, reject) => {
getSomething().then(function(value) {
// I want to resolve/reject the promise BASED ON the assertion -- if the assertion fails, I want to reject the promise; if it succeeds, I want to resolve it
assert.equal(value, 'the value', 'getSomething should return "the value".');
resolve();
});
});
}
I've noticed this doesn't work -- if the assertion fails in my test, the resolve() never gets called.
How would I be able to resolve/reject the promise conditioned upon the assertion? Should I wrap the assertion in a try/catch? I didn't see any documentation on the Intern docs about this (and most were using this.async() instead of ES6 promises).
What's happening in your code is that the assertion in the getSomething callback is throwing an exception, and that's preventing resolve from being called. The getSomething promise will be rejected, but since you're not returning it in the wrapper promise's initializer, the wrapper promise is never resolved or rejected.
There is no need to wrap the promise returned by getSomething in a new promise. Just return it directly.
I thought I had it all figured out regarding Promise, but this one actually throws me out of bed. When creating a new Promise with a executor taking two arguments, why is this method running before I either take then() or catch() at that promise
Running node 6.2.2.
import assert = require('assert');
describe("When working with promises", () => {
let ar = [1, 2, 3, 4, 5, 6];
beforeEach(() => {
})
it("should be perfectly fine but isn't when mapping to promises", (done) => {
ar.map(num => {
return new Promise((resolve, reject) => {
done(new Error('Why on earth is ' + num + ' called'));
})
})
done();
})
it("should be perfectly fine when mapping to methods", (done) => {
ar.map(num => {
return (resolve, reject) => {
done(new Error(num + ' is not called ever'));
}
})
done();
})
});
First test fails, and second test is successful.
If you check the documentation for Promise, you will find that the function that is given to the constructor is run immediately. It is supposed to kick off the asynchronous calculation and install the two callbacks there (so that resolve and reject are not invoked just now, but whenever that calculation completes or fails).
The Promise function is not the asynchronous calculation, it just wraps that calculation and the two callbacks you need to keep track of it together into a nice package (and returns immediately after this setup is done).
Your second example creates an anonymous function for each number, but does not invoke any of them.
why is this method running before I either take then() or catch() at that promise
The Promise does not care if you install any handlers/chains. The calculation will have been started (or not) no matter if anyone is watching it or not.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise:
[...] The executor function is executed immediately by the Promise implementation, passing resolve and reject functions [...].
That's the way, the Promise implementation works. You can also create a new promise and attach chained then() or catch() handlers later when the promise already succeeded or failed.
const p = new Promise(someExecutor);
// do some other things
p.then(someHandler);
// do some other things
p.catch(someOtherHandler);
If you do not want the executor to execute, yet, then don't pass it to the Promise constructur, yet.
To achieve the same behavior you have to wrap promises in a factory. You can use a lambda functions for that.
it("should be perfectly fine but isn't when mapping to promises", (done) => {
ar.map(num => {
return () => new Promise((resolve, reject) => {
done(new Error('Why on earth is ' + num + ' called'));
})
})
done();
})
So you have stateless factories to call later without creating promises (that run immediately) during map.
It permits you to compose and join Promises for later batch execution using Promise.all, Promise.race, or custom chaining.
If you want something to run only (i.e. not before) a "then()" handler is attached, then you can use plain then-ables ( https://promisesaplus.com/ )
var runLater = {
then: function(resolve, reject) {
var p = new Promise (...); // Creating a promise is optional
resolve(p); // you can return a plain value
}
}
Note this is not a Promise, so it does not have a "catch" method.
But it can be given to any function expecting a promise:
`Promise.all([runLater])
return as result from a then handled .then(function() { return runLater; })
Promise.resolve(runLater) => Now it is a promise with then/catch
Any of those will call the runLater.then method.