Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions bin/check.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,11 @@ program
}
});

// Push command (alias for check-tests manual **/**.md)
// Push command (alias for check-tests manual **/*.test.md)
program
.command('push')
.option('-d, --dir <dir>', 'test directory')
.option('-f, --files <files...>', 'file paths or glob patterns to push (defaults to **/*.test.md)')
.option('--no-skipped', 'throw error if skipped tests found')
.option('--typescript', 'enable typescript support')
.option('--sync', 'import tests to testomatio and wait for completion')
Expand All @@ -260,12 +261,15 @@ program
.option('--test-alias <test-alias>', 'Specify custom alias for test/it etc (separated by commas if multiple)')
.option('--exclude <pattern>', 'Glob pattern to exclude files from analysis')
.option('--force', 'skip git checks and force push files')
.description('Push manual tests from markdown files (alias for check-tests manual **/**.md)')
.description(
'Push manual tests from markdown files. Use --files to pass paths or glob patterns (defaults to **/*.test.md).',
)
.action(async opts => {
// Alias: call main action with 'manual' framework and '**/**.md' files
const globalOpts = program.opts();
const mergedOpts = { ...globalOpts, ...opts, updateIds: true };
await mainAction('manual', '**/**.md', mergedOpts);
const files =
opts.files && opts.files.length ? (opts.files.length === 1 ? opts.files[0] : opts.files) : '**/*.test.md';
await mainAction('manual', files, mergedOpts);
});

