Grid.utils.test.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import { copyToClipboard } from 'ui'
  2. import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
  3. import {
  4. formatFilterURLParams,
  5. formatSortURLParams,
  6. handleCellKeyDown,
  7. } from '@/components/grid/BrivenGrid.utils'
  8. const { toastError, toastSuccess } = vi.hoisted(() => ({
  9. toastError: vi.fn(),
  10. toastSuccess: vi.fn(),
  11. }))
  12. vi.mock('sonner', () => ({
  13. toast: {
  14. error: toastError,
  15. success: toastSuccess,
  16. },
  17. }))
  18. // Sort URL syntax: `column:order`
  19. describe('BrivenGrid.utils: formatSortURLParams', () => {
  20. test('should return an array of sort options based on URL params', () => {
  21. const mockInput = ['id:asc', 'name:desc']
  22. const output = formatSortURLParams('fakeTable', mockInput)
  23. expect(output).toStrictEqual([
  24. { table: 'fakeTable', column: 'id', ascending: true },
  25. { table: 'fakeTable', column: 'name', ascending: false },
  26. ])
  27. })
  28. test('should reject any malformed sort options based on URL params', () => {
  29. const mockInput = ['id', 'name:asc', ':asc']
  30. const output = formatSortURLParams('fakeTable', mockInput)
  31. expect(output).toStrictEqual([
  32. {
  33. table: 'fakeTable',
  34. column: 'name',
  35. ascending: true,
  36. },
  37. ])
  38. })
  39. })
  40. // Filter URL syntax: `column:operatorAbbreviation:value`
  41. describe('BrivenGrid.utils: formatFilterURLParams', () => {
  42. test('should return an array of filter options based on URL params', () => {
  43. const mockInput = ['id:gte:20', 'id:lte:40']
  44. const output = formatFilterURLParams(mockInput)
  45. expect(output).toHaveLength(2)
  46. expect(output[0]).toStrictEqual({
  47. column: 'id',
  48. operator: '>=',
  49. value: '20',
  50. })
  51. expect(output[1]).toStrictEqual({
  52. column: 'id',
  53. operator: '<=',
  54. value: '40',
  55. })
  56. })
  57. test('should format filters for timestamps correctly', () => {
  58. const mockInput = ['created_at:gte:2022-05-30 03:00:00']
  59. const output = formatFilterURLParams(mockInput)
  60. expect(output[0]).toStrictEqual({
  61. column: 'created_at',
  62. operator: '>=',
  63. value: '2022-05-30 03:00:00',
  64. })
  65. })
  66. test('should reject any malformed filter options based on URL params', () => {
  67. const mockInput = ['id', ':gte', ':50', 'id:eq:10']
  68. const output = formatFilterURLParams(mockInput)
  69. expect(output).toHaveLength(1)
  70. })
  71. test('should reject any filter options with unrecognized operator', () => {
  72. const mockInput = ['id:meme:40', 'name:eq:town']
  73. const output = formatFilterURLParams(mockInput)
  74. expect(output).toHaveLength(1)
  75. })
  76. test('should allow filter options to have empty value based on URL params', () => {
  77. const mockInput = ['id:ilike:']
  78. const output = formatFilterURLParams(mockInput)
  79. expect(output).toHaveLength(1)
  80. expect(output[0]).toStrictEqual({
  81. column: 'id',
  82. operator: '~~*',
  83. value: '',
  84. })
  85. })
  86. })
  87. describe('BrivenGrid.utils: handleCellKeyDown', () => {
  88. beforeEach(() => {
  89. toastError.mockReset()
  90. toastSuccess.mockReset()
  91. vi.unstubAllGlobals()
  92. vi.spyOn(window.document, 'hasFocus').mockReturnValue(true)
  93. })
  94. afterEach(() => {
  95. vi.unstubAllGlobals()
  96. vi.restoreAllMocks()
  97. })
  98. test('should copy the selected cell value when Meta+C is pressed', async () => {
  99. const writeText = vi.fn().mockResolvedValue(undefined)
  100. vi.stubGlobal('navigator', {
  101. clipboard: { writeText },
  102. })
  103. const args = {
  104. mode: 'SELECT',
  105. column: { key: 'name' },
  106. row: { name: 'hello from safari' },
  107. rowIdx: 0,
  108. selectCell: vi.fn(),
  109. } as unknown as Parameters<typeof handleCellKeyDown>[0]
  110. const event = {
  111. key: 'C',
  112. metaKey: true,
  113. ctrlKey: false,
  114. altKey: false,
  115. nativeEvent: new KeyboardEvent('keydown', { key: 'C', metaKey: true }),
  116. preventDefault: vi.fn(),
  117. preventGridDefault: vi.fn(),
  118. } as unknown as Parameters<typeof handleCellKeyDown>[1]
  119. handleCellKeyDown(args, event)
  120. await vi.waitFor(() => {
  121. expect(writeText).toHaveBeenCalledWith('hello from safari')
  122. })
  123. expect(event.preventDefault).toHaveBeenCalled()
  124. expect(event.preventGridDefault).toHaveBeenCalled()
  125. await vi.waitFor(() => {
  126. expect(toastSuccess).toHaveBeenCalledWith('Copied cell value to clipboard')
  127. })
  128. })
  129. })
  130. describe('shared clipboard util', () => {
  131. beforeEach(() => {
  132. vi.unstubAllGlobals()
  133. vi.spyOn(window.document, 'hasFocus').mockReturnValue(true)
  134. })
  135. afterEach(() => {
  136. vi.unstubAllGlobals()
  137. vi.restoreAllMocks()
  138. })
  139. test('should invoke the callback after writing text to the clipboard', async () => {
  140. const writeText = vi.fn().mockResolvedValue(undefined)
  141. const onCopy = vi.fn()
  142. vi.stubGlobal('navigator', {
  143. clipboard: { writeText },
  144. })
  145. await copyToClipboard('hello from safari', onCopy)
  146. expect(writeText).toHaveBeenCalledWith('hello from safari')
  147. expect(onCopy).toHaveBeenCalled()
  148. })
  149. })