diff --git a/packages/app/e2e/seed.ts b/packages/app/e2e/seed.ts index 79b3c2a..d606741 100644 --- a/packages/app/e2e/seed.ts +++ b/packages/app/e2e/seed.ts @@ -67,9 +67,18 @@ const MEMBER_DID = "did:plc:e2e-test-member"; [SPHERE_ID], ); + // IDs must be valid TID strings (tidToDate derives createdAt from them) + const FR_001 = "3mhyagkx2ok2m"; + const FR_002 = "3mhyagkx2ol2m"; + const FR_003 = "3mhyagkx2om2m"; + const FR_004 = "3mhyagkx2on2m"; + const FR_005 = "3mhyagkx2oo2m"; + const COMMENT_001 = "3mhyagkx2op2m"; + const COMMENT_002 = "3mhyagkx2oq2m"; + const featureRequests = [ { - id: "fr-001", + id: FR_001, number: 1, title: "Add dark mode support", description: "It would be great to have a dark mode option for better readability at night.", @@ -78,7 +87,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; authorDid: MEMBER_DID, }, { - id: "fr-002", + id: FR_002, number: 2, title: "Export data as CSV", description: "Allow users to export their data in CSV format for analysis.", @@ -87,7 +96,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; authorDid: OWNER_DID, }, { - id: "fr-003", + id: FR_003, number: 3, title: "Mobile app", description: "A native mobile application would improve the user experience significantly.", @@ -96,7 +105,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; authorDid: MEMBER_DID, }, { - id: "fr-004", + id: FR_004, number: 4, title: "Keyboard shortcuts", description: "Add keyboard shortcuts for common actions like voting and navigation.", @@ -105,7 +114,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; authorDid: OWNER_DID, }, { - id: "fr-005", + id: FR_005, number: 5, title: "Windows phone support", description: "Please add support for Windows Phone platform.", @@ -124,25 +133,25 @@ const MEMBER_DID = "did:plc:e2e-test-member"; } db.run(`INSERT INTO feature_request_votes (request_id, author_did) VALUES (?, ?)`, [ - "fr-001", + FR_001, OWNER_DID, ]); db.run(`INSERT INTO feature_request_votes (request_id, author_did) VALUES (?, ?)`, [ - "fr-001", + FR_001, MEMBER_DID, ]); db.run(`INSERT INTO feature_request_votes (request_id, author_did) VALUES (?, ?)`, [ - "fr-002", + FR_002, MEMBER_DID, ]); db.run( `INSERT INTO feature_request_comments (id, request_id, author_did, content) VALUES (?, ?, ?, ?)`, - ["comment-001", "fr-001", OWNER_DID, "Great idea! We should prioritize this."], + [COMMENT_001, FR_001, OWNER_DID, "Great idea! We should prioritize this."], ); db.run( `INSERT INTO feature_request_comments (id, request_id, author_did, content) VALUES (?, ?, ?, ?)`, - ["comment-002", "fr-001", MEMBER_DID, "I agree, dark mode would be very useful."], + [COMMENT_002, FR_001, MEMBER_DID, "I agree, dark mode would be very useful."], ); db.close(); @@ -170,10 +179,19 @@ const MEMBER_DID = "did:plc:e2e-test-member"; "sphere-alpha", ]); + // IDs must be valid TID strings (tidToDate derives createdAt from them) + const ALPHA_FR_001 = "3mhyagkx2or2m"; + const ALPHA_FR_002 = "3mhyagkx2os2m"; + const ALPHA_FR_003 = "3mhyagkx2ot2m"; + const ALPHA_FR_004 = "3mhyagkx2ou2m"; + const ALPHA_COMMENT_001 = "3mhyagkx2ov2m"; + const BETA_FR_001 = "3mhyagkx2ow2m"; + const BETA_FR_002 = "3mhyagkx2ox2m"; + // Alpha feature requests (#1-#4 — per-sphere numbering, covers all status tabs) const alphaRequests = [ { - id: "alpha-fr-001", + id: ALPHA_FR_001, number: 1, title: "Alpha dark mode", description: "Dark mode for Alpha sphere.", @@ -182,7 +200,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; authorDid: OWNER_DID, }, { - id: "alpha-fr-002", + id: ALPHA_FR_002, number: 2, title: "Alpha CSV export", description: "CSV export for Alpha sphere.", @@ -191,7 +209,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; authorDid: MEMBER_DID, }, { - id: "alpha-fr-003", + id: ALPHA_FR_003, number: 3, title: "Alpha done feature", description: "A completed feature.", @@ -200,7 +218,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; authorDid: OWNER_DID, }, { - id: "alpha-fr-004", + id: ALPHA_FR_004, number: 4, title: "Alpha rejected idea", description: "A rejected feature.", @@ -228,17 +246,17 @@ const MEMBER_DID = "did:plc:e2e-test-member"; } db.run(`INSERT INTO feature_request_votes (request_id, author_did) VALUES (?, ?)`, [ - "alpha-fr-001", + ALPHA_FR_001, OWNER_DID, ]); db.run(`INSERT INTO feature_request_votes (request_id, author_did) VALUES (?, ?)`, [ - "alpha-fr-001", + ALPHA_FR_001, MEMBER_DID, ]); db.run( `INSERT INTO feature_request_comments (id, request_id, author_did, content) VALUES (?, ?, ?, ?)`, - ["alpha-comment-001", "alpha-fr-001", OWNER_DID, "Alpha sphere comment on dark mode."], + [ALPHA_COMMENT_001, ALPHA_FR_001, OWNER_DID, "Alpha sphere comment on dark mode."], ); // ---- Sphere B: beta.test ---- @@ -259,7 +277,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; // Beta feature requests (#1-#2 — independent numbering from Alpha) const betaRequests = [ { - id: "beta-fr-001", + id: BETA_FR_001, number: 1, title: "Beta mobile app", description: "Mobile app for Beta sphere.", @@ -268,7 +286,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; authorDid: MEMBER_DID, }, { - id: "beta-fr-002", + id: BETA_FR_002, number: 2, title: "Beta API access", description: "Public API for Beta sphere.", @@ -296,7 +314,7 @@ const MEMBER_DID = "did:plc:e2e-test-member"; } db.run(`INSERT INTO feature_request_votes (request_id, author_did) VALUES (?, ?)`, [ - "beta-fr-001", + BETA_FR_001, MEMBER_DID, ]); diff --git a/packages/core/src/__tests__/sphere-operations.test.ts b/packages/core/src/__tests__/sphere-operations.test.ts index 363df5a..ad0e40b 100644 --- a/packages/core/src/__tests__/sphere-operations.test.ts +++ b/packages/core/src/__tests__/sphere-operations.test.ts @@ -80,7 +80,7 @@ describe("findSphereByAtUri", () => { // ---- upsertSphereFromRecord ---- describe("upsertSphereFromRecord", () => { - it("creates a new sphere and owner membership", () => { + it("ignores record when no local sphere exists for the DID", () => { upsertSphereFromRecord({ did: OWNER_DID, rkey: SPHERE_ID, @@ -92,20 +92,9 @@ describe("upsertSphereFromRecord", () => { pdsUri: "at://did:plc:owner1/com.exosphere.sphere/sphere-1", }); + // Spheres are created locally, not via Jetstream — upsert is a no-op const sphere = db.select().from(spheres).where(eq(spheres.id, SPHERE_ID)).get(); - expect(sphere).toBeDefined(); - expect(sphere!.handle).toBe(SPHERE_HANDLE); - expect(sphere!.name).toBe("My Sphere"); - expect(sphere!.ownerDid).toBe(OWNER_DID); - - const member = db - .select() - .from(sphereMembers) - .where(and(eq(sphereMembers.sphereId, SPHERE_ID), eq(sphereMembers.did, OWNER_DID))) - .get(); - expect(member).toBeDefined(); - expect(member!.role).toBe("owner"); - expect(member!.status).toBe("active"); + expect(sphere).toBeUndefined(); }); it("updates an existing sphere owned by the same DID", () => { diff --git a/packages/feature-requests/src/__tests__/db-operations.test.ts b/packages/feature-requests/src/__tests__/db-operations.test.ts index 74039f5..93461b1 100644 --- a/packages/feature-requests/src/__tests__/db-operations.test.ts +++ b/packages/feature-requests/src/__tests__/db-operations.test.ts @@ -40,6 +40,8 @@ import { const AUTHOR_DID = "did:plc:author1"; const MOD_DID = "did:plc:mod1"; const SPHERE_ID = "test-sphere-001"; +// Valid TID string for comment IDs (insertComment derives updatedAt via tidToDate) +const COMMENT_TID_1 = "3mhy7w6tbg22b"; function seedFR(overrides: Partial & { id: string }) { const values = { @@ -175,7 +177,7 @@ describe("insertComment / updateComment / deleteCommentCascade", () => { it("inserts a comment", () => { seedFR({ id: "fr-1" }); insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Great idea!", @@ -190,14 +192,14 @@ describe("insertComment / updateComment / deleteCommentCascade", () => { it("upserts on conflict (same id updates content)", () => { seedFR({ id: "fr-1" }); insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Original", pdsUri: null, }); insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Updated via upsert", @@ -207,7 +209,7 @@ describe("insertComment / updateComment / deleteCommentCascade", () => { const comment = db .select() .from(featureRequestComments) - .where(eq(featureRequestComments.id, "c-1")) + .where(eq(featureRequestComments.id, COMMENT_TID_1)) .get(); expect(comment!.content).toBe("Updated via upsert"); }); @@ -215,18 +217,18 @@ describe("insertComment / updateComment / deleteCommentCascade", () => { it("updates a comment's content", () => { seedFR({ id: "fr-1" }); insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Original", pdsUri: null, }); - updateComment("c-1", "Edited content"); + updateComment(COMMENT_TID_1, "Edited content"); const comment = db .select() .from(featureRequestComments) - .where(eq(featureRequestComments.id, "c-1")) + .where(eq(featureRequestComments.id, COMMENT_TID_1)) .get(); expect(comment!.content).toBe("Edited content"); }); @@ -234,17 +236,17 @@ describe("insertComment / updateComment / deleteCommentCascade", () => { it("cascade-deletes comment and its votes", () => { seedFR({ id: "fr-1" }); insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Comment", pdsUri: null, }); db.insert(featureRequestCommentVotes) - .values({ commentId: "c-1", authorDid: "did:plc:voter1" }) + .values({ commentId: COMMENT_TID_1, authorDid: "did:plc:voter1" }) .run(); - deleteCommentCascade("c-1"); + deleteCommentCascade(COMMENT_TID_1); expect(db.select().from(featureRequestComments).all()).toHaveLength(0); expect(db.select().from(featureRequestCommentVotes).all()).toHaveLength(0); @@ -257,32 +259,32 @@ describe("insertCommentVote / deleteCommentVoteByAuthor", () => { it("inserts and deletes a comment vote", () => { seedFR({ id: "fr-1" }); insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Comment", pdsUri: null, }); - insertCommentVote("c-1", "did:plc:voter1", null); + insertCommentVote(COMMENT_TID_1, "did:plc:voter1", null); expect(db.select().from(featureRequestCommentVotes).all()).toHaveLength(1); - deleteCommentVoteByAuthor("c-1", "did:plc:voter1"); + deleteCommentVoteByAuthor(COMMENT_TID_1, "did:plc:voter1"); expect(db.select().from(featureRequestCommentVotes).all()).toHaveLength(0); }); it("ignores duplicate comment votes", () => { seedFR({ id: "fr-1" }); insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Comment", pdsUri: null, }); - insertCommentVote("c-1", "did:plc:voter1", null); - insertCommentVote("c-1", "did:plc:voter1", null); + insertCommentVote(COMMENT_TID_1, "did:plc:voter1", null); + insertCommentVote(COMMENT_TID_1, "did:plc:voter1", null); expect(db.select().from(featureRequestCommentVotes).all()).toHaveLength(1); }); }); @@ -379,27 +381,27 @@ describe("hideComment / unhideComment", () => { it("hides and unhides a comment", () => { seedFR({ id: "fr-1" }); insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Comment", pdsUri: null, }); - hideComment("c-1", MOD_DID); + hideComment(COMMENT_TID_1, MOD_DID); let comment = db .select() .from(featureRequestComments) - .where(eq(featureRequestComments.id, "c-1")) + .where(eq(featureRequestComments.id, COMMENT_TID_1)) .get(); expect(comment!.hiddenAt).toBeTruthy(); expect(comment!.moderatedBy).toBe(MOD_DID); - unhideComment("c-1"); + unhideComment(COMMENT_TID_1); comment = db .select() .from(featureRequestComments) - .where(eq(featureRequestComments.id, "c-1")) + .where(eq(featureRequestComments.id, COMMENT_TID_1)) .get(); expect(comment!.hiddenAt).toBeNull(); expect(comment!.moderatedBy).toBeNull(); @@ -420,9 +422,9 @@ describe("handleFeatureRequestModeration", () => { it("hides a comment by pdsUri and returns true", () => { seedFR({ id: "fr-1" }); - const commentPdsUri = "at://did:plc:author1/com.exosphere.featureRequestComment/c-1"; + const commentPdsUri = `at://did:plc:author1/com.exosphere.featureRequestComment/${COMMENT_TID_1}`; insertComment({ - id: "c-1", + id: COMMENT_TID_1, requestId: "fr-1", authorDid: AUTHOR_DID, content: "Comment", @@ -435,7 +437,7 @@ describe("handleFeatureRequestModeration", () => { const comment = db .select() .from(featureRequestComments) - .where(eq(featureRequestComments.id, "c-1")) + .where(eq(featureRequestComments.id, COMMENT_TID_1)) .get(); expect(comment!.hiddenAt).toBeTruthy(); });