Closed ceafive closed 9 months ago
This generally suggests that you have some kind of a build tool setup / configuration problem.
What build tools are you using?
Can you share a Github repo that shows this problem happening?
edit sorry, just realized you said "it works fine when running, but fails with tests". What test tool and version are you using?
Unfortunately can't share a Github repo. Build tools: ejected CRA with Webpack 5. We use Jest v29.5.0
Not sure what to tell you without some kind of reproduction to look at, other than to try logging reselect
and createSelector
in that file and see what's actually being imported. It's definitely some kind of a module loading / import issue.
So I get reselect.cjs
when I console.log reselect
and I get undefined
when i console.log reselect.createSelector
as in, you're getting a string of "reselect.cjs"
?
If so, yeah, that's 100% broken. I would expect it to either be an object, or undefined.
I still don't have an answer for why this is happening - I'd need to see a repro to be able to investigate what's going on.
To be clear, this sounds like it's an issue with Jest and loading the module, specifically.
Yeah getting a string of reselect.cjs
. This is how 5.1.0 looks like in node_modules
This is how 4.1.8 looks like in node_modules
Yeah, both of those are expected - we changed the packaging setup for Reselect 5, and we tested it pretty thoroughly against a variety of build tools.
All I can say atm is that apparently something is causing Jest to drastically misinterpret the library, but I don't know what. If you can provide a repo that demonstrates this happening, I can take a look, but without that I can't do anything.
Like, does this happen in a brand new repo with Jest 19 + Reselect? Does this only happen in your repo? Do you have a Jest config that's doing a bunch of complex setup, or is it basic Jest out of the box?
can you share what your jest.config.js
looks like?
Here you go @aryaemami59
import fs from "fs"
import type {Config} from "@jest/types"
import {projects} from "./tools/jest/project-definitions"
type ArrayElement<A> = A extends readonly (infer T)[] ? T : never
type SingleJestProjectType = Exclude<ArrayElement<Config.InitialOptions["projects"]>, string>
const genReactAppJestConfig = (
_pkg: Record<string, any>,
projectPath: string,
srcDir: string,
): SingleJestProjectType => {
const setupFiles = [fs.existsSync(`${projectPath}/setupTests.ts`) && `${projectPath}/setupTests.ts`].filter(
Boolean,
) as string[]
const setupFilesAfterEnv = [
fs.existsSync(`${projectPath}/setupTestsAfterEnv.ts`) && `${projectPath}/setupTestsAfterEnv.ts`,
].filter(Boolean) as string[]
return {
rootDir: `${projectPath}${srcDir}`,
roots: [`${projectPath}${srcDir}`],
setupFiles,
setupFilesAfterEnv,
moduleNameMapper: {
"@mockData/(.*)": `${projectPath}/__mocks__/$1`,
"^@app/(.*)$": `<rootDir>/$1`,
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy",
"\\.(css|less|sass|scss)$": path.resolve(__dirname, "./config/jest/cssMock.js"),
"@next/core-logger": "@next/core-logger/lib/client",
"^@manifest/constants$": `<rootDir>/templating/constants`,
},
moduleFileExtensions: ["web.js", "js", "web.ts", "ts", "web.tsx", "tsx", "json", "web.jsx", "jsx", "node"],
modulePaths: [],
testEnvironment: "jsdom",
testMatch: [`<rootDir>/**/__tests__/**/*.{js,jsx,ts,tsx}`, `<rootDir>/**/*.{spec,test}.{js,jsx,ts,tsx}`],
// TODO: 52076 - Refactor transform ignore patterns
transformIgnorePatterns: [
"/node_modules/(?!launchdarkly-node-server-sdk|applicationinsights)/",
"\\.pnp\\.[^\\/]+$",
],
transform: {
"\\.[jt]sx?$": [
"babel-jest",
{
rootMode: "upward",
},
],
"^.+\\.css$": path.resolve(__dirname, `./config/jest/cssTransform.js`),
"^(?!.*\\.(css|json)$)": path.resolve(__dirname, `./config/jest/fileTransform.js`),
},
snapshotSerializers: ["@emotion/jest/serializer"],
}
}
const config = async (relativePathToRoot = "."): Promise<Config.InitialOptions> => {
return {
collectCoverage: true,
collectCoverageFrom: [
"**/*.{ts,tsx}",
"!**/*.cy.{ts,tsx}",
"!**/*.stories.{ts,tsx}",
"!**/*.d.ts",
"!**/templating/manifest.ts",
"!**/cypress/**",
"!**/components/plp/categoryPills/*.{ts,tsx}", // Excluded for coverage (POC)
"!**/components/plp/tabScrollNavigation/*.{ts,tsx}", // Excluded for coverage (POC)
],
coverageReporters: ["json-summary", "lcov", "text"],
watchPlugins: ["jest-watch-typeahead/filename", "jest-watch-typeahead/testname"],
projects: await Promise.all(
projects
.map(project => ({
...project,
projectDir: path.resolve(project.rootDir.replace("./", `${relativePathToRoot}/`)),
}))
.filter(project => fs.existsSync(`${project.projectDir}/package.json`))
.map(async project => {
const pkg = await import(`${project.projectDir}/package.json`)
return {
displayName: pkg.name,
...(genReactAppJestConfig(
pkg,
path.resolve(project.rootDir.replace("./", `${relativePathToRoot}/`)),
project.srcDir ?? "/src",
) as Record<string, any>),
}
})
.filter(Boolean),
),
}
}
export default config
Okay, I don't know what about that config is an issue, but given that you do have a large complex custom Jest config, I would strongly suspect the issue is in that config somewhere.
Read up on jest configs and I have found we use a fileTransform.js
that stringifies imports and that was the issue
Yep, that's roughly what I assumed to be happening. Glad you got that figured out!
I am using
createSelector
from reselect 5.1.0 and it works when I run the app but when I run my Jest tests I get an error like in the image below. I really really need help with this one. When I downgrade to 4.1.8, the tests pass but thecreateSelector
doesn't memoize properly when I run the appThis is how I am importing it