From c71ab9031e254b881e08839ad63c76e47398c694 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Tue, 16 Sep 2025 22:03:47 +0530 Subject: [PATCH 1/8] wip --- apps/web/package.json | 2 +- apps/web/tests/partner-groups/index.test.ts | 71 +++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 apps/web/tests/partner-groups/index.test.ts diff --git a/apps/web/package.json b/apps/web/package.json index 4c83893747f..10628534593 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,7 +8,7 @@ "lint": "next lint", "start": "next start", "script": "tsx ./scripts/run.ts", - "test": "pnpm prisma:generate && vitest -no-file-parallelism --bail=1", + "test": "pnpm prisma:generate && vitest -no-file-parallelism --bail=1 tests/partner-groups", "generate-openapi": "tsx ./scripts/generate-openapi.ts", "prisma:generate": "dotenv-flow -e .env -- pnpm --filter=@dub/prisma generate", "prisma:push": "dotenv-flow -e .env -- pnpm --filter=@dub/prisma push", diff --git a/apps/web/tests/partner-groups/index.test.ts b/apps/web/tests/partner-groups/index.test.ts new file mode 100644 index 00000000000..6c0094c23dc --- /dev/null +++ b/apps/web/tests/partner-groups/index.test.ts @@ -0,0 +1,71 @@ +// Add group +// Add 1 default links +// Enroll new partner to the group +// Verify the partner default links has been created correctly + +// Add one more default links +// Verify the new default links has been created correctly + +// Update one of the default links +// Verify the default links has been updated correctly + +// Add another group (more to lesser) +// Add 1 default links +// Move the existing partner to the new group +// Verify that the first default link should be updated to the new link, and the second should no longer be a default. + +// Add a case for lesser to more links + +import { generateRandomName } from "@/lib/names"; +import { GroupProps } from "@/lib/types"; +import { GroupSchema } from "@/lib/zod/schemas/groups"; +import { RESOURCE_COLORS } from "@/ui/colors"; +import { randomValue } from "@dub/utils"; +import slugify from "@sindresorhus/slugify"; +import { describe, expect, test } from "vitest"; +import { IntegrationHarness } from "../utils/integration"; + +const expectedGroup = { + clickReward: null, + leadReward: null, + saleReward: null, + discount: null, + additionalLinks: null, + maxPartnerLinks: 10, + linkStructure: "short", +}; + +describe.sequential("/groups/**", async () => { + const h = new IntegrationHarness(); + const { workspace, http } = await h.init(); + + // Create a new group + test("POST /groups", async () => { + const groupName = generateRandomName(); + + const newGroup = { + name: groupName, + slug: slugify(groupName), + color: randomValue(RESOURCE_COLORS), + }; + + const { status, data } = await http.post({ + path: `/groups?workspaceId=${workspace.id}`, + body: { + name: newGroup.name, + slug: newGroup.slug, + color: newGroup.color, + }, + }); + + expect(status).toEqual(201); + expect(() => GroupSchema.parse(data)).not.toThrow(); + + expect(data).toMatchObject({ + ...expectedGroup, + name: newGroup.name, + slug: newGroup.slug, + color: newGroup.color, + }); + }); +}); From 6e438f114e01ae84a8048fd2e47c12fded81c046 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Sat, 20 Sep 2025 13:07:28 +0530 Subject: [PATCH 2/8] Update index.test.ts --- apps/web/tests/partner-groups/index.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/web/tests/partner-groups/index.test.ts b/apps/web/tests/partner-groups/index.test.ts index 6c0094c23dc..20ee2764cb5 100644 --- a/apps/web/tests/partner-groups/index.test.ts +++ b/apps/web/tests/partner-groups/index.test.ts @@ -1,3 +1,5 @@ +// TODO(kiran): + // Add group // Add 1 default links // Enroll new partner to the group From d5c21346317f20a86d3349d7b10e4f8d32cca474 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Fri, 17 Oct 2025 15:13:49 +0530 Subject: [PATCH 3/8] remove unused types --- apps/web/lib/types.ts | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/apps/web/lib/types.ts b/apps/web/lib/types.ts index de06c2cebc1..27f8c3ecd7b 100644 --- a/apps/web/lib/types.ts +++ b/apps/web/lib/types.ts @@ -74,16 +74,11 @@ import { import { PartnerPayoutResponseSchema, PayoutResponseSchema, - PayoutSchema, } from "./zod/schemas/payouts"; import { programLanderSchema } from "./zod/schemas/program-lander"; import { programDataSchema } from "./zod/schemas/program-onboarding"; import { - PartnerProgramInviteSchema, ProgramEnrollmentSchema, - ProgramInviteSchema, - ProgramMetricsSchema, - ProgramPartnerLinkSchema, ProgramSchema, ProgramWithLanderDataSchema, } from "./zod/schemas/programs"; @@ -423,8 +418,6 @@ export type CustomerProps = z.infer; export type PartnerProps = z.infer; -export type ProgramPartnerLinkProps = z.infer; - export type PartnerProfileCustomerProps = z.infer< typeof PartnerProfileCustomerSchema >; @@ -443,12 +436,6 @@ export type ProgramWithLanderDataProps = z.infer< typeof ProgramWithLanderDataSchema >; -export type ProgramInviteProps = z.infer; - -export type PartnerProgramInviteProps = z.infer< - typeof PartnerProgramInviteSchema ->; - export type ProgramEnrollmentProps = z.infer; export type PartnerProgramEnrollmentProps = z.infer< @@ -461,8 +448,6 @@ export type PayoutsCount = { amount: number; }; -export type PayoutProps = z.infer; - export type PayoutResponse = z.infer; export type PartnerPayoutResponse = z.infer; @@ -506,11 +491,6 @@ export type RewardProps = z.infer; export type CreatePartnerProps = z.infer; export type ProgramData = z.infer; - -export type ProgramMetrics = z.infer; - -export type PayoutMethod = "stripe" | "paypal"; - export type PaymentMethodOption = { currency?: string; mandate_options?: { @@ -518,7 +498,6 @@ export type PaymentMethodOption = { transaction_type?: string; }; }; - export interface FolderLinkCount { folderId: string; _count: number; From 3d6a7f007de960dcbd0cfa46ddd64756bcaef549 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Fri, 31 Oct 2025 09:23:03 +0530 Subject: [PATCH 4/8] Update index.test.ts --- apps/web/tests/partner-groups/index.test.ts | 163 +++++++++++++++----- 1 file changed, 126 insertions(+), 37 deletions(-) diff --git a/apps/web/tests/partner-groups/index.test.ts b/apps/web/tests/partner-groups/index.test.ts index 20ee2764cb5..66f2a723eb9 100644 --- a/apps/web/tests/partner-groups/index.test.ts +++ b/apps/web/tests/partner-groups/index.test.ts @@ -1,25 +1,9 @@ -// TODO(kiran): - -// Add group -// Add 1 default links -// Enroll new partner to the group -// Verify the partner default links has been created correctly - -// Add one more default links -// Verify the new default links has been created correctly - -// Update one of the default links -// Verify the default links has been updated correctly - -// Add another group (more to lesser) -// Add 1 default links -// Move the existing partner to the new group -// Verify that the first default link should be updated to the new link, and the second should no longer be a default. - -// Add a case for lesser to more links - import { generateRandomName } from "@/lib/names"; -import { GroupProps } from "@/lib/types"; +import { + GroupExtendedProps, + GroupProps, + GroupWithProgramProps, +} from "@/lib/types"; import { GroupSchema } from "@/lib/zod/schemas/groups"; import { RESOURCE_COLORS } from "@/ui/colors"; import { randomValue } from "@dub/utils"; @@ -27,22 +11,27 @@ import slugify from "@sindresorhus/slugify"; import { describe, expect, test } from "vitest"; import { IntegrationHarness } from "../utils/integration"; -const expectedGroup = { +const expectedGroup: Partial = { + id: expect.any(String), + name: expect.any(String), + slug: expect.any(String), + color: expect.any(String), clickReward: null, leadReward: null, saleReward: null, discount: null, - additionalLinks: null, maxPartnerLinks: 10, linkStructure: "short", + additionalLinks: expect.any(Array), }; describe.sequential("/groups/**", async () => { const h = new IntegrationHarness(); - const { workspace, http } = await h.init(); + const { http } = await h.init(); + + let group: GroupProps; - // Create a new group - test("POST /groups", async () => { + test("POST /groups - create group", async () => { const groupName = generateRandomName(); const newGroup = { @@ -52,22 +41,122 @@ describe.sequential("/groups/**", async () => { }; const { status, data } = await http.post({ - path: `/groups?workspaceId=${workspace.id}`, - body: { - name: newGroup.name, - slug: newGroup.slug, - color: newGroup.color, - }, + path: "/groups", + body: newGroup, }); expect(status).toEqual(201); expect(() => GroupSchema.parse(data)).not.toThrow(); - - expect(data).toMatchObject({ + expect(data).toStrictEqual({ ...expectedGroup, - name: newGroup.name, - slug: newGroup.slug, - color: newGroup.color, + ...newGroup, + }); + + group = data; + }); + + test("GET /groups/[groupId] - fetch single group", async () => { + const { status, data } = await http.get({ + path: `/groups/${group.id}`, + }); + + const { + applicationFormData, + applicationFormPublishedAt, + landerData, + landerPublishedAt, + program, + ...fetchedGroup + } = data; + + expect(status).toEqual(200); + expect(fetchedGroup).toStrictEqual({ + ...group, + utmTemplate: null, + }); + }); + + test("PATCH /groups/[groupId] - update group", async () => { + const toUpdate = { + name: generateRandomName(), + color: randomValue(RESOURCE_COLORS), + maxPartnerLinks: 5, + linkStructure: "query", + additionalLinks: [ + { + domain: "example.com", + path: "", + validationMode: "domain", + }, + { + domain: "acme.com", + path: "/products", + validationMode: "exact", + }, + ], + }; + + const { status, data: updatedGroup } = await http.patch({ + path: `/groups/${group.id}`, + body: toUpdate, + }); + + expect(status).toEqual(200); + expect(updatedGroup).toStrictEqual({ + ...group, + ...toUpdate, + }); + + group = updatedGroup; + }); + + test("GET /groups - fetch all groups", async () => { + const { status, data: groups } = await http.get({ + path: "/groups", + }); + + expect(status).toEqual(200); + expect(Array.isArray(groups)).toBe(true); + expect(groups.length).toBeGreaterThan(0); + + const fetchedGroup = groups.find((g) => g.id === group.id); + + expect(fetchedGroup).toStrictEqual({ + id: group.id, + name: group.name, + slug: group.slug, + color: group.color, + additionalLinks: group.additionalLinks, + maxPartnerLinks: group.maxPartnerLinks, + linkStructure: group.linkStructure, + totalPartners: 0, + totalClicks: 0, + totalLeads: 0, + totalSales: 0, + totalSaleAmount: 0, + totalConversions: 0, + totalCommissions: 0, + netRevenue: 0, }); }); + + test("DELETE /groups/[groupId] - delete group", async () => { + const { status, data } = await http.delete<{ id: string }>({ + path: `/groups/${group.id}`, + }); + + expect(status).toEqual(200); + expect(data).toStrictEqual({ + id: group.id, + }); + + const { status: getStatus } = await http.get({ + path: `/groups/${group.id}`, + }); + + expect(getStatus).toEqual(404); + }); }); + +// TODO(kiran): +// Add more test cases to test the default link creation and group move From 2e4acee2c3bd33c17bca582814fd7564b9d915a6 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Fri, 31 Oct 2025 09:34:06 +0530 Subject: [PATCH 5/8] Update index.test.ts --- apps/web/tests/partner-groups/index.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/tests/partner-groups/index.test.ts b/apps/web/tests/partner-groups/index.test.ts index 66f2a723eb9..1b6d6a458c7 100644 --- a/apps/web/tests/partner-groups/index.test.ts +++ b/apps/web/tests/partner-groups/index.test.ts @@ -35,7 +35,7 @@ describe.sequential("/groups/**", async () => { const groupName = generateRandomName(); const newGroup = { - name: groupName, + name: `E2E-${groupName}`, slug: slugify(groupName), color: randomValue(RESOURCE_COLORS), }; @@ -78,7 +78,7 @@ describe.sequential("/groups/**", async () => { test("PATCH /groups/[groupId] - update group", async () => { const toUpdate = { - name: generateRandomName(), + name: `E2E-${generateRandomName}`, color: randomValue(RESOURCE_COLORS), maxPartnerLinks: 5, linkStructure: "query", From d4e145143890a42552af6314f8895a42a97f65de Mon Sep 17 00:00:00 2001 From: Kiran K Date: Fri, 31 Oct 2025 15:35:36 +0530 Subject: [PATCH 6/8] Update package.json --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index df8424c1d7f..3782cfc9395 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,7 +8,7 @@ "lint": "next lint", "start": "next start", "script": "tsx ./scripts/run.ts", - "test": "pnpm prisma:generate && vitest -no-file-parallelism --bail=1 tests/partner-groups", + "test": "pnpm prisma:generate && vitest -no-file-parallelism --bail=1", "generate-openapi": "tsx ./scripts/generate-openapi.ts", "prisma:generate": "dotenv-flow -e .env -- pnpm --filter=@dub/prisma generate", "prisma:push": "dotenv-flow -e .env -- pnpm --filter=@dub/prisma push", From da4d4e65ccdef9cf60fa5eda46c590f0a3288647 Mon Sep 17 00:00:00 2001 From: Kiran K Date: Fri, 31 Oct 2025 16:01:24 +0530 Subject: [PATCH 7/8] Update index.test.ts --- apps/web/tests/partner-groups/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/tests/partner-groups/index.test.ts b/apps/web/tests/partner-groups/index.test.ts index 1b6d6a458c7..42c4770621c 100644 --- a/apps/web/tests/partner-groups/index.test.ts +++ b/apps/web/tests/partner-groups/index.test.ts @@ -78,7 +78,7 @@ describe.sequential("/groups/**", async () => { test("PATCH /groups/[groupId] - update group", async () => { const toUpdate = { - name: `E2E-${generateRandomName}`, + name: `E2E-${generateRandomName()}`, color: randomValue(RESOURCE_COLORS), maxPartnerLinks: 5, linkStructure: "query", From 46bb84dcc801607b8b285be7453b6023a633067f Mon Sep 17 00:00:00 2001 From: Kiran K Date: Fri, 31 Oct 2025 17:32:27 +0530 Subject: [PATCH 8/8] Update delete-group-modal.tsx --- apps/web/ui/modals/delete-group-modal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/ui/modals/delete-group-modal.tsx b/apps/web/ui/modals/delete-group-modal.tsx index f86ce304765..253b7c36e4d 100644 --- a/apps/web/ui/modals/delete-group-modal.tsx +++ b/apps/web/ui/modals/delete-group-modal.tsx @@ -98,7 +98,7 @@ const DeleteGroupModal = ({

To verify, type{" "} - Delete group + confirm delete group {" "} below

@@ -113,7 +113,7 @@ const DeleteGroupModal = ({ className="block w-full rounded-md border-neutral-300 text-neutral-900 placeholder-neutral-400 focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm" aria-invalid="true" autoFocus={!isMobile} - pattern="Delete group" + pattern="confirm delete group" />