Jump Into Our API Testing Adventure – $250 Prize + Swag for first 15 submissions

Visual Diff Validator

  • A color-coded, visual diff viewer in Postman that compares API responses to a stored baseline and highlights added, changed, and removed fields
  • Powered by the diff npm package for precision.

Why I think it could help people?

It helps testers and developers quickly identify added, removed, or changed fields in API responses with a clear, color-coded summary and highlights, making regression testing faster, more reliable, and easier to interpret.
Problem inspired from: Compare 2 responses using Postman

Code:

Public collection link
Request 1
Pre Request Script

// Update the baseline_response environment variable with the current response
const response = pm.response.json();
pm.globals.set("baseline_response", JSON.stringify(response));

Request 2
Pre Request Script:

// Check if the environment variable 'baseline_response' is set
const baselineResponse = pm.globals.get("baseline_response");
if (!baselineResponse) {
    console.warn("Warning: The 'baseline_response' variable is not set. Please run the previous request before proceeding to compare responses.");
}

Post Response Script:

const Diff = pm.require('npm:[email protected]');
const _ = require('lodash');

// Get current and baseline responses
let current = pm.response.json();
let baselineStr = pm.globals.get("baseline_response");
let baseline = {};

try {
  baseline = JSON.parse(baselineStr);
} catch (e) {
  console.error("Failed to parse baseline:", e);
}

// Clean both objects
let cleanedCurrent = _.omit(current, ['id', 'createdAt', 'updatedAt']);
let cleanedBaseline = _.omit(baseline, ['id', 'createdAt', 'updatedAt']);

// Compare
let allKeys = _.union(Object.keys(cleanedCurrent), Object.keys(cleanedBaseline));

let addedFields = [];
let changedFields = [];
let removedFields = [];

let rows = allKeys.map(key => {
  let baselineVal = cleanedBaseline[key];
  let currentVal = cleanedCurrent[key];

  let isChanged = baselineVal !== undefined && currentVal !== undefined && !_.isEqual(baselineVal, currentVal);
  let isAdded = baselineVal === undefined && currentVal !== undefined;
  let isRemoved = baselineVal !== undefined && currentVal === undefined;

  if (isChanged) changedFields.push(key);
  if (isAdded) addedFields.push(key);
  if (isRemoved) removedFields.push(key);

  // Word-level diff for changed values
  let diffHtml = '';
  if (isChanged) {
    let diffParts = Diff.diffWords(
      JSON.stringify(baselineVal),
      JSON.stringify(currentVal)
    );
    diffHtml = diffParts.map(part => {
      if (part.added) return `<span style="background:#d4f8d4">${part.value}</span>`;
      if (part.removed) return `<span style="background:#f8d4d4;text-decoration:line-through">${part.value}</span>`;
      return part.value;
    }).join('');
  }

  return {
    field: key,
    baseline: baselineVal !== undefined ? JSON.stringify(baselineVal) : '',
    current: currentVal !== undefined ? JSON.stringify(currentVal) : '',
    currentDiff: isChanged ? diffHtml : (currentVal !== undefined ? JSON.stringify(currentVal) : ''),
    changed: isChanged,
    added: isAdded,
    removed: isRemoved
  };
});

// Visualizer
pm.visualizer.set(`
  <style>
    body { font-family: monospace; padding: 1rem; }
    .summary h3 { margin: 0 0 .5rem 0; }
    .summary ul { margin: 0 0 1.5rem 1.25rem; padding: 0; }
    li { margin: .3rem 0; }
    table { border-collapse: collapse; width: 100%; }
    th, td { border: 1px solid #ccc; padding: 8px; vertical-align: top; text-align: left; }
    .changed { background-color: #fff3b0; }
    .added { background-color: #d4f8d4; }
    .removed { background-color: #f8d4d4; }
  </style>

  <div class="summary">
    <h3>📊 Changes Summary:</h3>
    <ul>
      <li><strong>Fields Added:</strong> {{addedCount}} {{#if addedList.length}}→ {{addedList}}{{/if}}</li>
      <li><strong>Fields Modified:</strong> {{changedCount}} {{#if changedList.length}}→ {{changedList}}{{/if}}</li>
      <li><strong>Fields Deleted:</strong> {{removedCount}} {{#if removedList.length}}→ {{removedList}}{{/if}}</li>
    </ul>
  </div>

  <table>
    <thead>
      <tr>
        <th>Field</th>
        <th>Baseline</th>
        <th>Current</th>
      </tr>
    </thead>
    <tbody>
      {{#each rows}}
        <tr class="{{#if changed}}changed{{/if}}{{#if added}} added{{/if}}{{#if removed}} removed{{/if}}">
          <td>{{field}}</td>
          <td>{{baseline}}</td>
          <td>{{{currentDiff}}}</td>
        </tr>
      {{/each}}
    </tbody>
  </table>
`, {
  rows,
  addedCount: addedFields.length,
  changedCount: changedFields.length,
  removedCount: removedFields.length,
  addedList: addedFields.join(', '),
  changedList: changedFields.join(', '),
  removedList: removedFields.join(', ')
});

Reference: Compare two responses | Documentation | Postman API Network

2 Likes