← tests

items

Every method on one resource, over the rows of the large item payload: a row read, its headers alone, and four writes that answer as if they had written.

Comparable across every framework. Each row sends one row-sized body or none and answers one row or nothing, so the methods differ in what the framework does with the request rather than in how much it serialises. A measured row may not leave the server changed, so the writes store nothing and no framework's store is what is measured.

{draw.item} is a row of items.large, picked per request.

testheftrequestbasewhat differs from the base
items.create2POST /itemsbody.bind_smallthe body kept as a new resource and answered 201 with its location
items.replace2PUT /items/{draw.item}items.createthe same resource through a different HTTP method
items.update2PATCH /items/{draw.item}items.replacethe same resource through a different HTTP method
items.read1GET /items/{draw.item}parameters.onea row found by the id the route captured, instead of a fixed body
items.delete1DELETE /items/{draw.item}items.readthe same resource through a different HTTP method
items.head1HEAD /items/{draw.item}items.readthe same resource through a different HTTP method

items.create

heft 2

base body.bind_smallbase of items.replace

A new item posted as JSON and answered 201, with where it would live and what it would hold. Nothing is stored, so the answer is always the id after the last row. Read against body.bind_small, the difference is a body bound to a model and answered as a created resource rather than echoed with counts.

Request

POST /items
content-typeapplication/json

payload items.new

{"name":"amber-trowel-4410","category":"garden","priceCents":2499,"inStock":true}

Expected response

HTTP 201
locationmatches /^(https?:\/\/[^/]+)?\/items\/1426$/

payload items.new as row 1426

{"id":1426,"name":"amber-trowel-4410","category":"garden","priceCents":2499,"inStock":true}

Compared as parsed JSON, so key order and how a number is written do not matter.

Test source, tests/items/create.ts
tests/items/create.tsopen on GitHub →
import { performanceTest } from "#kit";
import { CREATED, created, items } from "#payloads";

const path = "/items";

/** Relative, or absolute on whatever host the framework thinks it is. */
const LOCATION = new RegExp(`^(https?://[^/]+)?/items/${CREATED}$`);

export default performanceTest({
  id: { family: "items", name: "create" },
  path,
  base: "body.bind_small",
  varies: "creation",
  heft: 2,
  about:
    "A new item posted as JSON and answered 201, with where it would live and " +
    "what it would hold. Nothing is stored, so the answer is always the id " +
    "after the last row. Read against body.bind_small, the difference is a " +
    "body bound to a model and answered as a created resource rather than " +
    "echoed with counts.",

  request: (c) => c.post(path, items.new.value).status(201).bodyIs(created).hasHeader("location", LOCATION),
});

items.replace

heft 2

base items.createbase of items.update

A whole item put at an id and answered with the item under that id. Read against items.create, the difference is the id coming from the path rather than from the server.

Request

PUT /items/{draw.item}
content-typeapplication/json

payload items.new

{"name":"amber-trowel-4410","category":"garden","priceCents":2499,"inStock":true}

Expected response

HTTP 200

payload items.new as row {draw.item}

{"id":1417,"name":"amber-trowel-4410","category":"garden","priceCents":2499,"inStock":true}

Compared as parsed JSON, so key order and how a number is written do not matter. Shown with 1417 for {draw.item}.

Test source, tests/items/replace.ts
tests/items/replace.tsopen on GitHub →
import { performanceTest } from "#kit";
import { items, replaced } from "#payloads";

const path = "/items/{draw.item}";

export default performanceTest({
  id: { family: "items", name: "replace" },
  path,
  base: "items.create",
  varies: "method",
  heft: 2,
  about:
    "A whole item put at an id and answered with the item under that id. Read " +
    "against items.create, the difference is the id coming from the path " +
    "rather than from the server.",

  request: (c) => {
    const id = c.draw.item();
    return c.put(`/items/${id}`, items.new.value).okWith(replaced(id));
  },
});

items.update

heft 2

base items.replace

Two fields patched onto a row and answered with the row as it would be. The handler has to read the row, merge the body into it and serialise the result. Read against items.replace, the difference is the merge.

Request

PATCH /items/{draw.item}
content-typeapplication/json

payload items.patch

