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
8 changes: 8 additions & 0 deletions .c8rc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"all": true,
"include": ["src/**/*.js"],
"exclude": ["src/schemas/dereferenceSchemas.js"],
"reporter": ["text", "lcov", "json", "json-summary"],
"report-dir": "coverage",
"check-coverage": false
}
161 changes: 161 additions & 0 deletions .claude/skills/tdd-coverage/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# TDD and Coverage Skill

**Type:** Rigid (follow exactly)

## When to Use

Use this skill when:
- Creating new functionality
- Modifying existing code
- Fixing bugs
- Refactoring

## Mandatory Process

### 1. Test First (TDD)

Before writing or modifying any implementation code:

1. **Write the test(s)** that describe the expected behavior
2. **Run the test** - it should FAIL (red)
3. **Write the implementation** to make the test pass
4. **Run the test** - it should PASS (green)
5. **Refactor** if needed, keeping tests passing

### 2. Coverage Verification

After any code change:

```bash
# Run tests with coverage
npm run test:coverage

# Verify coverage hasn't decreased
npm run test:coverage:ratchet
```

**Coverage must not decrease.** If ratchet check fails:
1. Add tests for uncovered code
2. Re-run coverage until ratchet passes

### 3. Coverage Thresholds

Current thresholds are in `coverage-thresholds.json`. These values must only increase:

| Metric | Threshold |
|--------|-----------|
| Lines | 100% |
| Statements | 100% |
| Functions | 100% |
| Branches | 100% |

### 4. Test Location

| Code | Test File |
|------|-----------|
| `src/validate.js` | `test/validate.test.js` |
| `src/resolvePaths.js` | `test/resolvePaths.test.js` |
| `src/files.js` | `test/files.test.js` |
| Schema validation | `test/schema.test.js` |

### 5. Test Structure Pattern

```javascript
const sinon = require("sinon");

(async () => {
const { expect } = await import("chai");
const { functionUnderTest } = require("../src/module");

describe("functionUnderTest", function () {
describe("input validation", function () {
it("should throw error when required param missing", function () {
expect(() => functionUnderTest()).to.throw();
});
});

describe("happy path", function () {
it("should return expected result for valid input", function () {
const result = functionUnderTest({ validInput: true });
expect(result).to.deep.equal(expectedOutput);
});
});

describe("edge cases", function () {
it("should handle boundary condition", function () {
// test edge case
});
});
});
})();
```

### 6. Checklist

Before completing any code change:

- [ ] Tests written BEFORE implementation (or for existing code: tests added)
- [ ] All tests pass (`npm test`)
- [ ] Coverage hasn't decreased (`npm run test:coverage:ratchet`)
- [ ] New code has corresponding test coverage
- [ ] Error paths are tested (not just happy paths)

## Commands Reference

```bash
# Run all tests
npm test

# Run tests with coverage report
npm run test:coverage

# Run coverage ratchet check
npm run test:coverage:ratchet

# Generate HTML coverage report
npm run test:coverage:html
```

## Common Patterns

### Testing async functions

```javascript
it("should handle async operation", async function () {
const result = await asyncFunction();
expect(result).to.exist;
});
```

### Mocking with Sinon

```javascript
const stub = sinon.stub(fs, "readFileSync").returns("mock content");
try {
const result = functionUnderTest();
expect(result).to.equal("expected");
} finally {
stub.restore();
}
```

### Testing error handling

```javascript
it("should throw on invalid input", function () {
expect(() => functionUnderTest(null)).to.throw(/error message/);
});
```

### Testing transformations

```javascript
it("should transform v2 object to v3", function () {
const result = transformToSchemaKey({
currentSchema: "schema_v2",
targetSchema: "schema_v3",
object: v2Object,
});
expect(result.newProperty).to.equal(expectedValue);
});
```
6 changes: 6 additions & 0 deletions .github/workflows/auto-dev-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ jobs:
if: steps.check_changes.outputs.skip_release == 'false'
run: npm run build

