@@ -172,9 +174,9 @@ function SectionSkeleton({ count, aspect }: { count: number; aspect: string }) {
- {Array.from({ length: count }).map((_, i) => (
+ {Array.from({ length: count }, (_, i) => `skeleton-${i}`).map((key) => (
{aspect !== "none" && (
diff --git a/src/server/services/discovery.service.ts b/src/server/services/discovery.service.ts
index dd0efe8..ff7fb0b 100644
--- a/src/server/services/discovery.service.ts
+++ b/src/server/services/discovery.service.ts
@@ -1,6 +1,6 @@
import { and, count, desc, eq, isNotNull, lt, sql } from "drizzle-orm";
import { db as prodDb } from "../../db/index.ts";
-import { globalItems, setups, setupItems, users } from "../../db/schema.ts";
+import { globalItems, setupItems, setups, users } from "../../db/schema.ts";
type Db = typeof prodDb;
@@ -44,10 +44,7 @@ export async function getPopularSetups(
.leftJoin(users, eq(users.id, setups.userId))
.where(eq(setups.isPublic, true))
.groupBy(setups.id, setups.name, setups.createdAt, users.displayName)
- .orderBy(
- desc(sql`COUNT(${setupItems.id})`),
- desc(setups.id),
- )
+ .orderBy(desc(sql`COUNT(${setupItems.id})`), desc(setups.id))
.limit(fetchLimit);
// Apply cursor filter in JS (composite cursor: itemCount_id)
diff --git a/tests/routes/discovery.test.ts b/tests/routes/discovery.test.ts
index 8c28d51..8f02b8d 100644
--- a/tests/routes/discovery.test.ts
+++ b/tests/routes/discovery.test.ts
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it } from "bun:test";
import { Hono } from "hono";
-import { globalItems, items, setups, setupItems } from "../../src/db/schema.ts";
+import { globalItems, setups } from "../../src/db/schema.ts";
import { discoveryRoutes } from "../../src/server/routes/discovery.ts";
import { createTestDb } from "../helpers/db.ts";
@@ -45,26 +45,6 @@ async function insertPublicSetup(
return row;
}
-async function insertItem(
- db: TestDb["db"],
- userId: number,
- name: string,
-): Promise {
- const [row] = await db
- .insert(items)
- .values({ name, categoryId: 1, userId })
- .returning();
- return row.id;
-}
-
-async function addItemToSetup(
- db: TestDb["db"],
- setupId: number,
- itemId: number,
-) {
- await db.insert(setupItems).values({ setupId, itemId });
-}
-
describe("Discovery Routes", () => {
let app: Hono;
let db: TestDb["db"];
diff --git a/tests/services/discovery.service.test.ts b/tests/services/discovery.service.test.ts
index 767ce0c..dd632b7 100644
--- a/tests/services/discovery.service.test.ts
+++ b/tests/services/discovery.service.test.ts
@@ -3,8 +3,8 @@ import { eq } from "drizzle-orm";
import {
globalItems,
items,
- setups,
setupItems,
+ setups,
users,
} from "../../src/db/schema.ts";
import {
@@ -31,11 +31,7 @@ async function insertGlobalItem(
return row;
}
-async function insertItem(
- db: TestDb["db"],
- userId: number,
- categoryId = 1,
-) {
+async function insertItem(db: TestDb["db"], userId: number, categoryId = 1) {
const [row] = await db
.insert(items)
.values({ name: "Test Item", categoryId, userId })
@@ -115,7 +111,11 @@ describe("Discovery Service", () => {
const item2 = await insertItem(db, userId);
const item3 = await insertItem(db, userId);
- await insertPublicSetup(db, userId, "Setup A", [item1.id, item2.id, item3.id]);
+ await insertPublicSetup(db, userId, "Setup A", [
+ item1.id,
+ item2.id,
+ item3.id,
+ ]);
await insertPublicSetup(db, userId, "Setup B", [item1.id, item2.id]);
await insertPublicSetup(db, userId, "Setup C", [item1.id]);
@@ -129,7 +129,11 @@ describe("Discovery Service", () => {
const item2 = await insertItem(db, userId);
const item3 = await insertItem(db, userId);
- await insertPublicSetup(db, userId, "Setup A", [item1.id, item2.id, item3.id]);
+ await insertPublicSetup(db, userId, "Setup A", [
+ item1.id,
+ item2.id,
+ item3.id,
+ ]);
await insertPublicSetup(db, userId, "Setup B", [item1.id, item2.id]);
await insertPublicSetup(db, userId, "Setup C", [item1.id]);
@@ -144,7 +148,8 @@ describe("Discovery Service", () => {
it("includes creatorName from users.displayName", async () => {
// Update user display name
- await db.update(users)
+ await db
+ .update(users)
.set({ displayName: "Jean-Luc" })
.where(eq(users.id, userId));
@@ -160,11 +165,20 @@ describe("Discovery Service", () => {
describe("getRecentGlobalItems", () => {
it("returns items ordered by createdAt descending", async () => {
// Insert items with slight delay to get different timestamps
- const item1 = await insertGlobalItem(db, { brand: "BrandA", model: "Model1" });
+ const item1 = await insertGlobalItem(db, {
+ brand: "BrandA",
+ model: "Model1",
+ });
await new Promise((r) => setTimeout(r, 5));
- const item2 = await insertGlobalItem(db, { brand: "BrandB", model: "Model2" });
+ const item2 = await insertGlobalItem(db, {
+ brand: "BrandB",
+ model: "Model2",
+ });
await new Promise((r) => setTimeout(r, 5));
- const item3 = await insertGlobalItem(db, { brand: "BrandC", model: "Model3" });
+ const item3 = await insertGlobalItem(db, {
+ brand: "BrandC",
+ model: "Model3",
+ });
const result = await getRecentGlobalItems(db);
expect(result.items).toHaveLength(3);
@@ -208,12 +222,36 @@ describe("Discovery Service", () => {
describe("getTrendingCategories", () => {
it("returns categories ordered by item count descending", async () => {
// 3 items in Tents, 1 in Bags, 2 in Stoves
- await insertGlobalItem(db, { brand: "BrandA", model: "Tent1", category: "Tents" });
- await insertGlobalItem(db, { brand: "BrandB", model: "Tent2", category: "Tents" });
- await insertGlobalItem(db, { brand: "BrandC", model: "Tent3", category: "Tents" });
- await insertGlobalItem(db, { brand: "BrandD", model: "Bag1", category: "Bags" });
- await insertGlobalItem(db, { brand: "BrandE", model: "Stove1", category: "Stoves" });
- await insertGlobalItem(db, { brand: "BrandF", model: "Stove2", category: "Stoves" });
+ await insertGlobalItem(db, {
+ brand: "BrandA",
+ model: "Tent1",
+ category: "Tents",
+ });
+ await insertGlobalItem(db, {
+ brand: "BrandB",
+ model: "Tent2",
+ category: "Tents",
+ });
+ await insertGlobalItem(db, {
+ brand: "BrandC",
+ model: "Tent3",
+ category: "Tents",
+ });
+ await insertGlobalItem(db, {
+ brand: "BrandD",
+ model: "Bag1",
+ category: "Bags",
+ });
+ await insertGlobalItem(db, {
+ brand: "BrandE",
+ model: "Stove1",
+ category: "Stoves",
+ });
+ await insertGlobalItem(db, {
+ brand: "BrandF",
+ model: "Stove2",
+ category: "Stoves",
+ });
const result = await getTrendingCategories(db);
expect(result).toHaveLength(3);
@@ -226,7 +264,11 @@ describe("Discovery Service", () => {
});
it("excludes items with null category", async () => {
- await insertGlobalItem(db, { brand: "BrandA", model: "Tent1", category: "Tents" });
+ await insertGlobalItem(db, {
+ brand: "BrandA",
+ model: "Tent1",
+ category: "Tents",
+ });
// No category — should be excluded
await insertGlobalItem(db, { brand: "BrandB", model: "NoCategory" });