Skip to content

Commit 6f02719

Browse files
authored
feat: rollup-dev-server for CT (#15215)
1 parent 23c5486 commit 6f02719

20 files changed

+569
-18
lines changed

circle.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,16 @@ jobs:
10551055
name: Run tests
10561056
command: yarn workspace @cypress/webpack-dev-server test
10571057

1058+
npm-rollup-dev-server:
1059+
<<: *defaults
1060+
steps:
1061+
- attach_workspace:
1062+
at: ~/
1063+
- check-conditional-ci
1064+
- run:
1065+
name: Run tests
1066+
command: yarn workspace @cypress/rollup-dev-server test
1067+
10581068
npm-webpack-batteries-included-preprocessor:
10591069
<<: *defaults
10601070
steps:
@@ -1734,6 +1744,9 @@ linux-workflow: &linux-workflow
17341744
- npm-webpack-dev-server:
17351745
requires:
17361746
- build
1747+
- npm-rollup-dev-server:
1748+
requires:
1749+
- build
17371750
- npm-webpack-preprocessor:
17381751
requires:
17391752
- build

npm/rollup-dev-server/.eslintrc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"plugins": [
3+
"cypress",
4+
"@cypress/dev"
5+
],
6+
"extends": [
7+
"plugin:@cypress/dev/general",
8+
"plugin:@cypress/dev/tests",
9+
"plugin:@cypress/dev/react"
10+
],
11+
"parser": "@typescript-eslint/parser",
12+
"env": {
13+
"cypress/globals": true
14+
},
15+
"globals": {
16+
"jest": "readonly"
17+
},
18+
"rules": {
19+
"no-console": "off",
20+
"mocha/no-global-tests": "off",
21+
"@typescript-eslint/no-unused-vars": "off",
22+
"react/jsx-filename-extension": [
23+
"warn",
24+
{
25+
"extensions": [
26+
".js",
27+
".jsx",
28+
".tsx"
29+
]
30+
}
31+
]
32+
},
33+
"overrides": [
34+
{
35+
"files": [
36+
"lib/*"
37+
],
38+
"rules": {
39+
"no-console": 1
40+
}
41+
},
42+
{
43+
"files": [
44+
"**/*.json"
45+
],
46+
"rules": {
47+
"quotes": "off",
48+
"comma-dangle": "off"
49+
}
50+
}
51+
]
52+
}

npm/rollup-dev-server/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# 🍣 + 🌲 Cypress Component Testing w/ Rollup
2+
3+
> **Note** this package is not meant to be used outside of cypress component testing.

