Skip to content

Commit 0c9827b

Browse files
committed
test(table): share one table-definition fixture factory
buildTable was copy-pasted into 13 route test files under app/api/table, each a near-identical TableDefinition literal. A required field added to that type would have failed 13 files individually. packages/testing already owned createTableColumn and createTableRow but no definition factory, and — as it turns out — did not export any of them from the barrel, so they were unreachable from @sim/testing. Adds createTableDefinition beside them and exports all three. The fixture type is a structural stand-in rather than TableDefinition itself, because packages/* must not import from apps/* — the same approach the existing factories in that file already take. No assertion changed. Call sites that varied a field pass it as an override; the four files with several call sites hoist a shared options const and spread it so each call still gets a fresh object.
1 parent 465cea2 commit 0c9827b

15 files changed

Lines changed: 255 additions & 299 deletions

File tree

apps/sim/app/api/table/[tableId]/delete-async/route.test.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { hybridAuthMockFns, resetEnvFlagsMock, setEnvFlags } from '@sim/testing'
4+
import {
5+
createTableDefinition,
6+
hybridAuthMockFns,
7+
resetEnvFlagsMock,
8+
setEnvFlags,
9+
type TableDefinitionFactoryOptions,
10+
} from '@sim/testing'
511
import { NextRequest, NextResponse } from 'next/server'
612
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
7-
import type { TableDefinition } from '@/lib/table'
813

914
const {
1015
mockCheckAccess,
@@ -58,22 +63,9 @@ import { POST } from '@/app/api/table/[tableId]/delete-async/route'
5863

5964
afterAll(resetEnvFlagsMock)
6065

61-
function buildTable(overrides: Partial<TableDefinition> = {}): TableDefinition {
62-
return {
63-
id: 'tbl_1',
64-
name: 'People',
65-
description: null,
66-
schema: { columns: [{ name: 'status', type: 'string' }] },
67-
metadata: null,
68-
rowCount: 1000,
69-
maxRows: 1_000_000,
70-
workspaceId: 'workspace-1',
71-
createdBy: 'user-1',
72-
archivedAt: null,
73-
createdAt: new Date(),
74-
updatedAt: new Date(),
75-
...overrides,
76-
}
66+
const TABLE_FIXTURE: TableDefinitionFactoryOptions = {
67+
columns: [{ name: 'status', type: 'string' }],
68+
rowCount: 1000,
7769
}
7870

7971
function makeRequest(body: unknown, tableId = 'tbl_1') {
@@ -99,7 +91,7 @@ describe('POST /api/table/[tableId]/delete-async', () => {
9991
userId: 'user-1',
10092
authType: 'session',
10193
})
102-
mockCheckAccess.mockResolvedValue({ ok: true, table: buildTable() })
94+
mockCheckAccess.mockResolvedValue({ ok: true, table: createTableDefinition(TABLE_FIXTURE) })
10395
mockMarkTableJobRunning.mockResolvedValue(true)
10496
mockRunTableDelete.mockResolvedValue(undefined)
10597
mockTableFilterError.mockReturnValue(null)
@@ -168,7 +160,10 @@ describe('POST /api/table/[tableId]/delete-async', () => {
168160
})
169161

170162
it('returns 400 when the table is archived', async () => {
171-
mockCheckAccess.mockResolvedValue({ ok: true, table: buildTable({ archivedAt: new Date() }) })
163+
mockCheckAccess.mockResolvedValue({
164+
ok: true,
165+
table: createTableDefinition({ ...TABLE_FIXTURE, archivedAt: new Date() }),
166+
})
172167
const response = await makeRequest(validBody)
173168
expect(response.status).toBe(400)
174169
expect(mockRunTableDelete).not.toHaveBeenCalled()

apps/sim/app/api/table/[tableId]/dispatches/route.test.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { hybridAuthMockFns } from '@sim/testing'
4+
import { createTableDefinition, hybridAuthMockFns } from '@sim/testing'
55
import { NextRequest } from 'next/server'
66
import { beforeEach, describe, expect, it, vi } from 'vitest'
7-
import type { TableDefinition } from '@/lib/table'
87

98
const { mockCheckAccess, mockListActiveDispatches, mockCountRunningCells } = vi.hoisted(() => ({
109
mockCheckAccess: vi.fn(),
@@ -27,24 +26,6 @@ vi.mock('@/app/api/table/utils', async () => {
2726

2827
import { GET } from '@/app/api/table/[tableId]/dispatches/route'
2928

30-
function buildTable(overrides: Partial<TableDefinition> = {}): TableDefinition {
31-
return {
32-
id: 'tbl_1',
33-
name: 'People',
34-
description: null,
35-
schema: { columns: [] },
36-
metadata: null,
37-
rowCount: 0,
38-
maxRows: 1_000_000,
39-
workspaceId: 'workspace-1',
40-
createdBy: 'user-1',
41-
archivedAt: null,
42-
createdAt: new Date(),
43-
updatedAt: new Date(),
44-
...overrides,
45-
}
46-
}
47-
4829
function makeRequest(tableId = 'tbl_1') {
4930
const req = new NextRequest(`http://localhost:3000/api/table/${tableId}/dispatches`)
5031
return GET(req, { params: Promise.resolve({ tableId }) })
@@ -75,7 +56,7 @@ describe('GET /api/table/[tableId]/dispatches', () => {
7556
userId: 'user-1',
7657
authType: 'session',
7758
})
78-
mockCheckAccess.mockResolvedValue({ ok: true, table: buildTable() })
59+
mockCheckAccess.mockResolvedValue({ ok: true, table: createTableDefinition() })
7960
mockListActiveDispatches.mockResolvedValue([])
8061
mockCountRunningCells.mockResolvedValue({ byRowId: {}, hasRunning: false })
8162
})

apps/sim/app/api/table/[tableId]/export-async/route.test.ts

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { hybridAuthMockFns } from '@sim/testing'
4+
import { createTableDefinition, hybridAuthMockFns } from '@sim/testing'
55
import { NextRequest } from 'next/server'
66
import { beforeEach, describe, expect, it, vi } from 'vitest'
7-
import type { TableDefinition } from '@/lib/table'
87

98
const { mockCheckAccess, mockMarkTableJobRunning, mockRunTableExport } = vi.hoisted(() => ({
109
mockCheckAccess: vi.fn(),
@@ -34,24 +33,6 @@ vi.mock('@/app/api/table/utils', async () => {
3433

3534
import { POST } from '@/app/api/table/[tableId]/export-async/route'
3635

37-
function buildTable(overrides: Partial<TableDefinition> = {}): TableDefinition {
38-
return {
39-
id: 'tbl_1',
40-
name: 'People',
41-
description: null,
42-
schema: { columns: [{ name: 'name', type: 'string' }] },
43-
metadata: null,
44-
rowCount: 50000,
45-
maxRows: 1_000_000,
46-
workspaceId: 'workspace-1',
47-
createdBy: 'user-1',
48-
archivedAt: null,
49-
createdAt: new Date(),
50-
updatedAt: new Date(),
51-
...overrides,
52-
}
53-
}
54-
5536
function makeRequest(body: unknown, tableId = 'tbl_1') {
5637
const req = new NextRequest(`http://localhost:3000/api/table/${tableId}/export-async`, {
5738
method: 'POST',
@@ -71,7 +52,13 @@ describe('POST /api/table/[tableId]/export-async', () => {
7152
userId: 'user-1',
7253
authType: 'session',
7354
})
74-
mockCheckAccess.mockResolvedValue({ ok: true, table: buildTable() })
55+
mockCheckAccess.mockResolvedValue({
56+
ok: true,
57+
table: createTableDefinition({
58+
columns: [{ name: 'name', type: 'string' }],
59+
rowCount: 50000,
60+
}),
61+
})
7562
mockMarkTableJobRunning.mockResolvedValue(true)
7663
mockRunTableExport.mockResolvedValue(undefined)
7764
})

apps/sim/app/api/table/[tableId]/export/download/route.test.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { hybridAuthMockFns } from '@sim/testing'
4+
import { createTableDefinition, hybridAuthMockFns } from '@sim/testing'
55
import { NextRequest } from 'next/server'
66
import { beforeEach, describe, expect, it, vi } from 'vitest'
7-
import type { TableDefinition } from '@/lib/table'
87

98
const { mockCheckAccess, mockGetTableJob, mockGeneratePresignedDownloadUrl } = vi.hoisted(() => ({
109
mockCheckAccess: vi.fn(),
@@ -27,24 +26,6 @@ vi.mock('@/app/api/table/utils', async () => {
2726

2827
import { GET } from '@/app/api/table/[tableId]/export/download/route'
2928

30-
function buildTable(overrides: Partial<TableDefinition> = {}): TableDefinition {
31-
return {
32-
id: 'tbl_1',
33-
name: 'People',
34-
description: null,
35-
schema: { columns: [] },
36-
metadata: null,
37-
rowCount: 0,
38-
maxRows: 1_000_000,
39-
workspaceId: 'workspace-1',
40-
createdBy: 'user-1',
41-
archivedAt: null,
42-
createdAt: new Date(),
43-
updatedAt: new Date(),
44-
...overrides,
45-
}
46-
}
47-
4829
function makeRequest(query: Record<string, string>, tableId = 'tbl_1') {
4930
const qs = new URLSearchParams(query).toString()
5031
const req = new NextRequest(`http://localhost:3000/api/table/${tableId}/export/download?${qs}`)
@@ -61,7 +42,7 @@ describe('GET /api/table/[tableId]/export/download', () => {
6142
userId: 'user-1',
6243
authType: 'session',
6344
})
64-
mockCheckAccess.mockResolvedValue({ ok: true, table: buildTable() })
45+
mockCheckAccess.mockResolvedValue({ ok: true, table: createTableDefinition() })
6546
mockGetTableJob.mockResolvedValue({
6647
id: 'job_1',
6748
type: 'export',

apps/sim/app/api/table/[tableId]/export/route.test.ts

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { hybridAuthMockFns } from '@sim/testing'
4+
import { createTableDefinition, hybridAuthMockFns } from '@sim/testing'
55
import { NextRequest } from 'next/server'
66
import { beforeEach, describe, expect, it, vi } from 'vitest'
7-
import type { TableDefinition } from '@/lib/table'
87

98
const { mockCheckAccess, mockQueryRows } = vi.hoisted(() => ({
109
mockCheckAccess: vi.fn(),
@@ -27,27 +26,6 @@ vi.mock('@/lib/table/rows/service', () => ({
2726
import { GET } from '@/app/api/table/[tableId]/export/route'
2827

2928
/** Table with an id-native column whose stable id (`col_email`) differs from its display name. */
30-
function buildTable(): TableDefinition {
31-
return {
32-
id: 'tbl_1',
33-
name: 'People',
34-
description: null,
35-
schema: {
36-
columns: [
37-
{ id: 'col_email', name: 'email', type: 'string' },
38-
{ name: 'legacy', type: 'string' }, // legacy: id == name
39-
],
40-
},
41-
metadata: null,
42-
rowCount: 1,
43-
maxRows: 100,
44-
workspaceId: 'workspace-1',
45-
createdBy: 'user-1',
46-
archivedAt: null,
47-
createdAt: new Date('2024-01-01'),
48-
updatedAt: new Date('2024-01-01'),
49-
}
50-
}
5129

