diff --git a/src/actions/admin-radio-autodj.test.ts b/src/actions/admin-radio-autodj.test.ts index dd74d19d..41c2e779 100644 --- a/src/actions/admin-radio-autodj.test.ts +++ b/src/actions/admin-radio-autodj.test.ts @@ -33,12 +33,8 @@ vi.mock("@/lib/services/staff-activity", () => ({ logStaffActivity: mockLogStaffActivity, })); -import { - createTrack, - deleteTrack, - toggleTrack, -} from "./admin-radio-autodj"; import { RadioAutoDjPlaylist } from "@/lib/db"; +import { createTrack, deleteTrack, toggleTrack } from "./admin-radio-autodj"; function form(data: Record): FormData { const fd = new FormData(); @@ -157,8 +153,10 @@ describe("createTrack", () => { }); it("swallows insert failures but still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); - await expect(createTrack(form({ title: "Track" }))).resolves.toBeUndefined(); + fakeDbConfig.fail = (kind: string) => kind === "insert"; + await expect( + createTrack(form({ title: "Track" })), + ).resolves.toBeUndefined(); expect(mockLogStaffActivity).not.toHaveBeenCalled(); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/radio/autodj"); }); @@ -212,7 +210,7 @@ describe("toggleTrack", () => { }); it("swallows update failures but still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "update" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "update"; await toggleTrack(form({ id: "2", isActive: "on" })); expect(mockLogStaffActivity).not.toHaveBeenCalled(); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/radio/autodj"); @@ -246,9 +244,9 @@ describe("deleteTrack", () => { }); it("swallows delete failures but still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "delete" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "delete"; await deleteTrack(form({ id: "4" })); expect(mockLogStaffActivity).not.toHaveBeenCalled(); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/radio/autodj"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-radio-extra.test.ts b/src/actions/admin-radio-extra.test.ts index c8b464cd..a43b9d17 100644 --- a/src/actions/admin-radio-extra.test.ts +++ b/src/actions/admin-radio-extra.test.ts @@ -35,9 +35,15 @@ vi.mock("@/lib/services/site-settings", () => ({ })); vi.mock("@/lib/logger", () => ({ - logger: { error: mockLoggerError, warn: vi.fn(), info: vi.fn(), debug: vi.fn() }, + logger: { + error: mockLoggerError, + warn: vi.fn(), + info: vi.fn(), + debug: vi.fn(), + }, })); +import { RadioBanners, RadioRanks, WebsiteSetting } from "@/lib/db"; import { createRadioBanner, createRadioRank, @@ -48,11 +54,6 @@ import { updateRadioBanner, updateRadioRank, } from "./admin-radio-extra"; -import { - RadioBanners, - RadioRanks, - WebsiteSetting, -} from "@/lib/db"; function form(data: Record): FormData { const fd = new FormData(); @@ -158,7 +159,7 @@ describe("saveRadioSettings", () => { }); it("logs and continues when the bulk upsert fails", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await saveRadioSettings(form({ __keys: "radio_foo", radio_foo: "1" })); expect(mockLoggerError).toHaveBeenCalledWith( "Failed to bulk-save radio settings", @@ -216,7 +217,7 @@ describe("createRadioBanner", () => { }); it("logs and continues when the insert fails", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await createRadioBanner(form({ imagePath: "/banners/c.png" })); expect(mockLoggerError).toHaveBeenCalledWith( "Failed to create radio banner", @@ -266,7 +267,7 @@ describe("updateRadioBanner", () => { }); it("logs and continues on update failure", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "update" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "update"; await updateRadioBanner(form({ id: "3", imagePath: "/banners/x.png" })); expect(mockLoggerError).toHaveBeenCalledWith( "Failed to update radio banner", @@ -292,7 +293,7 @@ describe("deleteRadioBanner", () => { }); it("logs and continues on delete failure", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "delete" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "delete"; await deleteRadioBanner(form({ id: "6" })); expect(mockLoggerError).toHaveBeenCalledWith( "Failed to delete radio banner", @@ -339,7 +340,7 @@ describe("createRadioRank", () => { }); it("logs and continues on insert failure", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await createRadioRank(form({ name: "Broken" })); expect(mockLoggerError).toHaveBeenCalledWith( "Failed to create radio rank", @@ -383,7 +384,7 @@ describe("updateRadioRank", () => { }); it("logs and continues on update failure", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "update" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "update"; await updateRadioRank(form({ id: "2", name: "VIP" })); expect(mockLoggerError).toHaveBeenCalledWith( "Failed to update radio rank", @@ -409,7 +410,7 @@ describe("deleteRadioRank", () => { }); it("logs and continues on delete failure", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "delete" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "delete"; await deleteRadioRank(form({ id: "7" })); expect(mockLoggerError).toHaveBeenCalledWith( "Failed to delete radio rank", @@ -417,4 +418,4 @@ describe("deleteRadioRank", () => { ); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/radio/ranks"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-radio-moderation.test.ts b/src/actions/admin-radio-moderation.test.ts index f0b5ddbf..7cc1be71 100644 --- a/src/actions/admin-radio-moderation.test.ts +++ b/src/actions/admin-radio-moderation.test.ts @@ -32,8 +32,8 @@ vi.mock("@/lib/services/staff-activity", () => ({ logStaffActivity: mockLogStaffActivity, })); -import { deleteShout } from "./admin-radio-moderation"; import { RadioShouts } from "@/lib/db"; +import { deleteShout } from "./admin-radio-moderation"; function form(data: Record): FormData { const fd = new FormData(); @@ -92,9 +92,9 @@ describe("deleteShout", () => { }); it("swallows DB failures but still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "delete" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "delete"; await deleteShout(form({ id: "3" })); expect(mockLogStaffActivity).not.toHaveBeenCalled(); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/radio/moderation"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-radio-points.test.ts b/src/actions/admin-radio-points.test.ts index a80715db..5ea38546 100644 --- a/src/actions/admin-radio-points.test.ts +++ b/src/actions/admin-radio-points.test.ts @@ -42,8 +42,8 @@ vi.mock("@/lib/services/staff-activity", () => ({ logStaffActivity: mockLogStaffActivity, })); -import { savePoints } from "./admin-radio-points"; import { WebsiteSetting } from "@/lib/db"; +import { savePoints } from "./admin-radio-points"; function form(data: Record): FormData { const fd = new FormData(); @@ -62,7 +62,7 @@ beforeEach(() => { }); }); -const POINTS_KEYS = [ +const _POINTS_KEYS = [ "radio_points_enabled", "radio_points_per_minute", "radio_points_currency", @@ -165,7 +165,8 @@ describe("savePoints", () => { }); it("fails soft on DB errors but still revalidates and redirects", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? "db down" : false); + fakeDbConfig.fail = (kind: string) => + kind === "insert" ? "db down" : false; await savePoints( form({ radio_points_enabled: "on", radio_points_currency: "diamonds" }), ); @@ -174,4 +175,4 @@ describe("savePoints", () => { expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/radio/points"); expect(mockRedirect).toHaveBeenCalledWith("/admin/radio/points?saved=1"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-rare-values.test.ts b/src/actions/admin-rare-values.test.ts index 84660eca..811019a1 100644 --- a/src/actions/admin-rare-values.test.ts +++ b/src/actions/admin-rare-values.test.ts @@ -27,6 +27,7 @@ vi.mock("next/cache", () => ({ unstable_cache: (fn: any) => fn, })); +import { WebsiteRareValueCategories, WebsiteRareValues } from "@/lib/db"; import { createCategory, createValue, @@ -35,10 +36,6 @@ import { updateCategory, updateValue, } from "./admin-rare-values"; -import { - WebsiteRareValueCategories, - WebsiteRareValues, -} from "@/lib/db"; function form(data: Record): FormData { const fd = new FormData(); @@ -86,7 +83,7 @@ describe("createCategory", () => { }); it("swallows insert errors and still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await createCategory(form({ name: "A", badge: "B" })); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/rare-values"); }); @@ -116,7 +113,7 @@ describe("deleteCategory", () => { }); it("swallows DB errors and still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "delete" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "delete"; await deleteCategory(form({ id: "3" })); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/rare-values"); }); @@ -152,9 +149,7 @@ describe("createValue", () => { it("returns early when categoryId, name or furnitureIcon is missing", async () => { await createValue(form({ name: "X", furnitureIcon: "x.png" })); - await createValue( - form({ categoryId: "1", furnitureIcon: "x.png" }), - ); + await createValue(form({ categoryId: "1", furnitureIcon: "x.png" })); await createValue(form({ categoryId: "1", name: "X" })); expect(fakeDbConfig.ops).toHaveLength(0); expect(mockRevalidatePath).not.toHaveBeenCalled(); @@ -179,7 +174,7 @@ describe("createValue", () => { }); it("swallows insert errors and still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await createValue( form({ categoryId: "1", name: "X", furnitureIcon: "x.png" }), ); @@ -203,7 +198,7 @@ describe("deleteValue", () => { }); it("swallows delete errors and still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "delete" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "delete"; await deleteValue(form({ id: "4" })); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/rare-values"); }); @@ -231,7 +226,7 @@ describe("updateCategory", () => { }); it("swallows update errors and still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "update" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "update"; await updateCategory(form({ id: "1", name: "X", badge: "B" })); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/rare-values"); }); @@ -292,8 +287,8 @@ describe("updateValue", () => { }); it("swallows update errors and still revalidates", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "update" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "update"; await updateValue(form({ id: "1", name: "X", furnitureIcon: "x.png" })); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/rare-values"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-referrals.test.ts b/src/actions/admin-referrals.test.ts index 4e5ef8d8..bed58367 100644 --- a/src/actions/admin-referrals.test.ts +++ b/src/actions/admin-referrals.test.ts @@ -53,10 +53,26 @@ describe("updateReferralSettings", () => { }); expect(mockRequirePermission).toHaveBeenCalledWith("admin.referrals.edit"); - expect(mockSiteSettingUpdate).toHaveBeenNthCalledWith(1, "referrals_needed", "5"); - expect(mockSiteSettingUpdate).toHaveBeenNthCalledWith(2, "referral_reward_amount", "100"); - expect(mockSiteSettingUpdate).toHaveBeenNthCalledWith(3, "referral_reward_currency_type", "duckets"); - expect(mockSiteSettingUpdate).toHaveBeenNthCalledWith(4, "referrals_block_same_ip", "1"); + expect(mockSiteSettingUpdate).toHaveBeenNthCalledWith( + 1, + "referrals_needed", + "5", + ); + expect(mockSiteSettingUpdate).toHaveBeenNthCalledWith( + 2, + "referral_reward_amount", + "100", + ); + expect(mockSiteSettingUpdate).toHaveBeenNthCalledWith( + 3, + "referral_reward_currency_type", + "duckets", + ); + expect(mockSiteSettingUpdate).toHaveBeenNthCalledWith( + 4, + "referrals_block_same_ip", + "1", + ); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/referrals"); expect(result).toEqual({ ok: true, data: {} }); }); @@ -112,7 +128,10 @@ describe("updateReferralSettings", () => { rewardCurrency: "credits", blockSameIp: "0", }); - expect(result).toEqual({ ok: false, error: "Reward amount must be positive" }); + expect(result).toEqual({ + ok: false, + error: "Reward amount must be positive", + }); }); it("rejects an unsupported reward currency", async () => { @@ -158,4 +177,4 @@ describe("updateReferralSettings", () => { }); expect(mockRevalidatePath).not.toHaveBeenCalled(); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-settings.test.ts b/src/actions/admin-settings.test.ts index 4ecc2d01..b0c1e593 100644 --- a/src/actions/admin-settings.test.ts +++ b/src/actions/admin-settings.test.ts @@ -64,14 +64,14 @@ vi.mock("@/lib/services/habboassets", () => ({ clearBadgeCache: mockClearBadge, })); +import { WebsiteSetting } from "@/lib/db"; +import { PERMS } from "@/lib/permissions"; import { createSetting, deleteSetting, saveManagedSettings, updateSetting, } from "./admin-settings"; -import { WebsiteSetting } from "@/lib/db"; -import { PERMS } from "@/lib/permissions"; function form(data: Record): FormData { const fd = new FormData(); @@ -249,4 +249,4 @@ describe("deleteSetting", () => { expect(mockClearBadge).toHaveBeenCalledTimes(1); expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/settings"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-shop.test.ts b/src/actions/admin-shop.test.ts index d2416006..c146d1ef 100644 --- a/src/actions/admin-shop.test.ts +++ b/src/actions/admin-shop.test.ts @@ -43,12 +43,12 @@ vi.mock("@/lib/server-log", () => ({ logServerError: mockLogServerError, })); +import { WebsiteShopArticles } from "@/lib/db"; import { createShopArticle, deleteShopArticle, updateShopArticle, } from "./admin-shop"; -import { WebsiteShopArticles } from "@/lib/db"; function form(data: Record): FormData { const fd = new FormData(); @@ -157,7 +157,7 @@ describe("createShopArticle", () => { }); it("logs the error and returns without redirecting on insert failure", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await createShopArticle(form({ name: "Broken" })); expect(mockLogServerError).toHaveBeenCalledWith( "admin.shop_create_failed", @@ -237,7 +237,7 @@ describe("updateShopArticle", () => { }); it("logs the error and returns without rendering guards on failure", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "update" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "update"; await updateShopArticle(form({ id: "1", name: "Broken" })); expect(mockLogServerError).toHaveBeenCalledWith( "admin.shop_update_failed", @@ -273,7 +273,7 @@ describe("deleteShopArticle", () => { }); it("logs the error and returns without redirecting on failure", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "delete" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "delete"; await deleteShopArticle(form({ id: "3" })); expect(mockLogServerError).toHaveBeenCalledWith( "admin.shop_delete_failed", @@ -282,4 +282,4 @@ describe("deleteShopArticle", () => { ); expect(mockRedirect).not.toHaveBeenCalled(); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-theme.test.ts b/src/actions/admin-theme.test.ts index b759f764..382f4b6d 100644 --- a/src/actions/admin-theme.test.ts +++ b/src/actions/admin-theme.test.ts @@ -141,7 +141,7 @@ describe("saveTheme", () => { }); it("fails soft when a write fails and still redirects", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await saveTheme(form({ color_primary: "#123456" })); expect(mockReload).not.toHaveBeenCalled(); expect(mockLogStaffActivity).not.toHaveBeenCalled(); @@ -182,7 +182,7 @@ describe("applyPreset", () => { }); it("fails soft on write errors", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await applyPreset(form({ preset: "Ocean" })); expect(mockReload).not.toHaveBeenCalled(); expect(mockLogStaffActivity).not.toHaveBeenCalled(); @@ -195,10 +195,9 @@ describe("saveCustomTheme", () => { await saveCustomTheme(form({ name: "My Theme" })); expect(mockSnapshotCurrentTheme).toHaveBeenCalledTimes(1); - expect(mockUpsertCustomTheme).toHaveBeenCalledWith( - "My Theme", - { color_primary: "#ffffff" }, - ); + expect(mockUpsertCustomTheme).toHaveBeenCalledWith("My Theme", { + color_primary: "#ffffff", + }); expect(mockLogStaffActivity).toHaveBeenCalledWith({ staffId: 3, action: "theme_preset", @@ -254,9 +253,7 @@ describe("applyCustomTheme", () => { }), ); expect(mockRevalidatePath).toHaveBeenCalledWith("/", "layout"); - expect(mockRedirect).toHaveBeenCalledWith( - "/admin/theme?theme=Studio", - ); + expect(mockRedirect).toHaveBeenCalledWith("/admin/theme?theme=Studio"); }); it("redirects when the id is blank", async () => { @@ -293,7 +290,7 @@ describe("applyCustomTheme", () => { createdAt: 0, settings: { color_primary: "#abcdef" }, }); - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; await applyCustomTheme(form({ id: "t1" })); expect(mockReload).not.toHaveBeenCalled(); expect(mockLogStaffActivity).not.toHaveBeenCalled(); @@ -358,4 +355,4 @@ describe("deleteCustomTheme", () => { expect(mockRevalidatePath).not.toHaveBeenCalled(); expect(mockRedirect).toHaveBeenCalledWith("/admin/theme?deletedTheme=1"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-vouchers.test.ts b/src/actions/admin-vouchers.test.ts index 10d5cec6..1e79bee4 100644 --- a/src/actions/admin-vouchers.test.ts +++ b/src/actions/admin-vouchers.test.ts @@ -38,12 +38,8 @@ vi.mock("@/lib/safe-action-shared", () => ({ actionError: (message: string) => ({ ok: false, error: message }), })); -import { - createVoucher, - deleteVoucher, - updateVoucher, -} from "./admin-vouchers"; import { WebsiteShopVouchers } from "@/lib/db"; +import { createVoucher, deleteVoucher, updateVoucher } from "./admin-vouchers"; beforeEach(() => { vi.clearAllMocks(); @@ -120,7 +116,7 @@ describe("createVoucher", () => { }); it("returns an error when the insert fails", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "insert" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "insert"; const result = await createVoucher({ code: "X", amount: 1, maxUses: 1 }); expect(mockLogServerError).toHaveBeenCalledWith( "admin.voucher_create_failed", @@ -154,7 +150,7 @@ describe("deleteVoucher", () => { }); it("returns an error when the delete fails", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "delete" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "delete"; const result = await deleteVoucher({ id: "5" }); expect(mockLogServerError).toHaveBeenCalledWith( "admin.voucher_delete_failed", @@ -233,7 +229,7 @@ describe("updateVoucher", () => { }); it("returns an error when the update fails", async () => { - fakeDbConfig.fail = (kind: string) => (kind === "update" ? true : false); + fakeDbConfig.fail = (kind: string) => kind === "update"; const result = await updateVoucher({ id: "9", code: "X", @@ -250,4 +246,4 @@ describe("updateVoucher", () => { error: "Could not update voucher (code may already exist)", }); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-wordfilter.test.ts b/src/actions/admin-wordfilter.test.ts index 4fa03934..6b97ae6e 100644 --- a/src/actions/admin-wordfilter.test.ts +++ b/src/actions/admin-wordfilter.test.ts @@ -158,4 +158,4 @@ describe("deleteWord", () => { error: "Could not remove word", }); }); -}); \ No newline at end of file +}); diff --git a/src/actions/admin-writeable-boxes.test.ts b/src/actions/admin-writeable-boxes.test.ts index ba77d490..5f143bab 100644 --- a/src/actions/admin-writeable-boxes.test.ts +++ b/src/actions/admin-writeable-boxes.test.ts @@ -80,7 +80,6 @@ vi.mock("@/lib/db", async () => { }); import { WebsiteWriteableBoxes } from "@/lib/db"; -import { PERMS } from "@/lib/permissions"; import { createBox, deleteBox, @@ -106,9 +105,9 @@ beforeEach(() => { describe("createBox", () => { it("rejects callers without PAGES_EDIT", async () => { mockRequirePermission.mockRejectedValueOnce(new Error("denied")); - await expect(createBox(fakeForm({ title: "Hi" }) as FormData)).rejects.toThrow( - "denied", - ); + await expect( + createBox(fakeForm({ title: "Hi" }) as FormData), + ).rejects.toThrow("denied"); expect(state.insertCalls).toHaveLength(0); }); @@ -166,15 +165,12 @@ describe("createBox", () => { isActive: "0", }) as FormData, ); - expect( - (state.insertCalls.at(-1)?.values as Record).position, - ).toBe(expected); - expect( - (state.insertCalls.at(-1)?.values as Record).isActive, - ).toBe(false); - expect( - (state.insertCalls.at(-1)?.values as Record).icon, - ).toBeNull(); + const lastInsert = state.insertCalls.at(-1); + expect(lastInsert).toBeDefined(); + const vals = lastInsert?.values as Record; + expect(vals.position).toBe(expected); + expect(vals.isActive).toBe(false); + expect(vals.icon).toBeNull(); } }); @@ -267,7 +263,9 @@ describe("deleteBox", () => { it("swallows a failed delete", async () => { state.deleteError = new Error("db down"); - await expect(deleteBox(fakeForm({ id: "1" }) as FormData)).resolves.toBeUndefined(); + await expect( + deleteBox(fakeForm({ id: "1" }) as FormData), + ).resolves.toBeUndefined(); expect(mockLogStaffActivity).not.toHaveBeenCalled(); expect(mockRevalidatePath).not.toHaveBeenCalled(); }); @@ -282,7 +280,9 @@ describe("toggleBox", () => { it("activates when next is 1", async () => { await toggleBox(fakeForm({ id: "2", next: "1" }) as FormData); expect(state.updateCalls).toHaveLength(1); - expect((state.updateCalls[0].values as Record).isActive).toBe(true); + expect( + (state.updateCalls[0].values as Record).isActive, + ).toBe(true); expect(mockLogStaffActivity).toHaveBeenCalledWith( expect.objectContaining({ action: "writeable_box_toggle", @@ -294,7 +294,9 @@ describe("toggleBox", () => { it("hides when next is anything but 1", async () => { await toggleBox(fakeForm({ id: "2", next: "0" }) as FormData); - expect((state.updateCalls[0].values as Record).isActive).toBe(false); + expect( + (state.updateCalls[0].values as Record).isActive, + ).toBe(false); expect(mockLogStaffActivity).toHaveBeenCalledWith( expect.objectContaining({ description: "Hid writeable box #2", @@ -304,8 +306,10 @@ describe("toggleBox", () => { it("swallows a failed toggle", async () => { state.updateError = new Error("db down"); - await expect(toggleBox(fakeForm({ id: "2", next: "1" }) as FormData)).resolves.toBeUndefined(); + await expect( + toggleBox(fakeForm({ id: "2", next: "1" }) as FormData), + ).resolves.toBeUndefined(); expect(mockLogStaffActivity).not.toHaveBeenCalled(); expect(mockRevalidatePath).not.toHaveBeenCalled(); }); -}); \ No newline at end of file +}); diff --git a/src/actions/article-reactions.test.ts b/src/actions/article-reactions.test.ts index 30a433ce..f36d6c01 100644 --- a/src/actions/article-reactions.test.ts +++ b/src/actions/article-reactions.test.ts @@ -46,8 +46,7 @@ vi.mock("@/lib/db", async () => { throw e; } if (table === schema.WebsiteArticles) return state.articles; - if (table === schema.WebsiteArticleReactions) - return state.reactions; + if (table === schema.WebsiteArticleReactions) return state.reactions; return []; }), update: (table: unknown) => ({ @@ -211,4 +210,4 @@ describe("toggleReaction", () => { ).rejects.toThrow("NEXT_REDIRECT"); expect(WebsiteArticles).toBeDefined(); }); -}); \ No newline at end of file +}); diff --git a/src/actions/badges.test.ts b/src/actions/badges.test.ts index f2974114..e917a59f 100644 --- a/src/actions/badges.test.ts +++ b/src/actions/badges.test.ts @@ -106,4 +106,4 @@ describe("updateBadge", () => { expect(mockRevalidatePath).toHaveBeenCalledWith("/admin/import/badges"); expect(mockRequirePermission).toHaveBeenCalledWith(PERMS.CATALOG_EDIT); }); -}); \ No newline at end of file +}); diff --git a/src/actions/banners.test.ts b/src/actions/banners.test.ts index f0fd5482..6d75509a 100644 --- a/src/actions/banners.test.ts +++ b/src/actions/banners.test.ts @@ -75,11 +75,7 @@ vi.mock("@/lib/db", async () => { import { WebsiteBanner } from "@/lib/db"; import { PERMS } from "@/lib/permissions"; -import { - createBanner, - deleteBanner, - updateBanner, -} from "./banners"; +import { createBanner, deleteBanner, updateBanner } from "./banners"; function session() { return { @@ -172,7 +168,9 @@ describe("createBanner", () => { const result = await createBanner({ image: "i" }); expect(result.ok).toBe(false); expect(result.error).toBe("Validation failed"); - expect((result as { fieldErrors: Record }).fieldErrors.title).toBeDefined(); + expect( + (result as { fieldErrors: Record }).fieldErrors.title, + ).toBeDefined(); }); it("rejects an out-of-range isActive value", async () => { @@ -257,4 +255,4 @@ describe("deleteBanner", () => { expect(result.ok).toBe(false); expect(result.error).toBe("Validation failed"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/catalog-bc.test.ts b/src/actions/catalog-bc.test.ts index fb80c4fd..0882d398 100644 --- a/src/actions/catalog-bc.test.ts +++ b/src/actions/catalog-bc.test.ts @@ -1,6 +1,5 @@ import { eq } from "drizzle-orm"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { fakeForm } from "@/test/fake-form"; const state = vi.hoisted(() => ({ deletes: [] as { table: unknown; where: unknown }[], @@ -87,7 +86,6 @@ vi.mock("@/lib/db", async () => { }); import { CatalogItemsBc } from "@/lib/db"; -import { PERMS } from "@/lib/permissions"; import { createBcItem, createBcPage, @@ -110,7 +108,10 @@ beforeEach(() => { mockWithCatalogExport.mockImplementation( async (fn: () => unknown) => await fn(), ); - mockCatalogFailure.mockReturnValue({ message: "Catalog op failed", status: 400 }); + mockCatalogFailure.mockReturnValue({ + message: "Catalog op failed", + status: 400, + }); mockCreateBcOfferCommand.mockResolvedValue(501); mockCreatePageCommand.mockResolvedValue(201); mockSendCatalogUpdate.mockResolvedValue({}); @@ -265,7 +266,12 @@ describe("toggleBcPage", () => { it("toggles the requested field", async () => { const result = await toggleBcPage({ id: 2, field: "visible" }); expect(result).toEqual({ ok: true }); - expect(mockTogglePageCommand).toHaveBeenCalledWith("bc", 2, "visible", staff.id); + expect(mockTogglePageCommand).toHaveBeenCalledWith( + "bc", + 2, + "visible", + staff.id, + ); expect(mockSendCatalogUpdate).toHaveBeenCalled(); expect(mockRevalidatePath).toHaveBeenCalledWith( "/admin/catalog/builder-club", @@ -377,4 +383,4 @@ describe("reorderBcCatalogPages", () => { "/admin/catalog/builder-club", ); }); -}); \ No newline at end of file +}); diff --git a/src/actions/commandocentrum.test.ts b/src/actions/commandocentrum.test.ts index b3679feb..0e2ed6ba 100644 --- a/src/actions/commandocentrum.test.ts +++ b/src/actions/commandocentrum.test.ts @@ -102,7 +102,6 @@ vi.mock("@/lib/db", async () => { }; }); -import { PERMS } from "@/lib/permissions"; import { alertUser, disconnectUser, @@ -113,9 +112,9 @@ import { giveDiamonds, giveDuckets, hotelAlert, + sendGift, setMotto, setRank, - sendGift, updateCatalog, updateNavigator, updateWordFilter, @@ -297,10 +296,12 @@ describe("giveCredits / giveDuckets / giveDiamonds", () => { }); it("rejects negative amounts", async () => { - await expect(giveCredits({ userId: 1, credits: 0 })).resolves.toMatchObject({ - ok: false, - error: "Validation failed", - }); + await expect(giveCredits({ userId: 1, credits: 0 })).resolves.toMatchObject( + { + ok: false, + error: "Validation failed", + }, + ); }); }); @@ -452,4 +453,4 @@ describe("access control", () => { error: RCON_FAIL, }); }); -}); \ No newline at end of file +}); diff --git a/src/actions/daily-reward.test.ts b/src/actions/daily-reward.test.ts index fdd639ee..fb920fa3 100644 --- a/src/actions/daily-reward.test.ts +++ b/src/actions/daily-reward.test.ts @@ -33,7 +33,12 @@ vi.mock("@/lib/auth", () => ({ auth: mockAuth })); const mockRateLimit = vi.hoisted(() => vi.fn()); vi.mock("@/lib/rate-limit", () => ({ rateLimit: mockRateLimit })); -const mockLogger = vi.hoisted(() => ({ error: vi.fn(), warn: vi.fn(), info: vi.fn(), debug: vi.fn() })); +const mockLogger = vi.hoisted(() => ({ + error: vi.fn(), + warn: vi.fn(), + info: vi.fn(), + debug: vi.fn(), +})); vi.mock("@/lib/logger", () => ({ logger: mockLogger })); vi.mock("@/lib/services/daily-rewards", () => ({ @@ -264,4 +269,4 @@ describe("claimDailyReward", () => { "NEXT_REDIRECT: /me?daily=error", ); }); -}); \ No newline at end of file +}); diff --git a/src/actions/draw-badge.test.ts b/src/actions/draw-badge.test.ts index e5e2e5ee..c0ceecbb 100644 --- a/src/actions/draw-badge.test.ts +++ b/src/actions/draw-badge.test.ts @@ -258,8 +258,11 @@ describe("buyBadge", () => { }); expect(mockGiveBadge).toHaveBeenCalledWith(7, "MYBADGE"); expect(mockRevalidatePath).toHaveBeenCalledWith("/draw-badge"); - console.log("DEBUG caught:", state.caughtErrors.map((e) => (e as Error).message ?? e)); -}); + console.log( + "DEBUG caught:", + state.caughtErrors.map((e) => (e as Error).message ?? e), + ); + }); it("updates an existing badge slot instead of creating a new one", async () => { state.badges = [{ id: 1, badgePath: "MYBADGE.gif", published: true }]; @@ -363,4 +366,4 @@ describe("buyBadge", () => { "NEXT_REDIRECT: /draw-badge?error=fail", ); }); -}); \ No newline at end of file +}); diff --git a/src/actions/radio-apply.test.ts b/src/actions/radio-apply.test.ts index 40f02604..e4b3f40b 100644 --- a/src/actions/radio-apply.test.ts +++ b/src/actions/radio-apply.test.ts @@ -69,11 +69,7 @@ describe("applyDj", () => { await expect(applyDj(buildForm())).rejects.toThrow( "/radio/apply?submitted=1", ); - expect(state.rateLimit).toHaveBeenCalledWith( - "radio-apply:5", - 2, - 300_000, - ); + expect(state.rateLimit).toHaveBeenCalledWith("radio-apply:5", 2, 300_000); expect(state.insert).toHaveBeenCalledOnce(); expect(state.insert.mock.calls[0][0]).toBe(RadioApplications); expect(state.insert.mock.calls[0][1]).toMatchObject({ @@ -164,4 +160,4 @@ describe("applyDj", () => { ); expect(state.revalidatePath).toHaveBeenCalledWith("/radio/apply"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/radio-requests.test.ts b/src/actions/radio-requests.test.ts index 76d79a0d..eedad089 100644 --- a/src/actions/radio-requests.test.ts +++ b/src/actions/radio-requests.test.ts @@ -80,9 +80,9 @@ describe("submitRequest", () => { }); it("stores null for whichever of song/artist is left empty", async () => { - await expect( - submitRequest(buildForm({ artist: "" })), - ).rejects.toThrow("/radio/requests?posted=1"); + await expect(submitRequest(buildForm({ artist: "" }))).rejects.toThrow( + "/radio/requests?posted=1", + ); expect(state.insert.mock.calls[0][1]).toMatchObject({ songTitle: "Never Gonna Give You Up", artist: null, @@ -150,4 +150,4 @@ describe("submitRequest", () => { "/radio/requests?error=error", ); }); -}); \ No newline at end of file +}); diff --git a/src/actions/radio-shouts.test.ts b/src/actions/radio-shouts.test.ts index c219c3f8..00fc039e 100644 --- a/src/actions/radio-shouts.test.ts +++ b/src/actions/radio-shouts.test.ts @@ -93,21 +93,23 @@ describe("postShout", () => { }); it("rejects an empty or whitespace-only message as invalid", async () => { - await expect( - postShout(buildForm({ message: "" })), - ).rejects.toThrow("/radio/shouts?error=invalid"); - await expect( - postShout(buildForm({ message: " " })), - ).rejects.toThrow("/radio/shouts?error=invalid"); - await expect( - postShout(buildForm({ message: undefined })), - ).rejects.toThrow("/radio/shouts?error=invalid"); + await expect(postShout(buildForm({ message: "" }))).rejects.toThrow( + "/radio/shouts?error=invalid", + ); + await expect(postShout(buildForm({ message: " " }))).rejects.toThrow( + "/radio/shouts?error=invalid", + ); + await expect(postShout(buildForm({ message: undefined }))).rejects.toThrow( + "/radio/shouts?error=invalid", + ); expect(state.insert).not.toHaveBeenCalled(); expect(state.revalidatePath).toHaveBeenCalledWith("/radio/shouts"); }); it("redirects with error=moderated when content moderation rejects the message", async () => { - state.moderateOrThrow.mockRejectedValue(new Error("Blocked by word filter")); + state.moderateOrThrow.mockRejectedValue( + new Error("Blocked by word filter"), + ); await expect(postShout(buildForm())).rejects.toThrow( "/radio/shouts?error=moderated", ); @@ -141,4 +143,4 @@ describe("postShout", () => { "/radio/shouts?error=error", ); }); -}); \ No newline at end of file +}); diff --git a/src/actions/referral.test.ts b/src/actions/referral.test.ts index 64892dd7..5fc851ee 100644 --- a/src/actions/referral.test.ts +++ b/src/actions/referral.test.ts @@ -35,17 +35,19 @@ vi.mock("@/lib/services/rcon", () => ({ vi.mock("@/lib/db", async () => { const schema = await import("@/db/schema"); const { createFakeDb } = await import("@/test/fake-db"); - const fake = createFakeDb((table: unknown, projection: Record) => { - if ("referralsTotal" in projection) { - if (state.referralsFail) throw new Error("referrals down"); - return state.referralsRows; - } - if ("key" in projection) { - if (state.settingsFail) throw new Error("settings down"); - return state.settingsRows; - } - return []; - }); + const fake = createFakeDb( + (_table: unknown, projection: Record) => { + if ("referralsTotal" in projection) { + if (state.referralsFail) throw new Error("referrals down"); + return state.referralsRows; + } + if ("key" in projection) { + if (state.settingsFail) throw new Error("settings down"); + return state.settingsRows; + } + return []; + }, + ); return { ...schema, db: { @@ -218,9 +220,7 @@ describe("claimReferral", () => { }); it("rejects a non-positive or garbled reward amount as bad_config", async () => { - state.settingsRows = [ - { key: "referral_reward_amount", value: "abc" }, - ]; + state.settingsRows = [{ key: "referral_reward_amount", value: "abc" }]; await expect(claimReferral(new FormData())).rejects.toThrow( "/me?error=bad_config", ); @@ -259,4 +259,4 @@ describe("claimReferral", () => { ); expect(state.sendCurrency).toHaveBeenCalledTimes(1); }); -}); \ No newline at end of file +}); diff --git a/src/actions/register.test.ts b/src/actions/register.test.ts index cfb7985b..1b6cd7c6 100644 --- a/src/actions/register.test.ts +++ b/src/actions/register.test.ts @@ -59,14 +59,16 @@ vi.mock("@/lib/services/site-settings", () => ({ vi.mock("@/lib/db", async () => { const schema = await import("@/db/schema"); const { createFakeDb } = await import("@/test/fake-db"); - const fake = createFakeDb((table: unknown, projection: Record) => { - if ("total" in projection) { - if (state.failCount) return Promise.reject(new Error("count down")); - return [{ total: state.countTotal }]; - } - if (state.failUsernameCheck) throw new Error("check down"); - return state.userRows; - }); + const fake = createFakeDb( + (_table: unknown, projection: Record) => { + if ("total" in projection) { + if (state.failCount) return Promise.reject(new Error("count down")); + return [{ total: state.countTotal }]; + } + if (state.failUsernameCheck) throw new Error("check down"); + return state.userRows; + }, + ); return { ...schema, db: { @@ -163,14 +165,14 @@ describe("register", () => { expect(values.username).toBe("Bob_88"); expect(values.mail).toBe("foo@bar.com"); expect(state.after).toHaveBeenCalledOnce(); - await state.afterCb!(); + await state.afterCb?.(); expect(state.sendVerification).toHaveBeenCalledWith("foo@bar.com"); }); it("logs a warning when the verification email fails to send", async () => { state.sendVerification.mockRejectedValue(new Error("smtp down")); await register(PREV, buildForm({ mail: "x@y.com" })); - await state.afterCb!(); + await state.afterCb?.(); expect(state.logger.warn).toHaveBeenCalledWith( "Failed to send verification email after registration", ); @@ -219,7 +221,10 @@ describe("register", () => { it("rejects passwords without a digit", async () => { const result = await register( PREV, - buildForm({ password: "Secretsecret", password_confirmation: "Secretsecret" }), + buildForm({ + password: "Secretsecret", + password_confirmation: "Secretsecret", + }), ); expect(result.error).toContain("digit"); }); @@ -317,7 +322,10 @@ describe("register", () => { it("rejects an already-taken username", async () => { state.userRows = [{ id: 7 }]; const result = await runValidRegistration(); - expect(result).toEqual({ error: "That username is already taken", ok: false }); + expect(result).toEqual({ + error: "That username is already taken", + ok: false, + }); expect(state.insert).not.toHaveBeenCalled(); }); @@ -339,7 +347,10 @@ describe("register", () => { cause: { code: "ER_DUP_ENTRY" }, }); const result = await runValidRegistration(); - expect(result).toEqual({ error: "That username is already taken", ok: false }); + expect(result).toEqual({ + error: "That username is already taken", + ok: false, + }); expect(state.logger.error).not.toHaveBeenCalled(); }); @@ -367,4 +378,4 @@ describe("register", () => { const values = state.insert.mock.calls[0][1] as { look: string }; expect(values.look).toBe("hr-123-42.hd-180-1"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/rooms.test.ts b/src/actions/rooms.test.ts index bec34e5c..a2523680 100644 --- a/src/actions/rooms.test.ts +++ b/src/actions/rooms.test.ts @@ -1,7 +1,11 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const state = vi.hoisted(() => ({ - requirePermission: vi.fn(async () => ({ id: 100, rank: 7, username: "staff" })), + requirePermission: vi.fn(async () => ({ + id: 100, + rank: 7, + username: "staff", + })), revalidatePath: vi.fn(), del: vi.fn(async () => [{ affectedRows: 1 }]), update: vi.fn(async () => [{ affectedRows: 1 }]), @@ -27,10 +31,12 @@ vi.mock("@/lib/services/rcon", () => ({ rcon: { send: state.rconSend } })); vi.mock("@/lib/db", async () => { const schema = await import("@/db/schema"); const { createFakeDb } = await import("@/test/fake-db"); - const fake = createFakeDb((table: unknown, projection: Record) => { - if (state.denied) throw new Error("not allowed"); - return state.roomRows; - }); + const fake = createFakeDb( + (_table: unknown, _projection: Record) => { + if (state.denied) throw new Error("not allowed"); + return state.roomRows; + }, + ); return { ...schema, db: { @@ -92,9 +98,9 @@ describe("rooms actions", () => { it("denies room edits without permission", async () => { state.requirePermission.mockRejectedValueOnce(new Error("forbidden")); - await expect( - updateRoomItem({ roomId: 9, itemId: 4 }), - ).rejects.toThrow("forbidden"); + await expect(updateRoomItem({ roomId: 9, itemId: 4 })).rejects.toThrow( + "forbidden", + ); expect(state.update).not.toHaveBeenCalled(); }); @@ -114,7 +120,9 @@ describe("rooms actions", () => { await bulkDeleteRoomItems({ roomId: 9, itemIds: [] }); expect(state.del).toHaveBeenCalledWith(Items, expect.anything()); expect(state.logStaffActivity).toHaveBeenCalledWith( - expect.objectContaining({ description: "Deleted 0 item(s) from room #9" }), + expect.objectContaining({ + description: "Deleted 0 item(s) from room #9", + }), ); expect(state.revalidatePath).toHaveBeenCalledWith("/admin/rooms/9/furni"); }); @@ -242,4 +250,4 @@ describe("rooms actions", () => { await expect(updateRoom({ id: 9 })).rejects.toThrow("forbidden"); expect(state.update).not.toHaveBeenCalled(); }); -}); \ No newline at end of file +}); diff --git a/src/actions/sessions.test.ts b/src/actions/sessions.test.ts index 2de85c58..bc23dab2 100644 --- a/src/actions/sessions.test.ts +++ b/src/actions/sessions.test.ts @@ -156,4 +156,4 @@ describe("signOutAndRevokeTicket", () => { ); expect(state.signOut).toHaveBeenCalledWith({ redirectTo: "/" }); }); -}); \ No newline at end of file +}); diff --git a/src/actions/shop.test.ts b/src/actions/shop.test.ts index 0897a946..ac58b6eb 100644 --- a/src/actions/shop.test.ts +++ b/src/actions/shop.test.ts @@ -49,15 +49,17 @@ vi.mock("@/lib/server-log", () => ({ vi.mock("@/lib/db", async () => { const schema = await import("@/db/schema"); const { createFakeDb } = await import("@/test/fake-db"); - const fake = createFakeDb((table: unknown, projection: Record) => { - if (table === schema.UsersBadges) { - if (state.badgeQueue.length) return state.badgeQueue.shift() as RowList; - return state.badgeRows; - } - if (table === schema.User) return state.userRows; - if (table === schema.WebsiteShopArticles) return state.articleRows; - return []; - }); + const fake = createFakeDb( + (table: unknown, _projection: Record) => { + if (table === schema.UsersBadges) { + if (state.badgeQueue.length) return state.badgeQueue.shift() as RowList; + return state.badgeRows; + } + if (table === schema.User) return state.userRows; + if (table === schema.WebsiteShopArticles) return state.articleRows; + return []; + }, + ); const db = { ...fake, update: (table: unknown) => ({ @@ -116,8 +118,7 @@ describe("buyShopArticle", () => { state.badgeQueue = []; state.isBadge = false; state.transaction.mockImplementation( - async (fn: (tx: unknown) => Promise, txDb: unknown) => - fn(txDb), + async (fn: (tx: unknown) => Promise, txDb: unknown) => fn(txDb), ); }); @@ -127,7 +128,11 @@ describe("buyShopArticle", () => { ); expect(state.rateLimit).toHaveBeenCalledWith("shop-buy:5", 5, 60_000); expect(state.transaction).toHaveBeenCalled(); - expect(state.update).toHaveBeenCalledWith(User, expect.anything(), expect.anything()); + expect(state.update).toHaveBeenCalledWith( + User, + expect.anything(), + expect.anything(), + ); expect(state.insert).toHaveBeenCalledTimes(2); expect(state.insert.mock.calls[0][0]).toBe(UsersBadges); expect(state.insert.mock.calls[0][1]).toEqual({ @@ -164,9 +169,9 @@ describe("buyShopArticle", () => { }); it("omits the category query param when it is not numeric", async () => { - await expect(buyShopArticle(shopForm({ categoryId: "abc" }))).rejects.toThrow( - "/shop?bought=1&package=StarterPack", - ); + await expect( + buyShopArticle(shopForm({ categoryId: "abc" })), + ).rejects.toThrow("/shop?bought=1&package=StarterPack"); }); it("raises the buyer rank when the package grants a higher rank", async () => { @@ -213,7 +218,10 @@ describe("buyShopArticle", () => { it("ignores badge codes longer than 32 characters or whitespace", async () => { state.articleRows = [ - { ...ARTICLE, badges: "OK,, , VERYLONG_badge_code_that_exceeds_32_chars" }, + { + ...ARTICLE, + badges: "OK,, , VERYLONG_badge_code_that_exceeds_32_chars", + }, ]; await expect(buyShopArticle(shopForm())).rejects.toThrow( "/shop?category=1&bought=1", @@ -284,9 +292,9 @@ describe("buyShopArticle", () => { await expect( buyShopArticle(shopForm({ articleId: "t-shirt" })), ).rejects.toThrow("/shop?category=1&error=invalid"); - await expect(buyShopArticle(shopForm({ articleId: "4.5" }))).rejects.toThrow( - "/shop?category=1&error=invalid", - ); + await expect( + buyShopArticle(shopForm({ articleId: "4.5" })), + ).rejects.toThrow("/shop?category=1&error=invalid"); expect(state.transaction).not.toHaveBeenCalled(); }); @@ -335,7 +343,10 @@ describe("buyShopArticle", () => { await expect(buyShopArticle(shopForm())).rejects.toThrow( "/shop?category=1&bought=1", ); - const updateCall = state.update.mock.calls[0] as [unknown, Record]; + const updateCall = state.update.mock.calls[0] as [ + unknown, + Record, + ]; expect(updateCall[1]).toHaveProperty("credits"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/social.test.ts b/src/actions/social.test.ts index 83da6e45..e6dd6b4b 100644 --- a/src/actions/social.test.ts +++ b/src/actions/social.test.ts @@ -30,7 +30,8 @@ vi.mock("@/lib/db", async () => { const schema = await import("@/db/schema"); const { createFakeDb } = await import("@/test/fake-db"); const fake = createFakeDb(() => { - if (state.selectQueue.length) return state.selectQueue.shift() as Queue[number]; + if (state.selectQueue.length) + return state.selectQueue.shift() as Queue[number]; return state.rows; }); const db = { @@ -121,9 +122,9 @@ describe("sendFriendRequest", () => { }); it("redirects to the root path when no username is supplied", async () => { - await expect(sendFriendRequest(friendForm({ username: "" }))).rejects.toThrow( - "/?friend=sent", - ); + await expect( + sendFriendRequest(friendForm({ username: "" })), + ).rejects.toThrow("/?friend=sent"); expect(state.revalidatePath).toHaveBeenCalledWith("/messages"); }); @@ -131,9 +132,9 @@ describe("sendFriendRequest", () => { await expect( sendFriendRequest(friendForm({ userId: "abc" })), ).rejects.toThrow("/u/Bob?error=invalid"); - await expect(sendFriendRequest(friendForm({ userId: "0" }))).rejects.toThrow( - "/u/Bob?error=invalid", - ); + await expect( + sendFriendRequest(friendForm({ userId: "0" })), + ).rejects.toThrow("/u/Bob?error=invalid"); await expect( sendFriendRequest(friendForm({ userId: "5.5" })), ).rejects.toThrow("/u/Bob?error=invalid"); @@ -144,9 +145,9 @@ describe("sendFriendRequest", () => { }); it("blocks sending a request to yourself", async () => { - await expect(sendFriendRequest(friendForm({ userId: "5" }))).rejects.toThrow( - "/u/Bob?error=self", - ); + await expect( + sendFriendRequest(friendForm({ userId: "5" })), + ).rejects.toThrow("/u/Bob?error=self"); expect(state.insert).not.toHaveBeenCalled(); }); @@ -209,8 +210,7 @@ describe("postThread", () => { state.selectQueue = []; state.rows = []; state.transaction.mockImplementation( - async (fn: (tx: unknown) => Promise, txDb: unknown) => - fn(txDb), + async (fn: (tx: unknown) => Promise, txDb: unknown) => fn(txDb), ); }); @@ -324,8 +324,7 @@ describe("replyToThread", () => { state.selectQueue = []; state.rows = []; state.transaction.mockImplementation( - async (fn: (tx: unknown) => Promise, txDb: unknown) => - fn(txDb), + async (fn: (tx: unknown) => Promise, txDb: unknown) => fn(txDb), ); }); @@ -350,9 +349,7 @@ describe("replyToThread", () => { updatedAt: expect.any(Number), }); expect(state.revalidatePath).toHaveBeenCalledWith("/guilds/10/forum"); - expect(state.revalidatePath).toHaveBeenCalledWith( - "/guilds/10/forum/20", - ); + expect(state.revalidatePath).toHaveBeenCalledWith("/guilds/10/forum/20"); }); it("floors a null posts_count at one", async () => { @@ -418,4 +415,4 @@ describe("replyToThread", () => { "/guilds/10/forum/20?error=error", ); }); -}); \ No newline at end of file +}); diff --git a/src/actions/soundtracks.test.ts b/src/actions/soundtracks.test.ts index d47fff5a..5374e6db 100644 --- a/src/actions/soundtracks.test.ts +++ b/src/actions/soundtracks.test.ts @@ -1,7 +1,11 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const state = vi.hoisted(() => ({ - requirePermission: vi.fn(async () => ({ id: 100, rank: 7, username: "staff" })), + requirePermission: vi.fn(async () => ({ + id: 100, + rank: 7, + username: "staff", + })), revalidatePath: vi.fn(), del: vi.fn(async () => [{ affectedRows: 1 }]), update: vi.fn(async () => [{ affectedRows: 1 }]), @@ -82,8 +86,14 @@ describe("soundtrack actions", () => { it("denies updates without the catalog edit permission", async () => { state.requirePermission.mockRejectedValueOnce(new Error("forbidden")); await expect( - updateSoundtrack({ id: 12, name: "x", author: "y", track: "z", length: 1 }), + updateSoundtrack({ + id: 12, + name: "x", + author: "y", + track: "z", + length: 1, + }), ).rejects.toThrow("forbidden"); expect(state.update).not.toHaveBeenCalled(); }); -}); \ No newline at end of file +}); diff --git a/src/actions/test-helpers.test.ts b/src/actions/test-helpers.test.ts index 11e1bd33..70e37fd1 100644 --- a/src/actions/test-helpers.test.ts +++ b/src/actions/test-helpers.test.ts @@ -3,14 +3,19 @@ import { createMockAuth, createMockDb, createMockLogStaffActivity, - createMockRevalidatePath, createMockRcon, + createMockRevalidatePath, } from "./test-helpers"; describe("test-helpers", () => { it("createMockDb returns vi.fn-backed query methods", () => { const db = createMockDb(); - expect(Object.keys(db).sort()).toEqual(["delete", "insert", "select", "update"]); + expect(Object.keys(db).sort()).toEqual([ + "delete", + "insert", + "select", + "update", + ]); for (const method of ["insert", "update", "delete", "select"]) { expect(db[method as keyof typeof db]).toBeTypeOf("function"); expect(vi.isMockFunction(db[method as keyof typeof db])).toBe(true); @@ -19,7 +24,11 @@ describe("test-helpers", () => { it("createMockAuth returns next-auth-like object", () => { const auth = createMockAuth(); - expect(auth).toEqual({ auth: expect.any(Function), handlers: {}, signOut: expect.any(Function) }); + expect(auth).toEqual({ + auth: expect.any(Function), + handlers: {}, + signOut: expect.any(Function), + }); expect(vi.isMockFunction(auth.auth)).toBe(true); expect(vi.isMockFunction(auth.signOut)).toBe(true); }); @@ -47,4 +56,4 @@ describe("test-helpers", () => { const b = createMockRevalidatePath(); expect(a).not.toBe(b); }); -}); \ No newline at end of file +}); diff --git a/src/actions/ticket-templates.test.ts b/src/actions/ticket-templates.test.ts index 85e4b436..6a5f99f7 100644 --- a/src/actions/ticket-templates.test.ts +++ b/src/actions/ticket-templates.test.ts @@ -20,7 +20,10 @@ const actionErrorClass = vi.hoisted( ); vi.mock("@/lib/safe-action", () => ({ - adminAction: (opts: { permission?: string | readonly string[]; schema?: z.ZodType }, handler: (ctx: any) => unknown) => { + adminAction: ( + opts: { permission?: string | readonly string[]; schema?: z.ZodType }, + handler: (ctx: any) => unknown, + ) => { return async (input: unknown) => { const needed = Array.isArray(opts.permission) ? opts.permission @@ -140,12 +143,14 @@ describe("createTemplate", () => { }); it("rejects empty titles and content", async () => { - expect( - await createTemplate({ title: "", content: "x" }), - ).toMatchObject({ ok: false, error: "Validation failed" }); - expect( - await createTemplate({ title: "T", content: "" }), - ).toMatchObject({ ok: false, error: "Validation failed" }); + expect(await createTemplate({ title: "", content: "x" })).toMatchObject({ + ok: false, + error: "Validation failed", + }); + expect(await createTemplate({ title: "T", content: "" })).toMatchObject({ + ok: false, + error: "Validation failed", + }); }); it("requires the tickets edit permission", async () => { @@ -203,4 +208,4 @@ describe("deleteTemplate", () => { error: "Unauthorized", }); }); -}); \ No newline at end of file +}); diff --git a/src/actions/tickets.test.ts b/src/actions/tickets.test.ts index 4c1a8b58..647ce4a5 100644 --- a/src/actions/tickets.test.ts +++ b/src/actions/tickets.test.ts @@ -13,7 +13,12 @@ const actionErrorClass = vi.hoisted( const state = vi.hoisted(() => ({ allowed: [] as string[], - tickets: [] as { id: number; assigneeId: number | null; status: string; priority: string }[], + tickets: [] as { + id: number; + assigneeId: number | null; + status: string; + priority: string; + }[], insertCall: undefined as unknown, updateCall: undefined as unknown, rowsForSelect: [] as unknown[], @@ -21,7 +26,10 @@ const state = vi.hoisted(() => ({ })); vi.mock("@/lib/safe-action", () => ({ - adminAction: (opts: { permission?: string | readonly string[]; schema?: z.ZodType }, handler: (ctx: any) => unknown) => { + adminAction: ( + opts: { permission?: string | readonly string[]; schema?: z.ZodType }, + handler: (ctx: any) => unknown, + ) => { return async (input: unknown) => { const needed = Array.isArray(opts.permission) ? opts.permission @@ -63,7 +71,10 @@ vi.mock("@/lib/safe-action-shared", () => ({ })); vi.mock("@/lib/permissions", () => ({ - PERMS: { TICKETS_EDIT: "admin.tickets.edit", MOD_TICKETS_EDIT: "mod.tickets.edit" }, + PERMS: { + TICKETS_EDIT: "admin.tickets.edit", + MOD_TICKETS_EDIT: "mod.tickets.edit", + }, })); vi.mock("@/lib/services/audit", () => ({ logAudit: vi.fn() })); @@ -135,8 +146,13 @@ describe("adminReplyTicket", () => { }); it("inserts a staff message and auto-assigns an unassigned ticket", async () => { - state.tickets = [{ id: 1, assigneeId: null, status: "open", priority: "low" }]; - const res = await adminReplyTicket({ ticketId: 1, message: "Working on it" }); + state.tickets = [ + { id: 1, assigneeId: null, status: "open", priority: "low" }, + ]; + const res = await adminReplyTicket({ + ticketId: 1, + message: "Working on it", + }); expect(res).toEqual({ ok: true, data: {} }); expect(state.insertCall.values).toMatchObject({ ticketId: 1, @@ -154,7 +170,9 @@ describe("adminReplyTicket", () => { }); it("does not clobber an existing assignee", async () => { - state.tickets = [{ id: 2, assigneeId: 55, status: "open", priority: "low" }]; + state.tickets = [ + { id: 2, assigneeId: 55, status: "open", priority: "low" }, + ]; await adminReplyTicket({ ticketId: 2, message: "Already owned" }); expect(state.updateCall.values).toMatchObject({ status: "waiting" }); expect(state.updateCall.values.assigneeId).toBeUndefined(); @@ -163,7 +181,9 @@ describe("adminReplyTicket", () => { describe("updateTicketStatus", () => { it("sets closedAt when closing a ticket", async () => { - state.tickets = [{ id: 3, assigneeId: 55, status: "waiting", priority: "low" }]; + state.tickets = [ + { id: 3, assigneeId: 55, status: "waiting", priority: "low" }, + ]; const res = await updateTicketStatus({ ticketId: 3, status: "closed" }); expect(res).toEqual({ ok: true, data: {} }); expect(state.updateCall.values).toMatchObject({ status: "closed" }); @@ -178,7 +198,9 @@ describe("updateTicketStatus", () => { }); it("auto-assigns when moving an unowned ticket to in_progress", async () => { - state.tickets = [{ id: 4, assigneeId: null, status: "open", priority: "low" }]; + state.tickets = [ + { id: 4, assigneeId: null, status: "open", priority: "low" }, + ]; await updateTicketStatus({ ticketId: 4, status: "in_progress" }); expect(state.updateCall.values).toMatchObject({ status: "in_progress", @@ -203,7 +225,9 @@ describe("updateTicketStatus", () => { describe("assignTicket", () => { it("marks an assigned ticket in_progress", async () => { - state.tickets = [{ id: 6, assigneeId: null, status: "open", priority: "low" }]; + state.tickets = [ + { id: 6, assigneeId: null, status: "open", priority: "low" }, + ]; const res = await assignTicket({ ticketId: 6, assigneeId: 42 }); expect(res).toEqual({ ok: true, data: {} }); expect(state.updateCall.values).toMatchObject({ @@ -220,7 +244,9 @@ describe("assignTicket", () => { }); it("returns the ticket to open when unassigning", async () => { - state.tickets = [{ id: 7, assigneeId: 42, status: "in_progress", priority: "low" }]; + state.tickets = [ + { id: 7, assigneeId: 42, status: "in_progress", priority: "low" }, + ]; await assignTicket({ ticketId: 7, assigneeId: null }); expect(state.updateCall.values).toMatchObject({ assigneeId: null, @@ -254,14 +280,19 @@ describe("updateTicketPriority", () => { it("throws when the ticket does not exist", async () => { state.tickets = []; - expect(await updateTicketPriority({ ticketId: 1, priority: "high" })).toEqual({ + expect( + await updateTicketPriority({ ticketId: 1, priority: "high" }), + ).toEqual({ ok: false, error: "Ticket not found", }); }); it("rejects an unknown priority value", async () => { - const res = await updateTicketPriority({ ticketId: 1, priority: "max" as never }); + const res = await updateTicketPriority({ + ticketId: 1, + priority: "max" as never, + }); expect(res).toMatchObject({ ok: false, error: "Validation failed" }); }); -}); \ No newline at end of file +}); diff --git a/src/actions/translations.test.ts b/src/actions/translations.test.ts index adf0c772..9a875ae6 100644 --- a/src/actions/translations.test.ts +++ b/src/actions/translations.test.ts @@ -3,9 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; const state = vi.hoisted(() => ({ allowed: [] as string[], saveCmsTranslation: vi.fn(), - translationError: vi.fn< - (code: string, args?: { key?: string }) => string - >(), + translationError: vi.fn<(code: string, args?: { key?: string }) => string>(), patchJson5: vi.fn(), readFile: vi.fn(), writeFile: vi.fn(), @@ -81,7 +79,11 @@ vi.mock("node:fs/promises", () => ({ readFile: state.readFile, writeFile: state.writeFile, mkdir: vi.fn(), - default: { readFile: state.readFile, writeFile: state.writeFile, mkdir: vi.fn() }, + default: { + readFile: state.readFile, + writeFile: state.writeFile, + mkdir: vi.fn(), + }, })); vi.mock("@/lib/cms-translations", () => ({ @@ -97,10 +99,13 @@ const mockGetClientTranslationFile = vi.hoisted(() => vi.fn()); vi.mock("@/lib/client-translation-files", async (importOriginal) => { const original = await importOriginal(); - return { ...original, getClientTranslationFile: mockGetClientTranslationFile }; + return { + ...original, + getClientTranslationFile: mockGetClientTranslationFile, + }; }); -import { CLIENT_TRANSLATION_FILES, getClientTranslationFile } from "@/lib/client-translation-files"; +import { CLIENT_TRANSLATION_FILES } from "@/lib/client-translation-files"; import { saveClientTranslations, saveTranslations } from "./translations"; const snapshot = { messages: { "a.b": "x" }, revision: "ab".repeat(32) }; @@ -173,7 +178,11 @@ describe("saveTranslations", () => { it("rejects an unsupported locale and a malformed revision", async () => { expect( - await saveTranslations({ locale: "xx" as never, revision: "a".repeat(64), changes: {} }), + await saveTranslations({ + locale: "xx" as never, + revision: "a".repeat(64), + changes: {}, + }), ).toMatchObject({ ok: false, error: "Validation failed" }); expect( await saveTranslations({ locale: "en", revision: "short", changes: {} }), @@ -183,7 +192,11 @@ describe("saveTranslations", () => { it("requires the settings edit permission", async () => { state.allowed = []; expect( - await saveTranslations({ locale: "en", revision: "a".repeat(64), changes: {} }), + await saveTranslations({ + locale: "en", + revision: "a".repeat(64), + changes: {}, + }), ).toEqual({ ok: false, error: "Unauthorized" }); }); }); @@ -191,12 +204,18 @@ describe("saveTranslations", () => { describe("saveClientTranslations", () => { it("reports an unknown file id", async () => { mockGetClientTranslationFile.mockReturnValueOnce(undefined); - const res = await saveClientTranslations({ fileId: "badge-texts-en", data: {} }); + const res = await saveClientTranslations({ + fileId: "badge-texts-en", + data: {}, + }); expect(res).toEqual({ ok: false, error: "Unknown file" }); }); it("refuses to write read-only files", async () => { - const res = await saveClientTranslations({ fileId: "ui-texts-en", data: {} }); + const res = await saveClientTranslations({ + fileId: "ui-texts-en", + data: {}, + }); expect(res).toEqual({ ok: false, error: "File is read-only" }); expect(state.writeFile).not.toHaveBeenCalled(); }); @@ -207,7 +226,10 @@ describe("saveClientTranslations", () => { fileId: "badge-texts-en", data: { x: "y" }, }); - expect(res).toEqual({ ok: true, data: { commentsLost: false, unpatchedKeys: [] } }); + expect(res).toEqual({ + ok: true, + data: { commentsLost: false, unpatchedKeys: [] }, + }); expect(state.writeFile).toHaveBeenCalledWith( expect.stringContaining("badge-texts-en.json"), JSON.stringify({ x: "y" }, null, 4), @@ -217,12 +239,18 @@ describe("saveClientTranslations", () => { it("writes a surgical JSON5 patch when every key is patchable", async () => { state.readFile.mockResolvedValue('{"greeting": "hi",}'); - state.patchJson5.mockReturnValue({ content: '{"greeting": "ciao",}', unpatchedKeys: [] }); + state.patchJson5.mockReturnValue({ + content: '{"greeting": "ciao",}', + unpatchedKeys: [], + }); const res = await saveClientTranslations({ fileId: "ui-texts-it", data: { greeting: "ciao" }, }); - expect(res).toEqual({ ok: true, data: { commentsLost: false, unpatchedKeys: [] } }); + expect(res).toEqual({ + ok: true, + data: { commentsLost: false, unpatchedKeys: [] }, + }); expect(state.patchJson5).toHaveBeenCalledWith( '{"greeting": "hi",}', { greeting: "hi" }, @@ -237,7 +265,10 @@ describe("saveClientTranslations", () => { it("falls back to re-serialization and flags comment loss for unpatched keys", async () => { state.readFile.mockResolvedValue('{"known": "old",}'); - state.patchJson5.mockReturnValue({ content: '{"known": "old",}', unpatchedKeys: ["brand-new"] }); + state.patchJson5.mockReturnValue({ + content: '{"known": "old",}', + unpatchedKeys: ["brand-new"], + }); const res = await saveClientTranslations({ fileId: "ui-texts-it", data: { known: "new", "brand-new": "val" }, @@ -260,18 +291,27 @@ describe("saveClientTranslations", () => { fileId: "external-texts", data: { x: "1" }, }); - expect(res).toEqual({ ok: true, data: { commentsLost: true, unpatchedKeys: ["x"] } }); + expect(res).toEqual({ + ok: true, + data: { commentsLost: true, unpatchedKeys: ["x"] }, + }); expect(state.patchJson5).toHaveBeenCalledWith("[1,2,3]", {}, { x: "1" }); }); it("validates fileId against the whitelist", async () => { - const res = await saveClientTranslations({ fileId: "hack" as never, data: {} }); + const res = await saveClientTranslations({ + fileId: "hack" as never, + data: {}, + }); expect(res).toMatchObject({ ok: false, error: "Validation failed" }); }); it("requires the settings edit permission", async () => { state.allowed = []; - const res = await saveClientTranslations({ fileId: "ui-texts-it", data: {} }); + const res = await saveClientTranslations({ + fileId: "ui-texts-it", + data: {}, + }); expect(res).toEqual({ ok: false, error: "Unauthorized" }); }); @@ -281,4 +321,4 @@ describe("saveClientTranslations", () => { saveClientTranslations({ fileId: "ui-texts-it", data: {} }), ).rejects.toThrow("EACCES"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/user-settings.test.ts b/src/actions/user-settings.test.ts index 8b400dac..b0416194 100644 --- a/src/actions/user-settings.test.ts +++ b/src/actions/user-settings.test.ts @@ -86,7 +86,9 @@ import { DatabaseError } from "@/lib/foundation/errors"; import { updateMotto, updateMottoAction } from "./user-settings"; const mockingForm = (motto: string): FormData => - ({ get: (key: string) => (key === "motto" ? motto : null) }) as unknown as FormData; + ({ + get: (key: string) => (key === "motto" ? motto : null), + }) as unknown as FormData; beforeEach(() => { vi.clearAllMocks(); @@ -99,9 +101,7 @@ beforeEach(() => { describe("updateMotto", () => { it("persists the motto, syncs RCON and revalidates /settings", async () => { - await updateMotto( - mockingForm(" hello world "), - ); + await updateMotto(mockingForm(" hello world ")); expect(state.updateCall.values).toEqual({ motto: " hello world " }); expect(state.rconSetMotto).toHaveBeenCalledWith(42, " hello world "); expect(mockRevalidatePath).toHaveBeenCalledWith("/settings"); @@ -126,9 +126,9 @@ describe("updateMotto", () => { await expect(updateMotto(mockingForm("boom"))).rejects.toThrow( databaseErrorClass, ); - await expect( - updateMotto(mockingForm("boom")), - ).rejects.toThrow("Failed to update motto"); + await expect(updateMotto(mockingForm("boom"))).rejects.toThrow( + "Failed to update motto", + ); }); it("does not sync RCON when the DB update fails", async () => { @@ -177,4 +177,4 @@ describe("DatabaseError propagation", () => { expect(err).toBeInstanceOf(DatabaseError); expect(err.name).toBe("DatabaseError"); }); -}); \ No newline at end of file +}); diff --git a/src/actions/watch.test.ts b/src/actions/watch.test.ts index 35cfd42a..8fdb61cb 100644 --- a/src/actions/watch.test.ts +++ b/src/actions/watch.test.ts @@ -3,7 +3,12 @@ import { z } from "zod"; const state = vi.hoisted(() => ({ allowed: [] as string[], - watches: [] as { id: number; staffId: number; targetUserId: number; reason: string }[], + watches: [] as { + id: number; + staffId: number; + targetUserId: number; + reason: string; + }[], insertCall: undefined as unknown, deleteCall: undefined as unknown, })); @@ -19,7 +24,10 @@ const actionErrorClass = vi.hoisted( ); vi.mock("@/lib/safe-action", () => ({ - adminAction: (opts: { permission?: string | readonly string[]; schema?: z.ZodType }, handler: (ctx: any) => unknown) => { + adminAction: ( + opts: { permission?: string | readonly string[]; schema?: z.ZodType }, + handler: (ctx: any) => unknown, + ) => { return async (input: unknown) => { const needed = Array.isArray(opts.permission) ? opts.permission @@ -73,9 +81,11 @@ vi.mock("@/lib/db", async () => { return []; }); db.insert = vi.fn((table) => ({ - values: ( - values: { staffId: number; targetUserId: number; reason: string }, - ) => { + values: (values: { + staffId: number; + targetUserId: number; + reason: string; + }) => { state.insertCall = { table, values }; return Promise.resolve([{ insertId: 1n }]); }, @@ -101,14 +111,19 @@ beforeEach(() => { describe("toggleUserWatch", () => { it("creates a watch when none exists and returns watching: true", async () => { - const res = await toggleUserWatch({ targetUserId: 42, reason: "suspicious" }); + const res = await toggleUserWatch({ + targetUserId: 42, + reason: "suspicious", + }); expect(res).toEqual({ ok: true, data: { watching: true } }); expect(state.insertCall.values).toEqual({ staffId: 100, targetUserId: 42, reason: "suspicious", }); - expect(mockRevalidateTag).toHaveBeenCalledWith("user-watch:100", { expire: 0 }); + expect(mockRevalidateTag).toHaveBeenCalledWith("user-watch:100", { + expire: 0, + }); }); it("defaults the reason to an empty string", async () => { @@ -125,7 +140,9 @@ describe("toggleUserWatch", () => { const res = await toggleUserWatch({ targetUserId: 42 }); expect(res).toEqual({ ok: true, data: { watching: false } }); expect(state.deleteCall.condition).toBeDefined(); - expect(mockRevalidateTag).toHaveBeenCalledWith("user-watch:100", { expire: 0 }); + expect(mockRevalidateTag).toHaveBeenCalledWith("user-watch:100", { + expire: 0, + }); }); it("requires the users view permission", async () => { @@ -137,14 +154,16 @@ describe("toggleUserWatch", () => { }); it("rejects invalid target user ids and oversized reasons", async () => { - expect( - await toggleUserWatch({ targetUserId: -1 }), - ).toMatchObject({ ok: false, error: "Validation failed" }); - expect( - await toggleUserWatch({ targetUserId: 0 }), - ).toMatchObject({ ok: false, error: "Validation failed" }); + expect(await toggleUserWatch({ targetUserId: -1 })).toMatchObject({ + ok: false, + error: "Validation failed", + }); + expect(await toggleUserWatch({ targetUserId: 0 })).toMatchObject({ + ok: false, + error: "Validation failed", + }); expect( await toggleUserWatch({ targetUserId: 1, reason: "x".repeat(256) }), ).toMatchObject({ ok: false, error: "Validation failed" }); }); -}); \ No newline at end of file +}); diff --git a/src/db/catalog-packages.test.ts b/src/db/catalog-packages.test.ts index daf0dbd4..736f38f1 100644 --- a/src/db/catalog-packages.test.ts +++ b/src/db/catalog-packages.test.ts @@ -14,7 +14,11 @@ describe("CatalogPackages table schema", () => { }); it("defines a uuid primary key", () => { - expect(columns.id).toMatchObject({ name: "id", primary: true, notNull: true }); + expect(columns.id).toMatchObject({ + name: "id", + primary: true, + notNull: true, + }); }); it("defines the package metadata columns as NOT NULL", () => { @@ -33,4 +37,4 @@ describe("CatalogPackages table schema", () => { expect(columns.updatedAt.name).toBe("updated_at"); expect(columns.updatedAt.notNull).toBe(true); }); -}); \ No newline at end of file +}); diff --git a/src/db/schema-gamedata.test.ts b/src/db/schema-gamedata.test.ts index 65a12f8a..3dac5cb5 100644 --- a/src/db/schema-gamedata.test.ts +++ b/src/db/schema-gamedata.test.ts @@ -1,5 +1,5 @@ -import { describe, expect, it } from "vitest"; import type { MySqlIndex } from "drizzle-orm/mysql-core"; +import { describe, expect, it } from "vitest"; import { GamedataDocs, GamedataFurnidata, @@ -94,4 +94,4 @@ describe("gamedata schema tables", () => { const docsCols = columnsOf(GamedataDocs); expect(docsCols.payloadSha1.hasDefault).toBe(true); }); -}); \ No newline at end of file +}); diff --git a/src/lib/services/translation-pool.test.ts b/src/lib/services/translation-pool.test.ts index fe98f088..ea552e65 100644 --- a/src/lib/services/translation-pool.test.ts +++ b/src/lib/services/translation-pool.test.ts @@ -10,7 +10,8 @@ vi.mock("node:worker_threads", () => { class FakeWorker { private handlers: Record = {}; on(event: string, handler: Handler) { - (this.handlers[event] ??= []).push(handler); + if (!this.handlers[event]) this.handlers[event] = []; + this.handlers[event].push(handler); return this; } emit(event: string, ...args: unknown[]) { diff --git a/src/lib/theme-resolver.test.ts b/src/lib/theme-resolver.test.ts index 4c6e77f6..889f1125 100644 --- a/src/lib/theme-resolver.test.ts +++ b/src/lib/theme-resolver.test.ts @@ -24,6 +24,7 @@ vi.mock("@/lib/db", async () => { query.where = self; query.orderBy = self; query.limit = self; + // biome-ignore lint/suspicious/noThenProperty: intentional thenable for await support query.then = ( resolve: (value: unknown) => unknown, reject: (error: unknown) => unknown, @@ -45,11 +46,11 @@ import { } from "@/lib/theme-blocks"; import { THEME_COLOR_KEYS } from "@/lib/theme-presets"; import { - type ResolvedTheme, generateScopedCss, getAllScopes, getFullScopeValues, getScopeValues, + type ResolvedTheme, resolveTheme, } from "./theme-resolver"; @@ -155,9 +156,7 @@ describe("resolveTheme", () => { }); it("matches module scopes", async () => { - state.scopes = [ - scope({ id: 1, type: "module", moduleId: "catalog" }), - ]; + state.scopes = [scope({ id: 1, type: "module", moduleId: "catalog" })]; state.values = [value(1, "color_primary", "#module")]; const resolved = await resolveTheme({ moduleId: "catalog" }); expect(resolved.palette.color_primary).toBe("#module"); @@ -212,7 +211,9 @@ describe("generateScopedCss", () => { }, }), ); - expect(rootCss).toContain('--theme-logo-url:url("http://logo/\\"quoted\\"")'); + expect(rootCss).toContain( + '--theme-logo-url:url("http://logo/\\"quoted\\"")', + ); expect(scopedCssBlocks).toHaveLength(3); expect(scopedCssBlocks[0]).toMatch(/^\[data-theme-site="hotel\.test"\]\{/); expect(scopedCssBlocks[0]).toContain("--color-primary:#111111;"); @@ -224,9 +225,7 @@ describe("generateScopedCss", () => { describe("admin helpers", () => { it("getAllScopes normalises bigint ids", async () => { - state.scopes = [ - scope({ id: 7n, parentId: 3n, type: "site" }), - ]; + state.scopes = [scope({ id: 7n, parentId: 3n, type: "site" })]; const rows = await getAllScopes(); expect(rows[0]?.id).toBe(7); expect(rows[0]?.parentId).toBe(3); diff --git a/src/test/fake-db-actions.ts b/src/test/fake-db-actions.ts index 97ba32f9..484eb5ee 100644 --- a/src/test/fake-db-actions.ts +++ b/src/test/fake-db-actions.ts @@ -68,8 +68,11 @@ export function createFakeActionDb(config: FakeActionDbConfig) { config.ops.push(op); const execute = () => run("insert", op); return { - then: (onFulfilled: (value: unknown) => unknown, onRejected: (error: unknown) => unknown) => - execute().then(onFulfilled, onRejected), + // biome-ignore lint/suspicious/noThenProperty: intentional thenable for await support + then: ( + onFulfilled: (value: unknown) => unknown, + onRejected: (error: unknown) => unknown, + ) => execute().then(onFulfilled, onRejected), catch: (onRejected: (error: unknown) => unknown) => execute().catch(onRejected), onDuplicateKeyUpdate: (dup: { set: Record }) => { @@ -115,8 +118,11 @@ export function createFakeActionDb(config: FakeActionDbConfig) { query[method] = self; } const selectOp = (): FakeDbOp => ({ kind: "select", table, projection }); - query.then = (onFulfilled: (value: unknown) => unknown, onRejected: (error: unknown) => unknown) => - run("select", selectOp()).then(onFulfilled, onRejected); + // biome-ignore lint/suspicious/noThenProperty: intentional thenable for await support + query.then = ( + onFulfilled: (value: unknown) => unknown, + onRejected: (error: unknown) => unknown, + ) => run("select", selectOp()).then(onFulfilled, onRejected); query.catch = (onRejected: (error: unknown) => unknown) => run("select", selectOp()).catch(onRejected); return query; @@ -147,4 +153,4 @@ export function updateOps(dbOps: FakeDbOp[]): FakeDbOp[] { export function deleteOps(dbOps: FakeDbOp[]): FakeDbOp[] { return dbOps.filter((op) => op.kind === "delete"); -} \ No newline at end of file +} diff --git a/src/test/fake-db.ts b/src/test/fake-db.ts index 54d7190b..835c0831 100644 --- a/src/test/fake-db.ts +++ b/src/test/fake-db.ts @@ -44,10 +44,12 @@ function makeQuery( ]) { query[method] = self; } + // biome-ignore lint/suspicious/noThenProperty: intentional thenable for await support query.then = ( onFulfilled: (value: unknown) => unknown, onRejected: (error: unknown) => unknown, - ) => Promise.resolve(resolve(table, projection)).then(onFulfilled, onRejected); + ) => + Promise.resolve(resolve(table, projection)).then(onFulfilled, onRejected); query.catch = (onRejected: (error: unknown) => unknown) => Promise.resolve(resolve(table, projection)).catch(onRejected); return query;