aboutsummaryrefslogtreecommitdiff
path: root/tests/timing.test.ts
blob: e2a0a0620337fd45de7a37e703d974b897c3c176 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*** IMPORT ------------------------------------------- ***/

import { expect, test } from "vitest";

/*** UTILITY ------------------------------------------ ***/

import type { Fetcher, FetcherResult } from "../source/library/fetcher/types.ts";
import { SessionStore } from "../source/library/state/session.svelte.ts";
import { createMemoryStorage } from "../source/library/state/storage.ts";

function delay(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

/*** TESTS -------------------------------------------- ***/

test("run() populates timing for a one-shot fetcher", async () => {
  const store = new SessionStore(createMemoryStorage());
  const tab = store.active;

  expect(tab).toBeDefined();

  if (!tab)
    return;

  const fetcher: Fetcher = () => Promise.resolve({ data: { hello: "world" } });
  const ok = await store.run(fetcher);

  expect(ok).toBe(true);
  expect(tab.timing).not.toBeNull();

  if (tab.timing === null)
    return;

  expect(tab.timing.startMs <= tab.timing.firstByteMs).toBe(true);
  expect(tab.timing.firstByteMs <= tab.timing.endMs).toBe(true);
  expect(tab.timing.endMs - tab.timing.startMs >= 0).toBe(true);
  expect(tab.streamIntervals.length).toEqual(0);
});

test("run() records intervals between async iterable payloads", async () => {
  const store = new SessionStore(createMemoryStorage());
  const tab = store.active;

  expect(tab).toBeDefined();

  if (!tab)
    return;

  async function* stream(): AsyncGenerator<FetcherResult> {
    yield { data: { n: 1 } };
    await delay(5);
    yield { data: { n: 2 } };
    await delay(5);
    yield { data: { n: 3 } };
  }

  const fetcher: Fetcher = () => stream();
  const ok = await store.run(fetcher);

  expect(ok).toBe(true);
  expect(tab.streamIntervals.length).toEqual(2);
  expect(tab.timing).not.toBeNull();

  if (tab.timing === null)
    return;

  expect(tab.timing.firstByteMs >= tab.timing.startMs).toBe(true);
  expect(tab.timing.endMs >= tab.timing.firstByteMs).toBe(true);

  for (const delta of tab.streamIntervals)
    expect(delta >= 0).toBe(true);
});

test("run() resets timing and streamIntervals on each invocation", async () => {
  const store = new SessionStore(createMemoryStorage());
  const tab = store.active;

  expect(tab).toBeDefined();

  if (!tab)
    return;

  async function* stream(): AsyncGenerator<FetcherResult> {
    yield { data: { n: 1 } };
    await delay(5);
    yield { data: { n: 2 } };
  }

  await store.run(() => stream());
  expect(tab.streamIntervals.length).toEqual(1);

  await store.run(() => Promise.resolve({ data: {} }));
  expect(tab.streamIntervals.length).toEqual(0);
  expect(tab.timing).not.toBeNull();
});