Skip to content

Commit bb59bdf

Browse files
test(dashboards): drop mock-call and rendered-text assertions
Removes assertions on mocked collaborators and rendered text from the dashboard, chart and analytics tests per the repository testing rules, keeping the observable checks (status codes, thrown errors, DOM roles, computed summaries, emitted zoom ranges). Deletes the animated-number test, which had no behavior left to assert. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6aTRnkiu7PxYZPNPXYEMV
1 parent 8e34901 commit bb59bdf

9 files changed

Lines changed: 34 additions & 210 deletions

File tree

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

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,16 @@ describe('analytics HTTP adapter', () => {
4444
it('authenticates before parsing and never uses a file share as authority', async () => {
4545
mocks.session.mockResolvedValue(null)
4646
expect((await POST(request({ invalid: true }), context)).status).toBe(401)
47-
expect(mocks.execute).not.toHaveBeenCalled()
4847
})
4948
it('validates the contract before the use case', async () => {
5049
expect(
5150
(await POST(request({ ...body, query: { ...body.query, sql: 'select *' } }), context)).status
5251
).toBe(400)
53-
expect(mocks.execute).not.toHaveBeenCalled()
5452
})
55-
it('forwards the viewer and asserted scope and emits a private response', async () => {
53+
it('emits a private response', async () => {
5654
const response = await POST(request(body), context)
5755
expect(response.status).toBe(200)
5856
expect(response.headers.get('cache-control')).toBe('private, no-store')
5957
expect(await response.json()).toMatchObject({ rows: [{ n: 0 }], truncated: false })
60-
expect(mocks.execute).toHaveBeenCalledWith(
61-
expect.objectContaining({
62-
principal: { kind: 'session', userId: 'viewer', sessionId: 'session' },
63-
input: { tableId: 'tbl_test', assertedWorkspaceId: 'workspace_test', query: body.query },
64-
})
65-
)
66-
expect(mocks.limit).toHaveBeenCalledWith('table-analytics', 'viewer', expect.any(Object))
6758
})
6859
})

‎apps/sim/components/charts/echarts-view.test.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ describe('EChartsView updates', () => {
6969
throw new Error('Invalid chart option')
7070
})
7171
await render(12)
72-
expect(container.querySelector('[role="alert"]')?.textContent).toBe('Invalid chart option')
72+
expect(container.querySelector('[role="alert"]')).not.toBeNull()
7373
await render(6)
7474
expect(container.querySelector('[role="alert"]')).toBeNull()
7575
})

‎apps/sim/components/dashboards/dashboard-panel.test.tsx‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ describe('dashboard empty-range transitions', () => {
6868
expect(chart).not.toBeNull()
6969
await render([])
7070
expect(container.querySelector('[role="img"]')).toBe(chart)
71-
expect(container.textContent).toContain('No data in this time range')
7271
await render([{ total: 12 }])
7372
expect(container.querySelector('[role="img"]')).toBe(chart)
74-
expect(container.textContent).not.toContain('No data in this time range')
7573
})
7674
})

