Skip to content

Commit e736f2b

Browse files
committed
temp-cli-and-templates-and-readme
Signed-off-by: Francesco Torchia <[email protected]>
1 parent 964ae31 commit e736f2b

File tree

16 files changed

+364
-32
lines changed

16 files changed

+364
-32
lines changed

.eslintignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ kubewarden-ui/
2828
styleguide/src/stories/Example/
2929
storybook/src/stories/Example/
3030
cypress/dist/
31-
cypress/bin/cypress.js
31+
cypress/bin/
32+
cypress/template/

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ sw.*
9191
cypress/videos
9292
cypress/screenshots
9393
cypress/accessibility
94+
browser-logs
9495
setupTestEnv.sh
9596

9697
# Storybook

cypress.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Import and use the base configuration from @rancher/cypress package
1+
// Import and use the base configuration from cypress package
22
import baseConfig from './cypress/base-config';
33

44
export default baseConfig;

cypress/README.md

Lines changed: 122 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,101 @@ Reusable Cypress E2E test utilities, page objects, and support files for Rancher
55
## Installation
66

77
```bash
8-
npm install @rancher/cypress
8+
npm install @rancher/cypress --save-dev
99
# or
10-
yarn add @rancher/cypress
10+
yarn add @rancher/cypress --dev
1111
```
1212

13-
## What's Included
13+
## Setup
1414

1515
This package provides:
1616

17-
- **Page Objects** (`/po/*`) - Reusable page object models for common UI components and pages
18-
- **Blueprints** (`/blueprints/*`) - Test fixtures and data blueprints
17+
- **E2E Tests** (`/e2e/*`) - Predefined Cypress tests for common Rancher Dashboard scenarios
18+
- **Page Objects** (`/e2e/po/*`) - Reusable page object models for common Rancher UI components and pages
19+
- **Blueprints** (`/e2e/blueprints/*`) - Test fixtures and data blueprints
1920
- **Support Files** (`/support/*`) - Custom Cypress commands and utilities
20-
- **Configuration** (`/config/*`) - Base Cypress configuration
21+
- **Cypress Configuration** (`/base-config`) - Base Cypress configuration
22+
- **Extendable Config** (`/extend-config`) - Utilities to extend Cypress config
23+
24+
### Using @rancher/cypress CLI
25+
26+
#### Available Commands
27+
28+
| Command | Description |
29+
|--------------------------------|--------------------------------------------------|
30+
| npx rancher-cypress open | Launch Cypress UI |
31+
| npx rancher-cypress run | Run Cypress tests |
32+
| npx rancher-cypress init | Scaffold a Cypress project structure |
33+
34+
#### What does `init` do?
35+
36+
The `init` command will:
37+
38+
- Create a new `cypress/` directory in your project (if one does not already exist)
39+
- Copy all template files and folders into `cypress/`
40+
- Copy `cypress.config.ts` into your project root (not inside `cypress/`)
41+
- Abort if a `cypress/` directory or `cypress.config.ts` already exists, to avoid overwriting your work
42+
43+
This provides a ready-to-use Cypress project structure for Rancher Dashboard E2E testing.
44+
45+
---
46+
47+
### Manual Setup
48+
49+
#### Cypress Configuration
50+
51+
Create a `cypress.config.ts` file in your consuming project:
52+
53+
Use default base configuration:
54+
55+
```typescript
56+
import baseConfig from '@rancher/cypress/base-config';
57+
58+
export default baseConfig;
59+
```
60+
61+
Or extend the base configuration:
62+
63+
```typescript
64+
import { extendConfig } from '@rancher/cypress/extend-config';
65+
66+
export default extendConfig({
67+
env: {
68+
yourCustomEnvVar: 'value',
69+
},
70+
e2e: {
71+
specPattern: yourCustomSpecPattern
72+
}
73+
});
74+
```
75+
76+
#### Package.json
77+
78+
Add new tasks to Cypress configuration in `package.json`:
79+
80+
```json
81+
{
82+
"cypress": {
83+
"tasks": {
84+
"cypress:open": "npx rancher-cypress open --e2e --browser chrome",
85+
"cypress:run": "npx rancher-cypress run",
86+
}
87+
}
88+
}
89+
```
90+
91+
#### TypeScript Configuration
92+
93+
> **Important:**
94+
> To enable type completion for custom Cypress commands and page objects, add `"cypress"` to the `types` array in your root `tsconfig.json`:
95+
>
96+
> ```json
97+
> {
98+
> "compilerOptions": {
99+
> "types": ["cypress"]
100+
> }
101+
> }
102+
> ```
21103
22104
## Usage
23105
@@ -54,33 +136,47 @@ This will load all custom Cypress commands like:
54136
### Using Blueprints (Fixtures)
55137

56138
```typescript
57-
cy.fixture('@rancher/cypress/blueprints/my-fixture.json').then((data) => {
139+
cy.fixture('@rancher/cypress/blueprints/fixture.json').then((data) => {
58140
// use fixture data
59141
});
60142
```
61143

