cypress-validate 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -7
- package/bin/cypress-validate.js +1 -1
- package/lib/commands/info.js +1 -1
- package/lib/commands/install.js +1 -1
- package/lib/commands/open.js +2 -4
- package/lib/commands/record.js +2 -4
- package/lib/commands/run.js +2 -5
- package/lib/commands/screenshot.js +76 -62
- package/lib/commands/show-report.js +1 -1
- package/lib/commands/verify.js +1 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -8,20 +8,60 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## 🚀
|
|
11
|
+
## 🚀 Step-by-Step Guide
|
|
12
|
+
|
|
13
|
+
### 1. Installation
|
|
14
|
+
In your existing Cypress project, install `cypress-validate` as a dev dependency:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install --save-dev cypress-validate
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Scaffold Your First Test
|
|
21
|
+
Generate a new spec file using the `generate` command (like `codegen`):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx cypress-validate generate --name login --type spec --url http://localhost:3000
|
|
25
|
+
```
|
|
26
|
+
*This creates `cypress/e2e/login.cy.js` with a boilerplate test.*
|
|
27
|
+
|
|
28
|
+
### 3. Run Your Tests
|
|
29
|
+
Execute your tests in headless mode with a simple command:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx cypress-validate run
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 4. Debug in UI Mode
|
|
36
|
+
Open the interactive Test Runner to debug failure:
|
|
12
37
|
|
|
13
38
|
```bash
|
|
14
|
-
|
|
15
|
-
|
|
39
|
+
npx cypress-validate open --spec cypress/e2e/login.cy.js
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 5. View the Report
|
|
43
|
+
After a run finishes, view the HTML results instantly:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx cypress-validate show-report
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## �️ Troubleshooting
|
|
16
52
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
53
|
+
### Peer Dependency Conflicts (`ERESOLVE`)
|
|
54
|
+
If you see an `ERESOLVE could not resolve` error during installation, it is usually because another plugin in your project (like `@4tw/cypress-drag-drop`) has a strict peer dependency on an older version of Cypress (e.g., `< 14`), while you are using a newer version.
|
|
55
|
+
|
|
56
|
+
To bypass this and install `cypress-validate`, use:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install --save-dev cypress-validate --legacy-peer-deps
|
|
20
60
|
```
|
|
21
61
|
|
|
22
62
|
---
|
|
23
63
|
|
|
24
|
-
##
|
|
64
|
+
## �📋 Command Reference
|
|
25
65
|
|
|
26
66
|
### `run` — Run tests headlessly *(like `npx playwright test`)*
|
|
27
67
|
|
package/bin/cypress-validate.js
CHANGED
package/lib/commands/info.js
CHANGED
package/lib/commands/install.js
CHANGED
package/lib/commands/open.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const execa = require('execa');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { logger } = require('../utils/logger');
|
|
6
6
|
const { findProjectRoot } = require('../utils/config-finder');
|
|
@@ -24,10 +24,8 @@ module.exports = async function openCommand(opts) {
|
|
|
24
24
|
if (opts.env) args.push('--env', opts.env);
|
|
25
25
|
if (opts.port) args.push('--port', opts.port);
|
|
26
26
|
|
|
27
|
-
const cypressBin = path.join(projectRoot, 'node_modules', '.bin', 'cypress');
|
|
28
|
-
|
|
29
27
|
try {
|
|
30
|
-
await execa(
|
|
28
|
+
await execa('npx', ['cypress', ...args], {
|
|
31
29
|
cwd: projectRoot,
|
|
32
30
|
stdio: 'inherit',
|
|
33
31
|
});
|
package/lib/commands/record.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const execa = require('execa');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const chalk = require('chalk');
|
|
6
6
|
const { logger } = require('../utils/logger');
|
|
@@ -40,10 +40,8 @@ module.exports = async function recordCommand(opts) {
|
|
|
40
40
|
logger.divider();
|
|
41
41
|
logger.blank();
|
|
42
42
|
|
|
43
|
-
const cypressBin = path.join(projectRoot, 'node_modules', '.bin', 'cypress');
|
|
44
|
-
|
|
45
43
|
try {
|
|
46
|
-
await execa(
|
|
44
|
+
await execa('npx', ['cypress', ...args], {
|
|
47
45
|
cwd: projectRoot,
|
|
48
46
|
stdio: 'inherit',
|
|
49
47
|
env: {
|
package/lib/commands/run.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const execa = require('execa');
|
|
4
4
|
const chalk = require('chalk');
|
|
5
5
|
const fs = require('fs-extra');
|
|
6
6
|
const path = require('path');
|
|
@@ -105,11 +105,8 @@ module.exports = async function runCommand(opts) {
|
|
|
105
105
|
logger.divider();
|
|
106
106
|
logger.blank();
|
|
107
107
|
|
|
108
|
-
// Resolve cypress binary
|
|
109
|
-
const cypressBin = path.join(projectRoot, 'node_modules', '.bin', 'cypress');
|
|
110
|
-
|
|
111
108
|
try {
|
|
112
|
-
const proc = execa(
|
|
109
|
+
const proc = execa('npx', ['cypress', ...args], {
|
|
113
110
|
cwd: projectRoot,
|
|
114
111
|
stdio: 'inherit',
|
|
115
112
|
env: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const execa = require('execa');
|
|
4
4
|
const fs = require('fs-extra');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const os = require('os');
|
|
@@ -9,37 +9,37 @@ const { logger, createSpinner } = require('../utils/logger');
|
|
|
9
9
|
const { findProjectRoot } = require('../utils/config-finder');
|
|
10
10
|
|
|
11
11
|
module.exports = async function screenshotCommand(opts) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
logger.title('Cypress Validate — Screenshot');
|
|
13
|
+
logger.divider();
|
|
14
|
+
logger.step(`URL: ${chalk.cyan(opts.url)}`);
|
|
15
|
+
logger.step(`Output: ${chalk.cyan(opts.output)}`);
|
|
16
|
+
logger.step(`Browser: ${chalk.cyan(opts.browser)}`);
|
|
17
|
+
if (opts.fullPage) logger.step('Full-page: enabled');
|
|
18
|
+
logger.divider();
|
|
19
|
+
logger.blank();
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const projectRoot = findProjectRoot();
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
// Parse viewport
|
|
24
|
+
let viewportWidth = 1280;
|
|
25
|
+
let viewportHeight = 720;
|
|
26
|
+
if (opts.viewport) {
|
|
27
|
+
const parts = opts.viewport.split('x');
|
|
28
|
+
viewportWidth = parseInt(parts[0], 10) || 1280;
|
|
29
|
+
viewportHeight = parseInt(parts[1], 10) || 720;
|
|
30
|
+
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
// Build a temporary spec file
|
|
33
|
+
const tmpDir = path.join(os.tmpdir(), 'cypress-validate-screenshot');
|
|
34
|
+
await fs.ensureDir(tmpDir);
|
|
35
|
+
const specsDir = path.join(tmpDir, 'cypress', 'e2e');
|
|
36
|
+
await fs.ensureDir(specsDir);
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const outputAbs = path.resolve(process.cwd(), opts.output);
|
|
39
|
+
await fs.ensureDir(path.dirname(outputAbs));
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const tempSpec = path.join(specsDir, '__screenshot__.cy.js');
|
|
42
|
+
const specContent = `
|
|
43
43
|
/// <reference types="cypress" />
|
|
44
44
|
describe('cypress-validate screenshot', () => {
|
|
45
45
|
it('captures a screenshot of ${opts.url}', () => {
|
|
@@ -51,12 +51,12 @@ describe('cypress-validate screenshot', () => {
|
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
53
|
`;
|
|
54
|
-
|
|
54
|
+
await fs.writeFile(tempSpec, specContent, 'utf-8');
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
// Write a temporary cypress config
|
|
57
|
+
const tmpConfigPath = path.join(tmpDir, 'cypress.config.js');
|
|
58
|
+
const screenshotDir = path.dirname(outputAbs);
|
|
59
|
+
await fs.writeFile(tmpConfigPath, `
|
|
60
60
|
const { defineConfig } = require('cypress');
|
|
61
61
|
module.exports = defineConfig({
|
|
62
62
|
e2e: {
|
|
@@ -67,40 +67,54 @@ module.exports = defineConfig({
|
|
|
67
67
|
});
|
|
68
68
|
`, 'utf-8');
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
const spinner = createSpinner('Taking screenshot...');
|
|
71
|
+
spinner.start();
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
try {
|
|
74
|
+
await execa('npx', [
|
|
75
|
+
'cypress',
|
|
76
|
+
'run',
|
|
77
|
+
'--spec', tempSpec,
|
|
78
|
+
'--config-file', tmpConfigPath,
|
|
79
|
+
'--browser', opts.browser,
|
|
80
|
+
'--headless',
|
|
81
|
+
], {
|
|
82
|
+
cwd: tmpDir,
|
|
83
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
84
|
+
});
|
|
74
85
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
'--headless',
|
|
82
|
-
], {
|
|
83
|
-
cwd: tmpDir,
|
|
84
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
85
|
-
});
|
|
86
|
+
// Move screenshot to intended output location
|
|
87
|
+
// Cypress structure: screenshotsFolder/SpecName/SnapshotName.png
|
|
88
|
+
const possiblePaths = [
|
|
89
|
+
path.join(screenshotDir, 'cypress-validate screenshot', 'screenshot.png'),
|
|
90
|
+
path.join(screenshotDir, '__screenshot__.cy.js', 'screenshot.png'),
|
|
91
|
+
];
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
let moved = false;
|
|
94
|
+
for (const p of possiblePaths) {
|
|
95
|
+
if (await fs.pathExists(p)) {
|
|
96
|
+
await fs.move(p, outputAbs, { overwrite: true });
|
|
97
|
+
moved = true;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
92
101
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
process.exit(1);
|
|
101
|
-
} finally {
|
|
102
|
-
await fs.remove(tmpDir).catch(() => { });
|
|
102
|
+
if (moved) {
|
|
103
|
+
spinner.succeed(chalk.green('Screenshot saved!'));
|
|
104
|
+
logger.blank();
|
|
105
|
+
logger.info(`File: ${chalk.cyan(outputAbs)}`);
|
|
106
|
+
} else {
|
|
107
|
+
spinner.fail(chalk.red('Screenshot captured but could not be located'));
|
|
108
|
+
logger.warn(`Checked: ${possiblePaths.join(', ')}`);
|
|
103
109
|
}
|
|
110
|
+
} catch (err) {
|
|
111
|
+
spinner.fail(chalk.red('Screenshot failed'));
|
|
112
|
+
logger.error(err.message);
|
|
113
|
+
logger.warn('Ensure Cypress is installed: ' + chalk.cyan('npx cypress-validate install'));
|
|
114
|
+
process.exit(1);
|
|
115
|
+
} finally {
|
|
116
|
+
await fs.remove(tmpDir).catch(() => { });
|
|
117
|
+
}
|
|
104
118
|
|
|
105
|
-
|
|
119
|
+
logger.blank();
|
|
106
120
|
};
|
|
@@ -42,7 +42,7 @@ module.exports = async function showReportCommand(opts) {
|
|
|
42
42
|
logger.step(`Port: ${chalk.cyan(port)}`);
|
|
43
43
|
logger.blank();
|
|
44
44
|
try {
|
|
45
|
-
const
|
|
45
|
+
const execa = require('execa');
|
|
46
46
|
logger.info(`Open: ${chalk.cyan(`http://localhost:${port}`)}`);
|
|
47
47
|
logger.blank();
|
|
48
48
|
await execa('npx', ['serve', '-p', port, reportRoot], {
|
package/lib/commands/verify.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cypress-validate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A Playwright-style CLI for Cypress — run, open, generate, screenshot, report and more via npx cypress-validate",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -61,5 +61,11 @@
|
|
|
61
61
|
},
|
|
62
62
|
"bugs": {
|
|
63
63
|
"url": "https://github.com/mvsaran/cypress-validate/issues"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"cypress": "^15.10.0",
|
|
67
|
+
"mochawesome": "^7.1.4",
|
|
68
|
+
"mochawesome-merge": "^5.1.1",
|
|
69
|
+
"mochawesome-report-generator": "^6.3.2"
|
|
64
70
|
}
|
|
65
|
-
}
|
|
71
|
+
}
|