Files
cypress/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js
2021-03-16 17:34:03 -04:00

109 lines
3.6 KiB
JavaScript

// @ts-check
const debug = require('debug')('@cypress/react')
const tryLoadWebpackConfig = require('../utils/tryLoadWebpackConfig')
const { getTranspileFolders } = require('../utils/get-transpile-folders')
const { addFolderToBabelLoaderTranspileInPlace } = require('../utils/babel-helpers')
/**
* Finds the ModuleScopePlugin plugin and adds given folder
* to that list. This allows react-scripts to import folders
* outside of the default "/src" folder.
* WARNING modifies the input webpack options argument.
* @see https://github.com/bahmutov/cypress-react-unit-test/issues/289
* @param {string} folderName Folder to add, should be absolute
*/
function allowModuleSourceInPlace (folderName, webpackOptions) {
if (!folderName) {
return
}
if (!webpackOptions.resolve) {
return
}
if (!Array.isArray(webpackOptions.resolve.plugins)) {
return
}
const moduleSourcePlugin = webpackOptions.resolve.plugins.find((plugin) => {
return Array.isArray(plugin.appSrcs)
})
if (!moduleSourcePlugin) {
debug('cannot find module source plugin')
return
}
debug('found module source plugin %o', moduleSourcePlugin)
if (!moduleSourcePlugin.appSrcs.includes(folderName)) {
moduleSourcePlugin.appSrcs.push(folderName)
debug('added folder %s to allowed sources', folderName)
}
}
const addCypressToWebpackEslintRulesInPlace = (webpackOptions) => {
const globalsToAdd = ['cy', 'Cypress', 'before', 'after', 'context']
if (webpackOptions.module && Array.isArray(webpackOptions.module.rules)) {
const modulePre = webpackOptions.module.rules.find(
(rule) => rule.enforce === 'pre',
)
if (modulePre && Array.isArray(modulePre.use)) {
debug('found Pre block %o', modulePre)
const useEslintLoader = modulePre.use.find(
(use) => use.loader && use.loader.includes('eslint-loader'),
)
if (useEslintLoader) {
debug('found useEslintLoader %o', useEslintLoader)
if (useEslintLoader.options) {
if (Array.isArray(useEslintLoader.options.globals)) {
debug(
'adding cy to existing globals %o',
useEslintLoader.options.globals,
)
useEslintLoader.options.globals.push(...globalsToAdd)
} else {
debug('setting new list of globals with cy and Cypress')
useEslintLoader.options.globals = globalsToAdd
}
debug('updated globals %o', useEslintLoader.options.globals)
} else {
debug('eslint loader does not have options ⚠️')
}
}
}
}
}
module.exports = function findReactScriptsWebpackConfig (config) {
// this is required because
// 1) we use our own HMR and we don't need react-refresh transpiling overhead
// 2) it doesn't work with process.env=test @see https://github.com/cypress-io/cypress-realworld-app/pull/832
process.env.FAST_REFRESH = 'false'
const webpackConfig = tryLoadWebpackConfig('react-scripts/config/webpack.config')
if (!webpackConfig) {
throw new Error('⚠️ Could not find Webpack options for react-scripts. Make sure that you have react-scripts module available.')
}
// because for react-scripts user doesn't have direct access to webpack webpackConfig
// we must implicitly inject everything required to run tests
addCypressToWebpackEslintRulesInPlace(webpackConfig)
getTranspileFolders(config).forEach((cypressFolder) => {
allowModuleSourceInPlace(cypressFolder, webpackConfig)
addFolderToBabelLoaderTranspileInPlace(cypressFolder, webpackConfig)
})
debug('resolved webpack config: %o', webpackConfig)
return webpackConfig
}