JSON Patch Test Suite

1.1.0 · maintenance · verified Wed Apr 22

This package (`json-patch-test-suite`) serves as the official and community-maintained collection of test cases designed to validate implementations of the IETF JSON Patch specification (RFC 6902). It does not provide an actual JSON Patch implementation, but rather offers a standardized data set comprising source documents, applicable patches, and either the expected resulting document or a description of an anticipated error. The current stable version is 1.1.0. As a static test suite for a well-established RFC, its release cadence is infrequent, primarily occurring when new edge cases are identified or the RFC itself undergoes revisions. Its primary value lies in offering a neutral, comprehensive, and widely-adopted benchmark that allows developers to rigorously test their JSON Patch libraries for strict conformance to the RFC 6902 standard, ensuring interoperability and correctness across various programming languages and environments. This helps to prevent divergent interpretations of the specification.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to load the `tests.json` file from the `json-patch-test-suite` package and iterate through each test record. It shows how to integrate the test data with a hypothetical `applyPatch` function (which you would replace with your actual JSON Patch implementation) to validate its behavior against the suite's expected outcomes or errors. The example uses Node.js `fs` and `path` for file loading.

import * as fs from 'fs';
import * as path from 'path';

// IMPORTANT: This 'applyPatch' function is a placeholder.
// You must integrate your actual JSON Patch implementation here
// (e.g., from 'fast-json-patch', 'json-patch', etc.)
const applyPatch = (doc: any, patch: any[]): any => {
  // In a real scenario, this would apply the patch and return the new document.
  // For this example, we'll simulate a success or throw an error based on patch content.
  if (!doc || !patch) throw new Error('Invalid input for patch application.');
  if (patch.some((op: any) => op.path === '/invalid/path' && op.op === 'add')) {
    throw new Error('Simulated patch error: Invalid path operation.');
  }
  return { ...doc, patched: true }; // Simulate a successful patch
};

interface TestRecord {
  doc: any;
  patch: any[];
  expected?: any;
  error?: string;
  comment?: string;
  disabled?: boolean;
}

// Dynamically resolve the path to the installed json-patch-test-suite package.
// This is generally safer than assuming 'node_modules' directly.
const resolvePackagePath = (packageName: string) => {
  try {
    return path.dirname(require.resolve(packageName + '/package.json'));
  } catch (e) {
    throw new Error(`Could not find package ${packageName}. Is it installed?`);
  }
};

const suitePackagePath = resolvePackagePath('json-patch-test-suite');
const testsPath = path.join(suitePackagePath, 'tests.json');

const testSuite: TestRecord[] = JSON.parse(fs.readFileSync(testsPath, 'utf8'));

let passedTests = 0;
let failedTests = 0;

console.log(`Running ${testSuite.length} JSON Patch tests from the suite...\n`);

testSuite.forEach((test, index) => {
  if (test.disabled) {
    // console.log(`Skipping disabled test [${index + 1}]: ${test.comment}`);
    return;
  }

  try {
    const result = applyPatch(test.doc, test.patch);

    if (test.expected !== undefined) {
      if (JSON.stringify(result) === JSON.stringify(test.expected)) {
        passedTests++;
      } else {
        failedTests++;
        console.error(`FAIL [${index + 1}]: ${test.comment || 'Unnamed test'}`);
        console.error('  Doc:', JSON.stringify(test.doc));
        console.error('  Patch:', JSON.stringify(test.patch));
        console.error('  Expected:', JSON.stringify(test.expected));
        console.error('  Got:', JSON.stringify(result));
        console.error('--------------------------------------------------');
      }
    } else if (test.error !== undefined) {
      failedTests++;
      console.error(`FAIL [${index + 1}]: ${test.comment || 'Unnamed test'} (Expected error, but patch succeeded)`);
      console.error('--------------------------------------------------');
    }
    // If no expected/error, assume success if no exception
  } catch (e: any) {
    if (test.error !== undefined) {
      passedTests++; // We expected an error, and got one. Good enough for basic check.
    } else {
      failedTests++;
      console.error(`FAIL [${index + 1}]: ${test.comment || 'Unnamed test'} (Unexpected error)`);
      console.error('  Error:', e.message);
      console.error('  Doc:', JSON.stringify(test.doc));
      console.error('  Patch:', JSON.stringify(test.patch));
      console.error('--------------------------------------------------');
    }
  }
});

console.log(`\nTests finished: ${passedTests} passed, ${failedTests} failed.`);
if (failedTests > 0) {
  process.exit(1);
}

view raw JSON →