@@ -7,14 +7,21 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
77import type { TableInfo , TableRow } from '@/lib/table'
88import { RowModal } from '@/app/workspace/[workspaceId]/tables/[tableId]/components/row-modal/row-modal'
99
10- const { mockToastError, mockUseTimezoneState, mockUpdateRow, mockDeleteRow, mockDeleteRows } =
11- vi . hoisted ( ( ) => ( {
12- mockToastError : vi . fn ( ) ,
13- mockUseTimezoneState : vi . fn ( ) ,
14- mockUpdateRow : vi . fn ( ) ,
15- mockDeleteRow : vi . fn ( ) ,
16- mockDeleteRows : vi . fn ( ) ,
17- } ) )
10+ const {
11+ mockToastError,
12+ mockUseTimezoneState,
13+ mockCreateRow,
14+ mockUpdateRow,
15+ mockDeleteRow,
16+ mockDeleteRows,
17+ } = vi . hoisted ( ( ) => ( {
18+ mockToastError : vi . fn ( ) ,
19+ mockUseTimezoneState : vi . fn ( ) ,
20+ mockCreateRow : vi . fn ( ) ,
21+ mockUpdateRow : vi . fn ( ) ,
22+ mockDeleteRow : vi . fn ( ) ,
23+ mockDeleteRows : vi . fn ( ) ,
24+ } ) )
1825
1926vi . mock ( 'next/navigation' , ( ) => ( {
2027 useParams : ( ) => ( { workspaceId : 'workspace-1' } ) ,
@@ -23,6 +30,7 @@ vi.mock('@/hooks/queries/general-settings', () => ({
2330 useTimezoneState : mockUseTimezoneState ,
2431} ) )
2532vi . mock ( '@/hooks/queries/tables' , ( ) => ( {
33+ useCreateTableRow : ( ) => ( { mutateAsync : mockCreateRow , isPending : false } ) ,
2634 useUpdateTableRow : ( ) => ( { mutateAsync : mockUpdateRow , isPending : false } ) ,
2735 useDeleteTableRow : ( ) => ( { mutateAsync : mockDeleteRow , isPending : false } ) ,
2836 useDeleteTableRows : ( ) => ( { mutateAsync : mockDeleteRows , isPending : false } ) ,
@@ -35,11 +43,12 @@ vi.mock('@sim/emcn', () => {
3543 createElement ( 'button' , { type : 'button' , ...props } , children ) ,
3644 ChipConfirmModal : passthrough ,
3745 ChipDatePicker : ( { value, onChange } : { value ?: string ; onChange : ( value : string ) => void } ) =>
38- createElement (
39- 'button' ,
40- { type : 'button' , 'data-testid' : 'date' , onClick : ( ) => onChange ( value ?? '2026-11-01' ) } ,
41- value
42- ) ,
46+ createElement ( 'input' , {
47+ 'data-testid' : 'date' ,
48+ value : value ?? '' ,
49+ onChange : ( event : { currentTarget : { value : string } } ) =>
50+ onChange ( event . currentTarget . value ) ,
51+ } ) ,
4352 ChipModal : passthrough ,
4453 ChipModalBody : passthrough ,
4554 ChipModalError : passthrough ,
@@ -80,13 +89,6 @@ vi.mock('@sim/emcn', () => {
8089 'Update Row'
8190 ) ,
8291 ChipModalHeader : passthrough ,
83- ChipTimePicker : ( { value, onChange } : { value ?: string ; onChange : ( value : string ) => void } ) =>
84- createElement ( 'input' , {
85- 'data-testid' : 'time' ,
86- value : value ?? '' ,
87- onChange : ( event : { currentTarget : { value : string } } ) =>
88- onChange ( event . currentTarget . value ) ,
89- } ) ,
9092 Label : passthrough ,
9193 toast : { error : mockToastError } ,
9294 }
@@ -113,6 +115,85 @@ function changeInput(input: HTMLInputElement, value: string) {
113115 input . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) )
114116}
115117
118+ describe ( 'RowModal add mode' , ( ) => {
119+ beforeEach ( ( ) => {
120+ vi . clearAllMocks ( )
121+ mockCreateRow . mockResolvedValue ( undefined )
122+ mockUseTimezoneState . mockReturnValue ( { timezone : 'America/Los_Angeles' , status : 'ready' } )
123+ } )
124+
125+ it ( 'inserts the complete row under column ids in one request without updating' , async ( ) => {
126+ const container = document . createElement ( 'div' )
127+ document . body . appendChild ( container )
128+ const root = createRoot ( container )
129+ const props = {
130+ mode : 'add' as const ,
131+ isOpen : true ,
132+ onClose : vi . fn ( ) ,
133+ table : {
134+ id : 'table-3' ,
135+ name : 'People' ,
136+ schema : { columns : [ { id : 'col_name' , name : 'Name' , type : 'string' as const } ] } ,
137+ } ,
138+ onSuccess : vi . fn ( ) ,
139+ }
140+
141+ ; ( globalThis as { IS_REACT_ACT_ENVIRONMENT ?: boolean } ) . IS_REACT_ACT_ENVIRONMENT = true
142+ act ( ( ) => root . render ( createElement ( RowModal , props ) ) )
143+
144+ const nameInput = container . querySelector < HTMLInputElement > ( '[data-testid="modal-input"]' )
145+ expect ( nameInput ?. value ) . toBe ( '' )
146+ act ( ( ) => changeInput ( nameInput as HTMLInputElement , 'Ada' ) )
147+ const submit = container . querySelector < HTMLButtonElement > ( '[data-testid="submit"]' )
148+ await act ( async ( ) => submit ?. click ( ) )
149+
150+ expect ( mockCreateRow ) . toHaveBeenCalledWith ( { data : { col_name : 'Ada' } } )
151+ expect ( mockUpdateRow ) . not . toHaveBeenCalled ( )
152+ expect ( props . onSuccess ) . toHaveBeenCalledTimes ( 1 )
153+
154+ act ( ( ) => root . unmount ( ) )
155+ container . remove ( )
156+ } )
157+ } )
158+
159+ describe ( 'RowModal column ids' , ( ) => {
160+ beforeEach ( ( ) => {
161+ vi . clearAllMocks ( )
162+ mockUpdateRow . mockResolvedValue ( undefined )
163+ mockUseTimezoneState . mockReturnValue ( { timezone : 'America/Los_Angeles' , status : 'ready' } )
164+ } )
165+
166+ it ( 'shows and saves edit values stored under the column id' , async ( ) => {
167+ const container = document . createElement ( 'div' )
168+ document . body . appendChild ( container )
169+ const root = createRoot ( container )
170+ const props = {
171+ mode : 'edit' as const ,
172+ isOpen : true ,
173+ onClose : vi . fn ( ) ,
174+ table : {
175+ id : 'table-4' ,
176+ name : 'People' ,
177+ schema : { columns : [ { id : 'col_name' , name : 'Name' , type : 'string' as const } ] } ,
178+ } ,
179+ row : { ...row , data : { col_name : 'Ada' } } ,
180+ onSuccess : vi . fn ( ) ,
181+ }
182+
183+ act ( ( ) => root . render ( createElement ( RowModal , props ) ) )
184+
185+ const nameInput = container . querySelector < HTMLInputElement > ( '[data-testid="modal-input"]' )
186+ expect ( nameInput ?. value ) . toBe ( 'Ada' )
187+ act ( ( ) => changeInput ( nameInput as HTMLInputElement , 'Grace' ) )
188+ const submit = container . querySelector < HTMLButtonElement > ( '[data-testid="submit"]' )
189+ await act ( async ( ) => submit ?. click ( ) )
190+
191+ expect ( mockUpdateRow ) . toHaveBeenCalledWith ( { rowId : 'row-1' , data : { col_name : 'Grace' } } )
192+ act ( ( ) => root . unmount ( ) )
193+ container . remove ( )
194+ } )
195+ } )
196+
116197describe ( 'RowModal expiration editing' , ( ) => {
117198 beforeEach ( ( ) => {
118199 vi . clearAllMocks ( )
@@ -136,7 +217,9 @@ describe('RowModal expiration editing', () => {
136217 ; ( globalThis as { IS_REACT_ACT_ENVIRONMENT ?: boolean } ) . IS_REACT_ACT_ENVIRONMENT = true
137218 act ( ( ) => root . render ( createElement ( RowModal , props ) ) )
138219
139- expect ( container . querySelector < HTMLInputElement > ( '[data-testid="time"]' ) ?. value ) . toBe ( '01:00' )
220+ expect ( container . querySelector < HTMLInputElement > ( '[data-testid="date"]' ) ?. value ) . toBe (
221+ '2026-11-01T01:00:00'
222+ )
140223 expect ( container . querySelector < HTMLButtonElement > ( '[data-testid="submit"]' ) ?. disabled ) . toBe (
141224 false
142225 )
@@ -153,9 +236,9 @@ describe('RowModal expiration editing', () => {
153236 } )
154237 act ( ( ) => root . render ( createElement ( RowModal , props ) ) )
155238
156- const timeInput = container . querySelector < HTMLInputElement > ( '[data-testid="time "]' )
157- expect ( timeInput ?. value ) . toBe ( '01 :00' )
158- act ( ( ) => changeInput ( timeInput as HTMLInputElement , '01 :30' ) )
239+ const dateInput = container . querySelector < HTMLInputElement > ( '[data-testid="date "]' )
240+ expect ( dateInput ?. value ) . toBe ( '2026-11-01T01:00 :00' )
241+ act ( ( ) => changeInput ( dateInput as HTMLInputElement , '2026-11-01T01 :30' ) )
159242
160243 const submit = container . querySelector < HTMLButtonElement > ( '[data-testid="submit"]' )
161244 await act ( async ( ) => submit ?. click ( ) )
@@ -193,15 +276,15 @@ describe('RowModal expiration editing', () => {
193276 expect ( container . querySelector ( '[aria-label="Edit starts_at"]' ) ?. textContent ) . toBe (
194277 'Loading timezone…'
195278 )
196- expect ( container . querySelector < HTMLInputElement > ( '[data-testid="time "]' ) ) . toBeNull ( )
279+ expect ( container . querySelector < HTMLInputElement > ( '[data-testid="date "]' ) ) . toBeNull ( )
197280
198281 mockUseTimezoneState . mockReturnValue ( {
199282 timezone : 'America/Los_Angeles' ,
200283 status : 'ready' ,
201284 } )
202285 act ( ( ) => root . render ( createElement ( RowModal , props ) ) )
203286
204- expect ( container . querySelector < HTMLInputElement > ( '[data-testid="time "]' ) ) . not . toBeNull ( )
287+ expect ( container . querySelector < HTMLInputElement > ( '[data-testid="date "]' ) ) . not . toBeNull ( )
205288 act ( ( ) => root . unmount ( ) )
206289 container . remove ( )
207290 } )
@@ -226,7 +309,9 @@ describe('RowModal expiration editing', () => {
226309
227310 act ( ( ) => root . render ( createElement ( RowModal , props ) ) )
228311
229- expect ( container . querySelector < HTMLInputElement > ( '[data-testid="time"]' ) ?. value ) . toBe ( '01:00' )
312+ expect ( container . querySelector < HTMLInputElement > ( '[data-testid="date"]' ) ?. value ) . toBe (
313+ '2026-11-01T01:00:00'
314+ )
230315 expect ( container . querySelector < HTMLButtonElement > ( '[data-testid="submit"]' ) ?. disabled ) . toBe (
231316 false
232317 )
0 commit comments