if (process.argv.length <= 2) {
Expand Down
51 changes: 51 additions & 0 deletions cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,57 @@ npx check-tests <framework> <files> [options]
- `<framework>` - Test framework to analyze (codeceptjs, jasmine, jest, mocha, newman, playwright, qunit, testcafe, nightwatch)
- `<files>` - Glob pattern to match test files (e.g., `"tests/**/*_test.js"`)

## Push Command

The `push` command is a shortcut for importing markdown-based manual tests into Testomat.io. It is equivalent to `check-tests manual <files>` with `--update-ids` enabled by default.

```bash
npx check-tests push [options]
```

### Push Options

| Option | Description | Default |
| ------------------------ | ----------------------------------------------- | -------------- |
| `-d, --dir <dir>` | Test directory to scan | Current dir |
| `-f, --files <files...>` | One or more file paths or glob patterns to push | `**/*.test.md` |
| `--force` | Skip git checks and force push files | false |

The `push` command also accepts the same Testomat.io and analysis options as the main command (`--sync`, `--create`, `--no-empty`, `--keep-structure`, `--clean-ids`, `--purge`, `--no-detached`, `--no-skipped`, `--exclude`, etc.).

### `--files` Option

Use `--files` (or `-f`) to override the default glob (`**/*.test.md`). It accepts:

- a **single file path** — push exactly that file
- **multiple file paths** — push every listed file
- a **glob pattern** (in quotes) — push every file matched by the pattern
- **multiple glob patterns** — push the union of files matched by each pattern

Paths and patterns are resolved relative to `--dir` (or the current directory if `--dir` is not set).

### Push Examples

```bash
# Push every **/*.test.md file under the current directory (default behaviour)
TESTOMATIO=your-api-key npx check-tests push

# Push a single markdown file
TESTOMATIO=your-api-key npx check-tests push --files docs/login.test.md

# Push several specific files
TESTOMATIO=your-api-key npx check-tests push -f docs/login.test.md docs/checkout.test.md

# Push everything matching a custom glob (quote the pattern!)
TESTOMATIO=your-api-key npx check-tests push --files "manual-tests/**/*.md"

# Combine multiple globs (e.g. smoke + regression suites)
TESTOMATIO=your-api-key npx check-tests push -f "smoke/**/*.test.md" "regression/**/*.test.md"

# Use a non-default directory together with --files
TESTOMATIO=your-api-key npx check-tests push -d ./tests --files "**/*.md"
```

## CLI Options

### Basic Options
Expand Down
10 changes: 8 additions & 2 deletions src/updateIds/updateIds-markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ const glob = require('glob');
const path = require('path');
const { TAG_REGEX } = require('./constants');

function resolvePatterns(workDir, pattern) {
const base = path.resolve(workDir);
const patterns = Array.isArray(pattern) ? pattern : [pattern];
return patterns.map(p => path.join(base, p));
}

/**
* Insert test ids (@T12345678) and suite ids (@S12345678) into markdown test files
* @param {*} testomatioMap mapping of test ids received from testomatio server
Expand All @@ -12,7 +18,7 @@ const { TAG_REGEX } = require('./constants');
* @returns
*/
function updateIdsMarkdown(testomatioMap, workDir, opts = {}) {
const patternWithFullPath = path.join(path.resolve(workDir), opts.pattern);
const patternWithFullPath = resolvePatterns(workDir, opts.pattern);
const files = glob.sync(patternWithFullPath);
debug('Files:', files);

Expand Down Expand Up @@ -131,7 +137,7 @@ function updateId(lines, lineNumber, mappedId) {
* Remove test ids from markdown test files
*/
function cleanIdsMarkdown(testomatioMap, workDir, opts = { dangerous: false }) {
const patternWithFullPath = path.join(path.resolve(workDir), opts.pattern);
const patternWithFullPath = resolvePatterns(workDir, opts.pattern);
const files = glob.sync(patternWithFullPath);

debug('Files:', files);
Expand Down
91 changes: 89 additions & 2 deletions tests/push_command_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const path = require('path');

describe('push command', () => {
let testDir;
const testMarkdownFile = 'test-manual.md';
const testMarkdownFile = 'manual.test.md';
const testMarkdownContent = `<!-- suite -->
# Manual Test Suite

Expand Down Expand Up @@ -67,7 +67,7 @@ priority: medium
});

expect(output).to.include('SHOWING MANUAL TESTS');
expect(output).to.include('**/**.md');
expect(output).to.include('**/*.test.md');
expect(output).to.include('Login functionality');
expect(output).to.include('Invalid login');
} catch (error) {
Expand Down Expand Up @@ -157,6 +157,93 @@ priority: medium
}
});

it('should accept a single file path via --files', () => {
const extraContent = `<!-- suite -->
# Extra Suite

<!-- test -->
## Extra Test
- step
`;
fs.writeFileSync(path.join(testDir, 'extra.md'), extraContent);

const output = execSync(`node bin/check.js push -d ${testDir} --files extra.md`, {
cwd: path.join(__dirname, '..'),
encoding: 'utf8',
timeout: 10000,
});

expect(output).to.include('SHOWING MANUAL TESTS FROM extra.md');
expect(output).to.include('Extra Test');
expect(output).to.not.include('Login functionality');
});

it('should accept multiple file paths via --files', () => {
const extraContent = `<!-- suite -->
# Extra Suite

<!-- test -->
## Extra Test
- step
`;
fs.writeFileSync(path.join(testDir, 'extra.md'), extraContent);

const output = execSync(`node bin/check.js push -d ${testDir} -f ${testMarkdownFile} extra.md`, {
cwd: path.join(__dirname, '..'),
encoding: 'utf8',
timeout: 10000,
});

expect(output).to.include('SHOWING MANUAL TESTS');
expect(output).to.include('Login functionality');
expect(output).to.include('Extra Test');
});

it('should accept a glob pattern via --files', () => {
const output = execSync(`node bin/check.js push -d ${testDir} --files "*.md"`, {
cwd: path.join(__dirname, '..'),
encoding: 'utf8',
timeout: 10000,
});

expect(output).to.include('SHOWING MANUAL TESTS FROM *.md');
expect(output).to.include('Login functionality');
});

it('should accept a file path inside a subdirectory via --files', () => {
const subDir = path.join(testDir, 'nested');
fs.mkdirSync(subDir, { recursive: true });
const nestedContent = `<!-- suite -->
# Nested Suite

<!-- test -->
## Nested Test
- step
`;
fs.writeFileSync(path.join(subDir, 'nested.md'), nestedContent);

const output = execSync(`node bin/check.js push -d ${testDir} --files nested/nested.md`, {
cwd: path.join(__dirname, '..'),
encoding: 'utf8',
timeout: 10000,
});

expect(output).to.include('SHOWING MANUAL TESTS FROM nested/nested.md');
expect(output).to.include('Nested Test');
expect(output).to.not.include('Login functionality');
});

it('should expose --files option in --help output', () => {
const output = execSync('node bin/check.js push --help', {
cwd: path.join(__dirname, '..'),
encoding: 'utf8',
});

expect(output).to.include('--files');
expect(output).to.include('-f');
expect(output).to.include('**/*.test.md');
});

it('should work with empty directory (finds tests in current project)', () => {
const emptyDir = path.join(testDir, 'empty');
fs.mkdirSync(emptyDir, { recursive: true });
Expand Down
Loading