I added a DateTimePicker to my app which seems to work, however, I'm unable to mock the picker in my Jest tests.
I keep getting the following error:
Test suite failed to run
TypeError: (0 , _material.generateUtilityClasses) is not a function
7 | import type { Property, EnumProperty } from "../../types";
> 8 | import { DateTimePicker } from "#mui/x-date-pickers/DateTimePicker";
| ^
9 | import { DateTime } from "luxon";
at Object.<anonymous> (node_modules/#mui/x-date-pickers/node/internals/components/PickersToolbarText.js:32:54)
at Object.<anonymous> (node_modules/#mui/x-date-pickers/node/DateTimePicker/DateTimePickerToolbar.js:20:27)
at Object.<anonymous> (node_modules/#mui/x-date-pickers/node/DesktopDateTimePicker/DesktopDateTimePicker.js:20:30)
at Object.<anonymous> (node_modules/#mui/x-date-pickers/node/DesktopDateTimePicker/index.js:13:30)
at Object.<anonymous> (node_modules/#mui/x-date-pickers/node/DateTimePicker/DateTimePicker.js:22:30)
at Object.<anonymous> (node_modules/#mui/x-date-pickers/node/DateTimePicker/index.js:13:23)
at Object.<anonymous> (src/components/myFile/myFile.tsx:8:1)
I've tried each of the following, but can't get jest to detect the mock.
jest.mock("#mui/x-date-pickers", () => require("../../../__mocks__/x-date-pickers"));
jest.mock("#mui/x-date-pickers", () => (
<div>
Hello
</div>
));
jest.mock("#mui/x-date-pickers");
Below is the line throwing the error. It's just a regular import statement:
import { DateTimePicker } from "#mui/x-date-pickers/DateTimePicker";
My mocked file at the location "../../../mocks/x-date-pickers" relative to the unit test file. I'm not expecting the mock to work yet, but I'm at least expecting it to be picked up.
import React from "react";
import { DateTimePickerProps } from "#mui/x-date-pickers";
export const DateTimePicker = (props: DateTimePickerProps) => (
<input
data-testid="mockedDateField"
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
props.onChange(event.target.value);
}}
/>
);
Any help would be appreciated!
The problem was I needed to add DateTimePicker to the end of my mock:
jest.mock("#mui/x-date-pickers/DateTimePicker", () => require("../../../__mocks__/x-date-pickers"));
Related
I get an error when testing with jest on code that imports a homegrown library.
Other than jest, the other processes are successful, how can I make the test succeed?
FAIL src/pages/e2e.spec.tsx
● Test suite failed to run
Cannot find module 'components/layout/Layout' from 'src/pages/index.tsx'
Require stack:
src/pages/index.tsx
src/pages/e2e.spec.tsx
> 1 | import { Layout } from 'components/layout/Layout'
| ^
2 | import { HomepageComponent } from 'components/parts/home'
3 | import { useSearchMedicines } from 'hooks/api/product/useSearchMedicines'
4 | import { useRouter } from 'next/router'
at Resolver._throwModNotFoundError (node_modules/jest-resolve/build/resolver.js:427:11)
at Object.<anonymous> (src/pages/index.tsx:1:1)
at Object.<anonymous> (src/pages/e2e.spec.tsx:7:1)
try
commnad:
npm test
code
import { render, screen } from '#testing-library/react'
import userEvent from '#testing-library/user-event'
import { Layout } from 'components/layout/Layout'
import styled from '#emotion/styled'
import { Header } from 'components/parts/common/header'
import { useTranslationText } from 'locale'
import Home from './index'
describe('Home', () => {
it('should display search results', async () => {
// Render the Home component
render(<Home />)
// Search for a new keyword
const searchInput = screen.getByRole('textbox')
userEvent.clear(searchInput)
userEvent.type(searchInput, 'new keyword')
userEvent.click(screen.getByRole('button'))
// Wait for new search results to load
const newMedicineNames = await screen.findAllByTestId('medicine-name')
expect(newMedicineNames.length).greaterThan(0)
expect(newMedicineNames[0]).not.equal(medicineNames[0])
})
})
expect
test success
Test Suites: 0 failed, 1 passed, 1 total
Tests: 0 failed, 1 passed, 1 total
this is what I have in my test file and have no idea how to fix it was searching everywhere could not find the solution
import { render } from '#testing-library/react';
import { ImageGallery } from '../index';
describe('Swiper has to render', () => {
test('Will Swiper render', () => {
const { asFragment } = render(<ImageGallery />);
expect(asFragment()).toMatchSnapshot();
});
});
having this in my test file
having an error
like that
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
SyntaxError: Unexpected token 'export'
1 | /* eslint-disable import/no-unresolved */
2 | import React, { useState, useCallback } from 'react';
> 3 | import { Swiper, SwiperSlide } from 'swiper/react';
| ^
4 | import ImageViewer from 'react-simple-image-viewer';
5 |
6 | import 'swiper/css/bundle';
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1728:14)
at Object.<anonymous> (src/components/ImageGallery/ImageGallery.js:3:1)
Issue on facebook/jest
Currently working on a project where I need to dynamically load other components in the main application system, I'm facing an issue with some error that throws a Jest Invariant constraint violation when trying to import dynamically a module.
An example is accessible at https://gitlab.com/matthieu88160/stryker-issue
In this project, I have a class used to load a component and another that will use the ComponentLoader and add some check and post-processing (this part of the code is not present in the accessible project).
In the GitLab job, two test suites are executed and one fails. My problem is that the two test suites are exactly the same, obviously, I copy-pasted the first one to create. The second one and by the way demonstrate the issue.
I already tried some workaround found on the web without any success.
Here is the code of the component I try to test :
import {existsSync} from 'fs';
import {format} from 'util';
export default class ComponentLoader
{
static load(file) {
if(existsSync(file)) {
return import(file);
}
throw new Error(
format('Component file "%s" does not exist. Cannot load module', file)
);
}
}
And the test itself:
import {describe, expect, test} from '#jest/globals';
import {format} from 'util';
import {fileURLToPath} from 'url';
import {dirname} from 'path';
import mock from 'jest-mock';
describe(
'ComponentLoader',
() => {
describe('load', () => {
test('load method is able to load a component from a file', () => new Promise(
resolve => {
Promise.all(
[import('../src/ComponentLoader.mjs'), import('./fixture/component/A1/component.fixture.mjs')]
).then(modules => {
const file = format(
'%s/./fixture/component/A1/component.fixture.mjs',
dirname(fileURLToPath(import.meta.url))
);
modules[0].default.load(file).then(obj => {
expect(obj).toBe(modules[1]);
resolve();
});
});
})
);
});
}
);
And here the error report:
PASS test/ComponentLoaderA.test.mjs
FAIL test/ComponentLoaderB.test.mjs
● ComponentLoader › load › load method is able to load a component from a file
15 | static load(file) {
16 | if(existsSync(file)) {
> 17 | return import(file);
| ^
18 | }
19 |
20 | throw new Error(
at invariant (node_modules/jest-runtime/build/index.js:2004:11)
at Function.load (src/ComponentLoader.mjs:17:13)
at test/ComponentLoaderB.test.mjs:21:44
The interesting element from my point of view is the fact the ComponentLoaderA.test.mjs and the ComponentLoaderB.test.mjs are exactly the same.
The full error trace I found is:
CComponentLoader load load method is able to load a component from a file
Error:
at invariant (importTest/.stryker-tmp/sandbox7042873/node_modules/jest-runtime/build/index.js:2004:11)
at Runtime.loadEsmModule (importTest/.stryker-tmp/sandbox7042873/node_modules/jest-runtime/build/index.js:534:7)
at Runtime.linkModules (importTest/.stryker-tmp/sandbox7042873/node_modules/jest-runtime/build/index.js:616:19)
at importModuleDynamically (importTest/.stryker-tmp/sandbox7042873/node_modules/jest-runtime/build/index.js:555:16)
at importModuleDynamicallyWrapper (internal/vm/module.js:443:21)
at exports.importModuleDynamicallyCallback (internal/process/esm_loader.js:30:14)
at Function.load (importTest/.stryker-tmp/sandbox7042873/src/ComponentLoader.mjs:89:11)
at importTest/.stryker-tmp/sandbox7042873/test/ComponentLoaderB.test.mjs:22:37
at new Promise (<anonymous>)
at Object.<anonymous> (importTest/.stryker-tmp/sandbox7042873/test/ComponentLoaderB.test.mjs:14:79)
It seems the error does not have any message.
Further information from the jest-runtime investigation :
It seems that between the tests, the sandbox context is lost for a reason I cannot be able to manage to find at the moment.
In node_modules/jest-runtime/build/index.js:2004:11 :
The condition is NULL, the error is then thrown without a message.
function invariant(condition, message) {
if (!condition) {
throw new Error(message);
}
}
In node_modules/jest-runtime/build/index.js:534:7 :
The context is NULL, and no message given, creating my empty error message.
const context = this._environment.getVmContext();
invariant(context);
The toString() of this._environment.getVmContext method as follow:
getVmContext() {
return this.context;
}
The current _environment presents a null context :
NodeEnvironment {
context: null,
fakeTimers: null,
[...]
}
The deeper point I can reach is this code where the context appear to be null :
const module = new (_vm().SourceTextModule)(transformedCode, {
context,
identifier: modulePath,
importModuleDynamically: (specifier, referencingModule) => {
return this.linkModules(
specifier,
referencingModule.identifier,
referencingModule.context
)},
initializeImportMeta(meta) {
meta.url = (0, _url().pathToFileURL)(modulePath).href;
}
});
The context variable is not empty and _vm().SourceTextModule is a class extending Module.
I can notice in the importModuleDynamically execution using console.log(this._environment) that the context is currently null.
The Spied on code is not called when the test is at the second position. (or a second render) and test case fails
Test case passes if the test case is at the first position(or on first render).
Using a very basic create-react-app OOTB example and simplifying it even more for a MCVE:
MyModule.js
import React from 'react';
import someClass from './someClass';
function App() {
someClass.track("someevent");
return null;
}
export default App;
someClass.js
class SomeClass {
constructor() {
this.someProp = null;
}
getSatellite() {
return {
track: () => {}
};
}
track(someProp) {
///THIS BELOW IF CLAUSE IS THE PROBLEM
if (this.someProp === someProp) {
return;
} else {
this.someProp = someProp;
}
///////////////////////
this.getSatellite().track('someevent');
}
}
const instance = new SomeClass();
export default instance;
App.js
import React from 'react';
import MyModule from './MyModule'
function App() {
return (
<div className="App">
<MyModule />
</div>
);
}
export default App;
App.test.js
import React from 'react';
import { render } from '#testing-library/react';
import App from './App';
import someClass from './someClass';
test('renders learn react link', () => {
render(<App />);
});
// it works if this test case is first one, weird :-|
test('renders class', () => {
const track = jest.fn();
jest.spyOn(someClass, 'getSatellite').mockImplementation(()=>{
console.log('here i am');
return {
track
}
})
render(<App />);
expect(track).toHaveBeenCalledTimes(1);
});
Output:
✓ renders learn react link (17ms)
✕ renders class (5ms)
● renders class
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
18 | })
19 | render(<App />);
> 20 | expect(track).toHaveBeenCalledTimes(1);
| ^
21 | });
22 |
at Object.<anonymous> (src/App.test.js:20:17)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 10.472s
Let me know if you need anything in the comments.
In the first render(<App />) the someProp of someClass is being set as someevent.
Now in the next render I am only mocking the function call, but not resetting the someProp. That's why the if (this.someProp === someProp) is taking effect.
So I need to reset the someProp to another value or null and it will work fine.
I have a very simple app.ts file that looks like this:
import { Navigation, WebDriver } from "selenium-webdriver";
class MyWebDriver extends WebDriver {
navigate(): Navigation {
return new MyNavigation(this);
}
}
class MyNavigation extends Navigation {
constructor(driver: WebDriver) {
super(driver);
}
}
I have also installed the NPM package selenium-webdriver#4.0.0-alpha5 and I'm using NodeJS version 10.15.3.
Now when I build the project and run the app.js file on the command line, I get the following circular dependency exception:
C:\temp\MyTestNodejsProject>node app.js
C:\temp\MyTestNodejsProject\app.js:9
class MyNavigation extends selenium_webdriver_1.Navigation {
^
TypeError: Class extends value undefined is not a constructor or null
at Object.<anonymous> (C:\temp\MyTestNodejsProject\app.js:9:49)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
The above circular dependency exception is complaining about line 9 of the app.js file below:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const selenium_webdriver_1 = require("selenium-webdriver");
class MyWebDriver extends selenium_webdriver_1.WebDriver {
navigate() {
return new MyNavigation(this);
}
}
class MyNavigation extends selenium_webdriver_1.Navigation {
constructor(driver) {
super(driver);
}
}
//# sourceMappingURL=app.js.map
Can someone please help me figure out how to fix this circular dependency? I've spent days on this and don't see where the circular dependency is happening. Please provide a working code snippet.
============ EDIT =============
I did a sanity check to make sure that Navigation was properly imported (to make sure that wasn't the issue) and modified the code to be:
import { Navigation, WebDriver } from "selenium-webdriver";
class MyWebDriver extends WebDriver {
navigate(): Navigation {
return new Navigation(this);
}
}
Then when I built & ran app.js, the circular dependency exception went away, and app.js ran just fine.