{"priceCents":1999,"inStock":false}

Expected response

HTTP 200

payload row {draw.item} of items.large with items.patch applied

{"id":1417,"name":"slate-seed-6074","category":"garden","priceCents":1999,"inStock":false}

Compared as parsed JSON, so key order and how a number is written do not matter. Shown with 1417 for {draw.item}.

Test source, tests/items/update.ts
tests/items/update.tsopen on GitHub →
import { performanceTest } from "#kit";
import { items, patched } from "#payloads";

const path = "/items/{draw.item}";

export default performanceTest({
  id: { family: "items", name: "update" },
  path,
  base: "items.replace",
  varies: "method",
  heft: 2,
  about:
    "Two fields patched onto a row and answered with the row as it would be. " +
    "The handler has to read the row, merge the body into it and serialise " +
    "the result. Read against items.replace, the difference is the merge.",

  request: (c) => {
    const id = c.draw.item();
    return c.patch(`/items/${id}`, items.patch.value).okWith(patched(id));
  },
});

items.read

heft 1

base parameters.onebase of errors.not_found, items.delete, items.head

One row of the large payload, looked up by the id in the path. The id is drawn per request, so each instance reads a different row. Read against parameters.one, the difference is a lookup and one row serialised in place of an echo beside the small payload.

Request

GET /items/{draw.item}

No body.

Expected response

HTTP 200

payload row {draw.item} of items.large

{"id":1417,"name":"slate-seed-6074","category":"garden","priceCents":9466,"inStock":true}

Compared as parsed JSON, so key order and how a number is written do not matter. Shown with 1417 for {draw.item}.

Test source, tests/items/read.ts
tests/items/read.tsopen on GitHub →
import { performanceTest } from "#kit";
import { row } from "#payloads";

const path = "/items/{draw.item}";

export default performanceTest({
  id: { family: "items", name: "read" },
  path,
  base: "parameters.one",
  varies: "lookup",
  heft: 1,
  about:
    "One row of the large payload, looked up by the id in the path. The id is " +
    "drawn per request, so each instance reads a different row. Read against " +
    "parameters.one, the difference is a lookup and one row serialised in " +
    "place of an echo beside the small payload.",

  request: (c) => {
    const id = c.draw.item();
    return c.get(`/items/${id}`).okWith(row(id));
  },
});

items.delete

heft 1

base items.read

A row deleted and answered 204 with no body. Nothing is removed, so every instance finds the row it names. Read against items.read, the difference is that nothing is serialised at all.

Request

DELETE /items/{draw.item}

No body.

Expected response

HTTP 204

No body.

Test source, tests/items/delete.ts
tests/items/delete.tsopen on GitHub →
import { performanceTest } from "#kit";

const path = "/items/{draw.item}";

export default performanceTest({
  id: { family: "items", name: "delete" },
  path,
  base: "items.read",
  varies: "method",
  heft: 1,
  about:
    "A row deleted and answered 204 with no body. Nothing is removed, so " +
    "every instance finds the row it names. Read against items.read, the " +
    "difference is that nothing is serialised at all.",

  request: (c) => c.delete(`/items/${c.draw.item()}`).status(204).emptyBody(),
});

items.head

heft 1

base items.read

The same lookup asked with HEAD, which the framework answers from its GET route with no body. Read against items.read, the difference is the body left unwritten. Content-Length is not checked, because a framework that streams its JSON sends none on the GET either.

Request

HEAD /items/{draw.item}

No body.

Expected response

HTTP 200
content-typematches /^application\/json/

No body.

Test source, tests/items/head.ts
tests/items/head.tsopen on GitHub →
import { performanceTest } from "#kit";

const path = "/items/{draw.item}";

export default performanceTest({
  id: { family: "items", name: "head" },
  path,
  base: "items.read",
  varies: "method",
  heft: 1,
  about:
    "The same lookup asked with HEAD, which the framework answers from its GET " +
    "route with no body. Read against items.read, the difference is the body " +
    "left unwritten. Content-Length is not checked, because a framework that " +
    "streams its JSON sends none on the GET either.",

  request: (c) => c.head(`/items/${c.draw.item()}`).ok().hasHeader("content-type", /^application\/json/).emptyBody(),
});