-
Notifications
You must be signed in to change notification settings - Fork 498
Paginated list tests #1088
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Paginated list tests #1088
Conversation
Older cmux preview screenshots (latest comment is below)Preview ScreenshotsOpen Workspace (1 hr expiry) Β· Open Dev Browser (1 hr expiry) Β· Open Diff Heatmap Screenshot capture was skipped.
Generated by cmux preview system |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
π WalkthroughWalkthroughThis PR replaces a simple cursor model with a new abstract Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Client as Client Code
participant PL as PaginatedList (abstract)
participant Impl as ArrayPaginatedList (concrete)
participant Filter as Filter/Order Logic
User->>Client: request page (after/before, limit)
Client->>PL: next/prev(options)
PL->>Impl: nextOrPrev(type, options)
rect rgb(230,245,255)
note over Impl,Filter: Apply filters & ordering to full dataset
Impl->>Filter: evaluate items
Filter-->>Impl: filtered/sorted list
end
rect rgb(245,230,255)
note over Impl: Assign per-item cursors
Impl->>Impl: compute prevCursor / nextCursor
Impl->>Impl: slice by limit & precision
end
Impl-->>PL: QueryResult{ items[{item,prevCursor,nextCursor}], isFirst,isLast, cursor }
PL-->>Client: QueryResult to caller
rect rgb(245,240,230)
note over Client,PL: Composition flows (map/flatMap/merge)
Client->>PL: map/filter/merge => new PaginatedList
Client->>PL: composed.next(options)
end
Estimated code review effortπ― 4 (Complex) | β±οΈ ~50 minutes Poem
π₯ Pre-merge checks | β 2 | β 1β Failed checks (1 inconclusive)
β Passed checks (2 passed)
βοΈ Tip: You can configure your own custom pre-merge checks in the settings. β¨ Finishing touches
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive test coverage for the paginated lists utility and refactors cursor semantics from a single itemCursor to separate prevCursor and nextCursor fields. The changes also include extensive documentation improvements and fixes to the pagination logic.
- Refactored cursor representation: each item now has both
prevCursor(position before the item) andnextCursor(position after the item) instead of a singleitemCursor - Fixed while loop condition in
nextOrPrevto properly stop when reaching list boundaries - Added comprehensive test suite with 783 lines covering basic pagination, filtering, sorting, cursor semantics, utility methods (map, filter, flatMap, merge), and edge cases
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| packages/stack-shared/src/utils/paginated-lists.tsx | Refactored cursor fields from itemCursor to prevCursor/nextCursor, updated ArrayPaginatedList cursor format to before-${number}, fixed pagination loop logic, added extensive JSDoc documentation for all public methods, and removed unused range import |
| packages/stack-shared/src/utils/paginated-lists.test.ts | Added comprehensive test suite covering ArrayPaginatedList functionality, cursor semantics, filtering, ordering, limitPrecision modes, utility methods (map, filter, flatMap, merge), edge cases, and complete pagination walkthroughs |
π‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Greptile SummaryAdded comprehensive test coverage for paginated list utilities and refactored cursor semantics from single Key changes:
Issues found:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant PaginatedList
participant ArrayPaginatedList
Client->>PaginatedList: next({after: "before-0", limit: 2, filter, orderBy})
PaginatedList->>PaginatedList: nextOrPrev("next", options)
loop while limitRemaining > 0 && !includesLast
PaginatedList->>ArrayPaginatedList: _nextOrPrev("next", {cursor, limit, filter, orderBy})
ArrayPaginatedList->>ArrayPaginatedList: Extract cursor position
ArrayPaginatedList->>ArrayPaginatedList: Calculate new cursor position
ArrayPaginatedList->>ArrayPaginatedList: Create entries with prevCursor/nextCursor
ArrayPaginatedList->>ArrayPaginatedList: Slice array window
ArrayPaginatedList->>ArrayPaginatedList: Filter items
ArrayPaginatedList->>ArrayPaginatedList: Sort items
ArrayPaginatedList-->>PaginatedList: {items, isFirst, isLast, cursor}
PaginatedList->>PaginatedList: Append/prepend to result
PaginatedList->>PaginatedList: Update limitRemaining
end
PaginatedList->>PaginatedList: Verify items are sorted
PaginatedList->>PaginatedList: Trim to exact limit if needed
PaginatedList-->>Client: {items: [{item, prevCursor, nextCursor}], isFirst, isLast, cursor}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 files reviewed, 3 comments
There was a problem hiding this 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 (2)
packages/stack-shared/src/utils/paginated-lists.test.ts (1)
567-657: Consider adding backward pagination test for merged lists.All merge tests use forward pagination (
next). Given that the merge implementation has separate logic for handlingprevdirection with reversed iteration and cursor tracking, adding a test for backward pagination through merged lists would improve coverage and confidence.π§ͺ Suggested test for backward pagination on merged lists
it("should paginate backwards through merged list", async () => { const list1 = new ArrayPaginatedList([1, 3, 5, 7, 9]); const list2 = new ArrayPaginatedList([2, 4, 6, 8, 10]); const merged = PaginatedList.merge(list1, list2); const last = await merged.prev({ before: merged.getLastCursor(), limit: 4, filter: () => true, orderBy: (a, b) => a - b, limitPrecision: "exact", }); expect(items(last)).toEqual([7, 8, 9, 10]); const middle = await merged.prev({ before: last.cursor, limit: 4, filter: () => true, orderBy: (a, b) => a - b, limitPrecision: "exact", }); expect(items(middle)).toEqual([3, 4, 5, 6]); });packages/stack-shared/src/utils/paginated-lists.tsx (1)
336-336: Acceptable use ofanyfor heterogeneous cursor types.Using
anyfor the cursor type parameter is reasonable here since merged lists may have different cursor types, and the merged cursor is JSON-encoded. Consider adding a brief comment explaining this design choice.π Suggested comment
static merge< Item, Filter extends unknown, OrderBy extends unknown, >( + // Cursor type is `any` because merged lists may have different cursor types; + // the merged cursor is a JSON-encoded array of individual list cursors ...lists: PaginatedList<Item, any, Filter, OrderBy>[] ): PaginatedList<Item, string, Filter, OrderBy> {
π Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
π Files selected for processing (2)
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
π§° Additional context used
π Path-based instructions (6)
**/*.{tsx,ts,jsx,js}
π CodeRabbit inference engine (AGENTS.md)
For blocking alerts and errors, never use
toast; instead, use alerts as toasts are easily missed by the user
Files:
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
**/*.{test,spec}.{ts,tsx,js,jsx}
π CodeRabbit inference engine (AGENTS.md)
When writing tests, prefer
.toMatchInlineSnapshot()over other selectors if possible; check snapshot-serializer.ts to understand how snapshots are formatted and how non-deterministic values are handled
Files:
packages/stack-shared/src/utils/paginated-lists.test.ts
**/*.{tsx,ts}
π CodeRabbit inference engine (AGENTS.md)
NEVER use Next.js dynamic functions if avoidable; prefer using client components instead to keep pages static (e.g., use
usePathnameinstead ofawait params)
Files:
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
**/*.{ts,tsx,js,jsx}
π CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: NEVER try-catch-all, NEVER void a promise, and NEVER use .catch(console.error) or similar; use loading indicators instead; if asynchronous handling is necessary, userunAsynchronouslyorrunAsynchronouslyWithAlertinstead
Use ES6 maps instead of records wherever possible
Files:
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
**/*.{ts,tsx}
π CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Code defensively; prefer?? throwErr(...)over non-null assertions with good error messages explicitly stating violated assumptions
Avoid theanytype; when necessary, leave a comment explaining why it's used, why the type system fails, and how errors would be caught at compile-, test-, or runtime
Files:
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
**/*.{tsx,css}
π CodeRabbit inference engine (AGENTS.md)
**/*.{tsx,css}: Keep hover/click animations snappy and fast; don't delay actions with pre-transitions (e.g., no fade-in on button hover) as it makes UI feel sluggish; instead apply transitions after the action like smooth fade-out when hover ends
When creating hover transitions, avoid hover-enter transitions and use only hover-exit transitions (e.g.,transition-colors hover:transition-none)
Files:
packages/stack-shared/src/utils/paginated-lists.tsx
π§ Learnings (1)
π Learning: 2026-01-07T00:55:19.856Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T00:55:19.856Z
Learning: Applies to **/e2e/**/*.{test,spec}.{ts,tsx,js,jsx} : ALWAYS add new E2E tests when changing the API or SDK interface; err on the side of creating too many tests due to the critical nature of the authentication industry
Applied to files:
packages/stack-shared/src/utils/paginated-lists.test.ts
𧬠Code graph analysis (2)
packages/stack-shared/src/utils/paginated-lists.test.ts (3)
apps/e2e/tests/helpers.ts (1)
it(12-12)packages/stack-shared/src/utils/paginated-lists.tsx (1)
ArrayPaginatedList(433-458)packages/stack-shared/src/utils/strings.tsx (1)
stringCompare(61-65)
packages/stack-shared/src/utils/paginated-lists.tsx (1)
packages/stack-shared/src/utils/errors.tsx (1)
StackAssertionError(69-85)
β° 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). (16)
- GitHub Check: Vercel Agent Review
- GitHub Check: CodeQL analysis (javascript-typescript)
- GitHub Check: Agent
- GitHub Check: Cursor Bugbot
- GitHub Check: build (22.x)
- GitHub Check: lint_and_build (latest)
- GitHub Check: all-good
- GitHub Check: restart-dev-and-test-with-custom-base-port
- GitHub Check: check_prisma_migrations (22.x)
- GitHub Check: docker
- GitHub Check: setup-tests-with-custom-base-port
- GitHub Check: E2E Tests (Node 22.x, Freestyle prod)
- GitHub Check: E2E Tests (Node 22.x, Freestyle mock)
- GitHub Check: setup-tests
- GitHub Check: build (22.x)
- GitHub Check: restart-dev-and-test
π Additional comments (7)
packages/stack-shared/src/utils/paginated-lists.test.ts (3)
1-9: LGTM on imports and helper setup.The
itemshelper function cleanly extracts item values from paginated results, improving test readability.
11-96: Solid coverage of forward pagination scenarios.Tests correctly verify boundary flags (
isFirst/isLast), cursor continuation, and edge cases (empty array, limit 0).
734-782: Excellent integration tests for complete traversal.These walkthrough tests validate that repeated pagination calls correctly collect all items in both forward and backward directions, providing confidence in the cursor continuation logic.
packages/stack-shared/src/utils/paginated-lists.tsx (4)
32-76: Well-documented API with clear examples.The JSDoc comments effectively explain the cursor-based pagination model, including the stability guarantee that cursors remain valid even when filters change.
96-141: Robust implementation with sort validation.The sort order assertion (lines 119-127) is a good defensive measure that catches implementation bugs early. The loop correctly handles the different
limitPrecisionmodes.
396-408: Empty list implementation is correct.The
anytypes for filter/orderBy are acceptable here since an empty list never processes any items. The implementation correctly returnsisFirst: true, isLast: truefor all queries.
433-458: Clear implementation with appropriate performance caveat.The documentation correctly notes that this implementation re-filters and re-sorts on each query, making it suitable only for small datasets. The cursor stability (tied to original array indices) correctly implements the documented contract.
Preview Screenshotsβ³ Preview screenshots are being captured... Workspace and dev browser links will appear here once the preview environment is ready. Generated by cmux preview system |
There was a problem hiding this 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)
packages/stack-shared/src/utils/paginated-lists.tsx (1)
403-415: Consider using generic type parameters instead ofany.The
empty()factory usesanyfor Filter and OrderBy types. While this works functionally since the empty list never uses these values, using proper generics would improve type safety.π‘ Suggested improvement
- static empty() { - class EmptyPaginatedList extends PaginatedList<never, "first" | "last", any, any> { + static empty<Filter = unknown, OrderBy = unknown>(): PaginatedList<never, "first" | "last", Filter, OrderBy> { + class EmptyPaginatedList extends PaginatedList<never, "first" | "last", Filter, OrderBy> {
π Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
π Files selected for processing (2)
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
π§° Additional context used
π Path-based instructions (6)
**/*.{tsx,ts,jsx,js}
π CodeRabbit inference engine (AGENTS.md)
For blocking alerts and errors, never use
toast; instead, use alerts as toasts are easily missed by the user
Files:
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
**/*.{test,spec}.{ts,tsx,js,jsx}
π CodeRabbit inference engine (AGENTS.md)
When writing tests, prefer
.toMatchInlineSnapshot()over other selectors if possible; check snapshot-serializer.ts to understand how snapshots are formatted and how non-deterministic values are handled
Files:
packages/stack-shared/src/utils/paginated-lists.test.ts
**/*.{tsx,ts}
π CodeRabbit inference engine (AGENTS.md)
NEVER use Next.js dynamic functions if avoidable; prefer using client components instead to keep pages static (e.g., use
usePathnameinstead ofawait params)
Files:
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
**/*.{ts,tsx,js,jsx}
π CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: NEVER try-catch-all, NEVER void a promise, and NEVER use .catch(console.error) or similar; use loading indicators instead; if asynchronous handling is necessary, userunAsynchronouslyorrunAsynchronouslyWithAlertinstead
Use ES6 maps instead of records wherever possible
Files:
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
**/*.{ts,tsx}
π CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Code defensively; prefer?? throwErr(...)over non-null assertions with good error messages explicitly stating violated assumptions
Avoid theanytype; when necessary, leave a comment explaining why it's used, why the type system fails, and how errors would be caught at compile-, test-, or runtime
Files:
packages/stack-shared/src/utils/paginated-lists.test.tspackages/stack-shared/src/utils/paginated-lists.tsx
**/*.{tsx,css}
π CodeRabbit inference engine (AGENTS.md)
**/*.{tsx,css}: Keep hover/click animations snappy and fast; don't delay actions with pre-transitions (e.g., no fade-in on button hover) as it makes UI feel sluggish; instead apply transitions after the action like smooth fade-out when hover ends
When creating hover transitions, avoid hover-enter transitions and use only hover-exit transitions (e.g.,transition-colors hover:transition-none)
Files:
packages/stack-shared/src/utils/paginated-lists.tsx
π§ Learnings (1)
π Learning: 2026-01-07T00:55:19.856Z
Learnt from: CR
Repo: stack-auth/stack-auth PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-07T00:55:19.856Z
Learning: Applies to **/e2e/**/*.{test,spec}.{ts,tsx,js,jsx} : ALWAYS add new E2E tests when changing the API or SDK interface; err on the side of creating too many tests due to the critical nature of the authentication industry
Applied to files:
packages/stack-shared/src/utils/paginated-lists.test.ts
𧬠Code graph analysis (1)
packages/stack-shared/src/utils/paginated-lists.tsx (1)
packages/stack-shared/src/utils/errors.tsx (1)
StackAssertionError(69-85)
β° 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). (14)
- GitHub Check: Vercel Agent Review
- GitHub Check: Cursor Bugbot
- GitHub Check: docker
- GitHub Check: all-good
- GitHub Check: setup-tests-with-custom-base-port
- GitHub Check: build (22.x)
- GitHub Check: check_prisma_migrations (22.x)
- GitHub Check: setup-tests
- GitHub Check: build (22.x)
- GitHub Check: E2E Tests (Node 22.x, Freestyle mock)
- GitHub Check: lint_and_build (latest)
- GitHub Check: E2E Tests (Node 22.x, Freestyle prod)
- GitHub Check: restart-dev-and-test
- GitHub Check: restart-dev-and-test-with-custom-base-port
π Additional comments (8)
packages/stack-shared/src/utils/paginated-lists.tsx (3)
32-53: LGTM!The documentation is comprehensive with clear examples demonstrating usage patterns for cursor-based pagination.
96-141: LGTM!The
nextOrPrevimplementation correctly handles:
- Loop termination based on limit and boundary conditions
- Result sorting validation
- Proper cursor advancement when trimming for exact/at-most precision
181-222: LGTM!The
flatMapimplementation correctly passes the full item entry (including cursor metadata) to the mapper and propagates the new cursor structure.packages/stack-shared/src/utils/paginated-lists.test.ts (5)
11-96: LGTM!Comprehensive test coverage for basic forward pagination including edge cases (empty array, zero limit).
98-145: LGTM!Backward pagination tests properly verify cursor chaining and boundary flags.
147-221: LGTM!Thorough testing of the per-item
prevCursor/nextCursorsemantics including cursor chaining in both directions.
707-814: LGTM!Excellent coverage of merge backward pagination including:
- Single backward page (lines 707-737)
- Complete backward walkthrough (lines 739-764)
- Forward/backward consistency verification (lines 766-814)
These tests validate the fixes to merge backward pagination logic.
1-9: LGTM!Well-structured test file with comprehensive coverage. The helper function
items()at line 9 cleanly extracts item values from paginated results, reducing test verbosity.
Note
Modernizes pagination API and behavior with clearer cursor semantics and robust coverage.
QueryResult.itemsto includeprevCursor/nextCursorand updates slicing to use them innextOrPrevArrayPaginatedListto usebefore-{n}cursors, sort/filter before slicing, and computeisFirst/isLastagainst the sorted viewPaginatedList.mergeto build JSON array cursors per item, maintain order fornext/prev, and validate consistent comparators (adds extra error context)map/flatMapto preserve and propagate item cursorsPaginatedListandArrayPaginatedListfor usage and contractsmap/filter/flatMap),merge, and edge casesWritten by Cursor Bugbot for commit 39d7bd9. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Tests
βοΈ Tip: You can customize this high-level summary in your review settings.