- name: Run coverage and ratchet check
if: steps.check_changes.outputs.skip_release == 'false'
run: |
npm run test:coverage
npm run test:coverage:ratchet

- name: Configure Git
run: |
git config --global user.name 'github-actions[bot]'
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/npm-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,28 @@ jobs:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm run build # Automatically run tests because of the `postbuild` script in package.json

coverage:
name: Coverage Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: "npm"
cache-dependency-path: package-lock.json
node-version: 20
- run: npm ci
- run: npm run dereferenceSchemas
- name: Run tests with coverage
run: npm run test:coverage
- name: Check coverage ratchet
run: npm run test:coverage:ratchet
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/

threat-assessment:
if: github.event_name == 'release' && github.event.action == 'published'
Expand Down
47 changes: 47 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ When creating new schema version (e.g., v4):
**Test structure (Mocha + Chai):**
- `test/schema.test.js`: Validates all schema examples (auto-generated from schemas)
- `test/files.test.js`: Unit tests for `readFile()` with Sinon stubs
- `test/validate.test.js`: Tests for `validate()` and `transformToSchemaKey()`
- `test/resolvePaths.test.js`: Tests for path resolution

**Run tests:** `npm test` (or `mocha`)

Expand All @@ -115,6 +117,51 @@ const result = validate({ schemaKey: "step_v3", object: example });
assert.ok(result.valid, `Validation failed: ${result.errors}`);
```

### Testing Requirements (CRITICAL)

**TDD is mandatory for this project.** All code changes must follow test-driven development:

1. **Write tests first** - before any implementation
2. **Run tests** - verify they fail (red)
3. **Write implementation** - make tests pass
4. **Run tests** - verify they pass (green)
5. **Check coverage** - must not decrease

**Coverage enforcement:**

```bash
# Run tests with coverage
npm run test:coverage

# Verify coverage baseline (CI enforces this)
npm run test:coverage:ratchet

# Generate HTML report for detailed analysis
npm run test:coverage:html
```

**Current coverage thresholds (enforced by CI):**

| Metric | Threshold |
|--------|-----------|
| Lines | 100% |
| Statements | 100% |
| Functions | 100% |
| Branches | 100% |

**Coverage ratchet:** Thresholds in `coverage-thresholds.json` can only increase. CI fails if coverage decreases.

**Test file mapping:**

| Source | Test File |
|--------|-----------|
| `src/validate.js` | `test/validate.test.js` |
| `src/resolvePaths.js` | `test/resolvePaths.test.js` |
| `src/files.js` | `test/files.test.js` |
| Schema examples | `test/schema.test.js` |

**AI Tooling:** See `.claude/skills/tdd-coverage/SKILL.md` for detailed TDD workflow.

### Version Management & CI/CD Workflows

#### Auto Dev Release (`.github/workflows/auto-dev-release.yml`)
Expand Down
38 changes: 38 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Claude Code Configuration

This file is a pointer for Claude Code and similar AI assistants.

## Primary Documentation

See **[AGENTS.md](./AGENTS.md)** for complete project guidelines, architecture, and development workflows.

## Quick Reference

### Testing (CRITICAL)

**All code changes require TDD:**
1. Write tests first
2. Verify tests fail
3. Write implementation
4. Verify tests pass
5. Check coverage: `npm run test:coverage:ratchet`

**Coverage must never decrease.**

### Available Commands

```bash
npm test # Run tests
npm run test:coverage # Tests + coverage report
npm run test:coverage:ratchet # Verify coverage baseline
npm run build # Build schemas
```

### Key Files

| Purpose | Location |
|---------|----------|
| Project guidelines | `AGENTS.md` |
| TDD/Coverage skill | `.claude/skills/tdd-coverage/SKILL.md` |
| Coverage config | `.c8rc.json` |
| Coverage baseline | `coverage-thresholds.json` |
8 changes: 8 additions & 0 deletions coverage-thresholds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"description": "Coverage baseline thresholds. These values should only increase, never decrease.",
"lastUpdated": "2026-01-07",
"lines": 100,
"statements": 100,
"functions": 100,
"branches": 100
}
Loading