{"_id":"@djgilcrease/cypress-marks","_rev":"3-5046cda8e9bc8dde306263ad6fd27ac3","name":"@djgilcrease/cypress-marks","dist-tags":{"latest":"0.2.0"},"versions":{"0.0.0":{"name":"@djgilcrease/cypress-marks","version":"0.0.0","keywords":["cypress","testing","test-filtering","tags","marks","pytest","boolean-expressions"],"author":"","license":"MIT","_id":"@djgilcrease/cypress-marks@0.0.0","maintainers":[{"name":"digitalxero","email":"digitalxero@gmail.com"}],"dist":{"shasum":"4b977edd4673e01d35ea8195538e392637997b28","tarball":"https://registry.npmjs.org/@djgilcrease/cypress-marks/-/cypress-marks-0.0.0.tgz","fileCount":15,"integrity":"sha512-RkLN+fDW8e5EZCQDQmIwjfU3eo3yLz8GqbMqDoouSCLz0Uti94WiL60YllyFKaWBro/AUvptwkQRr+6ECtNFTQ==","signatures":[{"sig":"MEYCIQDXsJOzOtfMMr3cgaGjshBBObVCIsW2jb1UmTmzCjRi+wIhAOBpLhMAa2V9u51LS7/X6ccPvyHgN3roHRz3ia3GruIa","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":241730},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./plugin":{"import":{"types":"./dist/plugin.d.ts","default":"./dist/plugin.js"},"require":{"types":"./dist/plugin.d.cts","default":"./dist/plugin.cjs"}}},"gitHead":"1ddd6b8622342a78cb52f2c1412872935e1bfe07","scripts":{"lint":"eslint src tests","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"digitalxero","email":"digitalxero@gmail.com"},"repository":{"url":"","type":"git"},"_npmVersion":"10.5.0","description":"Cypress plugin for pytest-style test filtering with boolean expressions","directories":{},"_nodeVersion":"18.20.2","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","cypress":"^13.0.0","@eslint/js":"^9.0.0","typescript":"^5.0.0","@types/node":"^22.0.0","typescript-eslint":"^8.0.0","@vitest/coverage-v8":"^2.0.0"},"peerDependencies":{"cypress":">=10.0.0"},"optionalDependencies":{"globby":"^14.0.0","find-test-names":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cypress-marks_0.0.0_1770092048839_0.06635045665100114","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@djgilcrease/cypress-marks","version":"0.1.0","keywords":["cypress","testing","test-filtering","tags","marks","pytest","boolean-expressions"],"author":"","license":"MIT","_id":"@djgilcrease/cypress-marks@0.1.0","maintainers":[{"name":"digitalxero","email":"digitalxero@gmail.com"}],"homepage":"https://github.com/digitalxero/cypress-marks#readme","bugs":{"url":"https://github.com/digitalxero/cypress-marks/issues"},"dist":{"shasum":"ccad06588ac6193058e32490bf5fe92cdec8a2a6","tarball":"https://registry.npmjs.org/@djgilcrease/cypress-marks/-/cypress-marks-0.1.0.tgz","fileCount":15,"integrity":"sha512-e/8NUQX+sFafH0SDHx9sR92o0U4DUcE9tdNq3l8O+EM5JhpracTBj5R2Tmxcszm6h+OTxOZy1azuX0oew0Fl5Q==","signatures":[{"sig":"MEYCIQC/RsjJyx/EHVVPUkGEyutkPhceLPJTxOqw/rqxhwj9OQIhALqM96H5kOlaNo9AecIJFyVm8XCBSI+8jpoiHtP4IQ4d","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@djgilcrease%2fcypress-marks@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":241774},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./plugin":{"import":{"types":"./dist/plugin.d.ts","default":"./dist/plugin.js"},"require":{"types":"./dist/plugin.d.cts","default":"./dist/plugin.cjs"}}},"gitHead":"06afa2a087abfc6d8b4803007e8f2cc923d2d0c4","scripts":{"lint":"eslint src tests","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:e678d200-20f7-430d-b4c7-121e0bf0ef8c"}},"repository":{"url":"git+https://github.com/digitalxero/cypress-marks.git","type":"git"},"_npmVersion":"11.8.0","description":"Cypress plugin for pytest-style test filtering with boolean expressions","directories":{},"_nodeVersion":"20.20.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"^9.0.0","vitest":"^2.0.0","cypress":"^13.0.0","@eslint/js":"^9.0.0","typescript":"^5.0.0","@types/node":"^22.0.0","typescript-eslint":"^8.0.0","@vitest/coverage-v8":"^2.0.0"},"peerDependencies":{"cypress":">=10.0.0"},"optionalDependencies":{"globby":"^14.0.0","find-test-names":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/cypress-marks_0.1.0_1770095434928_0.49222938057577736","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@djgilcrease/cypress-marks","version":"0.2.0","description":"Cypress plugin for pytest-style test filtering with boolean expressions","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./plugin":{"import":{"types":"./dist/plugin.d.ts","default":"./dist/plugin.js"},"require":{"types":"./dist/plugin.d.cts","default":"./dist/plugin.cjs"}}},"scripts":{"build":"tsup","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","lint":"eslint src tests","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"keywords":["cypress","testing","test-filtering","tags","marks","pytest","boolean-expressions"],"author":"","license":"MIT","repository":{"type":"git","url":"git+https://github.com/digitalxero/cypress-marks.git"},"peerDependencies":{"cypress":">=10.0.0"},"devDependencies":{"@eslint/js":"^9.0.0","@types/node":"^22.0.0","@vitest/coverage-v8":"^2.0.0","cypress":"^13.0.0","eslint":"^9.0.0","tsup":"^8.0.0","typescript":"^5.0.0","typescript-eslint":"^8.0.0","vitest":"^2.0.0"},"optionalDependencies":{"globby":"^14.0.0"},"engines":{"node":">=18.0.0"},"gitHead":"a12255430a4e4f97e83f47df4841294259c0893c","_id":"@djgilcrease/cypress-marks@0.2.0","bugs":{"url":"https://github.com/digitalxero/cypress-marks/issues"},"homepage":"https://github.com/digitalxero/cypress-marks#readme","_nodeVersion":"20.20.0","_npmVersion":"11.8.0","dist":{"integrity":"sha512-ooTorZAYXrlZh09/vSQZ3HFjtcEsOz/2aRE93e0TBe1QfefZpMGse9N7/kwNi1YDlqMX6lT0iXTcCTbe8IDz+Q==","shasum":"893ef6977a78eaab4c7d0ce9d4f176d74912d8f9","tarball":"https://registry.npmjs.org/@djgilcrease/cypress-marks/-/cypress-marks-0.2.0.tgz","fileCount":15,"unpackedSize":385985,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@djgilcrease%2fcypress-marks@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC7LPq02QQ6H4Y+oIXiEMhE8iDT/fHATJ8K5sg7gJBvHwIhAJJwCE+l5oDXUblHFTN7kmmvWcifodlooTI8wzdnQgT0"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:e678d200-20f7-430d-b4c7-121e0bf0ef8c"}},"directories":{},"maintainers":[{"name":"digitalxero","email":"digitalxero@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cypress-marks_0.2.0_1770227544959_0.826705191304334"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-03T04:14:08.718Z","modified":"2026-02-04T17:52:25.390Z","0.0.0":"2026-02-03T04:14:08.975Z","0.1.0":"2026-02-03T05:10:35.062Z","0.2.0":"2026-02-04T17:52:25.118Z"},"bugs":{"url":"https://github.com/digitalxero/cypress-marks/issues"},"license":"MIT","homepage":"https://github.com/digitalxero/cypress-marks#readme","keywords":["cypress","testing","test-filtering","tags","marks","pytest","boolean-expressions"],"repository":{"type":"git","url":"git+https://github.com/digitalxero/cypress-marks.git"},"description":"Cypress plugin for pytest-style test filtering with boolean expressions","maintainers":[{"name":"digitalxero","email":"digitalxero@gmail.com"}],"readme":"# cypress-marks\n\n[![CI](https://github.com/digitalxero/cypress-marks/actions/workflows/ci.yml/badge.svg)](https://github.com/digitalxero/cypress-marks/actions/workflows/ci.yml)\n[![npm version](https://badge.fury.io/js/cypress-marks.svg)](https://www.npmjs.com/package/cypress-marks)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA Cypress plugin that filters tests using pytest-style expression parsing, providing `--env tags` (like pytest `-m`) and `--env tests` (like pytest `-k`) options with full boolean expression support.\n\n## Features\n\n- **Tag filtering**: `--env tags='@smoke and not @slow'`\n- **Test name filtering**: `--env tests='login or logout'`\n- **Path filtering**: `--env spec='file.cy.ts::Suite::test'` (pytest-style)\n- **Boolean expressions**: Full support for `and`, `or`, `not`, and parentheses\n- **Hierarchical tags**: Tags inherit through describe blocks\n- **Underscore mapping**: `test_login` matches \"test login\" in test names\n- **TypeScript support**: Full type definitions included\n\n## Installation\n\n```bash\nnpm install cypress-marks --save-dev\n```\n\n## Setup\n\n### 1. Register in support file\n\nAdd to your `cypress/support/e2e.ts`:\n\n```typescript\nimport { register } from 'cypress-marks';\n\nregister();\n```\n\n### 2. Configure plugin (optional, enables spec pre-filtering)\n\nAdd to your `cypress.config.ts`:\n\n```typescript\nimport { defineConfig } from 'cypress';\nimport { plugin } from 'cypress-marks/plugin';\n\nexport default defineConfig({\n  e2e: {\n    // IMPORTANT: Must be async and await the plugin!\n    async setupNodeEvents(on, config) {\n      ...\n      config = await plugin(on, config);\n\n      return config\n    },\n  },\n});\n```\n\n**Common mistakes:**\n```typescript\n// WRONG - not async, not awaiting\nsetupNodeEvents(on, config) {\n  return plugin(on, config);  // Returns Promise, not config!\n}\n\n// WRONG - not returning the config\nsetupNodeEvents(on, config) {\n  plugin(on, config);  // Config modifications are lost!\n}\n```\n\n## Usage\n\n### Tag Filtering\n\nTags must start with `@` prefix:\n\n```typescript\ndescribe('User Authentication', { tags: ['@smoke'] }, () => {\n  it('should login successfully', { tags: ['@critical'] }, () => {\n    // Test implementation\n  });\n\n  it('should handle invalid credentials', { tags: ['@negative'] }, () => {\n    // Test implementation\n  });\n});\n```\n\nRun with tag filters:\n\n```bash\n# Run only smoke tests\nnpx cypress run --env tags='@smoke'\n\n# Run smoke tests except slow ones\nnpx cypress run --env tags='@smoke and not @slow'\n\n# Run smoke or regression tests\nnpx cypress run --env tags='@smoke or @regression'\n\n# Complex expressions with parentheses\nnpx cypress run --env tags='(@smoke or @regression) and not @flaky'\n```\n\n### Test Name Filtering\n\nFilter by test name (case-insensitive substring match):\n\n```bash\n# Run tests containing \"login\"\nnpx cypress run --env tests='login'\n\n# Run tests containing \"login\" or \"logout\"\nnpx cypress run --env tests='login or logout'\n\n# Exclude tests containing \"slow\"\nnpx cypress run --env tests='not slow'\n```\n\n#### Underscore-to-Space Mapping\n\nUnderscores in expressions match spaces in test names:\n\n```bash\n# Matches \"user authentication\" in test names\nnpx cypress run --env tests='user_authentication'\n```\n\nTo match literal underscores, escape them:\n\n```bash\n# Matches \"user_auth\" literally\nnpx cypress run --env tests='user\\_auth'\n```\n\n### Path Filtering (Pytest-Style)\n\nSelect specific tests using pytest-style `::` separated paths:\n\n```bash\n# Run all tests in a specific file\nnpx cypress run --env spec='login.cy.ts'\n\n# Run all tests in a specific suite\nnpx cypress run --env spec='login.cy.ts::User Authentication'\n\n# Run a specific test\nnpx cypress run --env spec='login.cy.ts::User Authentication::should login successfully'\n\n# Nested suite hierarchy\nnpx cypress run --env spec='login.cy.ts::Auth::Login::validates credentials'\n\n# Use glob patterns for files\nnpx cypress run --env spec='**/auth/*.cy.ts::smoke'\n\n# Multiple files/tests (OR logic)\nnpx cypress run --env spec='login.cy.ts::login,logout.cy.ts::logout'\n```\n\n#### Path Syntax\n\n| Pattern | Description |\n|---------|-------------|\n| `file.cy.ts` | Run all tests in the file |\n| `file.cy.ts::Suite` | Run all tests in the suite (case-insensitive substring match) |\n| `file.cy.ts::Suite::test` | Run specific test (case-insensitive substring match) |\n| `file.cy.ts::Outer::Inner::test` | Nested suite path |\n| `**/*.cy.ts::Suite` | Glob pattern with suite filter |\n\n**Key behaviors:**\n- File path component uses glob matching (supports `*` and `**`)\n- Suite/test names use case-insensitive substring matching\n- Literal spaces are supported directly in names\n- Multiple specs separated by commas use OR logic\n\n### Combined Filtering\n\nUse both tag and name filters together:\n\n```bash\nnpx cypress run --env tags='@smoke',tests='login'\n```\n\nCombine path filtering with tag filtering:\n\n```bash\n# Run smoke tests in auth files\nnpx cypress run --env spec='**/auth/*.cy.ts',tags='@smoke'\n```\n\nAll specified conditions must match for a test to run (AND logic between filter types).\n\n### Filter Mode\n\nBy default, filtered tests appear as \"skipped\" in the Cypress reporter. To omit them entirely:\n\n```bash\nnpx cypress run --env tags='@smoke',marksOmitFiltered=true\n```\n\n## Expression Syntax\n\n### Operators\n\n| Operator | Description | Example |\n|----------|-------------|---------|\n| `and` | Logical AND | `@smoke and @fast` |\n| `or` | Logical OR | `@smoke or @regression` |\n| `not` | Logical NOT | `not @slow` |\n| `()` | Grouping | `(@smoke or @regression) and not @flaky` |\n\n### Precedence\n\nFrom highest to lowest:\n1. `not` (unary)\n2. `and` (binary, left-associative)\n3. `or` (binary, left-associative)\n\n### Examples\n\n```bash\n# Simple tag\n--env tags='@smoke'\n\n# Negation\n--env tags='not @slow'\n\n# AND (both must match)\n--env tags='@smoke and @critical'\n\n# OR (either matches)\n--env tags='@smoke or @regression'\n\n# Combined with precedence\n--env tags='@smoke and @critical or @regression'\n# Equivalent to: (@smoke and @critical) or @regression\n\n# Override precedence with parentheses\n--env tags='@smoke and (@critical or @regression)'\n```\n\n## Environment Variables\n\n| Variable | Type | Description |\n|----------|------|-------------|\n| `spec` | string | Pytest-style path filter (file::suite::test) |\n| `tags` | string | Tag filter expression |\n| `tests` | string | Test name filter expression |\n| `marksOmitFiltered` | boolean | Omit filtered tests vs skip (default: false) |\n| `marksFilterSpecs` | boolean | Pre-filter spec files (default: false, auto-enabled when `spec` is set) |\n| `marksDebug` | boolean | Enable debug logging (default: false) |\n\n## Tag Requirements\n\nTags **must** start with the `@` prefix:\n\n```typescript\n// Correct\n{ tags: ['@smoke', '@regression'] }\n\n// Incorrect - will throw TagValidationError\n{ tags: ['smoke', 'regression'] }\n```\n\nThis requirement applies to:\n- Tags defined in test/describe config\n- Tag identifiers in filter expressions\n\n## Advanced Usage\n\n### Programmatic Expression Evaluation\n\n```typescript\nimport { compile, createTagMatcher } from 'cypress-marks';\n\nconst expr = compile('@smoke and not @slow');\nconst tags = new Set(['@smoke', '@fast']);\nconst matcher = createTagMatcher(tags);\n\nconst matches = expr.evaluate(matcher); // true\n```\n\n### Custom Matchers\n\n```typescript\nimport { compile, createNameMatcher } from 'cypress-marks';\n\nconst expr = compile('login or logout');\nconst matcher = createNameMatcher('User can login successfully');\n\nconst matches = expr.evaluate(matcher); // true\n```\n\n## Spec Pre-Filtering\n\nWhen `marksFilterSpecs=true`, the plugin pre-scans spec files and excludes those with no matching tests. This prevents empty spec runs.\n\n**Required dependency:**\n```bash\nnpm install globby --save-dev\n```\n\n**Usage:**\n```bash\nnpx cypress run --env tags='@smoke',marksFilterSpecs=true\n```\n\n**How it works:**\n1. Parses each spec file to extract test names and tags (including inherited suite tags)\n2. Evaluates the filter expression against each test\n3. Excludes spec files where no tests would match\n4. Updates `config.specPattern` with only the matching specs\n\n**Limitations:**\n- Dynamic test generation (tests created at runtime) cannot be detected\n- The parser handles standard `describe`/`context`/`it`/`specify` syntax with `{ tags: [] }` config\n\n## Comparison with pytest\n\n| Feature | pytest | cypress-marks |\n|---------|--------|---------------|\n| Tag filtering | `-m 'smoke and not slow'` | `--env tags='@smoke and not @slow'` |\n| Name filtering | `-k 'login or logout'` | `--env tests='login or logout'` |\n| Path selection | `file.py::Class::test` | `--env spec='file.cy.ts::Suite::test'` |\n| Boolean ops | `and`, `or`, `not`, `()` | `and`, `or`, `not`, `()` |\n| Tag prefix | No requirement | Must start with `@` |\n\n## Contributing\n\n### Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Run tests with coverage\nnpm run test:coverage\n\n# Build\nnpm run build\n\n# Lint\nnpm run lint\n\n# Type check\nnpm run typecheck\n```\n\n### Release Process\n\nReleases are automated via GitHub Actions using [Conventional Commits](https://www.conventionalcommits.org/) and [svu](https://github.com/caarlos0/svu) for semantic versioning.\n\n**On Pull Request:**\n- Builds, tests, and lints\n- Publishes a release candidate to npm (e.g., `1.0.0-rc.feature-branch.42`)\n- Comments on the PR with the RC install command\n\n**On Merge to Main:**\n- Automatically determines the next version based on commit messages:\n  - `fix:` → patch bump (0.0.x)\n  - `feat:` → minor bump (0.x.0)\n  - `feat!:` or `BREAKING CHANGE:` → major bump (x.0.0)\n- Updates `package.json`, commits, and tags\n- Creates a GitHub Release with auto-generated notes\n- Publishes to npm\n\n**Commit Message Examples:**\n```bash\n# Patch release (0.0.1 → 0.0.2)\ngit commit -m \"fix: handle empty tag expressions correctly\"\n\n# Minor release (0.1.0 → 0.2.0)\ngit commit -m \"feat: add support for regex patterns in test filter\"\n\n# Major release (1.0.0 → 2.0.0)\ngit commit -m \"feat!: require @ prefix for all tags\"\n# or\ngit commit -m \"feat: new API\n\nBREAKING CHANGE: removed deprecated compile() options\"\n```\n\n### npm Trusted Publishing Setup\n\nThis project uses [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/) with GitHub Actions OIDC - no npm tokens required.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}