62-
### Using Base Configuration
63-
64-
In your project's `cypress.config.ts`:
65-
66-
```typescript
67-
import { getBaseConfig } from '@rancher/cypress/config/base.config';
68-
69-
const baseConfig = getBaseConfig();
70-
71-
export default {
72-
...baseConfig,
73-
e2e: {
74-
...baseConfig.e2e,
75-
specPattern: 'your-tests/**/*.spec.ts',
76-
// override any other settings
77-
}
78-
};
79-
```
144+
## Implementation & Publishing Notes
145+
146+
### Project Structure & Build Process
147+
- All source files (e2e, support, base-config.ts, extend-config.ts, globals.d.ts) are copied into a temporary `tmp/` directory before build.
148+
- The build script (`build.sh`) normalizes internal imports and compiles TypeScript from `tmp/` to `dist/` using `tsconfig.build.json`.
149+
- After compilation, TypeScript source files are also copied to `dist/` for better developer experience.
150+
- Non-TypeScript assets (README, package.json, etc.) are copied to `dist/` for publishing.
151+
- The published npm package only includes the `dist/` directory, as specified in `package.json`.
152+
153+
### TypeScript Configuration
154+
- `tsconfig.build.json` extends the main `tsconfig.json` but restricts compilation to `tmp/**/*` and outputs only to `dist/`.
155+
- Source maps and declaration maps are generated for easier debugging and type navigation.
156+
157+
### Clean Build Guarantee
158+
- Only the files actually referenced by the cypress code are included in the build, keeping the package minimal.
159+
160+
### Publishing
161+
- To manual publish, run:
162+
```bash
163+
npm run build
164+
cd dist
165+
npm publish
166+
```
167+
- To automate publishing, use the provided GitHub Actions workflow.
168+
Add a new release tag, and the workflow will build and publish the package to npm.
169+
```bash
170+
git tag cypress-pkg-v1.0.0
171+
git push upstream cypress-pkg-v1.0.0
172+
```
173+
174+
### Troubleshooting
175+
- If you see build errors not shown in VS Code, ensure you are using the same TypeScript config (`tsconfig.build.json`) for both build and editor, or manually run `npx tsc --project tsconfig.build.json` to check.
176+
- If you see stray build artifacts in dependency directories, check the build script and tsconfig paths to ensure all compilation is isolated to `tmp/` and `dist/`.
80177

81178
## Requirements
82179

83-
- Cypress 11.1.0
84180
- Node.js >= 20.0.0
85181
- TypeScript >= 5.0.0
86182

cypress/bin/cli.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env node
2+
3+
const { spawnSync } = require('child_process');
4+
5+
const [, , cmd, ...args] = process.argv;
6+
7+
function showHelp() {
8+
console.log(`\n@rancher/cypress CLI\n\nUsage:\n npx rancher-cypress <command> [args]\n\nCommands:\n open Launch Cypress UI\n run Run Cypress tests\n init Scaffold Cypress project structure\n\nExamples:\n npx rancher-cypress open\n npx rancher-cypress run\n npx rancher-cypress init\n`);
9+
}
10+
11+
if (!cmd) {
12+
showHelp();
13+
process.exit(0);
14+
}
15+
16+
if (cmd === 'init') {
17+
require('./init');
18+
} else {
19+
// Try to resolve cypress binary in the consuming project
20+
let cypressBin;
21+
22+
try {
23+
cypressBin = require.resolve('./node_modules/.bin/cypress', { paths: [process.cwd()] });
24+
} catch (e) {
25+
console.error('\nERROR: Cypress is not installed in this project.\nPlease install it with:\n npm install cypress --save-dev\n');
26+
process.exit(1);
27+
}
28+
const result = spawnSync(cypressBin, [cmd, ...args], { stdio: 'inherit' });
29+
30+
process.exit(result.status);
31+
}