npm/rollup-dev-server/cypress.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"pluginsFile": "cypress/plugins.js",
3+
"testFiles": "**/*.spec.*",
4+
"componentFolder": "cypress/components",
5+
"supportFile": "cypress/support/support.js",
6+
"video": false
7+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// import { mount } from '@cypress/vue'
2+
// Currently error: Vue is not defined.
3+
4+
xdescribe('Vue TODO: make this work', () => {
5+
it('mounts', () => {
6+
const mount = (comp) => {}
7+
const App = {
8+
template: `<div>Hello Vue</div>`,
9+
}
10+
11+
mount(App)
12+
})
13+
})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const someModule = () => {
2+
return 'This is a module'
3+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
describe('Support files', () => {
2+
it('can load a support file', () => {
3+
const $body = Cypress.$('body')
4+
5+
// Visual cue to help debug
6+
const $supportNode = Cypress.$(`<h1>Support file hasn't been loaded 😿</h1>`)
7+
8+
$body.append($supportNode)
9+
10+
// @ts-ignore
11+
expect(window.supportFileWasLoaded).to.be.true
12+
$supportNode.text('Support file was loaded! ⚡️')
13+
})
14+
})
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "Using fixtures to represent data",
3+
"email": "[email protected]",
4+
"body": "Fixtures are a great way to mock data for responses to routes"
5+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const { startDevServer } = require('@cypress/rollup-dev-server')
2+
const rollupConfig = require('../rollup.config.js').default
3+
4+
module.exports = (on, config) => {
5+
on('dev-server:start', async (options) => {
6+
return startDevServer({ options, rollupConfig })
7+
})
8+
9+
return config
10+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
before(() => {
2+
window.supportFileWasLoaded = true
3+
})
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
8+
<title>Components App</title>
9+
<script>
10+
function appendTargetIfNotExists(id, tag = 'div', parent = document.body) {
11+
let node = document.getElementById(id)
12+
13+
if (!node) {
14+
node = document.createElement(tag)
15+
node.setAttribute('id', id)
16+
parent.appendChild(node)
17+
}
18+
19+
node.innerHTML = ''
20+
21+
return node
22+
}
23+
24+
const Cypress = window.Cypress = parent.Cypress
25+
26+
const importsToLoad = [
27+
() => import('{{{specPath}}}'),
28+
() => {
29+
{{{supportFile}}}
30+
}
31+
]
32+
33+
Cypress.onSpecWindow(window, importsToLoad)
34+
Cypress.action('app:window:before:load', window)
35+
36+
beforeEach(() => {
37+
const root = appendTargetIfNotExists('__cy_root')
38+
39+
root.appendChild(appendTargetIfNotExists('__cy_app'))
40+
})
41+
42+
</script>
43+
44+
</head>
45+
46+
<body>
47+
<div id="app"></div>
48+
</body>
49+
50+
</html>

npm/rollup-dev-server/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./dist')

npm/rollup-dev-server/package.json

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "@cypress/rollup-dev-server",
3+
"version": "0.0.0-development",
4+
"description": "Launches Rollup Dev Server for Component Testing",
5+
"main": "index.js",
6+
"scripts": {
7+
"build": "tsc",
8+
"build-prod": "tsc",
9+
"cy:open": "node ../../scripts/start.js --component-testing --project ${PWD}",
10+
"cy:run": "node ../../scripts/cypress.js run-ct --project ${PWD}",
11+
"test": "yarn cy:run",
12+
"watch": "tsc -w"
13+
},
14+
"dependencies": {
15+
"debug": "4.3.2",
16+
"mustache": "4.1.0"
17+
},
18+
"devDependencies": {
19+
"@cypress/vue": "0.0.0-development",
20+
"@rollup/plugin-typescript": "8.2.0",
21+
"@types/mustache": "4.1.1",
22+
"nollup": "0.15.2",
23+
"rollup": "2.39.1",
24+
"vue": "2.6.12"
25+
},
26+
"peerDependencies": {
27+
"rollup": ">= 2"
28+
},
29+
"files": [
30+
"dist"
31+
],
32+
"license": "MIT",
33+
"repository": {
34+
"type": "git",
35+
"url": "https://github.com/cypress-io/cypress.git"
36+
},
37+
"homepage": "https://github.com/cypress-io/cypress/tree/master/npm/rollup-dev-server#readme",
38+
"bugs": "https://github.com/cypress-io/cypress/issues/new?template=1-bug-report.md",
39+
"publishConfig": {
40+
"access": "public"
41+
}
42+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import tsPlugin from '@rollup/plugin-typescript'
2+
import resolvePlugin from '@rollup/plugin-node-resolve'
3+
import commonjsPlugin from '@rollup/plugin-commonjs'
4+
5+
export default {
6+
plugins: [
7+
resolvePlugin(),
8+
commonjsPlugin(),
9+
tsPlugin({
10+
module: 'esnext',
11+
}),
12+
],
13+
output: {
14+
format: 'es',
15+
},
16+
}

npm/rollup-dev-server/src/index.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { EventEmitter } from 'events'
2+
import { debug as debugFn } from 'debug'
3+
import { start as createDevServer } from './startServer'
4+
import { Server } from 'http'
5+
import { RollupOptions } from 'rollup'
6+
const debug = debugFn('cypress:rollup-dev-server:rollup')
7+
8+
interface Options {
9+
specs: Cypress.Cypress['spec'][] // Why isn't this working? It works for webpack-dev-server
10+
config: Record<string, string>
11+
devServerEvents: EventEmitter
12+
[key: string]: unknown
13+
}
14+
15+
export interface StartDevServer {
16+
/* this is the Cypress options object */
17+
options: Options
18+
rollupConfig?: RollupOptions // TODO: user's rollup configuration.
19+
}
20+
21+
export interface ResolvedDevServerConfig {
22+
port: number
23+
server: Server
24+
}
25+
26+
export async function startDevServer (startDevServerArgs: StartDevServer): Promise<ResolvedDevServerConfig> {
27+
const { server, port } = await createDevServer(startDevServerArgs)
28+
29+
return new Promise(async (resolve) => {
30+
server.listen(port, 'localhost', () => {
31+
resolve({ port, server })
32+
})
33+
})
34+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { resolve } from 'path'
2+
import { readFileSync } from 'fs'
3+
import { render } from 'mustache'
4+
import { Express } from 'express'
5+
6+
const indexHtmlPath = resolve(__dirname, '../index-template.html')
7+
const readIndexHtml = () => readFileSync(indexHtmlPath).toString()
8+
9+
/**
10+
* Rormat the requested spec file.
11+
* Nollup writes everything to a single directory (eg /dist)
12+
* All outputted files are *.js.
13+
* RunnerCt requests specs using the original filename including extension.
14+
*
15+
* Example usage:
16+
* formatSpecName('/cypress/component/foo.spec.tsx') //=> 'foo.spec.js'
17+
*/
18+
function formatSpecName (filename: string) {
19+
const split = filename.split('/')
20+
const name = split[split.length - 1]
21+
const pos = name.lastIndexOf('.')
22+
const newName = `${name.substr(0, pos < 0 ? name.length : pos)}.js`
23+
24+
return `/${newName}`
25+
}
26+
27+
function handleIndex (indexHtml: string, projectRoot: string, supportFilePath: string, cypressSpecPath: string) {
28+
const specPath = `/${cypressSpecPath}`
29+
30+
console.log(supportFilePath)
31+
const supportFile = readFileSync(supportFilePath).toString()
32+
33+
return render(indexHtml, {
34+
supportFile,
35+
specPath: formatSpecName(specPath),
36+
})
37+
}
38+
39+
export const makeHtmlPlugin = (
40+
projectRoot: string,
41+
supportFilePath: string,
42+
server: Express,
43+
) => {
44+
const indexHtml = readIndexHtml()
45+
46+
server.use('/index.html', (req, res) => {
47+
const html = handleIndex(
48+
indexHtml,
49+
projectRoot,
50+
supportFilePath,
51+
req.headers.__cypress_spec_path as string,
52+
)
53+
54+
res.end(html)
55+
})
56+
}

0 commit comments

Comments
 (0)