SidePanelEditor.utils.test.ts217 lines · main
1import { describe, expect, test } from 'vitest'
2
3import { formatRowsForInsert, getRowFromSidePanel } from './SidePanelEditor.utils'
4import type { SupaRow } from '@/components/grid/types'
5import type { SidePanel } from '@/state/table-editor'
6
7describe('SidePanelEditor.utils.test.ts', () => {
8 test('formatRowsForInsert should for format rows with basic data types correctly', () => {
9 const rows = [
10 { id: 1, text: 'A' },
11 { id: 2, text: 'B' },
12 { id: 3, text: 'C' },
13 ]
14 const headers = ['id', 'text']
15 const columns = [
16 { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
17 { id: '2', name: 'text', data_type: 'text', format: 'text', is_nullable: true },
18 ]
19
20 const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
21 expect(formattedRows).toEqual(rows)
22 })
23
24 test('formatRowsForInsert should handle nullable columns if value is an empty string', () => {
25 const rows = [
26 { id: 1, text: 'A' },
27 { id: 2, text: '' },
28 { id: 3, text: 'C' },
29 ]
30 const headers = ['id', 'text']
31 const columns = [
32 { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
33 { id: '2', name: 'text', data_type: 'text', format: 'text', is_nullable: true },
34 ]
35
36 const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
37 expect(formattedRows).toEqual([
38 { id: 1, text: 'A' },
39 { id: 2, text: null },
40 { id: 3, text: 'C' },
41 ])
42 })
43
44 test('formatRowsForInsert should only convert empty strings to null for selected columns', () => {
45 const rows = [
46 { id: 1, name: '', email: '' },
47 { id: 2, name: 'Bob', email: '' },
48 ]
49 const headers = ['id', 'name', 'email']
50 const columns = [
51 { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
52 { id: '2', name: 'name', data_type: 'text', format: 'text', is_nullable: true },
53 { id: '3', name: 'email', data_type: 'text', format: 'text', is_nullable: true },
54 ]
55
56 const formattedRows = formatRowsForInsert({
57 rows,
58 headers,
59 columns: columns as any,
60 emptyStringAsNullHeaders: ['email'],
61 })
62
63 expect(formattedRows).toEqual([
64 { id: 1, name: '', email: null },
65 { id: 2, name: 'Bob', email: null },
66 ])
67 })
68
69 test('formatRowsForInsert should handle JSON object values properly', () => {
70 const rows = [{ id: 1, value: '{"key": "value"}' }]
71 const headers = ['id', 'value']
72 const columns = [
73 { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
74 { id: '2', name: 'value', data_type: 'json', format: 'jsonb', is_nullable: true },
75 ]
76
77 const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
78 expect(formattedRows).toEqual([{ id: 1, value: { key: 'value' } }])
79 })
80
81 test('formatRowsForInsert should handle JSON array values properly', () => {
82 const rows = [{ id: 1, value: '["item1", "item2", "item3"]' }]
83 const headers = ['id', 'value']
84 const columns = [
85 { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
86 { id: '2', name: 'value', data_type: 'json', format: 'jsonb', is_nullable: true },
87 ]
88
89 const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
90 expect(formattedRows).toEqual([{ id: 1, value: ['item1', 'item2', 'item3'] }])
91 })
92
93 test('formatRowsForInsert should handle Postgres array values properly', () => {
94 const rows = [{ id: 1, value: '{"item1", "item2", "item3"}' }]
95 const headers = ['id', 'value']
96 const columns = [
97 { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
98 { id: '2', name: 'value', data_type: 'ARRAY', format: '_text', is_nullable: true },
99 ]
100
101 const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
102 expect(formattedRows).toEqual([{ id: 1, value: ['item1', 'item2', 'item3'] }])
103 })
104
105 test('formatRowsForInsert should handle Postgres array values properly if provided JSON string', () => {
106 const rows = [{ id: 1, value: '["item1", "item2", "item3"]' }]
107 const headers = ['id', 'value']
108 const columns = [
109 { id: '1', name: 'id', data_type: 'bigint', format: 'int8', is_nullable: false },
110 { id: '2', name: 'value', data_type: 'ARRAY', format: '_text', is_nullable: true },
111 ]
112
113 const formattedRows = formatRowsForInsert({ rows, headers, columns: columns as any })
114 expect(formattedRows).toEqual([{ id: 1, value: ['item1', 'item2', 'item3'] }])
115 })
116})
117
118describe('getRowFromSidePanel', () => {
119 const mockRow: SupaRow = { idx: 1, id: 123, name: 'Test Row' }
120
121 test('returns undefined when sidePanel is undefined', () => {
122 expect(getRowFromSidePanel(undefined)).toBeUndefined()
123 })
124
125 test('returns row from json side panel', () => {
126 const sidePanel: SidePanel = {
127 type: 'json',
128 jsonValue: { row: mockRow, column: 'data', value: '{}' },
129 }
130 expect(getRowFromSidePanel(sidePanel)).toEqual(mockRow)
131 })
132
133 test('returns row from cell side panel', () => {
134 const sidePanel: SidePanel = {
135 type: 'cell',
136 value: { row: mockRow, column: 'name' },
137 }
138 expect(getRowFromSidePanel(sidePanel)).toEqual(mockRow)
139 })
140
141 test('returns undefined from cell side panel when value is undefined', () => {
142 const sidePanel: SidePanel = {
143 type: 'cell',
144 }
145 expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
146 })
147
148 test('returns row from row side panel', () => {
149 const sidePanel: SidePanel = {
150 type: 'row',
151 row: mockRow,
152 }
153 expect(getRowFromSidePanel(sidePanel)).toEqual(mockRow)
154 })
155
156 test('returns undefined from row side panel when row is undefined', () => {
157 const sidePanel: SidePanel = {
158 type: 'row',
159 }
160 expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
161 })
162
163 test('returns row from foreign-row-selector side panel', () => {
164 const sidePanel: SidePanel = {
165 type: 'foreign-row-selector',
166 foreignKey: {
167 foreignKey: {
168 schema: 'public',
169 table: 'users',
170 columns: [{ source: 'user_id', target: 'id' }],
171 deletionAction: 'NO ACTION',
172 updateAction: 'NO ACTION',
173 },
174 row: mockRow,
175 column: { name: 'user_id' } as any,
176 },
177 }
178 expect(getRowFromSidePanel(sidePanel)).toEqual(mockRow)
179 })
180
181 test('returns undefined for table side panel', () => {
182 const sidePanel: SidePanel = {
183 type: 'table',
184 mode: 'new',
185 }
186 expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
187 })
188
189 test('returns undefined for column side panel', () => {
190 const sidePanel: SidePanel = {
191 type: 'column',
192 }
193 expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
194 })
195
196 test('returns undefined for schema side panel', () => {
197 const sidePanel: SidePanel = {
198 type: 'schema',
199 mode: 'new',
200 }
201 expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
202 })
203
204 test('returns undefined for csv-import side panel', () => {
205 const sidePanel: SidePanel = {
206 type: 'csv-import',
207 }
208 expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
209 })
210
211 test('returns undefined for operation-queue side panel', () => {
212 const sidePanel: SidePanel = {
213 type: 'operation-queue',
214 }
215 expect(getRowFromSidePanel(sidePanel)).toBeUndefined()
216 })
217})