Closed vicusbass closed 4 years ago
Is this a fresh Next.js project? I had worked a little bit on Next, but the way it exposes Webpack options is async, so it is not really that easy :(
@bahmutov Yes, a new project, latest Next.js. Unfortunately, it's not a public project. I could create a "test project" if needed.
We have an ejected react-scripts app with typescript support and we get react is not defined
error as well. Would love help to make it work...
Edit: We actually resolved after DEBUG=cypress-react-unit-test,find-webpack yarn cy:open
showed that it could not find the webpack config. Problem was we actually did not have react-scripts
as a dependency anymore. After adding it, cypress/find-webpack can find the config
Can something like this work?
const { PHASE_PRODUCTION_BUILD } = require('next/constants')
const { findPagesDir } = require('next/dist/lib/find-pages-dir')
const loadConfig = require('next/dist/next-server/server/config').default
const getWebpackConfig = require('next/dist/build/webpack-config').default
const CWD = process.cwd()
async function webpackFinal(config = {}) {
const pagesDir = findPagesDir(CWD)
const nextConfig = await loadConfig(PHASE_PRODUCTION_BUILD, CWD)
const nextWebpackConfig = await getWebpackConfig(CWD, {
pagesDir,
entrypoints: {},
isServer: false,
target: 'server',
config: nextConfig,
// buildId: 'storybook',
})
config.plugins = [...nextWebpackConfig.plugins]
config.resolve = {
...config.resolve,
...nextWebpackConfig.resolve,
}
return config
}
const config = {
plugins: []
}
webpackFinal(config).then(console.log, console.error)
I have a similar issue and am trying to get cypress-react-unit-test working with my Next.js project.
Can something like this work?
const { PHASE_PRODUCTION_BUILD } = require('next/constants') const { findPagesDir } = require('next/dist/lib/find-pages-dir') const loadConfig = require('next/dist/next-server/server/config').default const getWebpackConfig = require('next/dist/build/webpack-config').default const CWD = process.cwd() async function webpackFinal(config = {}) { const pagesDir = findPagesDir(CWD) const nextConfig = await loadConfig(PHASE_PRODUCTION_BUILD, CWD) const nextWebpackConfig = await getWebpackConfig(CWD, { pagesDir, entrypoints: {}, isServer: false, target: 'server', config: nextConfig, // buildId: 'storybook', }) config.plugins = [...nextWebpackConfig.plugins] config.resolve = { ...config.resolve, ...nextWebpackConfig.resolve, } return config } const config = { plugins: [] } webpackFinal(config).then(console.log, console.error)
This does output a webpack config. But when I copy the output into a webpack.config.js
file and load it like in this example, I get the following error in a cypress unit test:
WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration.plugins[0] misses the property 'apply'.
function
-> The run point of the plugin, required method.
- configuration.plugins[1] misses the property 'apply'.
function
-> The run point of the plugin, required method.
- configuration.resolve.plugins[0] misses the property 'apply'.
function
-> The run point of the plugin, required method.
Hello there! Has there been any development on this issue? Just wondering. Its an amazing lib and really want to make it my all stop shop for testing my react / nextjs apps. Thanks!
I manage to get working next.js with cypress https://github.com/leosuncin/mui-next-ts/tree/wip/crud-api I use typescript and absolute paths, but the main parts are in the webpack config
const options = {
webpackOptions: {
resolve: {
extensions: ['.ts', '.tsx', '.js'], // Not only load *.spec.js files also *.spec.ts and *.spec.tsx
alias: { // Typescript alias, I defined here because Cypress fail to load when only set in tsconfig.json
components: path.resolve(__dirname, '../../components/'),
services: path.resolve(__dirname, '../../services/'),
libs: path.resolve(__dirname, '../../libs/'),
machines: path.resolve(__dirname, '../../machines/'),
middlewares: path.resolve(__dirname, '../../middlewares/'),
hooks: path.resolve(__dirname, '../../hooks/'),
pages: path.resolve(__dirname, '../../pages/'),
},
modules: [path.resolve(__dirname, '../..'), 'node_modules'], // THIS IS IMPORTANT: Make works the absolute paths inside components
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader', // Load typescript files
options: { transpileOnly: true },
},
],
},
},
};
The tsconfig.json
{
"extends": "../tsconfig.json",
"include": ["**/*.ts"],
"exclude": ["../node_modules"],
"compilerOptions": {
"isolatedModules": false,
"target": "es6",
"module": "es6",
"jsx": "react", // THIS IS IMPORTANT: Enable JSX transpilation
"baseUrl": "..", // Set baseUrl to up directory
"paths": { // Absolute paths
"components": ["components/*"],
"services": ["services/*"],
"libs": ["libs/*"],
"machines": ["machines/*"],
"middlewares": ["middlewares/*"],
"hooks": ["hooks/*"],
"pages": ["pages/*"],
"utils": ["utils/*"]
},
"types": [
"cypress",
"@testing-library/cypress"
]
}
}
The simple solution to React is not defined
is to import React inside every component (Next.js internally auto import in every component by default), but I got the same error with Jest and found the easy one is to import React.
Still I have some minor problems, like I can't import components using absolute paths inside test components
https://github.com/leosuncin/mui-next-ts/blob/wip/crud-api/cypress/component/login-form.test.tsx
I still experimenting with this
Hey @leosuncin ,
Two questions:
1 - if I dont use the absolute paths, I guess i dont have to worry about that right? And then same things for the aliases in the webpack options, right?
2 - Why is the baseUrl ..
? Just out of curiosity.
Will try this out today
1- Yes, you don't need to worry, you can omit that part
const options = {
webpackOptions: {
resolve: {
extensions: ['.ts', '.tsx', '.js'], // Not only load *.spec.js files also *.spec.ts and *.spec.tsx
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader', // Load typescript files
options: { transpileOnly: true },
},
],
},
},
};
{
"extends": "../tsconfig.json",
"include": ["**/*.ts"],
"exclude": ["../node_modules"],
"compilerOptions": {
"isolatedModules": false,
"target": "es6",
"module": "es6",
"jsx": "react", // THIS IS IMPORTANT: Enable JSX transpilation
"types": [
"cypress",
"@testing-library/cypress"
]
}
}
2- Is the project root, under cypress directory I need to go up one directory
# Project root
├── babel.config.js
├── components
│ ├── cards
│ └── todo
├── cypress
│ ├── component
│ ├── fixtures
│ ├── integration
│ ├── plugins
│ ├── README.md
│ ├── screenshots
│ ├── support
│ ├── tsconfig.json <-- You are here
│ └── videos
├── cypress.json
├── cypress-unit.json
├── jest.config.js
├── jest.setup.ts
├── next.config.js
├── next-env.d.ts
├── package.json
├── pages
│ ├── api
│ ├── _app.tsx
│ ├── _document.tsx
│ └── index.tsx
├── README.md
├── __tests__
│ ├── components
│ └── pages
├── tsconfig.json
└── tsconfig.test.json
I had to install a couple of dependencies I wasnt expecting but it is working 🙌
I have two questions @leosuncin How would you test something like a router.push from nextjs? Just curious on how to do that. trying to test a login that after successful login that redirects
And another thing i dont get (might be more of a cypress thing instead or just testing) - but you are passing the onSubmit directly to the login component. If I have this inside the whole component and the logic is inside the component itself how would you test that that functon works. would you mock a fetch / axios call? or would you use a stub to intercept the http calls and generate failure and success cases for the tests?
Thanks!
I don't know how to mock next/router
I have a login form that have a Link
component that throws an error because it can't find the Router provider, what I did was mute that error since I don't need to test the router behavior and the form is render anyway.
I had other test component that make network requests, so I stub the network request with cy.route
; also I enabled the experimental fetch polyfil, since I use fetch to make the requests.
https://github.com/leosuncin/mui-next-ts/blob/wip/crud-api/cypress/component/todo.test.tsx
:tada: This issue has been resolved in version 4.14.0 :tada:
The release is available on:
Your semantic-release bot :package::rocket:
When running a unit test for a React component in a Nextjs project, mounting the component fails because
React is not defined
. My guess is it has something to do with the way Nextjs is handling webpack. It works correctly only if React is explicitely imported in the component module, which is not required by Nextjs.