HarborClient already lets you attach pre-request and post-request scripts at the collection, folder, and request levels. Within each of those lists, every script row also has a stage: Before all, Before each, Main, After each, or After all.

Those stages are easy to overlook, but they open up testing patterns that would otherwise mean duplicating code, re-parsing payloads, or mixing setup logic into every assertion.

HarborClient PreRequest and PostRequest tabs on an Echo GET request with scripting help and Snippets controls
Four script stages—collection and request, pre and post—run in order around every send.

How stages run

Inside one pre-request or post-request list, HarborClient expands scripts in this order:

  • Before all scripts run once
  • For each Main script: all Before each scripts, then that main script, then all After each scripts
  • After all scripts run once

A few details matter when you design tests around this model:

  • “Before all” means once for that scope’s list on this send—not once for an entire collection run. Collection runner still invokes the same per-request pipeline for every request.
  • before-each and after-each only run when at least one Main script exists in that list.
  • before-all and after-all still run even if there are no Main scripts.
  • Across scopes, pre-request and post-request lists run collection → folder → request. Mutable hc.data is shared across every script slot in the same send.

That last point is what makes stages especially useful for testing: you can parse once, seed fixtures once, wrap each assertion block, and clean up once—without one giant script.

Six testing opportunities

1. Parse the response once, assert many times

In post-request scripts, put expensive parsing in Before all, store the result on hc.data, and keep each Main script focused on one assertion group.

// Stage: Before all (post-request)
const body = hc.response.json();
hc.data.user = body.data;
hc.data.links = body._links;
// Stage: Main — profile shape
hc.test('user has an id and email', () => {
  hc.expect(hc.data.user).to.have.property('id');
  hc.expect(hc.data.user.email).to.match(/@/);
});
// Stage: Main — hypermedia links
hc.test('response exposes a self link', () => {
  hc.expect(hc.data.links).to.have.property('self');
});

You avoid re-parsing large JSON (or HTML via hc.response.document()) in every test row, and failures stay easier to diagnose because each Main script stays small.

2. Reset fixtures before each Main test

When one request list has several Main scripts that mutate shared state, use Before each to re-seed a clean fixture bag.

// Stage: Before each (post-request)
hc.data.scratch = {
  expectedRole: 'editor',
  seenIds: []
};

This mirrors the familiar unit-test pattern: each Main assertion block starts from the same baseline, even if an earlier Main script wrote temporary values into hc.data.

3. Capture diagnostics after each assertion block

After each is ideal for lightweight diagnostics that should run after every Main script—timing notes, partial counters, or values you want in console output when a suite is flaky.

// Stage: After each (post-request)
const n = (hc.data.checksRun || 0) + 1;
hc.data.checksRun = n;
console.log(`Finished check block ${n} for ${hc.info.requestName}`);

Keep Main scripts for expectations; keep After each for bookkeeping that should not clutter the assertions themselves.

4. Aggregate results in After all

Use After all for final bookkeeping once every Main test has finished for this scope: persist a summary variable, bump a counter, or assert that companion scripts actually ran.

// Stage: After all (post-request)
hc.collection.variables.set(
  'lastChecksRun',
  String(hc.data.checksRun || 0)
);

hc.test('ran at least one main check block', () => {
  hc.expect(hc.data.checksRun || 0).to.be.at.least(1);
});

Collection- or folder-level After all scripts are especially handy during collection runs, because they execute for every request that inherits that scope.

5. Layer auth and defaults across collection, folder, and request

Stages pair well with HarborClient’s three scopes. A common pre-request pattern:

  • Collection Before all: set org-wide values (API host, tenant id, default Accept header).
  • Folder Before all: add folder-specific auth or path prefixes for one API surface.
  • Request Main: build the final URL, body, or one-off headers for that case.
// Collection pre-request — Before all
hc.collection.variables.set('apiBase', 'https://api.example.com');

// Folder pre-request — Before all
hc.request.headers.add({ key: 'X-Service', value: 'billing' });

// Request pre-request — Main
hc.request.url =
  `${hc.collection.variables.get('apiBase')}/v1/invoices/{{invoiceId}}`;

Because scopes concatenate in order, later Main scripts can rely on earlier Before all setup without copying it into every request.

6. Setup and teardown without a Main script

You do not need a Main script to run hooks. A list can contain only Before all and After all rows—useful for lightweight enable/disable toggles, seeding hc.data, or tearing down cookies and temporary values.

// Pre-request — Before all only
hc.data.startedAt = Date.now();
hc.cookies.clear('session');

// Post-request — After all only
const ms = Date.now() - (hc.data.startedAt || Date.now());
console.log(`Send finished in ${ms}ms`);

That makes stages practical for shared snippets too: install a setup hook once, keep Main assertion scripts separate, and toggle rows independently.

Bonus: multi-step request prep with Before each

On the pre-request side, multiple Main scripts can prepare work in steps—for example one Main that fetches a CSRF token via hc.fetch, and another that attaches it. Put resets in Before each so each step starts predictably:

// Pre-request — Before each
hc.data.stepError = null;

// Pre-request — Main (step 1): fetch token
// Pre-request — Main (step 2): attach Authorization header

Choosing a stage

  • Before all — expensive shared setup or parsing for this list.
  • Before each — per-Main reset so modular tests stay isolated.
  • Main — the real work: mutate the request, or assert against the response.
  • After each — diagnostics and counters that should follow every Main.
  • After all — final summary, teardown, or cross-check that the suite did useful work.

If you have been stacking everything into a single Main script, splitting by stage is one of the quickest ways to get clearer tests without leaving HarborClient.

For the full scripting surface—including hc.test, hc.expect, hc.data, variables, and execution helpers—see the HarborClient scripting docs at harborclient.com/scripting.

Leave a Reply

Trending

Discover more from HarborClient Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading