Skip to content

Conversation

@devkiran
Copy link
Collaborator

@devkiran devkiran commented Dec 2, 2025

Summary by CodeRabbit

  • New Features

    • Added cursor-based pagination (startingAfter/endingBefore) alongside offset-based pagination and query validation.
  • Refactor

    • Centralized pagination logic into a shared helper and updated query schemas to layer cursor pagination with legacy pagination (deprecated).
  • Performance

    • Added/updated composite database indexes to improve pagination and time-range queries.
  • Tests

    • Added comprehensive pagination tests covering offset, cursor flows, mixed methods, error cases, and sort orders.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Contributor

vercel bot commented Dec 2, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
dub Error Error Dec 9, 2025 4:22am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

Walkthrough

This PR centralizes pagination by adding getPaginationOptions (cursor + offset), updates Zod query schemas to expose cursor pagination (marking offset deprecated), refactors API callsites to use the helper, adds composite DB indexes including id as a tiebreaker, and adds comprehensive pagination tests.

Changes

Cohort / File(s) Summary
Pagination utility & types
apps/web/lib/api/pagination.ts
New getPaginationOptions(filters) with cursor and offset support, Filters/PaginationOptions types, validation and errors.
Zod pagination primitives
apps/web/lib/zod/schemas/misc.ts
getPaginationQuerySchema accepts optional pageSize + deprecated flag; new getCursorPaginationQuerySchema exported.
Zod schema integrations
apps/web/lib/zod/schemas/commissions.ts, apps/web/lib/zod/schemas/customers.ts, apps/web/lib/zod/schemas/links.ts
Inserted cursor pagination schema before existing pagination merge; preserved deprecated offset pagination.
API callsites / endpoints
apps/web/app/(ee)/api/customers/route.ts, apps/web/lib/api/commissions/get-commissions.ts, apps/web/lib/api/links/get-links-for-workspace.ts
Replaced manual page/pageSize/sort handling with getPaginationOptions(filters); getLinksForWorkspace signature changed to accept a single filters object.
Database schema / indexes
packages/prisma/schema/commission.prisma, packages/prisma/schema/customer.prisma, packages/prisma/schema/link.prisma
Composite indexes updated to include id as tiebreaker (Commission, Customer, Link).
Tests (pagination)
apps/web/tests/commissions/pagination.test.ts, apps/web/tests/customers/pagination.test.ts, apps/web/tests/links/list-links.test.ts
New comprehensive tests covering offset & cursor pagination, invalid combos/limits, mixed-method precedence, and sort-order assertions.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant API as Web API
  participant Pager as getPaginationOptions
  participant DB as Prisma/Database

  Client->>API: GET /... with query params (page,pageSize,startingAfter,endingBefore,sortBy,...)
  API->>Pager: parse filters → getPaginationOptions(filters)
  Pager-->>API: pagination options (take, skip or cursor, orderBy, cursorId)
  API->>DB: Prisma.findMany({...filters..., ...paginationOptions})
  DB-->>API: results
  API-->>Client: 200 + items (pagination metadata if applicable)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

Areas needing attention:

  • getPaginationOptions: correctness of precedence (cursor vs offset), error cases (both cursors set), max page size enforcement, deterministic orderBy with id tiebreaker.
  • Callsite changes: ensure all callers (notably getLinksForWorkspace) updated to new signature and pass filters object.
  • Prisma index updates: verify indexes align with orderBy directions used by cursor logic.
  • Tests: ensure assumptions about deterministic ordering and cursor semantics match implementation.

Possibly related PRs

  • PR #3172 — Implements the same cursor+offset pagination refactor and adds getPaginationOptions and cursor pagination schemas across the same endpoints.
  • PR #3182 — Reverts the pagination changes (removes getPaginationOptions and cursor pagination schemas); directly conflicts with this work.

Suggested reviewers

  • steven-tey

Poem

🐰
I hopped through queries, filters in paw,
Cursor or page — I learned each law.
I nudged the indexes, kept order precise,
Now pages hop smooth as carrot-sliced. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title directly and clearly describes the main change: introducing cursor-based pagination support across the application.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cursor-based-pagination

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4127762 and e158f2c.

📒 Files selected for processing (2)
  • apps/web/app/(ee)/api/customers/route.ts (3 hunks)
  • apps/web/lib/zod/schemas/customers.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/lib/zod/schemas/customers.ts
  • apps/web/app/(ee)/api/customers/route.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@devkiran devkiran requested a review from steven-tey December 8, 2025 10:03
@devkiran devkiran marked this pull request as ready for review December 8, 2025 16:52
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/tests/links/list-links.test.ts (1)

9-42: Fix temporal dead zone in GET /links test cleanup

onTestFinished closes over firstLink before it is declared:

  • Line 15–17 use firstLink.id in the cleanup.
  • const { data: firstLink } = ... is only defined starting at line 19.

Because const bindings are in the temporal dead zone until their declaration runs, this will throw a ReferenceError when the cleanup callback is registered or executed.

A simple fix is to register the cleanup after firstLink is created:

-  onTestFinished(async () => {
-    await h.deleteLink(firstLink.id);
-  });
-
-  const { data: firstLink } = await http.post<Link>({
+  const { data: firstLink } = await http.post<Link>({
     path: "/links",
     body: { url, domain },
   });
+
+  onTestFinished(async () => {
+    await h.deleteLink(firstLink.id);
+  });

This keeps the behavior identical while avoiding the TDZ issue.

🧹 Nitpick comments (11)
packages/prisma/schema/commission.prisma (1)

48-58: New (programId, createdAt, id) index aligns with cursor-pagination access pattern

This index matches the expected ordering for cursor-based pagination by createdAt with id as a tiebreaker under a given programId, which should improve query performance and stability. You still retain the more complex [programId, createdAt, status, amount, earnings] index for other queries; you can revisit index overlap later if needed.

apps/web/lib/zod/schemas/links.ts (1)

7-18: Cursor + deprecated page-based pagination composition in getLinksQuerySchemaBase looks sound

Merging getCursorPaginationQuerySchema ahead of the deprecated getPaginationQuerySchema cleanly exposes both cursor params (startingAfter, endingBefore) and legacy page/pageSize, which matches how getPaginationOptions expects filters.

One minor follow-up to consider: linksExportQuerySchema omits page and pageSize but still inherits startingAfter/endingBefore from getLinksQuerySchemaBase. If the export endpoint never uses cursor pagination, you might want to omit those as well for clearer docs and validation, or explicitly document that they’re ignored for exports.

Also applies to: 160-179, 272-292

apps/web/lib/zod/schemas/customers.ts (1)

1-8: Customers query schema now cleanly supports cursor + deprecated page-based pagination

getCustomersQuerySchema correctly layers:

  • core filters and sort fields,
  • cursor pagination (startingAfter / endingBefore with a concrete example), and
  • deprecated page-based pagination with CUSTOMERS_MAX_PAGE_SIZE.

That matches the expectations of getPaginationOptions and clearly nudges clients towards cursor-based pagination.

For getCustomersCountQuerySchema, you omit page, pageSize, sortBy, and sortOrder, but cursor params still pass through. If the /customers/count endpoint never uses cursors, you might eventually tighten this by omitting startingAfter/endingBefore as well so the count contract is unambiguously “no pagination here”.

Also applies to: 13-73, 85-93

apps/web/lib/zod/schemas/commissions.ts (1)

131-136: Consider omitting cursor fields from count/export query schemas (optional)

getCommissionsCountQuerySchema and commissionsExportQuerySchema still allow startingAfter / endingBefore via getCommissionsQuerySchema, but those values are typically irrelevant for a global count or full export. If these endpoints never use cursor pagination, consider omitting cursor fields here as well to make the API surface clearer and avoid confusing no-op parameters.

Also applies to: 301-325

apps/web/tests/customers/pagination.test.ts (2)

18-30: Tests assume at least 10 customers in the E2E workspace

Several tests access baseline[4], baseline[5], and compare slices up to index 10. This is fine with the current seeded data, but will start failing if the fixture workspace ever has fewer than 10 customers. If you want the suite to be more robust to fixture changes, you could either seed the required minimum inside the tests or explicitly assert baseline.length >= 10 with a clear failure message.

Also applies to: 32-78, 163-255


258-277: Deduplicate pagination helper assertions across test suites (optional)

expectSortedByCreatedAt, expectSortedByCreatedAtAsc, and expectNoOverlap are mirrored in the commissions pagination tests. Consider moving these helpers into a shared test utility (for example under tests/utils/pagination.ts) to avoid duplication and keep future changes to pagination assertions in one place.

apps/web/lib/api/links/get-links-for-workspace.ts (1)

17-39: Relying on parsed filters for pagination fields (optional clarification)

getPaginationOptions assumes page, pageSize, sortBy, and sortOrder are present and valid on filters. As long as all callers pass in objects produced by getLinksQuerySchemaExtended.parse, that’s guaranteed via Zod defaults and enums. If this function is ever reused with unvalidated inputs, you may want to either export and reuse the Filters type from pagination.ts or document that pre-validation is required.

Also applies to: 156-157

apps/web/lib/api/pagination.ts (1)

4-20: Document or generalize the id-based cursor assumption (optional)

PaginationOptions.cursor and the secondary orderBy key are hard-coded to id, which matches your current models but is an implicit requirement. If you ever paginate on a model whose cursor column is not id, you’ll need to extend this helper. Consider either documenting this assumption in a comment or parameterizing the cursor field name in the future.

Also applies to: 24-55

apps/web/lib/zod/schemas/misc.ts (1)

31-66: Optional: push mutual-exclusion check into Zod as well

You currently enforce startingAfter / endingBefore mutual exclusivity in getPaginationOptions, which is sufficient for runtime behavior. If you want clients of the Zod schema alone (e.g. non-HTTP callers) to see validation errors earlier, you could add a .refine on getCursorPaginationQuerySchema to reject payloads that specify both fields.

Also applies to: 68-93

apps/web/tests/commissions/pagination.test.ts (2)

18-29: Tests rely on having at least 10 commissions in the E2E workspace

As with the customers suite, several expectations depend on baseline[4], baseline[5], and slices up to index 10. That’s fine with current fixtures but will break if the seeded workspace ever has fewer commissions. If you’d like these tests to be more resilient, you could either seed the necessary minimum inside the suite or assert baseline.length >= 10 with a clear failure reason.

Also applies to: 31-77, 180-280


283-302: Extract shared pagination assertion helpers (optional)

expectSortedByCreatedAt, expectSortedByCreatedAtAsc, and expectNoOverlap are duplicated from the customers pagination tests. Pulling them into a shared test helper module would reduce duplication and keep pagination-specific assertions consistent across suites.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 23ae40e and 9aceb2d.

📒 Files selected for processing (14)
  • apps/web/app/(ee)/api/customers/route.ts (3 hunks)
  • apps/web/lib/api/commissions/get-commissions.ts (2 hunks)
  • apps/web/lib/api/links/get-links-for-workspace.ts (3 hunks)
  • apps/web/lib/api/pagination.ts (1 hunks)
  • apps/web/lib/zod/schemas/commissions.ts (2 hunks)
  • apps/web/lib/zod/schemas/customers.ts (2 hunks)
  • apps/web/lib/zod/schemas/links.ts (2 hunks)
  • apps/web/lib/zod/schemas/misc.ts (2 hunks)
  • apps/web/tests/commissions/pagination.test.ts (1 hunks)
  • apps/web/tests/customers/pagination.test.ts (1 hunks)
  • apps/web/tests/links/list-links.test.ts (2 hunks)
  • packages/prisma/schema/commission.prisma (1 hunks)
  • packages/prisma/schema/customer.prisma (1 hunks)
  • packages/prisma/schema/link.prisma (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-09-24T16:13:00.387Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: packages/prisma/schema/partner.prisma:151-153
Timestamp: 2025-09-24T16:13:00.387Z
Learning: In the Dub codebase, Prisma schemas use single-column indexes without brackets (e.g., `@index(partnerId)`) and multi-column indexes with brackets (e.g., `@index([programId, partnerId])`). This syntax pattern is consistently used throughout their schema files and works correctly with their Prisma version.

Applied to files:

  • packages/prisma/schema/commission.prisma
  • packages/prisma/schema/link.prisma
  • packages/prisma/schema/customer.prisma
📚 Learning: 2025-06-06T07:59:03.120Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.

Applied to files:

  • packages/prisma/schema/link.prisma
  • apps/web/lib/zod/schemas/links.ts
  • apps/web/lib/api/links/get-links-for-workspace.ts
  • apps/web/tests/links/list-links.test.ts
📚 Learning: 2025-10-06T15:48:45.956Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2935
File: packages/prisma/schema/workspace.prisma:21-36
Timestamp: 2025-10-06T15:48:45.956Z
Learning: In the Dub repository (dubinc/dub), Prisma schema changes are not managed with separate migration files. Do not flag missing Prisma migration files when schema changes are made to files like `packages/prisma/schema/workspace.prisma` or other schema files.

Applied to files:

  • packages/prisma/schema/customer.prisma
📚 Learning: 2025-10-17T08:18:19.278Z
Learnt from: devkiran
Repo: dubinc/dub PR: 0
File: :0-0
Timestamp: 2025-10-17T08:18:19.278Z
Learning: In the apps/web codebase, `@/lib/zod` should only be used for places that need OpenAPI extended zod schema. All other places should import from the standard `zod` package directly using `import { z } from "zod"`.

Applied to files:

  • apps/web/lib/api/links/get-links-for-workspace.ts
  • apps/web/lib/zod/schemas/customers.ts
🧬 Code graph analysis (9)
apps/web/app/(ee)/api/customers/route.ts (2)
apps/web/lib/zod/schemas/customers.ts (1)
  • getCustomersQuerySchemaExtended (75-83)
apps/web/lib/api/pagination.ts (1)
  • getPaginationOptions (24-84)
apps/web/tests/customers/pagination.test.ts (2)
apps/web/tests/utils/integration.ts (1)
  • IntegrationHarness (14-118)
apps/web/lib/types.ts (1)
  • Customer (426-426)
apps/web/lib/api/pagination.ts (2)
packages/prisma/client.ts (1)
  • Prisma (30-30)
apps/web/lib/api/errors.ts (1)
  • DubApiError (58-75)
apps/web/lib/api/commissions/get-commissions.ts (1)
apps/web/lib/api/pagination.ts (1)
  • getPaginationOptions (24-84)
apps/web/lib/zod/schemas/links.ts (1)
apps/web/lib/zod/schemas/misc.ts (2)
  • getCursorPaginationQuerySchema (69-93)
  • getPaginationQuerySchema (32-66)
apps/web/lib/zod/schemas/commissions.ts (1)
apps/web/lib/zod/schemas/misc.ts (2)
  • getCursorPaginationQuerySchema (69-93)
  • getPaginationQuerySchema (32-66)
apps/web/lib/api/links/get-links-for-workspace.ts (1)
apps/web/lib/api/pagination.ts (1)
  • getPaginationOptions (24-84)
apps/web/tests/links/list-links.test.ts (1)
apps/web/tests/utils/integration.ts (1)
  • IntegrationHarness (14-118)
apps/web/tests/commissions/pagination.test.ts (2)
apps/web/tests/utils/integration.ts (1)
  • IntegrationHarness (14-118)
apps/web/lib/types.ts (1)
  • CommissionResponse (443-443)
🔇 Additional comments (10)
packages/prisma/schema/link.prisma (1)

94-103: Adding id as tiebreaker in composite index for cursor pagination looks correct

Including id after createdAt(sort: Desc) makes ordering deterministic and aligns with the new cursor-based pagination that sorts by createdAt then id. Syntax and column order are consistent with existing Prisma index patterns.

packages/prisma/schema/customer.prisma (1)

27-35: Extending customer index with id is consistent with cursor pagination requirements

Updating the index to [projectId, createdAt, id] gives deterministic ordering and supports keyset pagination on createdAt with id as a tiebreaker, without affecting existing filters.

apps/web/lib/api/commissions/get-commissions.ts (1)

6-10: Switch to getPaginationOptions cleanly centralizes commissions pagination

Delegating skip/take and orderBy to getPaginationOptions(filters) keeps this query focused on filtering and inclusion logic, and aligns it with the new cursor-based pagination behavior (deterministic sort by sortBy + id). Just ensure getCommissionsQuerySchema continues to define sensible defaults for page, pageSize, sortBy, and sortOrder so filters always satisfy the helper’s expectations.

Also applies to: 35-73

apps/web/app/(ee)/api/customers/route.ts (1)

4-15: Unified pagination via getPaginationOptions in customers route looks correct

Parsing filters once with getCustomersQuerySchemaExtended and then spreading ...getPaginationOptions(filters) into prisma.customer.findMany is a clean refactor:

  • Keeps filtering logic focused on business fields (email, externalId, search, country, linkId, customerIds).
  • Delegates page vs cursor behavior and deterministic ordering (sortBy + id) to a shared helper.
  • Lines up with the new customer index on [projectId, createdAt, id] for the default sort.

Just ensure that any future changes to the customers pagination schema (e.g., new sort fields) are mirrored in the Prisma indexes where needed to preserve performance characteristics.

Also applies to: 40-83

apps/web/lib/zod/schemas/commissions.ts (1)

5-8: Cursor + offset pagination schema layering looks consistent

Merging the cursor schema first and the paginated (deprecated) page/pageSize schema afterwards cleanly exposes both pagination styles, and the dedicated COMMISSIONS_MAX_PAGE_SIZE keeps the per-endpoint limit explicit. No functional issues spotted.

Also applies to: 56-129

apps/web/tests/customers/pagination.test.ts (1)

5-207: Strong end-to-end coverage of new pagination behavior

This suite does a good job validating offset vs cursor pagination, mixed-parameter precedence, sort order in both directions, and error handling for invalid combinations and large page values. The use of a common baseline plus ID-slice comparisons makes regressions around ordering and overlap easy to catch.

apps/web/lib/api/links/get-links-for-workspace.ts (1)

17-39: Centralizing link pagination via getPaginationOptions looks good

Switching to a single filters parameter and spreading getPaginationOptions(filters) into the Prisma query cleanly delegates all pagination and ordering concerns to the shared helper while preserving the existing filtering logic (tags, folders, search, dates, etc.). This keeps the endpoint aligned with the new pagination behavior used by other routes.

Also applies to: 41-42, 60-157

apps/web/lib/api/pagination.ts (1)

4-12: Shared pagination helper correctly models offset + cursor semantics

The getPaginationOptions implementation cleanly handles:

  • Mutual exclusion of startingAfter / endingBefore with a clear DubApiError.
  • Enforcing a maximum page value.
  • Determining take and skip for both offset and cursor modes.
  • Using a stable two-field orderBy (primary sortBy, secondary id) for deterministic pagination.

This should be a solid foundation for reusing across different Prisma models that have an id primary key.

Also applies to: 22-84

apps/web/lib/zod/schemas/misc.ts (1)

31-66: Pagination + cursor Zod schemas are well-structured and composable

The extended getPaginationQuerySchema options (custom pageSize, deprecated flag) and the new getCursorPaginationQuerySchema give you a nice building block for endpoints that need both legacy page-based pagination and the new cursor style, with clear OpenAPI docs and examples. No issues spotted with the Zod setup.

Also applies to: 68-93

apps/web/tests/commissions/pagination.test.ts (1)

5-280: Commissions pagination behavior is thoroughly covered

This suite mirrors the customers pagination tests and gives solid coverage for offset vs cursor flows, mixed-parameter precedence, invalid cursor combinations, large page values, and both sort directions. Using a shared baseline and ID-slice checks should make any future regressions in ordering or pagination logic very visible.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/tests/customers/pagination.test.ts (1)

52-65: Consider adding explicit sort parameters for deterministic results.

The cursor-based pagination tests (lines 52-65, 67-79, 138-149, 152-162) omit sortBy and sortOrder parameters while comparing results against a baseline fetched with explicit sortBy: "createdAt" and sortOrder: "desc". If the API's default sort order differs or changes, these tests could become flaky.

For example, update the startingAfter test:

 test("Cursor forward (startingAfter)", async () => {
   const firstPage = baseline.slice(0, 5);
   const lastId = firstPage[4].id;

   const { status, data } = await http.get<Customer[]>({
     path: "/customers",
-    query: { pageSize: "5", startingAfter: lastId },
+    query: { 
+      pageSize: "5", 
+      startingAfter: lastId,
+      sortBy: "createdAt",
+      sortOrder: "desc"
+    },
   });

   expect(status).toEqual(200);
   expectSortedByCreatedAt(data);

   expect(data.map((c) => c.id)).toEqual(baselineIds.slice(5, 10));
 });

Apply similar changes to the other cursor-based tests for consistency.

Also applies to: 67-79, 138-149, 152-162

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9aceb2d and 4127762.

📒 Files selected for processing (3)
  • apps/web/tests/commissions/pagination.test.ts (1 hunks)
  • apps/web/tests/customers/pagination.test.ts (1 hunks)
  • apps/web/tests/links/list-links.test.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/tests/links/list-links.test.ts
  • apps/web/tests/commissions/pagination.test.ts
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/tests/customers/pagination.test.ts (2)
apps/web/tests/utils/integration.ts (1)
  • IntegrationHarness (14-118)
apps/web/lib/types.ts (1)
  • Customer (426-426)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (3)
apps/web/tests/customers/pagination.test.ts (3)

1-31: LGTM! Well-structured test setup.

The test setup correctly establishes a baseline dataset with explicit sort parameters and validates the ordering before running tests. This ensures deterministic test behavior.


81-256: Excellent error handling and sort order coverage!

The tests comprehensively cover:

  • Validation of mutually exclusive cursor parameters
  • Page size limits with helpful error messages
  • Invalid cursor ID handling (returning empty arrays)
  • Both ascending and descending sort orders with explicit parameters

The explicit inclusion of sortBy and sortOrder in the ascending order tests (lines 164-256) ensures deterministic behavior.


259-278: LGTM! Helper functions are correctly implemented.

The helper functions properly validate:

  • Monotonically decreasing timestamps for descending order (using >=)
  • Monotonically increasing timestamps for ascending order (using <=)
  • No overlapping customer IDs between pages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants