// Note that for the most part, everything has to be mocked to the
// gills for tests here, so we do most of our testing in a separate
// integration suite and predominantly test purer private functions
// here.

import {
  jest,
  describe,
  beforeEach,
  test,
  expect,
  it,
  beforeAll,
} from "@jest/globals";
import rewire from "rewire";
import makeServiceWorkerEnv from "service-worker-mock";
import { parse as parseCookies } from "cookie";
import * as buffer from "node:buffer";
import * as stream from "node:stream/web";
import * as node_util from "node:util";

import {
  specProxyProcessRequest,
  specProxyProcessResponse,
  specMakeRequestWithFallback,
} from "./index";

// Import the header constant for testing
const HEADER_SPEC_ACTIVITY = "x-atvak-activity-count";

// Workers supply `crypto` globally, but it's not present in our testing environment
// so let's fake it.
import * as crypto from "crypto";

Object.defineProperty(globalThis, "crypto", {
  value: {
    randomUUID: () => crypto.randomUUID(),
  },
});

const TEST_URL = new URL("https://specprotected.com");
const TEST_SPEC_TRAFFIC_URL = new URL(
  "https://specprotected.com/spec_traffic/somewhere",
);

describe("processing", () => {
  beforeEach(() => {
    // temporary workaround until https://github.com/nodejs/node/pull/46615#issuecomment-1604484636
    // lands in node 18.x
    delete global.location;
    delete global.performance;
    delete global.navigator;
    // delete global.self;

    Object.assign(global, makeServiceWorkerEnv());

    Object.assign(globalThis, {
      Blob: buffer.Blob,
      File: buffer.File,
      TextDecoder: node_util.TextDecoder,
      TextEncoder: node_util.TextEncoder,
      ReadableStream: stream.ReadableStream,
      TransformStream: stream.TransformStream,
      WritableStream: stream.WritableStream,
    });

    // blow away the Promise from Fetch API
    global.fetch = (v: any) => v;
    // create a fake version of the ExtendableEvent to use,
    // also doesn't use Promises
    global.simple_event = {
      waitUntil: jest.fn((v: any) => v),
      request: new Request("https://spectrust.com", {
        method: "GET",
        headers: {
          "X-Forwarded-For": "127.0.0.1",
          Host: "spectrust.com",
        },

        // ReadableStream is difficult to mock so can't test mirroring
        // which modifies the body object...
        // we also have to set it to null because service-worker-mock uses
        // a garbage implementation of this when it's not provided and disrupts
        // our use of the tee() function
        body: null,
      }),
    };
  });

  test("disabled proxy is noop", () => {
    expect(
      specProxyProcessRequest(global.simple_event, { disableSpecProxy: true })
        .request,
    ).toBe(global.simple_event.request);

    expect(
      specProxyProcessRequest(global.simple_event, { disableSpecProxy: false })
        .request,
    ).not.toBe(global.simple_event.request);
  });

  test("traffic split", () => {
    expect(
      specProxyProcessRequest(global.simple_event, { percentageOfIPs: 0 })
        .request,
    ).toBe(global.simple_event.request);

    expect(
      specProxyProcessRequest(global.simple_event, { percentageOfIPs: 100 })
        .request,
    ).not.toBe(global.simple_event.request);
  });

  test("proxy forks request in mirror split mode", () => {
    expect(
      specProxyProcessRequest(global.simple_event, {
        splitExchangeMirroring: true,
      }).request,
    ).toEqual(global.simple_event.request);

    expect(global.simple_event.waitUntil.mock.calls.length).toEqual(1);
  });

  // Note: libraries that make the request will change the Host header
  // for us. Cloudflare does this automatically, Fastly does this through
  // the use of the `backend` configuration property on the request.
  test("in mirror split mode, Host header of mirrored request is unchanged", () => {
    expect(
      specProxyProcessRequest(global.simple_event, {
        splitExchangeMirroring: true,
      }).request,
    ).toEqual(global.simple_event.request);

    let specProxyRequest = global.simple_event.waitUntil.mock.calls[0][0];
    console.log(specProxyRequest.headers, global.simple_event.request.headers);
    expect(specProxyRequest.headers.get("host")).toEqual(
      global.simple_event.request.headers.get("host"),
    );
  });

  test("proxy replaces request in inline mode", () => {
    let request = specProxyProcessRequest(global.simple_event, {
      inlineMode: true,
    }).request;
    expect(request).not.toEqual(global.simple_event.request);
    expect(request.url).toEqual("https://spectrust.com.spec-internal.com/");

    expect(global.simple_event.waitUntil.mock.calls.length).toEqual(0);
  });

  test("sending traffic to /spec_traffic in inline mode goes to spec proxy", () => {
    let event = global.simple_event;
    event.request.url = "https://spectrust.com/spec_traffic/somewhere";
    let request = specProxyProcessRequest(global.simple_event, {
      inlineMode: true,
    }).request;
    expect(request.url).toEqual(
      "https://spectrust.com.spec-internal.com/spec_traffic/somewhere",
    );

    expect(global.simple_event.waitUntil.mock.calls.length).toEqual(0);
  });

  test("sending traffic to /spec_traffic in mirror mode goes to spec proxy", () => {
    let event = global.simple_event;
    event.request.url = "https://spectrust.com/spec_traffic/somewhere";
    let request = specProxyProcessRequest(global.simple_event, {
      inlineMode: false,
    }).request;
    expect(request.url).toEqual(
      "https://spectrust.com.spec-internal.com/spec_traffic/somewhere",
    );

    expect(global.simple_event.waitUntil.mock.calls.length).toEqual(0);
  });

  test("sending traffic to /spec_traffic when it's disabled forwards traffic in mirror mode", () => {
    let event = global.simple_event;
    event.request.url = "https://spectrust.com/spec_traffic/somewhere";
    let request = specProxyProcessRequest(global.simple_event, {
      disableSpecTraffic: true,
      splitExchangeMirroring: true,
    }).request;
    expect(request).toEqual(global.simple_event.request);

    expect(global.simple_event.waitUntil.mock.calls.length).toEqual(1);
  });
});

