Skip to content

Testing

Rut.ts has comprehensive test coverage to ensure reliability.

Test Suite#

The library is tested using Jest with 523 test cases covering all functions and edge cases.

Shell
npm test

Coverage Statistics#

  • 16 Test suites (one per public function, plus error, property-based, differential, bundle-smoke, and type-level suites)
  • 523 Test cases (comprehensive coverage)
  • 100% Pass rate

Beyond example-based tests#

Example-based unit tests are only part of the story. The suite also runs:

  • Property-based testing with fast-check — generated inputs assert invariants (round-tripping, idempotence, verifier correctness) across large random samples rather than a handful of hand-picked cases.
  • A seeded, reproducible differential harness vs frozen v3.4.0 and v4.1.0 baselines — the current implementation is compared against verbatim snapshots of both prior major lines (validate and, for 4.1.0, equals) on shared inputs; a fixed seed keeps any divergence reproducible.
  • Periodic Stryker mutation testing — mutants are injected to confirm the tests actually fail when behavior changes, reaching ~94% mutation score on the Modulo 11 hot path.

What's Tested#

✅ Valid RUT Cases#

  • Different formats (with/without dots, hyphens)
  • K verifier (uppercase and lowercase)
  • 8 and 9 character RUTs
  • All verifier digits (0-9, K)

✅ Invalid RUT Cases#

  • Wrong verifier digits
  • Leading-zero padding (rejected by the acceptance predicates since 5.0.0)
  • Too short/long RUTs
  • Invalid characters
  • K not at the end
  • Empty strings
  • Non-string inputs

✅ Edge Cases#

  • Body bounds: 7-digit floor (1.000.000-9 is the smallest valid RUT) and 8-digit maximum (99.999.999-9); just-under-minimum inputs are rejected
  • Verifier digit 0
  • Multiple K letters
  • Special characters
  • Whitespace handling
  • Parentheses

✅ Safe Mode#

  • The 7 throwing helpers (clean, format, decompose, getBody, getVerifier, calculateVerifier, mask) tested with throwOnError: false
  • Null return validation
  • Combined options testing

✅ Incremental Formatting#

  • Progressive formatting at each length
  • Hyphen appearance at 8+ chars
  • Leading zeros in incremental mode
  • Very long inputs
  • Empty inputs

✅ Strict Mode#

  • Suspicious pattern detection
  • Normal RUTs pass strict mode
  • Edge cases with strict mode

Test Organization#

Tests are organized by function:

Code
tests/
├── validate.test.ts            (106 tests)
├── format.test.ts               (69 tests)
├── clean.test.ts                (62 tests)
├── calculateVerifier.test.ts    (47 tests)
├── equals.test.ts               (47 tests, default + requireValid:false modes)
├── getVerifier.test.ts          (41 tests)
├── getBody.test.ts              (29 tests)
├── decompose.test.ts            (21 tests)
├── generate.test.ts             (19 tests)
├── InvalidRutError.test.ts      (18 tests)
├── property.test.ts             (18 tests, property-based via fast-check)
├── isValidRut.test.ts           (15 tests)
├── differential.test.ts         (13 tests, full corpus opt-in via RUN_DIFFERENTIAL=1)
├── mask.test.ts                 (13 tests)
├── dist.smoke.test.ts            (4 tests, runs against the built bundle)
└── types.test.ts                 (1 test, compile-time type assertions)

Each test file includes:

  • describe blocks for organization
  • Happy path tests
  • Error case tests
  • Edge case tests
  • Safe mode tests

Running Tests#

Shell
# Run all tests
npm test
 
# Run specific test file
npm test validate
 
# Run in watch mode
npm test -- --watch
 
# Run with coverage
npm test -- --coverage

Example Test Cases#

validate() Tests#

TypeScript
describe('validate', () => {
  test('validates correct RUTs', () => {
    expect(validate('12.345.678-5')).toBe(true)
    expect(validate('18.972.631-7')).toBe(true)
  })
  
  test('rejects invalid RUTs', () => {
    expect(validate('12.345.678-0')).toBe(false)
    expect(validate('invalid')).toBe(false)
  })
  
  test('strict mode rejects suspicious patterns', () => {
    expect(validate('11.111.111-1', { strict: true })).toBe(false)
  })
})

format() Tests#

TypeScript
describe('format', () => {
  test('formats with dots', () => {
    expect(format('123456785')).toBe('12.345.678-5')
  })
  
  test('formats without dots', () => {
    expect(format('123456785', { dots: false })).toBe('12345678-5')
  })
  
  test('incremental formatting', () => {
    expect(format('1234', { incremental: true })).toBe('1.234')
    expect(format('12345678', { incremental: true })).toBe('1.234.567-8')
  })
})

Safe Mode Tests#

TypeScript
describe('safe mode', () => {
  test('returns null instead of throwing', () => {
    expect(clean('invalid', { throwOnError: false })).toBeNull()
    expect(format('123', { throwOnError: false })).toBeNull()
    expect(decompose('abc', { throwOnError: false })).toBeNull()
  })
})

Contributing Tests#

When contributing, please:

  1. Add tests for new features
  2. Ensure all tests pass
  3. Maintain test organization with describe blocks
  4. Test both happy paths and error cases
  5. Include edge cases
  6. Test safe mode behavior

See Contributing for more details.