From 88090d35b146e8a9c41631b70453841320c9a6ba Mon Sep 17 00:00:00 2001 From: Allan Lasser Date: Fri, 19 Apr 2024 11:50:16 -0400 Subject: [PATCH] Creates placeholder addon page --- src/api/types/addons.ts | 4 +- src/lib/api/addons.test.ts | 95 +++++++++++++++++++ src/lib/api/addons.ts | 14 +++ .../app/add-ons/[owner]/[repo]/+layout.ts | 18 ++++ .../app/add-ons/[owner]/[repo]/+page.svelte | 12 +++ 5 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 src/lib/api/addons.test.ts create mode 100644 src/routes/app/add-ons/[owner]/[repo]/+layout.ts diff --git a/src/api/types/addons.ts b/src/api/types/addons.ts index 54572f45b..f3c8e51b5 100644 --- a/src/api/types/addons.ts +++ b/src/api/types/addons.ts @@ -1,11 +1,11 @@ import type { PageParams } from "./common"; export interface AddOnParams extends PageParams { - query?: boolean; + query?: string; active?: boolean; default?: boolean; featured?: boolean; premium?: boolean; category?: string; - respository?: string; + repository?: string; } diff --git a/src/lib/api/addons.test.ts b/src/lib/api/addons.test.ts new file mode 100644 index 000000000..7a5cb95a8 --- /dev/null +++ b/src/lib/api/addons.test.ts @@ -0,0 +1,95 @@ +import { vi, test, describe, it, expect, beforeEach, afterEach } from "vitest"; +import * as addons from "./addons"; +import { BASE_API_URL } from "@/config/config"; +import { addonsList } from "@/test/fixtures/addons"; +import { emptyList } from "@/test/fixtures/common"; + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("getAddons", () => { + let mockFetch; + beforeEach(() => { + mockFetch = vi + .fn() + .mockResolvedValue({ ok: true, json: async () => addonsList }); + }); + it("calls the addons API endpoint", async () => { + await addons.getAddons({}, mockFetch); + const expectedEndpoint = new URL(`addons`, BASE_API_URL); + expect(mockFetch).toHaveBeenCalledWith( + expectedEndpoint, + expect.any(Object), + ); + }); + it("passes parameters through as query arguments", async () => { + await addons.getAddons( + { active: true, featured: true, query: "foobar" }, + mockFetch, + ); + const expectedEndpoint = new URL(`addons`, BASE_API_URL); + expectedEndpoint.searchParams.set("active", "true"); + expectedEndpoint.searchParams.set("featured", "true"); + expectedEndpoint.searchParams.set("query", "foobar"); + expect(mockFetch).toHaveBeenCalledWith( + expectedEndpoint, + expect.any(Object), + ); + }); + it("returns the full list", async () => { + const response = await addons.getAddons({}, mockFetch); + expect(response).toBe(addonsList); + }); + it("calls SvelteKit's error fn given a response error", async () => { + mockFetch = vi.fn().mockResolvedValue({ + ok: false, + status: 500, + statusText: "Server Error!", + }); + await expect(addons.getAddons({}, mockFetch)).rejects.toThrowError(); + }); +}); + +test("getPinnedAddons", async () => { + const mockFetch = vi + .fn() + .mockResolvedValue({ ok: true, json: async () => {} }); + await addons.getPinnedAddons(mockFetch); + expect(mockFetch).toHaveBeenCalledWith( + new URL(`addons?active=true`, BASE_API_URL), + expect.any(Object), + ); +}); + +describe("getAddon", async () => { + let mockFetch; + beforeEach(() => { + mockFetch = vi.fn().mockResolvedValue({ + ok: true, + json: async () => addonsList, + }); + }); + afterEach(() => { + vi.restoreAllMocks(); + }); + it("calls the addons list endpoint with a respository query argument", async () => { + await addons.getAddon("MuckRock", "addon-repo", mockFetch); + expect(mockFetch).toHaveBeenCalledWith( + new URL(`addons?repository=MuckRock%2Faddon-repo`, BASE_API_URL), + expect.any(Object), + ); + }); + it("returns the first result in the addon list", async () => { + const response = await addons.getAddon("MuckRock", "addon-repo", mockFetch); + expect(response).toEqual(addonsList.results[0]); + }); + it("returns null if the returned list is empty", async () => { + mockFetch = vi.fn().mockResolvedValue({ + ok: true, + json: async () => emptyList, + }); + const response = await addons.getAddon("MuckRock", "addon-repo", mockFetch); + expect(response).toEqual(null); + }); +}); diff --git a/src/lib/api/addons.ts b/src/lib/api/addons.ts index 1a26b4d12..a46e65894 100644 --- a/src/lib/api/addons.ts +++ b/src/lib/api/addons.ts @@ -35,3 +35,17 @@ export async function getPinnedAddons( ): Promise> { return getAddons({ active: true }, fetch); } + +export async function getAddon( + owner: string, + repo: string, + fetch = globalThis.fetch, +): Promise { + const repository = [owner, repo].join("/"); + const addons = await getAddons({ repository }, fetch); + // there should only be one result, if the addon exists + if (addons.results.length < 1) { + return null; + } + return addons.results[0]; +} diff --git a/src/routes/app/add-ons/[owner]/[repo]/+layout.ts b/src/routes/app/add-ons/[owner]/[repo]/+layout.ts new file mode 100644 index 000000000..d7732afd2 --- /dev/null +++ b/src/routes/app/add-ons/[owner]/[repo]/+layout.ts @@ -0,0 +1,18 @@ +import { breadcrumbTrail } from "$lib/utils/navigation"; +import { getAddon } from "@/lib/api/addons.js"; +import { error } from "@sveltejs/kit"; + +export async function load({ url, params, fetch, parent }) { + const { owner, repo } = params; + const addon = await getAddon(owner, repo, fetch); + if (!addon) { + return error(404, "Add-On Not Found"); + } + const breadcrumbs = await breadcrumbTrail(parent, [ + { href: url.pathname, title: addon.name }, + ]); + return { + addon, + breadcrumbs, + }; +} diff --git a/src/routes/app/add-ons/[owner]/[repo]/+page.svelte b/src/routes/app/add-ons/[owner]/[repo]/+page.svelte index e69de29bb..ad3be7874 100644 --- a/src/routes/app/add-ons/[owner]/[repo]/+page.svelte +++ b/src/routes/app/add-ons/[owner]/[repo]/+page.svelte @@ -0,0 +1,12 @@ + + + + +

{data.addon.name}

+

Placeholder

+
+