File size: 2,546 Bytes
6c3af4e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { beforeEach, describe, expect, it, vi } from "vitest";

vi.mock("./logEntries", () => ({ addLogEntry: vi.fn() }));

vi.mock("./searchTokenHash", () => ({
  getSearchTokenHash: vi.fn().mockResolvedValue("token-hash"),
}));

import { fetchPageContents } from "./pageContent";

const fetchMock = vi.fn();
vi.stubGlobal("fetch", fetchMock);

function getRequestedUrl(): URL {
  return new URL(fetchMock.mock.calls[0][0]);
}

describe("fetchPageContents", () => {
  beforeEach(() => {
    fetchMock.mockReset();
  });

  it("does not call the server when there is nothing to read", async () => {
    expect(await fetchPageContents("cats", [])).toEqual({});
    expect(fetchMock).not.toHaveBeenCalled();
  });

  it("asks for every URL in one request and returns what came back", async () => {
    const contents = { "https://a.example/": "text from a" };
    fetchMock.mockResolvedValue(
      new Response(JSON.stringify(contents), { status: 200 }),
    );

    const result = await fetchPageContents("cats", [
      "https://a.example/",
      "https://b.example/",
    ]);

    const requestedUrl = getRequestedUrl();
    expect(requestedUrl.pathname).toBe("/page-content");
    expect(requestedUrl.searchParams.get("q")).toBe("cats");
    expect(requestedUrl.searchParams.get("token")).toBe("token-hash");
    expect(requestedUrl.searchParams.getAll("url")).toEqual([
      "https://a.example/",
      "https://b.example/",
    ]);
    expect(result).toEqual(contents);
  });

  it("falls back to no page content when the server errors", async () => {
    fetchMock.mockResolvedValue(new Response(null, { status: 500 }));

    expect(await fetchPageContents("cats", ["https://a.example/"])).toEqual({});
  });

  it("falls back to no page content when the request fails", async () => {
    fetchMock.mockRejectedValue(new Error("network down"));

    expect(await fetchPageContents("cats", ["https://a.example/"])).toEqual({});
  });

  it("gives up on a server that never answers", async () => {
    vi.useFakeTimers();
    try {
      fetchMock.mockImplementation(
        (_url: string, init?: RequestInit) =>
          new Promise((_resolve, reject) => {
            init?.signal?.addEventListener("abort", () =>
              reject(new Error("The operation was aborted")),
            );
          }),
      );

      const pending = fetchPageContents("cats", ["https://a.example/"]);
      await vi.advanceTimersByTimeAsync(20000);

      expect(await pending).toEqual({});
    } finally {
      vi.useRealTimers();
    }
  });
});