Skip to content
This repository was archived by the owner on Mar 5, 2022. It is now read-only.

Commit 7ebe714

Browse files
New rollup example and template (#444)
Co-authored-by: Gleb Bahmutov <[email protected]>
1 parent 5733f5d commit 7ebe714

File tree

18 files changed

+1046
-466
lines changed

18 files changed

+1046
-466
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ Folder Name | Description
221221
[visual-testing-with-happo](examples/visual-testing-with-happo) | [Visual testing](#visual-testing) for components using 3rd party service [Happo](https://happo.io/)
222222
[visual-testing-with-applitools](examples/visual-testing-with-applitools) | [Visual testing](#visual-testing) for components using 3rd party service [Applitools.com](https://applitools.com/)
223223
[using-babel](examples/using-babel) | Bundling specs and loaded source files using project's existing `.babelrc` file
224+
[webpack-file](examples/rollup) | Bundle component and specs using [rollup](http://rollupjs.org/guide/en/).
224225
[webpack-file](examples/webpack-file) | Load existing `webpack.config.js` file
225226
[webpack-options](examples/webpack-options) | Using the default Webpack options from `@cypress/webpack-preprocessor` to transpile JSX specs
226227
<!-- prettier-ignore-end -->

circle.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,19 @@ workflows:
172172
npm run only-covered
173173
working_directory: examples/webpack-file
174174

175+
- cypress/run:
176+
name: Example Rollup
177+
requires:
178+
- Install
179+
# each example installs "cypress-react-unit-test" as a local dependency (symlink)
180+
executor: cypress/base-12
181+
install-command: npm install --no-bin-links
182+
verify-command: echo 'Already verified'
183+
no-workspace: true
184+
working_directory: examples/rollup
185+
command: npm test
186+
store_artifacts: true
187+
175188
- cypress/run:
176189
name: Example Webpack options
177190
requires:
@@ -338,6 +351,7 @@ workflows:
338351
- Example Tailwind
339352
- Example Webpack file
340353
- Example Webpack options
354+
- Example Rollup
341355
- Visual Sudoku
342356
- Visual with Percy
343357
- Visual with Happo

examples/rollup/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

examples/rollup/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# example: rollup
2+
3+
> Compiling component tests using Rollup bundler
4+
5+
## Usage
6+
7+
1. Make sure the root project has been built .
8+
9+
```bash
10+
# in the root of the project
11+
npm install
12+
npm run build
13+
```
14+
15+
2. Run `npm install` in this folder to symlink the `cypress-react-unit-test` dependency.
16+
17+
```bash
18+
# in this folder
19+
npm install
20+
npm run build
21+
```
22+
23+
3. Start Cypress
24+
25+
```bash
26+
npm run cy:open
27+
# or just run headless tests
28+
npm test
29+
```

examples/rollup/babel.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = {
2+
presets: [
3+
'@babel/preset-env',
4+
'@babel/preset-typescript',
5+
'@babel/preset-react',
6+
],
7+
plugins: ['@babel/plugin-proposal-class-properties'],
8+
}

examples/rollup/cypress.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"testFiles": "**/*spec.{ts,tsx}",
3+
"experimentalComponentTesting": true,
4+
"experimentalFetchPolyfill": true,
5+
"componentFolder": "src",
6+
"fixturesFolder": false
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// <reference types="cypress" />
2+
describe('integration spec', () => {
3+
it('works', () => {
4+
expect(1).to.equal(1)
5+
})
6+
})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const rollupPreprocessor = require('@bahmutov/cy-rollup')
2+
3+
module.exports = (on, config) => {
4+
on(
5+
'file:preprocessor',
6+
rollupPreprocessor({
7+
configFile: 'rollup.config.js',
8+
}),
9+
)
10+
11+
require('@cypress/code-coverage/task')(on, config)
12+
// IMPORTANT to return the config object
13+
// with the any changed environment variables
14+
return config
15+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import 'cypress-react-unit-test/support'
2+
import '@cypress/code-coverage/support'

examples/rollup/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "example-rollup",
3+
"description": "Component testing using Rollup bundler",
4+
"private": true,
5+
"scripts": {
6+
"build": "../../node_modules/.bin/rollup -c",
7+
"test": "../../node_modules/.bin/cypress-expect run --passing 1",
8+
"cy:open": "../../node_modules/.bin/cypress open"
9+
},
10+
"devDependencies": {
11+
"cypress-react-unit-test": "file:../.."
12+
}
13+
}

examples/rollup/rollup.config.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import babel from '@rollup/plugin-babel'
2+
import replace from '@rollup/plugin-replace'
3+
import commonjs from '@rollup/plugin-commonjs'
4+
import nodeResolve from '@rollup/plugin-node-resolve'
5+
6+
const extensions = ['.ts', '.tsx', '.js', '.jsx']
7+
export default [
8+
{
9+
input: './src/index.ts',
10+
output: {
11+
dir: 'dist',
12+
format: 'esm',
13+
},
14+
plugins: [
15+
nodeResolve({ extensions }),
16+
// make sure that this is required to process cypress-react-unit-test code
17+
commonjs(),
18+
replace({ 'process.env.NODE_ENV': JSON.stringify('development') }),
19+
babel({
20+
exclude: /node_modules/,
21+
babelHelpers: 'inline',
22+
extensions,
23+
}),
24+
],
25+
},
26+
]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as React from 'react'
2+
import { MyAwesomeComponent } from './MyAwesomeComponent'
3+
import { mount } from 'cypress-react-unit-test'
4+
5+
describe('rollup for bundling components', () => {
6+
it('renders component processed by rollup', () => {
7+
mount(<MyAwesomeComponent />)
8+
9+
cy.contains('My awesome component!')
10+
})
11+
})
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as React from 'react'
2+
3+
interface MyAwesomeComponentProps {}
4+
5+
export const MyAwesomeComponent: React.FC<MyAwesomeComponentProps> = ({}) => {
6+
return (
7+
<h1>
8+
My <strong> awesome </strong> component!
9+
</h1>
10+
)
11+
}

examples/rollup/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { MyAwesomeComponent } from './MyAwesomeComponent'

examples/rollup/tsconfig.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"compilerOptions": {
3+
"jsx": "react",
4+
"baseUrl": ".",
5+
"noEmit": true,
6+
"target": "esnext",
7+
"types": ["cypress"],
8+
// ⚠️ required only for demo purposes, remove from code
9+
"paths": {
10+
"cypress-react-unit-test": ["../../lib/index.ts"]
11+
}
12+
},
13+
"exclude": ["node_modules"],
14+
"include": ["./src/**.ts*"]
15+
}

init/templates/rollup.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { mockFs, clearMockedFs } from '../test/mockFs'
2+
import { RollupTemplate } from './rollup'
3+
4+
describe('rollup-file install template', () => {
5+
afterEach(clearMockedFs)
6+
7+
it('suggests the right code', () => {
8+
expect(
9+
RollupTemplate.getPluginsCode(
10+
{
11+
rollupConfigPath: '/configs/rollup.config.js',
12+
},
13+
{ cypressProjectRoot: '/' },
14+
),
15+
).toContain("configFile: 'configs/rollup.config.js'")
16+
})
17+
18+
it('resolves rollup.config.js', () => {
19+
mockFs({
20+
'rollup.config.js': 'module.exports = { }',
21+
})
22+
23+
const { success, payload } = RollupTemplate.test(process.cwd())
24+
expect(success).toBe(true)
25+
expect(payload?.rollupConfigPath).toBe('/rollup.config.js')
26+
})
27+
28+
it('finds the closest package.json and tries to fetch rollup config path from scrips', () => {
29+
mockFs({
30+
'configs/rollup.js': 'module.exports = { }',
31+
'package.json': JSON.stringify({
32+
scripts: {
33+
build: 'rollup --config configs/rollup.js',
34+
},
35+
}),
36+
})
37+
38+
const { success, payload } = RollupTemplate.test(process.cwd())
39+
40+
expect(success).toBe(true)
41+
expect(payload?.rollupConfigPath).toBe('/configs/rollup.js')
42+
})
43+
44+
it('looks for package.json in the upper folder', () => {
45+
mockFs({
46+
'i/am/in/some/deep/folder/withFile': 'test',
47+
'somewhere/configs/rollup.js': 'module.exports = { }',
48+
'package.json': JSON.stringify({
49+
scripts: {
50+
build: 'rollup --config somewhere/configs/rollup.js',
51+
},
52+
}),
53+
})
54+
55+
const { success, payload } = RollupTemplate.test('i/am/in/some/deep/folder')
56+
57+
expect(success).toBe(true)
58+
expect(payload?.rollupConfigPath).toBe('/somewhere/configs/rollup.js')
59+
})
60+
61+
it('returns success:false if cannot find rollup config', () => {
62+
mockFs({
63+
'a.js': '1',
64+
'b.js': '2',
65+
})
66+
67+
const { success, payload } = RollupTemplate.test('/')
68+
expect(success).toBe(false)
69+
expect(payload).toBe(undefined)
70+
})
71+
})

init/templates/rollup.ts

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import path from 'path'
2+
import chalk from 'chalk'
3+
import findUp from 'find-up'
4+
import highlight from 'cli-highlight'
5+
import { createFindPackageJsonIterator } from '../findPackageJson'
6+
import { Template } from '../Template'
7+
8+
export function extractRollupConfigPathFromScript(script: string) {
9+
if (script.includes('rollup ')) {
10+
const cliArgs = script.split(' ').map(part => part.trim())
11+
const configArgIndex = cliArgs.findIndex(
12+
arg => arg === '--config' || arg === '-c',
13+
)
14+
15+
return configArgIndex === -1 ? null : cliArgs[configArgIndex + 1]
16+
}
17+
18+
return null
19+
}
20+
21+
export const RollupTemplate: Template<{ rollupConfigPath: string }> = {
22+
message:
23+
'It looks like you have custom `rollup.config.js`. We can use it to bundle the components for testing.',
24+
getExampleUrl: () =>
25+
'https://github.com/bahmutov/cypress-react-unit-test/tree/main/examples/rollup',
26+
recommendedComponentFolder: 'src',
27+
getPluginsCode: (payload, { cypressProjectRoot }) => {
28+
const includeWarnComment = !Boolean(payload)
29+
const rollupConfigPath = payload
30+
? path.relative(cypressProjectRoot, payload.rollupConfigPath)
31+
: 'rollup.config.js'
32+
33+
return [
34+
`// do not forget to install`,
35+
`const rollupPreprocessor = require('@bahmutov/cy-rollup')`,
36+
`module.exports = (on, config) => {`,
37+
` on(`,
38+
` 'file:preprocessor',`,
39+
` rollupPreprocessor({`,
40+
includeWarnComment
41+
? ' // TODO replace with valid rollup config path'
42+
: '',
43+
` configFile: '${rollupConfigPath}',`,
44+
` }),`,
45+
` )`,
46+
``,
47+
` require('@cypress/code-coverage/task')(on, config)`,
48+
` // IMPORTANT to return the config object`,
49+
` return config`,
50+
`}`,
51+
].join('\n')
52+
},
53+
printHelper: () => {
54+
console.log(
55+
`Make sure that it is also required to add some additional configuration to the ${chalk.red(
56+
'rollup.config.js',
57+
)}. Here is whats required:`,
58+
)
59+
60+
const code = highlight(
61+
[
62+
`import replace from '@rollup/plugin-replace'`,
63+
`import commonjs from '@rollup/plugin-commonjs'`,
64+
`import nodeResolve from '@rollup/plugin-node-resolve'`,
65+
``,
66+
`export default [`,
67+
` {`,
68+
` plugins: [`,
69+
` nodeResolve(),`,
70+
` // process cypress-react-unit-test-code`,
71+
` commonjs(),`,
72+
` // required for react sources`,
73+
` replace({ 'process.env.NODE_ENV': JSON.stringify('development') }),`,
74+
` ]`,
75+
` }`,
76+
`]`,
77+
].join('\n'),
78+
{ language: 'js' },
79+
)
80+
81+
console.log(`\n${code}\n`)
82+
},
83+
test: root => {
84+
const rollupConfigPath = findUp.sync('rollup.config.js', { cwd: root })
85+
if (rollupConfigPath) {
86+
return {
87+
success: true,
88+
payload: { rollupConfigPath },
89+
}
90+
}
91+
92+
const packageJsonIterator = createFindPackageJsonIterator(root)
93+
return packageJsonIterator.map(({ scripts }, packageJsonPath) => {
94+
if (!scripts) {
95+
return { continue: true }
96+
}
97+
98+
for (const script of Object.values(scripts)) {
99+
const rollupConfigRelativePath = extractRollupConfigPathFromScript(
100+
script,
101+
)
102+
103+
if (rollupConfigRelativePath) {
104+
const directoryRoot = path.resolve(packageJsonPath, '..')
105+
const rollupConfigPath = path.resolve(
106+
directoryRoot,
107+
rollupConfigRelativePath,
108+
)
109+
110+
return {
111+
continue: false,
112+
payload: { rollupConfigPath },
113+
}
114+
}
115+
}
116+
117+
return { continue: true }
118+
})
119+
},
120+
}

0 commit comments

Comments
 (0)