Skip to content

Commit 4c44272

Browse files
committed
Add support for CT using Vite as bundler
This currently relies on a small patch of @cypress/vite-dev-server [1]. Hopefully this patch can be submitted and accepted upstream. This fixes #698 [2]. [2] https://github.com/cypress-io/cypress/tree/develop/npm/vite-dev-server [1] #698
1 parent 11f5b06 commit 4c44272

15 files changed

+149
-12
lines changed

examples/ct-vite-react-ts/.npmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { defineConfig } from "cypress";
2+
import { devServer } from "@cypress/vite-dev-server";
3+
import react from "@vitejs/plugin-react";
4+
import { viteCommonjs } from "@originjs/vite-plugin-commonjs";
5+
import { addCucumberPreprocessorPlugin } from "@badeball/cypress-cucumber-preprocessor";
6+
import { createRollupPlugin } from "@badeball/cypress-cucumber-preprocessor/rollup";
7+
8+
export default defineConfig({
9+
component: {
10+
specPattern: "**/*.feature",
11+
devServer(devServerConfig) {
12+
return devServer({
13+
...devServerConfig,
14+
framework: "react",
15+
viteConfig: {
16+
plugins: [
17+
react(),
18+
createRollupPlugin(devServerConfig.cypressConfig),
19+
viteCommonjs(),
20+
],
21+
},
22+
});
23+
},
24+
async setupNodeEvents(on, config) {
25+
// This is required for the preprocessor to be able to generate JSON reports after each run, and more.
26+
await addCucumberPreprocessorPlugin(on, config);
27+
28+
// Make sure to return the config object as it might have been modified by the plugin.
29+
return config;
30+
},
31+
},
32+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Feature: App
2+
Scenario: render
3+
Given I render the component
4+
Then I should see the text "Hello world!"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as preprocessor from "@badeball/cypress-cucumber-preprocessor";
2+
3+
import { mount } from "cypress/react18"
4+
5+
import App from "../../src/App";
6+
7+
const { Given, Then } = preprocessor
8+
9+
Given("I render the component", () => {
10+
mount(<App />);
11+
});
12+
13+
Then("I should see the text {string}", (text: string) => {
14+
cy.contains(text).should("exist");
15+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
7+
<title>Components App</title>
8+
9+
</head>
10+
<body>
11+
12+
<div data-cy-root></div>
13+
</body>
14+
</html>

examples/ct-vite-react-ts/cypress/support/component.ts

Whitespace-only changes.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"scripts": {
3+
"postinstall": "patch-package"
4+
},
5+
"dependencies": {
6+
"@badeball/cypress-cucumber-preprocessor": "latest",
7+
"@cypress/vite-dev-server": "latest",
8+
"@originjs/vite-plugin-commonjs": "latest",
9+
"@vitejs/plugin-react": "latest",
10+
"cypress": "latest",
11+
"patch-package": "latest",
12+
"react": "latest",
13+
"react-dom": "latest",
14+
"typescript": "latest"
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
diff --git a/node_modules/@cypress/vite-dev-server/client/initCypressTests.js b/node_modules/@cypress/vite-dev-server/client/initCypressTests.js
2+
index f0602c1..d7f05a0 100644
3+
--- a/node_modules/@cypress/vite-dev-server/client/initCypressTests.js
4+
+++ b/node_modules/@cypress/vite-dev-server/client/initCypressTests.js
5+
@@ -36,7 +36,7 @@ if (supportFile) {
6+
// So we use the "@fs" bit to load the test file using its absolute path
7+
// Normalize path to not include a leading slash (different on Win32 vs Unix)
8+
const normalizedAbsolutePath = CypressInstance.spec.absolute.replace(/^\//, '')
9+
-const testFileAbsolutePathRoute = `${devServerPublicPathRoute}/@fs/${normalizedAbsolutePath}`
10+
+const testFileAbsolutePathRoute = `${devServerPublicPathRoute}/@fs/${normalizedAbsolutePath}?import`
11+
12+
/* Spec file import logic */
13+
// We need a slash before /src/my-spec.js, this does not happen by default.

examples/ct-vite-react-ts/src/App.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function App () {
2+
return <p>Hello world!</p>
3+
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"esModuleInterop": true,
4+
"moduleResolution": "node16",
5+
"jsx": "react-jsx"
6+
}
7+
}

examples/readme.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@ The examples illustrates using each bundler in each language flavor.
1414

1515
## Component testing
1616

17-
Only a single example illustrating component testing exist so far.
17+
Component testing works with both Webpack and Vite[^1] as a bundler.
1818

1919
| | CJS | ESM | TS |
2020
|-----------------|------------------------|------------------------|-----------------------------|
2121
| React + Webpack | | | [Link](ct-webpack-react-ts) |
22+
| React + Vite | | | [Link](ct-vite-react-ts) |
23+
24+
[patch-package]: https://github.com/ds300/patch-package
25+
[^1]: Using Vite requires patching `@cypress/vite-dev-server`, something which is easily achieved using [`patch-package`][patch-package] as the example illustrates.

lib/bundler-utils/rollup.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Plugin } from "rollup";
2+
3+
import { ICypressConfiguration } from "@badeball/cypress-configuration";
4+
5+
import { compile } from "../template";
6+
7+
export function createRollupPlugin(config: ICypressConfiguration): Plugin {
8+
return {
9+
name: "transform-feature",
10+
async transform(src: string, id: string) {
11+
if (/\.feature$/.test(id)) {
12+
return {
13+
code: await compile(config, src, id),
14+
map: null,
15+
};
16+
}
17+
},
18+
};
19+
}
20+
21+
export default createRollupPlugin;

lib/helpers/prepare-registry.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Registry, assignRegistry, freeRegistry } from "../registry";
2+
3+
const registry = new Registry(false);
4+
5+
assignRegistry(registry);
6+
7+
export function getAndFreeRegistry() {
8+
freeRegistry();
9+
return registry;
10+
}

lib/template.ts

+7-11
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export async function compile(
131131

132132
const createTestsPath = prepareLibPath("browser-runtime");
133133

134-
const registryPath = prepareLibPath("registry");
134+
const prepareRegistryPath = prepareLibPath("helpers", "prepare-registry");
135135

136136
const ensureRelativeToProjectRoot = (path: string) =>
137137
ensureIsRelative(configuration.projectRoot, path);
@@ -152,17 +152,13 @@ export async function compile(
152152
];
153153

154154
return `
155+
const { getAndFreeRegistry } = require(${prepareRegistryPath});
155156
const { default: createTests } = require(${createTestsPath});
156-
const { withRegistry } = require(${registryPath});
157-
158-
const registry = withRegistry(
159-
false,
160-
() => {
161-
${stepDefinitionPaths
162-
.map((stepDefintion) => `require(${stringify(stepDefintion)});`)
163-
.join("\n ")}
164-
}
165-
);
157+
${stepDefinitionPaths
158+
.map((stepDefintion) => `require(${stringify(stepDefintion)});`)
159+
.join("\n ")}
160+
161+
const registry = getAndFreeRegistry();
166162
167163
registry.finalize();
168164

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"pngjs": "^7.0.0",
9494
"prettier": "^2.8.8",
9595
"recast": "^0.22.0",
96+
"rollup": "^3.21.5",
9697
"stream-buffers": "^3.0.2",
9798
"strip-ansi": "^6.0.1",
9899
"strip-indent": "^3.0.0",

0 commit comments

Comments
 (0)