5230
function callGet(format: string) {
5331
const req = new NextRequest(`http://localhost:3000/api/table/tbl_1/export?format=${format}`, {
@@ -64,7 +42,19 @@ describe('table export route — id→name translation', () => {
6442
userId: 'user-1',
6543
authType: 'session',
6644
})
67-
mockCheckAccess.mockResolvedValue({ ok: true, table: buildTable() })
45+
mockCheckAccess.mockResolvedValue({
46+
ok: true,
47+
table: createTableDefinition({
48+
columns: [
49+
{ id: 'col_email', name: 'email', type: 'string' },
50+
{ name: 'legacy', type: 'string' }, // legacy: id == name
51+
],
52+
rowCount: 1,
53+
maxRows: 100,
54+
createdAt: new Date('2024-01-01'),
55+
updatedAt: new Date('2024-01-01'),
56+
}),
57+
})
6858
// Row data is keyed by stable column id (`col_email`), not the display name.
6959
mockQueryRows.mockResolvedValue({
7060
rows: [{ id: 'r1', data: { col_email: 'a@b.c', legacy: 'x' }, executions: {}, position: 0 }],

apps/sim/app/api/table/[tableId]/import-async/route.test.ts

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import { hybridAuthMockFns } from '@sim/testing'
4+
import {
5+
createTableDefinition,
6+
hybridAuthMockFns,
7+
type TableDefinitionFactoryOptions,
8+
} from '@sim/testing'
59
import { NextRequest } from 'next/server'
610
import { beforeEach, describe, expect, it, vi } from 'vitest'
7-
import type { TableDefinition } from '@/lib/table'
811

912
const { mockCheckAccess, mockMarkTableImporting, mockRunTableImport } = vi.hoisted(() => ({
1013
mockCheckAccess: vi.fn(),
@@ -34,22 +37,8 @@ vi.mock('@/app/api/table/utils', async () => {
3437

3538
import { POST } from '@/app/api/table/[tableId]/import-async/route'
3639

37-
function buildTable(overrides: Partial<TableDefinition> = {}): TableDefinition {
38-
return {
39-
id: 'tbl_1',
40-
name: 'People',
41-
description: null,
42-
schema: { columns: [{ name: 'name', type: 'string' }] },
43-
metadata: null,
44-
rowCount: 0,
45-
maxRows: 1_000_000,
46-
workspaceId: 'workspace-1',
47-
createdBy: 'user-1',
48-
archivedAt: null,
49-
createdAt: new Date(),
50-
updatedAt: new Date(),
51-
...overrides,
52-
}
40+
const TABLE_FIXTURE: TableDefinitionFactoryOptions = {
41+
columns: [{ name: 'name', type: 'string' }],
5342
}
5443

5544
function makeRequest(body: unknown, tableId = 'tbl_1') {
@@ -76,7 +65,7 @@ describe('POST /api/table/[tableId]/import-async', () => {
7665
userId: 'user-1',
7766
authType: 'session',
7867
})
79-
mockCheckAccess.mockResolvedValue({ ok: true, table: buildTable() })
68+
mockCheckAccess.mockResolvedValue({ ok: true, table: createTableDefinition(TABLE_FIXTURE) })
8069
mockMarkTableImporting.mockResolvedValue(true)
8170
mockRunTableImport.mockResolvedValue(undefined)
8271
})
@@ -126,7 +115,10 @@ describe('POST /api/table/[tableId]/import-async', () => {
126115
})
127116

128117
it('returns 400 when the target table is archived', async () => {
129-
mockCheckAccess.mockResolvedValue({ ok: true, table: buildTable({ archivedAt: new Date() }) })
118+
mockCheckAccess.mockResolvedValue({
119+
ok: true,
120+
table: createTableDefinition({ ...TABLE_FIXTURE, archivedAt: new Date() }),
121+
})
130122
const response = await makeRequest(validBody)
131123
expect(response.status).toBe(400)
132124
expect(mockRunTableImport).not.toHaveBeenCalled()

0 commit comments

Comments
 (0)