‎apps/sim/lib/charts/summary.test.ts‎

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** @vitest-environment jsdom */
22
import * as echarts from 'echarts'
3-
import { describe, expect, it, vi } from 'vitest'
3+
import { describe, expect, it } from 'vitest'
44
import {
55
chartSummaryExtension,
66
formatChartValue,
@@ -74,8 +74,10 @@ describe('resolved chart summaries', () => {
7474

7575
it('keeps missing data distinct from actual zero and excludes hidden legend series', () => {
7676
const chart = makeChart()
77-
const read = vi.fn()
78-
const stop = observeChartSummary(chart, (model) => read(summarizeChart(model, {})))
77+
let summary: ChartReadout | null = null
78+
const stop = observeChartSummary(chart, (model) => {
79+
summary = summarizeChart(model, {})
80+
})
7981
chart.setOption({
8082
animation: false,
8183
legend: { selected: { Hidden: false } },
@@ -94,32 +96,28 @@ describe('resolved chart summaries', () => {
9496
{ name: 'Hidden', type: 'line', data: [['2026-09-20', 100]] },
9597
],
9698
})
97-
expect(
98-
read.mock.lastCall![0].values.map(({ name, value }: { name: string; value: string }) => ({
99-
name,
100-
value,
101-
}))
102-
).toEqual([
103-
{ name: 'Zero', value: '0%' },
104-
{ name: 'Missing', value: '—' },
105-
])
99+
expect(summary).toMatchObject({
100+
values: [
101+
{ name: 'Zero', value: '0%' },
102+
{ name: 'Missing', value: '—' },
103+
],
104+
})
106105
stop()
107-
read.mockClear()
108-
chart.resize({ width: 700 })
109-
expect(read).not.toHaveBeenCalled()
110106
chart.dispose()
111107
})
112108

113109
it('restores a summary after hover and recomputes it on new data', () => {
114110
const chart = makeChart()
115-
const onReadout = vi.fn()
111+
let readout: ChartReadout | null = null
116112
const controller = bindTimeSeriesInteractions(chart, {
117113
range: { from: '2026-09-20T00:00:00Z', to: '2026-09-22T00:00:00Z' },
118114
firstTime: Date.parse('2026-09-20'),
119115
timeZone: 'UTC',
120116
columnLabels: {},
121117
cursorStore: createDashboardCursorStore(),
122-
onReadout,
118+
onReadout: (next) => {
119+
readout = next
120+
},
123121
})
124122
const option = (value: number) =>
125123
controller.prepareOption({
@@ -139,16 +137,16 @@ describe('resolved chart summaries', () => {
139137
})
140138
chart.setOption(option(2))
141139
controller.afterUpdate()
142-
expect(onReadout.mock.lastCall![0]).toMatchObject({
140+
expect(readout).toMatchObject({
143141
time: null,
144142
values: [{ value: '5', summary: 'Total' }],
145143
})
146144
chart.dispatchAction({ type: 'showTip', seriesIndex: 0, dataIndex: 0 })
147145
chart.dispatchAction({ type: 'hideTip' })
148-
expect(onReadout.mock.lastCall![0].values[0].value).toBe('5')
146+
expect(readout).toMatchObject({ values: [{ value: '5' }] })
149147
chart.setOption(option(7), { notMerge: true })
150148
controller.afterUpdate()
151-
expect(onReadout.mock.lastCall![0].values[0].value).toBe('10')
149+
expect(readout).toMatchObject({ values: [{ value: '10' }] })
152150
controller.dispose()
153151
chart.dispose()
154152
})

‎apps/sim/lib/charts/time-series.test.ts‎

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,13 @@ describe('time chart interactions', () => {
8484
it('shows timestamp and decimal values only in the hovered chart tooltip', () => {
8585
const { instance } = makeChart('one')
8686
const store = createDashboardCursorStore()
87-
const onReadout = vi.fn()
8887
const controller = bindTimeSeriesInteractions(instance, {
8988
range,
9089
timeZone: 'America/Los_Angeles',
9190
cursorStore: store,
9291
columnLabels: {},
9392
firstTime: time,
94-
onReadout,
93+
onReadout: () => {},
9594
})
9695
const option = controller.prepareOption({
9796
xAxis: { type: 'time' },
@@ -113,11 +112,10 @@ describe('time chart interactions', () => {
113112
expect(tooltip.formatter(params)).toBe('Sep 20, 17:00 PDT\nResolved: 71.63%')
114113
store.getState().setCursor({ owner: 'other', group: `${range.from}/${range.to}`, time })
115114
expect(tooltip.formatter(params)).toBe('')
116-
expect(onReadout).toHaveBeenLastCalledWith(expect.objectContaining({ time }))
117115
controller.dispose()
118116
expect(tooltip.formatter(params)).toBe('')
119117
})
120-
it('synchronizes by timestamp without feedback loops, isolates other ranges, and cleans up', () => {
118+
it('shares the hovered timestamp through the cursor store and clears it on leave', () => {
121119
const store = createDashboardCursorStore()
122120
const first = makeChart('one')
123121
const second = makeChart('two')
@@ -128,7 +126,7 @@ describe('time chart interactions', () => {
128126
cursorStore: store,
129127
columnLabels: {},
130128
firstTime: time,
131-
onReadout: vi.fn(),
129+
onReadout: () => {},
132130
}
133131
const bindings = [
134132
bindTimeSeriesInteractions(first.instance, config),
@@ -140,44 +138,27 @@ describe('time chart interactions', () => {
140138
]
141139
first.handlers.get('updateAxisPointer')?.({ axesInfo: [{ axisDim: 'x', value: time }] })
142140
expect(store.getState().cursor?.owner).toBe('one')
143-
expect(second.chart.dispatchAction).toHaveBeenCalledTimes(1)
144-
expect(second.chart.dispatchAction).toHaveBeenCalledWith({
145-
type: 'updateAxisPointer',
146-
x: time / 10000,
147-
y: 110,
148-
})
149-
expect(third.chart.dispatchAction).not.toHaveBeenCalledWith(
150-
expect.objectContaining({ x: time / 10000, type: 'updateAxisPointer' })
151-
)
152141
first.handlers.get('hideTip')?.({})
153142
expect(store.getState().cursor).toBeNull()
154143
bindings.forEach((binding) => binding.dispose())
155-
expect(second.handlers.size).toBe(0)
156-
second.chart.dispatchAction.mockClear()
157-
store.getState().setCursor({ owner: 'other', group: `${range.from}/${range.to}`, time })
158-
expect(second.chart.dispatchAction).not.toHaveBeenCalled()
159144
})
160-
it('queries only after a meaningful completed brush, clears it, and ignores clicks', () => {
161-
const { instance, handlers, chart } = makeChart('one')
162-
const onZoom = vi.fn()
145+
it('zooms only after a meaningful completed brush and ignores clicks', () => {
146+
const { instance, handlers } = makeChart('one')
147+
const zooms: unknown[] = []
163148
const controller = bindTimeSeriesInteractions(instance, {
164149
range,
165150
timeZone: 'UTC',
166151
cursorStore: createDashboardCursorStore(),
167152
columnLabels: {},
168153
firstTime: time,
169-
onReadout: vi.fn(),
170-
onZoom,
154+
onReadout: () => {},
155+
onZoom: (zoom) => zooms.push(zoom),
171156
})
172157
expect(handlers.has('brush')).toBe(false)
173158
handlers.get('brushEnd')?.({ areas: [{ coordRange: [time, time + 3600000], range: [30, 31] }] })
174-
expect(onZoom).not.toHaveBeenCalled()
159+
expect(zooms).toEqual([])
175160
handlers.get('brushEnd')?.({ areas: [{ coordRange: [time + 3600000, time], range: [80, 30] }] })
176-
expect(onZoom).toHaveBeenCalledExactlyOnceWith({
177-
from: '2026-09-21T00:00:00.000Z',
178-
to: '2026-09-21T01:00:00.000Z',
179-
})
180-
expect(chart.dispatchAction).toHaveBeenCalledWith({ type: 'brush', areas: [] })
161+
expect(zooms).toEqual([{ from: '2026-09-21T00:00:00.000Z', to: '2026-09-21T01:00:00.000Z' }])
181162
controller.dispose()
182163
})
183164
})

‎apps/sim/lib/skills/application/use-cases.test.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ describe('skill application use cases', () => {
7979
input: { workspaceId: workspace.workspaceId, skillId: 'builtin-create-dashboard' },
8080
})
8181
).rejects.toThrow('Dashboards are not enabled')
82-
expect(mocks.flag).toHaveBeenCalledWith(null)
8382
})
8483

8584
it.each(['skill-1', 'builtin-research'])(

‎apps/sim/lib/table/analytics/query.test.ts‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ describe('table analytics SQL', () => {
9797
})
9898
)
9999
expect(result.rows).toEqual([{ total: 0, sum: null }])
100-
expect(guards).toHaveBeenCalledWith(expect.any(Function), {
101-
seqscanOff: true,
102-
repeatableRead: true,
103-
})
104100
})
105101
it('fails on overflow or oversized output and marks top-N', async () => {
106102
execute.mockResolvedValue(

‎apps/sim/lib/table/application/analytics.test.ts‎

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -63,37 +63,17 @@ beforeEach(() => {
6363
})
6464
})
6565
describe('authorized table analytics', () => {
66-
it('checks dashboard rollout against the canonical organization before querying', async () => {
66+
it('rejects when dashboards are not enabled for the organization', async () => {
6767
mocks.flag.mockRejectedValue(new Error('Dashboards are not enabled'))
6868
await expect(readTableAnalytics.execute({ principal, input })).rejects.toThrow(
6969
'Dashboards are not enabled'
7070
)
71-
expect(mocks.flag).toHaveBeenCalledWith('org_test')
72-
expect(mocks.query).not.toHaveBeenCalled()
7371
})
7472

75-
it('authorizes the current viewer and passes canonical scope to the repository', async () => {
73+
it('returns analytics for an authorized viewer', async () => {
7674
expect(await readTableAnalytics.execute({ principal, input })).toHaveProperty('rows.0.n', 4)
77-
expect(mocks.permission).toHaveBeenCalledWith(
78-
'viewer',
79-
'workspace_test',
80-
'org_test',
81-
undefined,
82-
expect.any(Object)
83-
)
84-
expect(mocks.capability).toHaveBeenCalledWith(
85-
'viewer',
86-
'workspace_test',
87-
'tables.use',
88-
'org_test',
89-
undefined
90-
)
91-
expect(mocks.query.mock.calls[0][0]).toMatchObject({
92-
id: 'tbl_test',
93-
workspaceId: 'workspace_test',
94-
})
9575
})
96-
it('rejects API keys and delegation before loading protected data', async () => {
76+
it('rejects API keys', async () => {
9777
await expect(
9878
readTableAnalytics.execute({
9979
principal: { kind: 'workspace_api_key', workspaceId: 'workspace_test', keyId: 'key' },
@@ -106,23 +86,20 @@ describe('authorized table analytics', () => {
10686
input,
10787
})
10888
).rejects.toThrow()
109-
expect(mocks.table).not.toHaveBeenCalled()
11089
})
11190
it('conceals a table in another workspace and missing/archived tables', async () => {
11291
mocks.table.mockResolvedValueOnce({ id: 'tbl_test', workspaceId: 'other' })
11392
await expect(readTableAnalytics.execute({ principal, input })).rejects.toThrow('not found')
11493
mocks.table.mockResolvedValueOnce(null)
11594
await expect(readTableAnalytics.execute({ principal, input })).rejects.toThrow('not found')
116-
expect(mocks.query).not.toHaveBeenCalled()
11795
})
118-
it('rechecks membership and capability before querying', async () => {
96+
it('rejects without membership or the tables capability', async () => {
11997
mocks.permission.mockResolvedValueOnce(null)
12098
await expect(readTableAnalytics.execute({ principal, input })).rejects.toThrow('Insufficient')
12199
mocks.capability.mockRejectedValueOnce(new Error('Tables disabled'))
122100
await expect(readTableAnalytics.execute({ principal, input })).rejects.toThrow(
123101
'Tables disabled'
124102
)
125-
expect(mocks.query).not.toHaveBeenCalled()
126103
})
127104
it('rejects invalid domain input and propagates infrastructure errors', async () => {
128105
await expect(

0 commit comments

Comments
 (0)