ReferenceError: You are trying to `import` a file after the Jest environment has been torn down
JavascriptReactjsReact NativeJestjsEnzymeJavascript Problem Overview
I have a component that makes use of Animated
component from react native. I started writing a test case to simulate onPress
of a component, which calls a function that has Animated.timing
in it, and setState
.
running jest
works fine, but the tests never stops running, and one unrelated test case that I've written before never seem to pass now (which passed before).
running jest --watch
, I get this error:
ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.
at Function.bezier (node_modules/react-native/Libraries/Animated/src/Easing.js:113:21)
at ease (node_modules/react-native/Libraries/Animated/src/Easing.js:34:24)
at TimingAnimation._easing (node_modules/react-native/Libraries/Animated/src/Easing.js:133:18)
at TimingAnimation.onUpdate (node_modules/react-native/Libraries/Animated/src/animations/TimingAnimation.js:107:45)
RUNS src/__tests__/SlideDownMenu.test.js
/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/Easing.js:114
return _bezier(x1, y1, x2, y2);
^
TypeError: _bezier is not a function
at Function.bezier (/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/Easing.js:224:12)
at ease (/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/Easing.js:94:21)
at TimingAnimation._easing (/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/Easing.js:255:16)
at TimingAnimation.onUpdate (/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/animations/TimingAnimation.js:138:14)
at ontimeout (timers.js:386:11)
at tryOnTimeout (timers.js:250:5)
at Timer.listOnTimeout (timers.js:214:5)
Link to repl
https://repl.it/repls/PartialGrimyMetadata
Environment:
- OS: Linux 4.14
- Node: 6.14.2
- Yarn: 1.7.0
- npm: 3.10.10
- Watchman: Not Found
- Xcode: N/A
- Android Studio: Not Found
Javascript Solutions
Solution 1 - Javascript
OK, found a solution.
Should use jest.useFakeTimers()
Note: Put the code above just after import
section in your test file.
Solution 2 - Javascript
jest.useFakeTimers()
With above it's extremely important to understand this
jest.useFakeTimers() mocks out setTimeout and other timer functions with mock functions.
If running multiple tests inside of one file or describe block, jest.useFakeTimers(); can be called before each test manually or with a setup function such as beforeEach.
Not doing so will result in the internal usage counter not being reset.
Solution 3 - Javascript
I am using @testing-library/react-native
, so what I did is to cleanup
in the setup file.
// jest.setup.js
import { cleanup } from '@testing-library/react-native';
afterEach(cleanup);
Solution 4 - Javascript
Add "testEnvironment": "jsdom"
into jest
key in package.json or jest.config.js
"jest": {
"testEnvironment": "jsdom",
"preset": "react-native",
...
taken from: https://stackoverflow.com/a/64567257/728287
Solution 5 - Javascript
I would like to contribute to the answer.
Well let's see the error message
ReferenceError: You are trying to 'import' a file after the Jest environment has been torn down.
Torn down means: Jest already finished running and some part of your code is trying to execute after jest torn down or exited your test. This is pretty common on Javascript due to its asynchronous nature.
Sometimes it happens after a promise callback getting executed for example:
import { someProcess} from 'a-library'
task.job().then(result => {
someProcess(result)
})
In the example above the code imports someProcess
from a-library
If the method job
from the task
object takes longer than the jest execution its callback (then() invocation) will run outside jest because jest has continued. Therefore when someProcess
gets executed it will be loaded from a-library
so jest will complain that you are trying to load a library after jest has been torn.
The answer marked as the solution is partially right because calling jest.useFakeTimers()
will prevent your code to wait the n seconds you supposed to wait calling setTime or similars making your code artificially sincrhonoyus
Making your test await
those method calls would help you understand better your code.
The code that worked for me was
describe("Some test set " , ()=>{
let heavyWorkinService = library.workingService();
// We are marking the test function call as async
test(("Name of the test"), async ()=>{
// we are awaiting heavyWorkingService to done its job
await hevyWorkingService("some data")
})
})
In my real scenario my code was getting data from firebase, because am not using mocks for this test it was trying to import firebase after .get() data read returned so marking the test as async
and calling the method with await
keyword solved my problem
Of course there are a lot of ways to dealing with this error, just wanted you to know the true reason behind this error so you can work in the right solution for your tests!
Solution 6 - Javascript
add the below lines at the very end of the jest test file, after all, tests are written.
afterAll(() => {
mongoose.connection.close()
})
and also just run a single test file at a time, for example,
> jest --verbose --runInBand -- filename.test.js
Solution 7 - Javascript
None of above works for me. My solution is to add to jest-setup.js file this code:
import { Animated } from 'react-native';
Animated.timing = () => ({
start: () => jest.fn(),
});
Don't forget to include this file to your package.json jest configuration:
...
"jest": {
...,
"setupFiles": [
"<rootDir>/src/tests/jest-setup.js"
]
},
...
I hope it will help anybody
Solution 8 - Javascript
I was getting this issue while testing Apollo with react-native-testing-library
.
In this case there were two queries, in a parent and child component. The parent query needed to resolve before the child rendered and fired its query.
The solution was to run the wait()
function twice rather than just once. I assume the double-fire is necessary to ensure both queries run. The error message is very opaque though.
test("...", () => {
const rr = render(...);
await wait();
await wait(); // Child query must also run
expect(...);
}
// Wait a tick so the query runs
// https://www.apollographql.com/docs/react/development-testing/testing/#testing-final-state
export async function wait(ms = 0) {
await act(async () => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
});
}
Solution 9 - Javascript
I'm using @testing-library/react-native
. On my test case, I need to call render(<MyComponent/>)
twice so I needed to add afterEach(cleanup)
that way it fixed the issue.
Solution 10 - Javascript
In my case i was using typeorm and put that code inside my jest.setup.ts
afterAll(async () => {
const connection = getConnection();
connection.close();
});
Solution 11 - Javascript
I used jest.useFakeTimers
() in beforeEach
() method inside test suit of that file
beforeEach(() => {
jest.useFakeTimers();
});