//---------------------------------------------
// Private Function Testing
//---------------------------------------------

// "rewire" the library module to allow us to reach private functions
let spec = rewire("./dist/index.js");

describe("shouldHandleRequest", () => {
  let shouldHandleRequest = spec.__get__("shouldHandleRequest");

  test.each([
    ["0.0.0.0", undefined, true],
    ["0.0.0.40", undefined, true],
    ["0.0.0.99", undefined, true],
    ["0.0.0.100", undefined, true], // "wraps" to 0
    ["0.0.0.0", 100, true],
    ["0.0.0.40", 100, true],
    ["0.0.0.99", 100, true],
    ["0.0.0.0", 100, true],
    ["0.0.0.40", 50, true],
    ["0.0.0.49", 50, true],
    ["0.0.0.50", 50, false],
    ["0.0.0.60", 50, false],
    ["0.0.0.0", 0, false],
    ["0.0.0.40", 0, false],
    ["0.0.0.99", 0, false],
    ["0.0.0.100", 0, false],
    // some legit-looking IPs that don't exploit our algorithm for testing
    ["24.68.195.11", 50, false],
    ["74.232.255.255", 50, true],
    ["89.2.79.2", 50, false],
    ["67.67.67.67", 50, false],
    ["10.0.0.8", 50, true],
  ])("traffic split [ip=%s, split=%i]", (ip, split, expected) => {
    let headers = new Headers({ "x-forwarded-for": ip });
    expect(
      shouldHandleRequest(TEST_URL, headers, {
        percentageOfIPs: split,
      }),
    ).toEqual(expected);
  });

  test.each([
    ["0.0.0.100", undefined, true], // "wraps" to 0
    ["0.0.0.99", 100, true],
    ["0.0.0.0", 100, true],
    ["0.0.0.49", 50, true],
    ["0.0.0.50", 50, true],
    ["0.0.0.60", 50, true],
    ["0.0.0.0", 0, true],
    ["0.0.0.40", 0, true],
    ["0.0.0.99", 0, true],
    ["0.0.0.100", 0, true],
    // some legit-looking IPs that don't exploit our algorithm for testing
    ["24.68.195.11", 50, true],
    ["74.232.255.255", 50, true],
    ["89.2.79.2", 50, true],
    ["67.67.67.67", 50, true],
    ["10.0.0.8", 50, true],
  ])(
    "traffic split [ip=%s, split=%i], always send to /spec_traffic when enabled",
    (ip, split, expected) => {
      let headers = new Headers({ "x-forwarded-for": ip });
      expect(
        shouldHandleRequest(TEST_SPEC_TRAFFIC_URL, headers, {
          percentageOfIPs: split,
        }),
      ).toEqual(expected);
    },
  );

  test.each([
    ["0.0.0.100", undefined, true], // "wraps" to 0
    ["0.0.0.99", 100, true],
    ["0.0.0.0", 100, true],
    ["0.0.0.49", 50, true],
    ["0.0.0.50", 50, false],
    ["0.0.0.60", 50, false],
    ["0.0.0.0", 0, false],
    ["0.0.0.40", 0, false],
    ["0.0.0.99", 0, false],
    ["0.0.0.100", 0, false],
    // some legit-looking IPs that don't exploit our algorithm for testing
    ["24.68.195.11", 50, false],
    ["74.232.255.255", 50, true],
    ["89.2.79.2", 50, false],
    ["67.67.67.67", 50, false],
    ["10.0.0.8", 50, true],
  ])(
    "traffic split [ip=%s, split=%i], normal behavior when /spec_traffic disabled",
    (ip, split, expected) => {
      let headers = new Headers({ "x-forwarded-for": ip });
      expect(
        shouldHandleRequest(TEST_SPEC_TRAFFIC_URL, headers, {
          percentageOfIPs: split,
          disableSpecTraffic: true,
        }),
      ).toEqual(expected);
    },
  );

  test.each([
    ["X-Forwarded-For", 50, "0.0.0.0", true],
    ["X-Forwarded-For", 50, "0.0.0.60", false],
    ["Not-Checked-Header", 50, "0.0.0.0", false],
    ["Not-Checked-Header", 50, "0.0.0.99", false],
    // if it's 100% split, we expect to handle the request even if we can't find the
    // IP address on this header
    ["X-Forwarded-For", 100, "0.0.0.60", true],
    ["Not-Checked-Header", 100, "0.0.0.99", true],
  ])(
    'ip from header "%s" with %i%% split for ip %s"',
    (header, split, ip, expected) => {
      let headers = new Headers({});
      headers.set(header, ip);
      expect(
        shouldHandleRequest(TEST_URL, headers, {
          percentageOfIPs: split,
        }),
      ).toEqual(expected);
    },
  );

  // Check NaN handling, just in case.
  test.each([
    ["X-Forwarded-For", 50, "wtf", false],
    ["X-Forwarded-For", 99, "srs", false],
    // if it's 100% split, we expect to handle the request even if we can't find the
    // IP address on this header
    ["X-Forwarded-For", 100, "susfam", true],
    ["X-Forwarded-For", 100, ":ghost-shrug:", true],
  ])(
    'ip from header "%s" with %i%% split for ip %s"',
    (header, split, ip, expected) => {
      let headers = new Headers({});
      headers.set(header, ip);
      expect(
        shouldHandleRequest(TEST_URL, headers, {
          percentageOfIPs: split,
        }),
      ).toEqual(expected);
    },
  );
});

