I'm trying to add Cypress to a very basic CRA, but am running in to issues with Cypress being able to understand .scss files.
When I run npm run cypress
to run the test, I receive the following error:
Error: Webpack Compilation Error
./src/App.scss 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> .app {
| align-items: center;
| display: flex !important;
@ ./src/App.jsx 28:0-21
@ ./cypress/integration/App.spec.js
...
It seems like the sass-loader isn't being used when Cypress attempts to mount the component? How can I go about fixing this?
package.json:
{
"name": "cypress_test",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"cypress": "cypress open",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"dependencies": {
"@cypress/react": "^5.12.4",
"@cypress/webpack-dev-server": "^1.8.4",
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@fontsource/roboto": "^4.5.5",
"@mui/icons-material": "^5.6.2",
"@mui/material": "^5.6.3",
"@mui/styled-engine-sc": "^5.6.1",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^13.5.0",
"cypress": "^9.6.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "5.0.1",
"sass": "^1.51.0",
"styled-components": "^5.3.5",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@babel/core": "^7.17.9",
"@babel/preset-env": "^7.16.11",
"@cypress/webpack-preprocessor": "^5.11.1",
"babel-loader": "^8.2.5",
"eslint-plugin-cypress": "^2.12.1",
"html-webpack-plugin": "^4.5.2",
"webpack": "^5.72.0"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"overrides": [
{
"extends": [
"plugin:cypress/recommended"
],
"files": [
"cypress/**/*.js"
]
}
],
"resolutions": {
"@mui/styled-engine": "npm:@mui/styled-engine-sc@latest"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"jest": {
"coveragePathIgnorePatterns": [
"<rootDir>/cypress/"
]
}
}
App.spec.js:
import React from 'react';
import data from '../fixtures/data.json';
import App from '../../src/App.jsx';
describe('Test search functionality', () => {
beforeEach(() => {
cy.mount(<App />);
});
it('renders new fact when search is performed', () => {
cy.visit('http://localhost:3001')
// Type in search input
cy.get('input').type('Test');
// Click on search button
cy.get('.submit-btn').click();
// Intercept the request and return the mock data
cy
.intercept({
method: 'GET',
url: `${process.env.REACT_APP_API_ENDPOINT}/jokes/search?query=Test`
}, {
fixture: data.result[1]
})
.as('fetchFact');
// cy.wait(['@fetchFact']);
cy.get('p.copy').should('contain', data.result[1].value);
})
});
cypress/plugins/index.js:
const injectDevServer = require('@cypress/react/plugins/react-scripts');
module.exports = (on, config) => {
injectDevServer(on, config);
return config;
};
UPDATE: After trying the solution proposed below with modifications to the plugins/index.js file, I am receiving a new error:
Error: For the selected environment is no default script chunk format available:
JSONP Array push can be chosen when 'document' or 'importScripts' is available.
CommonJs exports can be chosen when 'require' or node builtins are available.
Make sure that your 'browserslist' includes only platforms that support these features or select an appropriate 'target' to allow selecting a chunk format by default. Alternatively specify the 'output.chunkFormat' directly.
updated /cypress/plugins/index.js:
const findWebpack = require('find-webpack')
const webpackPreprocessor = require('@cypress/webpack-preprocessor');
const injectDevServer = require('@cypress/react/plugins/react-scripts');
module.exports = (on, config) => {
const webpackOptions = findWebpack.getWebpackOptions();
if (!webpackOptions) {
throw new Error('Could not find Webpack in this project');
}
const cleanOptions = { reactScripts: true };
findWebpack.cleanForCypress(cleanOptions, webpackOptions);
const options = {
webpackOptions,
watchOptions: {},
};
on('file:preprocessor', webpackPreprocessor(options));
injectDevServer(on, config);
return config;
};
I also removed the browserslist
key from my package.json.
Try this to add CRA webpack config to the plugins/index
file of cypress:
/// <reference types="cypress" />
/// <reference types="../../../.." />
// @ts-check
const findWebpack = require('find-webpack')
const webpackPreprocessor = require('../../../..')
/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on) => {
// find the Webpack config used by react-scripts
const webpackOptions = findWebpack.getWebpackOptions()
if (!webpackOptions) {
throw new Error('Could not find Webpack in this project 😢')
}
// if we just pass webpackOptions to the preprocessor
// it won't work - because react-scripts by default
// includes plugins that split specs into chunks, etc.
// https://github.com/cypress-io/cypress-webpack-preprocessor/issues/31
// solution 1
// blunt: delete entire optimization object
// delete webpackOptions.optimization
// solution 2
// use a module that carefully removes only plugins
// that we found to be breaking the bundling
// https://github.com/bahmutov/find-webpack
const cleanOptions = {
reactScripts: true,
}
findWebpack.cleanForCypress(cleanOptions, webpackOptions)
const options = {
webpackOptions,
watchOptions: {},
}
on('file:preprocessor', webpackPreprocessor(options))
}
Here is some links that might be useful:
Cypress Webpack Preprocessor: https://github.com/cypress-io/cypress/tree/develop/npm/webpack-preprocessor#cypress-webpack-preprocessor
how to point Cypress at Webpack configuration from react-scripts dependency: https://github.com/cypress-io/cypress/tree/develop/npm/webpack-preprocessor/examples/react-app