@djgilcrease/cypress-marks
v0.2.0
Published
Cypress plugin for pytest-style test filtering with boolean expressions
Maintainers
Readme
cypress-marks
A 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.
Features
- Tag filtering:
--env tags='@smoke and not @slow' - Test name filtering:
--env tests='login or logout' - Path filtering:
--env spec='file.cy.ts::Suite::test'(pytest-style) - Boolean expressions: Full support for
and,or,not, and parentheses - Hierarchical tags: Tags inherit through describe blocks
- Underscore mapping:
test_loginmatches "test login" in test names - TypeScript support: Full type definitions included
Installation
npm install cypress-marks --save-devSetup
1. Register in support file
Add to your cypress/support/e2e.ts:
import { register } from 'cypress-marks';
register();2. Configure plugin (optional, enables spec pre-filtering)
Add to your cypress.config.ts:
import { defineConfig } from 'cypress';
import { plugin } from 'cypress-marks/plugin';
export default defineConfig({
e2e: {
// IMPORTANT: Must be async and await the plugin!
async setupNodeEvents(on, config) {
...
config = await plugin(on, config);
return config
},
},
});Common mistakes:
// WRONG - not async, not awaiting
setupNodeEvents(on, config) {
return plugin(on, config); // Returns Promise, not config!
}
// WRONG - not returning the config
setupNodeEvents(on, config) {
plugin(on, config); // Config modifications are lost!
}Usage
Tag Filtering
Tags must start with @ prefix:
describe('User Authentication', { tags: ['@smoke'] }, () => {
it('should login successfully', { tags: ['@critical'] }, () => {
// Test implementation
});
it('should handle invalid credentials', { tags: ['@negative'] }, () => {
// Test implementation
});
});Run with tag filters:
# Run only smoke tests
npx cypress run --env tags='@smoke'
# Run smoke tests except slow ones
npx cypress run --env tags='@smoke and not @slow'
# Run smoke or regression tests
npx cypress run --env tags='@smoke or @regression'
# Complex expressions with parentheses
npx cypress run --env tags='(@smoke or @regression) and not @flaky'Test Name Filtering
Filter by test name (case-insensitive substring match):
# Run tests containing "login"
npx cypress run --env tests='login'
# Run tests containing "login" or "logout"
npx cypress run --env tests='login or logout'
# Exclude tests containing "slow"
npx cypress run --env tests='not slow'Underscore-to-Space Mapping
Underscores in expressions match spaces in test names:
# Matches "user authentication" in test names
npx cypress run --env tests='user_authentication'To match literal underscores, escape them:
# Matches "user_auth" literally
npx cypress run --env tests='user\_auth'Path Filtering (Pytest-Style)
Select specific tests using pytest-style :: separated paths:
# Run all tests in a specific file
npx cypress run --env spec='login.cy.ts'
# Run all tests in a specific suite
npx cypress run --env spec='login.cy.ts::User Authentication'
# Run a specific test
npx cypress run --env spec='login.cy.ts::User Authentication::should login successfully'
# Nested suite hierarchy
npx cypress run --env spec='login.cy.ts::Auth::Login::validates credentials'
# Use glob patterns for files
npx cypress run --env spec='**/auth/*.cy.ts::smoke'
# Multiple files/tests (OR logic)
npx cypress run --env spec='login.cy.ts::login,logout.cy.ts::logout'Path Syntax
| Pattern | Description |
|---------|-------------|
| file.cy.ts | Run all tests in the file |
| file.cy.ts::Suite | Run all tests in the suite (case-insensitive substring match) |
| file.cy.ts::Suite::test | Run specific test (case-insensitive substring match) |
| file.cy.ts::Outer::Inner::test | Nested suite path |
| **/*.cy.ts::Suite | Glob pattern with suite filter |
Key behaviors:
- File path component uses glob matching (supports
*and**) - Suite/test names use case-insensitive substring matching
- Literal spaces are supported directly in names
- Multiple specs separated by commas use OR logic
Combined Filtering
Use both tag and name filters together:
npx cypress run --env tags='@smoke',tests='login'Combine path filtering with tag filtering:
# Run smoke tests in auth files
npx cypress run --env spec='**/auth/*.cy.ts',tags='@smoke'All specified conditions must match for a test to run (AND logic between filter types).
Filter Mode
By default, filtered tests appear as "skipped" in the Cypress reporter. To omit them entirely:
npx cypress run --env tags='@smoke',marksOmitFiltered=trueExpression Syntax
Operators
| Operator | Description | Example |
|----------|-------------|---------|
| and | Logical AND | @smoke and @fast |
| or | Logical OR | @smoke or @regression |
| not | Logical NOT | not @slow |
| () | Grouping | (@smoke or @regression) and not @flaky |
Precedence
From highest to lowest:
not(unary)and(binary, left-associative)or(binary, left-associative)
Examples
# Simple tag
--env tags='@smoke'
# Negation
--env tags='not @slow'
# AND (both must match)
--env tags='@smoke and @critical'
# OR (either matches)
--env tags='@smoke or @regression'
# Combined with precedence
--env tags='@smoke and @critical or @regression'
# Equivalent to: (@smoke and @critical) or @regression
# Override precedence with parentheses
--env tags='@smoke and (@critical or @regression)'Environment Variables
| Variable | Type | Description |
|----------|------|-------------|
| spec | string | Pytest-style path filter (file::suite::test) |
| tags | string | Tag filter expression |
| tests | string | Test name filter expression |
| marksOmitFiltered | boolean | Omit filtered tests vs skip (default: false) |
| marksFilterSpecs | boolean | Pre-filter spec files (default: false, auto-enabled when spec is set) |
| marksDebug | boolean | Enable debug logging (default: false) |
Tag Requirements
Tags must start with the @ prefix:
// Correct
{ tags: ['@smoke', '@regression'] }
// Incorrect - will throw TagValidationError
{ tags: ['smoke', 'regression'] }This requirement applies to:
- Tags defined in test/describe config
- Tag identifiers in filter expressions
Advanced Usage
Programmatic Expression Evaluation
import { compile, createTagMatcher } from 'cypress-marks';
const expr = compile('@smoke and not @slow');
const tags = new Set(['@smoke', '@fast']);
const matcher = createTagMatcher(tags);
const matches = expr.evaluate(matcher); // trueCustom Matchers
import { compile, createNameMatcher } from 'cypress-marks';
const expr = compile('login or logout');
const matcher = createNameMatcher('User can login successfully');
const matches = expr.evaluate(matcher); // trueSpec Pre-Filtering
When marksFilterSpecs=true, the plugin pre-scans spec files and excludes those with no matching tests. This prevents empty spec runs.
Required dependency:
npm install globby --save-devUsage:
npx cypress run --env tags='@smoke',marksFilterSpecs=trueHow it works:
- Parses each spec file to extract test names and tags (including inherited suite tags)
- Evaluates the filter expression against each test
- Excludes spec files where no tests would match
- Updates
config.specPatternwith only the matching specs
Limitations:
- Dynamic test generation (tests created at runtime) cannot be detected
- The parser handles standard
describe/context/it/specifysyntax with{ tags: [] }config
Comparison with pytest
| Feature | pytest | cypress-marks |
|---------|--------|---------------|
| Tag filtering | -m 'smoke and not slow' | --env tags='@smoke and not @slow' |
| Name filtering | -k 'login or logout' | --env tests='login or logout' |
| Path selection | file.py::Class::test | --env spec='file.cy.ts::Suite::test' |
| Boolean ops | and, or, not, () | and, or, not, () |
| Tag prefix | No requirement | Must start with @ |
Contributing
Development
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build
npm run build
# Lint
npm run lint
# Type check
npm run typecheckRelease Process
Releases are automated via GitHub Actions using Conventional Commits and svu for semantic versioning.
On Pull Request:
- Builds, tests, and lints
- Publishes a release candidate to npm (e.g.,
1.0.0-rc.feature-branch.42) - Comments on the PR with the RC install command
On Merge to Main:
- Automatically determines the next version based on commit messages:
fix:→ patch bump (0.0.x)feat:→ minor bump (0.x.0)feat!:orBREAKING CHANGE:→ major bump (x.0.0)
- Updates
package.json, commits, and tags - Creates a GitHub Release with auto-generated notes
- Publishes to npm
Commit Message Examples:
# Patch release (0.0.1 → 0.0.2)
git commit -m "fix: handle empty tag expressions correctly"
# Minor release (0.1.0 → 0.2.0)
git commit -m "feat: add support for regex patterns in test filter"
# Major release (1.0.0 → 2.0.0)
git commit -m "feat!: require @ prefix for all tags"
# or
git commit -m "feat: new API
BREAKING CHANGE: removed deprecated compile() options"npm Trusted Publishing Setup
This project uses npm Trusted Publishing with GitHub Actions OIDC - no npm tokens required.
License
MIT
