mattrguerra/meridian-ops-boardmainPrivate on GitHub, published here in full

paginate.test.ts

Language TypeScript3.2 KB104 lines

packages/ninety-client/test/paginate.test.ts

  1. import { describe, expect, it } from 'vitest'
  2. import {
  3. collect,
  4. fromArray,
  5. fromEnvelope,
  6. fromTeamKeyed,
  7. iterateAll,
  8. type Page,
  9. } from '../src/paginate.js'
  10. import { NinetySchemaError } from '../src/errors.js'
  11. const ctx = { endpoint: 'POST /test' }
  12. describe('fromEnvelope: Issues, KPIs', () => {
  13. it('reads items and totalCount', () => {
  14. const p = fromEnvelope<number>({ items: [1, 2, 3], totalCount: 10 }, { page: 0, pageSize: 3 }, ctx)
  15. expect(p.items).toEqual([1, 2, 3])
  16. expect(p.total).toBe(10)
  17. expect(p.hasMore).toBe(true)
  18. })
  19. it('reports hasMore false on the last page', () => {
  20. const p = fromEnvelope<number>({ items: [9, 10], totalCount: 10 }, { page: 4, pageSize: 2 }, ctx)
  21. expect(p.hasMore).toBe(false)
  22. })
  23. it('rejects a bare array', () => {
  24. expect(() => fromEnvelope([1, 2], { page: 0, pageSize: 2 }, ctx)).toThrow(NinetySchemaError)
  25. })
  26. })
  27. describe('fromArray: To-Dos, Teams', () => {
  28. it('wraps a bare array with no total', () => {
  29. const p = fromArray<number>([1, 2], { page: 0, pageSize: 5 }, ctx)
  30. expect(p.items).toEqual([1, 2])
  31. expect(p.total).toBeNull()
  32. expect(p.hasMore).toBe(false)
  33. })
  34. it('infers hasMore from a full page', () => {
  35. const p = fromArray<number>([1, 2, 3], { page: 0, pageSize: 3 }, ctx)
  36. expect(p.hasMore).toBe(true)
  37. })
  38. it('rejects an envelope', () => {
  39. expect(() => fromArray({ items: [] }, { page: 0, pageSize: 5 }, ctx)).toThrow(NinetySchemaError)
  40. })
  41. })
  42. describe('fromTeamKeyed: Rocks', () => {
  43. it('flattens and stamps teamId', () => {
  44. const raw = { teamA: [{ title: 'x' }], teamB: [{ title: 'y' }, { title: 'z' }] }
  45. const p = fromTeamKeyed<{ title: string }>(raw, { page: 0, pageSize: 50 }, ctx)
  46. expect(p.items).toHaveLength(3)
  47. expect(p.items.map((i) => i.teamId)).toEqual(['teamA', 'teamB', 'teamB'])
  48. expect(p.items[0]?.title).toBe('x')
  49. })
  50. it('rejects an array', () => {
  51. expect(() => fromTeamKeyed([], { page: 0, pageSize: 5 }, ctx)).toThrow(NinetySchemaError)
  52. })
  53. })
  54. describe('iterateAll', () => {
  55. const pageOf = (items: number[], page: number, pageSize: number, hasMore: boolean): Page<number> => ({
  56. items,
  57. total: null,
  58. pageIndex: page,
  59. pageSize,
  60. hasMore,
  61. })
  62. it('walks every page and stops when hasMore is false', async () => {
  63. const pages = [
  64. pageOf([1, 2], 0, 2, true),
  65. pageOf([3, 4], 1, 2, true),
  66. pageOf([5], 2, 2, false),
  67. ]
  68. const seen: number[] = []
  69. const all = await collect(
  70. iterateAll<number>(async (req) => {
  71. seen.push(req.page)
  72. return pages[req.page]!
  73. }, { page: 0, pageSize: 2 }),
  74. )
  75. expect(all).toEqual([1, 2, 3, 4, 5])
  76. expect(seen).toEqual([0, 1, 2])
  77. })
  78. it('stops on an empty page even if hasMore lies', async () => {
  79. const all = await collect(
  80. iterateAll<number>(async (req) => pageOf([], req.page, 2, true), { page: 0, pageSize: 2 }),
  81. )
  82. expect(all).toEqual([])
  83. })
  84. it('throws at the safety cap rather than looping forever', async () => {
  85. await expect(
  86. collect(
  87. iterateAll<number>(async (req) => pageOf([1], req.page, 1, true), { page: 0, pageSize: 1 }, { maxPages: 3 }),
  88. ),
  89. ).rejects.toThrow(/safety cap/)
  90. })
  91. })