describe("extractTopLevelDomain", () => {
  let extractTopLevelDomain = spec.__get__("extractTopLevelDomain");

  test.each([
    ["spec-trust.com", "spec-trust.com"],
    ["somewhere.spec-trust.com", "spec-trust.com"],
    ["somewhere.spec-trust.com.spec-internal.com", "spec-trust.com"],
    ["somewhere.spec-trust.edu", "spec-trust.edu"],
    ["somewhere.spec-trust.edu.spec-internal.com", "spec-trust.edu"],
    ["somewhere.spec-trust.gov", "spec-trust.gov"],
    ["somewhere.spec-trust.gov.spec-internal.com", "spec-trust.gov"],
    ["somewhere.spec-trust.int", "spec-trust.int"],
    ["somewhere.spec-trust.int.spec-internal.com", "spec-trust.int"],
    ["somewhere.spec-trust.net", "spec-trust.net"],
    ["somewhere.spec-trust.net.spec-internal.com", "spec-trust.net"],
    ["somewhere.spec-trust.org", "spec-trust.org"],
    ["somewhere.spec-trust.org.spec-internal.com", "spec-trust.org"],
    ["somewhere.spec-trust.uk", "spec-trust.uk"],
    ["somewhere.spec-trust.uk.spec-internal.com", "spec-trust.uk"],
    ["many.many.many.many.sub-domains.spec-trust.com", "spec-trust.com"],
    ["any.suffixes", "any.suffixes"],
    // if we don't match any known top-level domain suffix, we just get the whole thing
    [
      "subdomains.irrelevant.any.suffixes",
      "subdomains.irrelevant.any.suffixes",
    ],
    ["invalid-top-level-though", "invalid-top-level-though"],
    // invalid top-level domain suffix, but with spec-internal on the end winds up
    // matching to spec-internal
    ["somewhere.fun.to.go.spec-internal.com", "spec-internal.com"],
    ["staging.special.somebody.co.uk.spec-internal.com", "somebody.co.uk"],
    ["staging.somebody.ac.uk.spec-internal.com", "somebody.ac.uk"],
    ["staging.somebody.co.uk.spec-internal.com", "somebody.co.uk"],
    ["staging.somebody.gov.uk.spec-internal.com", "somebody.gov.uk"],
    ["staging.somebody.ltd.uk.spec-internal.com", "somebody.ltd.uk"],
    ["staging.somebody.me.uk.spec-internal.com", "somebody.me.uk"],
    ["staging.somebody.net.uk.spec-internal.com", "somebody.net.uk"],
    ["staging.somebody.nhs.uk.spec-internal.com", "somebody.nhs.uk"],
    ["staging.somebody.plc.uk.spec-internal.com", "somebody.plc.uk"],
    ["staging.somebody.police.uk.spec-internal.com", "somebody.police.uk"],
  ])("extract top level domain from %s", (host, expected) => {
    let headers = new Headers({ Host: host });
    expect(extractTopLevelDomain(headers)).toEqual(expected);
  });
});

describe("makeSpecUrl", () => {
  let makeSpecUrl = spec.__get__("makeSpecUrl");
  let MessageType = spec.__get__("MessageType");

  test.each([
    [
      "inline mode redirects to spec-internal w/unchanged path & query string",
      "https://www.customer.com/foobar?hello=world",
      MessageType.Request,
      { inlineMode: true },
      "https://www.customer.com.spec-internal.com/foobar?hello=world",
    ],
    [
      "default config (mirror mode) sends request to exchange endpoint",
      "https://www.customer.com/foobar?hello=world",
      MessageType.Request,
      {},
      "https://www.customer.com.spec-internal.com/speclayer/api/mirror/exchanges",
    ],
    [
      "default config (mirror mode) sends response to exchange endpoint",
      "https://www.customer.com/foobar?hello=world",
      MessageType.Response,
      {},
      "https://www.customer.com.spec-internal.com/speclayer/api/mirror/exchanges",
    ],
    [
      "split processing (mirror mode) sends request to request endpoint",
      "https://www.customer.com/foobar?hello=world",
      MessageType.Request,
      { splitExchangeMirroring: true },
      "https://www.customer.com.spec-internal.com/speclayer/api/mirror/requests",
    ],
    [
      "split processing (mirror mode) sends response to response endpoint",
      "https://www.customer.com/foobar?hello=world",
      MessageType.Response,
      { splitExchangeMirroring: true },
      "https://www.customer.com.spec-internal.com/speclayer/api/mirror/responses",
    ],
    [
      "domainOverride is applied if present",
      "https://www.customer.com/foobar?hello=world",
      MessageType.Request,
      { domainOverride: "alternative.com" },
      "https://alternative.com.spec-internal.com/speclayer/api/mirror/exchanges",
    ],
    [
      "localDev always directs to localhost:5000",
      "https://www.customer.com/foobar?hello=world",
      MessageType.Request,
      { localDev: true },
      "http://localhost:5000/speclayer/api/mirror/exchanges",
    ],
    [
      "we don't gaf about incoming protocol, it's always https",
      "http://www.customer.com/foobar?hello=world",
      MessageType.Request,
      {},
      "https://www.customer.com.spec-internal.com/speclayer/api/mirror/exchanges",
    ],
    [
      "we don't alter the path for spec-traffic",
      "http://www.customer.com/spec_traffic/foobar?hello=world",
      MessageType.Request,
      {},
      "https://www.customer.com.spec-internal.com/spec_traffic/foobar?hello=world",
    ],
    [
      "we don't change the domain if it already points to us",
      "http://www.customer.com.spec-internal.com/spec_traffic/foobar?hello=world",
      MessageType.Request,
      {},
      "https://www.customer.com.spec-internal.com/spec_traffic/foobar?hello=world",
    ],
  ])("%s", (_caseName, url, messageType, config, exp) => {
    let specUrl = makeSpecUrl(new URL(url), config, messageType);

    expect(specUrl.toString()).toEqual(exp);
  });
});

describe("setCommonSpecHeaders", () => {
  let setCommonSpecHeaders = spec.__get__("setCommonSpecHeaders");
  let setForwardingSpecHeaders = spec.__get__("setForwardingSpecHeaders");
  let setMirrorRequestHeaders = spec.__get__("setMirrorRequestHeaders");
  let setMirrorResponseHeaders = spec.__get__("setMirrorResponseHeaders");
  let SPEC_HEADER_CUSTOMER_KEY = spec.__get__("SPEC_HEADER_CUSTOMER_KEY");

  const FIXED_TS = "2026-04-30T00:00:00.000Z";

  beforeAll(() => {
    const FixedDate = class extends Date {
      toISOString() {
        return FIXED_TS;
      }
    };
    spec.__set__("Date", FixedDate);
  });

  afterAll(() => {
    spec.__set__("Date", Date);
  });

  test.each([
    [
      "sets customer key if present",
      new Headers(),
      { customerKey: "s3cr37" },
      new Headers({
        [SPEC_HEADER_CUSTOMER_KEY]: "s3cr37",
        "x-spec-origination-ts": FIXED_TS,
      }),
    ],
    [
      "overrides any existing customer key if present",
      new Headers({ [SPEC_HEADER_CUSTOMER_KEY]: "f4k3rz" }),
      { customerKey: "s3cr37" },
      new Headers({
        [SPEC_HEADER_CUSTOMER_KEY]: "s3cr37",
        "x-spec-origination-ts": FIXED_TS,
      }),
    ],
    [
      "does nothing if no customer key present",
      new Headers(),
      {},
      new Headers({ "x-spec-origination-ts": FIXED_TS }),
    ],
  ])("%s", (_caseName, headers, config, expHeaders) => {
    setCommonSpecHeaders(headers, config);

    // can't use direct equality, can't convert to object, but this works.
    expect([...headers.entries()]).toEqual([...expHeaders.entries()]);
  });
});

describe("setForwardingSpecHeaders", () => {
  let setForwardingSpecHeaders = spec.__get__("setForwardingSpecHeaders");
  let SPEC_HEADER_FORWARD_ORIGIN = spec.__get__("SPEC_HEADER_FORWARD_ORIGIN");

  test.each([
    [
      "sets fwd-origin header to URL hostname",
      new Headers(),
      "https://customer.com/hewooo",
      {},
      new Headers({ [SPEC_HEADER_FORWARD_ORIGIN]: "customer.com" }),
    ],
    [
      "overrides fwd-origin header if present",
      new Headers({ [SPEC_HEADER_FORWARD_ORIGIN]: "fakerz.com" }),
      "https://customer.com/hewooo",
      {},
      new Headers({ [SPEC_HEADER_FORWARD_ORIGIN]: "customer.com" }),
    ],
    [
      "ignores port if present in URL",
      new Headers(),
      "https://customer.com:5000/hewooo",
      {},
      new Headers({ [SPEC_HEADER_FORWARD_ORIGIN]: "customer.com" }),
    ],
    [
      "includes http & port for localhost and localdev",
      new Headers(),
      "https://localhost:5000/hewooo",
      { localDev: true },
      new Headers({ [SPEC_HEADER_FORWARD_ORIGIN]: "http://localhost:5000" }),
    ],
  ])(`makeSpecUrl: %s`, (_caseName, headers, url, config, expHeaders) => {
    setForwardingSpecHeaders(headers, new URL(url), config);

    expect([...headers.entries()]).toEqual([...expHeaders.entries()]);
  });
});

describe("setMirrorRequestHeaders", () => {
  let setMirrorRequestHeaders = spec.__get__("setMirrorRequestHeaders");
  let SPEC_MIRROR_HEADER_REQ_METHOD = spec.__get__(
    "SPEC_MIRROR_HEADER_REQ_METHOD",
  );
  let SPEC_MIRROR_HEADER_REQ_URI = spec.__get__("SPEC_MIRROR_HEADER_REQ_URI");
  let SPEC_MIRROR_HEADER_REQ_CONTENT_LENGTH = spec.__get__(
    "SPEC_MIRROR_HEADER_REQ_CONTENT_LENGTH",
  );

  // Allow us to make a Request
  Object.assign(global, makeServiceWorkerEnv());

  test.each([
    [
      "sets request method & uri",
      new Headers(),
      new Request("https://www.customer.com/foo?hello=world"),
      new Headers({
        [SPEC_MIRROR_HEADER_REQ_METHOD]: "GET",
        [SPEC_MIRROR_HEADER_REQ_URI]:
          "https://www.customer.com/foo?hello=world",
      }),
    ],
    [
      "sets content length if present ",
      new Headers(),
      new Request("https://www.customer.com/foo?hello=world", {
        headers: { "content-length": "50" },
      }),
      new Headers({
        [SPEC_MIRROR_HEADER_REQ_CONTENT_LENGTH]: "50",
        [SPEC_MIRROR_HEADER_REQ_METHOD]: "GET",
        [SPEC_MIRROR_HEADER_REQ_URI]:
          "https://www.customer.com/foo?hello=world",
      }),
    ],
    [
      "overrides all headers if already present",
      new Headers({
        [SPEC_MIRROR_HEADER_REQ_CONTENT_LENGTH]: "0",
        [SPEC_MIRROR_HEADER_REQ_METHOD]: "POST",
        [SPEC_MIRROR_HEADER_REQ_URI]: "https://www.fakerz.com/foo?hello=world",
      }),
      new Request("https://www.customer.com/foo?hello=world", {
        headers: { "content-length": "50" },
      }),
      new Headers({
        [SPEC_MIRROR_HEADER_REQ_CONTENT_LENGTH]: "50",
        [SPEC_MIRROR_HEADER_REQ_METHOD]: "GET",
        [SPEC_MIRROR_HEADER_REQ_URI]:
          "https://www.customer.com/foo?hello=world",
      }),
    ],
  ])("%s", (_caseName, headers, req, expHeaders) => {
    setMirrorRequestHeaders(headers, req);

    // can't use direct equality, can't convert to object, but this works.
    expect([...headers.entries()]).toEqual([...expHeaders.entries()]);
  });
});

describe("setMirrorResponseHeaders", () => {
  let setMirrorResponseHeaders = spec.__get__("setMirrorResponseHeaders");
  let SPEC_MIRROR_HEADER_RESP_STATUS = spec.__get__(
    "SPEC_MIRROR_HEADER_RESP_STATUS",
  );

  // Allow us to make a Response
  Object.assign(global, makeServiceWorkerEnv());

  test.each([
    [
      "sets response status header",
      new Headers(),
      new Response(null, { status: 200 }),
      new Headers({ [SPEC_MIRROR_HEADER_RESP_STATUS]: "200" }),
    ],
    [
      "overrides response status header if present",
      new Headers({ [SPEC_MIRROR_HEADER_RESP_STATUS]: "302" }),
      new Response(null, { status: 200 }),
      new Headers({ [SPEC_MIRROR_HEADER_RESP_STATUS]: "200" }),
    ],
    [
      "assigns other response headers from response",
      new Headers(),
      new Response(null, {
        status: 200,
        headers: { "content-length": "50", "x-foo": "foo" },
      }),
      new Headers({
        [SPEC_MIRROR_HEADER_RESP_STATUS]: "200",
        "x-spec-resp-head-content-length": "50",
        "x-spec-resp-head-x-foo": "foo",
      }),
    ],
    [
      "strips and overrides any headers from request with our prefix",
      new Headers({
        "x-spec-resp-head-content-length": "0",
        "x-spec-resp-head-fake": "fake",
        "x-spec-resp-head-x-foo": "foo",
        "x-spec-resp-head": "root removed",
      }),
      new Response(null, {
        status: 200,
        headers: { "content-length": "50", "x-foo": "foo" },
      }),
      new Headers({
        [SPEC_MIRROR_HEADER_RESP_STATUS]: "200",
        "x-spec-resp-head-content-length": "50",
        "x-spec-resp-head-x-foo": "foo",
      }),
    ],
  ])(`makeSpecUrl: %s`, (_caseName, headers, resp, expHeaders) => {
    setMirrorResponseHeaders(headers, resp);

    expect([...headers.entries()]).toEqual([...expHeaders.entries()]);
  });
});