cypress/bin/init.js

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs-extra');
4+
const path = require('path');
5+
6+
function copyTemplateFiles(templateDir, targetDir) {
7+
if (!fs.existsSync(templateDir)) {
8+
console.error(`Template directory not found: ${ templateDir }`);
9+
process.exit(1);
10+
}
11+
fs.copySync(templateDir, targetDir, {
12+
overwrite: false,
13+
errorOnExist: true,
14+
filter: (src) => {
15+
// Skip node_modules and .DS_Store
16+
const rel = path.relative(templateDir, src);
17+
18+
return !rel.includes('node_modules') && !rel.endsWith('.DS_Store');
19+
}
20+
});
21+
}
22+
23+
function main() {
24+
const cwd = process.cwd();
25+
const templateDir = path.join(__dirname, '../template');
26+
const targetCypressDir = path.join(cwd, 'cypress');
27+
const rootConfigFile = path.join(cwd, 'cypress.config.ts');
28+
29+
if (fs.existsSync(targetCypressDir)) {
30+
console.error('🚫 A cypress/ directory already exists in this project. Aborting.');
31+
process.exit(1);
32+
}
33+
if (fs.existsSync(rootConfigFile)) {
34+
console.error('🚫 A cypress.config.ts already exists in this project root. Aborting.');
35+
process.exit(1);
36+
}
37+
38+
console.log(`Scaffolding Cypress project structure in: ${ targetCypressDir }`);
39+
try {
40+
fs.ensureDirSync(targetCypressDir);
41+
42+
// Copy all template files except cypress.config.ts into cypress/
43+
copyTemplateFiles(templateDir, targetCypressDir);
44+
45+
// Copy cypress.config.ts to root if it exists in template
46+
const templateConfigFile = path.join(templateDir, 'cypress.config.ts');
47+
48+
if (fs.existsSync(templateConfigFile)) {
49+
fs.copyFileSync(templateConfigFile, rootConfigFile);
50+
}
51+
52+
// Remove cypress.config.ts from cypress/
53+
const copiedConfig = path.join(targetCypressDir, 'cypress.config.ts');
54+
55+
if (fs.existsSync(copiedConfig)) {
56+
fs.removeSync(copiedConfig);
57+
}
58+
59+
// Add Cypress scripts to package.json
60+
const pkgJsonPath = path.join(cwd, 'package.json');
61+
62+
if (fs.existsSync(pkgJsonPath)) {
63+
try {
64+
const pkg = fs.readJsonSync(pkgJsonPath);
65+
66+
pkg.scripts = pkg.scripts || {};
67+
let changed = false;
68+
69+
if (!pkg.scripts['cypress:open']) {
70+
pkg.scripts['cypress:open'] = 'rancher-cypress open --e2e --browser chrome';
71+
changed = true;
72+
}
73+
if (!pkg.scripts['cypress:run']) {
74+
pkg.scripts['cypress:run'] = 'rancher-cypress run';
75+
changed = true;
76+
}
77+
if (changed) {
78+
fs.writeJsonSync(pkgJsonPath, pkg, { spaces: 2 });
79+
console.log(' Added cypress:open and/or cypress:run scripts to package.json');
80+
} else {
81+
console.log('ℹ cypress:open and cypress:run scripts already exist in package.json');
82+
}
83+
} catch (e) {
84+
console.error('❌ Could not update package.json with Cypress scripts:', e);
85+
}
86+
} else {
87+
console.warn('⚠️ No package.json found in project root. Skipping script addition.');
88+
}
89+
90+
// Add or create tsconfig.json with "cypress" in types
91+
const tsConfigPath = path.join(cwd, 'tsconfig.json');
92+
if (fs.existsSync(tsConfigPath)) {
93+
try {
94+
const tsConfig = fs.readJsonSync(tsConfigPath);
95+
tsConfig.compilerOptions = tsConfig.compilerOptions || {};
96+
let types = tsConfig.compilerOptions.types || [];
97+
if (!Array.isArray(types)) types = [types];
98+
if (!types.includes('cypress')) {
99+
types.push('cypress');
100+
tsConfig.compilerOptions.types = types;
101+
fs.writeJsonSync(tsConfigPath, tsConfig, { spaces: 2 });
102+
console.log(' Added "cypress" to compilerOptions.types in tsconfig.json');
103+
} else {
104+
console.log(' "cypress" already present in compilerOptions.types in tsconfig.json');
105+
}
106+
} catch (e) {
107+
console.error('❌ Could not update tsconfig.json:', e);
108+
}
109+
} else {
110+
// Create a basic tsconfig.json
111+
const basicTsConfig = {
112+
compilerOptions: {
113+
target: "esnext",
114+
module: "commonjs",
115+
types: ["cypress"]
116+
}
117+
};
118+
try {
119+
fs.writeJsonSync(tsConfigPath, basicTsConfig, { spaces: 2 });
120+
console.log('Created basic tsconfig.json with "cypress" in types');
121+
} catch (e) {
122+
console.error('❌ Could not create tsconfig.json:', e);
123+
}
124+
}
125+
126+
console.log('✅ Cypress project structure created in ./cypress');
127+
console.log('Next steps:');
128+
console.log(' Edit cypress.config.ts as needed');
129+
console.log(' Run "yarn cypress:open" to launch Cypress');
130+
} catch (err) {
131+
if (err.code === 'EEXIST') {
132+
console.error('🚫 Some files already exist. Aborting to avoid overwrite.');
133+
} else {
134+
console.error('❌ Error copying template files:', err);
135+
}
136+
process.exit(1);
137+
}
138+
}
139+
140+
main();

cypress/build.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ cp README.md dist/
6565
cp .npmignore dist/
6666
cp globals.d.ts dist/
6767

68+
# Copy CLI and template for yarn link testing
69+
cp -r bin dist/
70+
cp -r template dist/
71+
6872
echo "Package built successfully in dist/ directory"
6973
echo "To test with yarn link:"
7074
echo " cd dist"

0 commit comments

Comments
 (0)