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 CHANGED
@@ -8,20 +8,60 @@
8
8
 
9
9
  ---
10
10
 
11
- ## 🚀 Quick Start
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
- # Run once without installing
15
- npx cypress-validate --help
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
- # Or install globally
18
- npm install -g cypress-validate
19
- cypress-validate --help
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
- ## 📋 Command Reference
64
+ ## �📋 Command Reference
25
65
 
26
66
  ### `run` — Run tests headlessly *(like `npx playwright test`)*
27
67
 
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
4
  const { Command } = require('commander');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { execa } = require('execa');
3
+ const execa = require('execa');
4
4
  const chalk = require('chalk');
5
5
  const { logger } = require('../utils/logger');
6
6
  const { findProjectRoot } = require('../utils/config-finder');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { execa } = require('execa');
3
+ const execa = require('execa');
4
4
  const { logger, createSpinner } = require('../utils/logger');
5
5
  const { findProjectRoot } = require('../utils/config-finder');
6
6
  const chalk = require('chalk');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { execa } = require('execa');
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(cypressBin, args, {
28
+ await execa('npx', ['cypress', ...args], {
31
29
  cwd: projectRoot,
32
30
  stdio: 'inherit',
33
31
  });
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { execa } = require('execa');
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(cypressBin, args, {
44
+ await execa('npx', ['cypress', ...args], {
47
45
  cwd: projectRoot,
48
46
  stdio: 'inherit',
49
47
  env: {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { execa } = require('execa');
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(cypressBin, args, {
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 { execa } = require('execa');
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
- 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();
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
- const projectRoot = findProjectRoot();
21
+ const projectRoot = findProjectRoot();
22
22
 
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
- }
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
- // 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);
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
- const outputAbs = path.resolve(process.cwd(), opts.output);
39
- await fs.ensureDir(path.dirname(outputAbs));
38
+ const outputAbs = path.resolve(process.cwd(), opts.output);
39
+ await fs.ensureDir(path.dirname(outputAbs));
40
40
 
41
- const tempSpec = path.join(specsDir, '__screenshot__.cy.js');
42
- const specContent = `
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
- await fs.writeFile(tempSpec, specContent, 'utf-8');
54
+ await fs.writeFile(tempSpec, specContent, 'utf-8');
55
55
 
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, `
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
- const spinner = createSpinner('Taking screenshot...');
71
- spinner.start();
70
+ const spinner = createSpinner('Taking screenshot...');
71
+ spinner.start();
72
72
 
73
- const cypressBin = path.join(projectRoot, 'node_modules', '.bin', 'cypress');
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
- try {
76
- await execa(cypressBin, [
77
- 'run',
78
- '--spec', tempSpec,
79
- '--config-file', tmpConfigPath,
80
- '--browser', opts.browser,
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
- // Move screenshot to intended output location
88
- const generatedScreenshot = path.join(screenshotDir, 'cypress-validate screenshot', 'screenshot.png');
89
- if (await fs.pathExists(generatedScreenshot)) {
90
- await fs.move(generatedScreenshot, outputAbs, { overwrite: true });
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
- spinner.succeed(chalk.green('Screenshot saved!'));
94
- logger.blank();
95
- logger.info(`File: ${chalk.cyan(outputAbs)}`);
96
- } catch (err) {
97
- spinner.fail(chalk.red('Screenshot failed'));
98
- logger.error(err.message);
99
- logger.warn('Ensure Cypress is installed: ' + chalk.cyan('npx cypress-validate install'));
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
- logger.blank();
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 { execa } = require('execa');
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], {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { execa } = require('execa');
3
+ const execa = require('execa');
4
4
  const { logger, createSpinner } = require('../utils/logger');
5
5
  const { findProjectRoot } = require('../utils/config-finder');
6
6
  const chalk = require('chalk');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress-validate",
3
- "version": "1.0.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
+ }