mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 20:35:07 +03:00
test(cron): add UTC timestamp tests and fix formatDate consistency
- CronJobTableCell.test.tsx: render tests asserting latest_run and next_run columns display timestamps with "(UTC)" suffix; also covers the absent-value dash fallback - CronJobs.utils.test.ts: unit tests for formatDate (UTC output, invalid input) and calculateDuration - CronJobs.utils.tsx: add timeZone: 'UTC' to formatDate so the fallback path is consistent with the primary TimestampInfo display Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
3c997edf0c
commit
80d5b366b7
3 files changed
+91
-25
No files matched your search
@@ -470,17 +470,20 @@ describe('formatDate', () => {
|
||||
expect(formatDate('not-a-date')).toBe('Invalid Date')
|
||||
})
|
||||
|
||||
it('displays time in UTC regardless of system timezone', () => {
|
||||
// 2026-06-15T09:25:00Z is 09:25 in UTC; the output must include 'UTC'
|
||||
const result = formatDate('2026-06-15T09:25:00.000Z')
|
||||
expect(result).toContain('UTC')
|
||||
it('returns Invalid Date for an empty string', () => {
|
||||
expect(formatDate('')).toBe('Invalid Date')
|
||||
})
|
||||
|
||||
it('formats the correct UTC hour, not local', () => {
|
||||
// 2026-01-01T00:30:00Z is midnight UTC; any local-timezone rendering
|
||||
// in a UTC+N zone would produce a different hour or even a different day.
|
||||
const result = formatDate('2026-01-01T00:30:00.000Z')
|
||||
expect(result).toContain('UTC')
|
||||
it('formats a UTC timestamp to the exact UTC hour and minute', () => {
|
||||
// Any local-timezone renderer in UTC+N would produce hour 11 or later
|
||||
// for this input; the only correct UTC answer is 09:25.
|
||||
expect(formatDate('2026-06-15T09:25:00.000Z')).toBe('15 Jun 2026, 09:25:00 UTC')
|
||||
})
|
||||
|
||||
it('formats a near-midnight UTC timestamp without rolling the day', () => {
|
||||
// 2026-01-01T00:30:00Z is 00:30 on Jan 1 in UTC.
|
||||
// A UTC+5 renderer would produce Dec 31 at 19:30 — the wrong day entirely.
|
||||
expect(formatDate('2026-01-01T00:30:00.000Z')).toBe('01 Jan 2026, 00:30:00 UTC')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { keyword, literal, safeSql, type SafeSqlFragment } from '@supabase/pg-meta/src/pg-format'
|
||||
import { toString as CronToString } from 'cronstrue'
|
||||
import dayjs from 'dayjs'
|
||||
import utc from 'dayjs/plugin/utc'
|
||||
import { Column } from 'react-data-grid'
|
||||
import { cn } from 'ui'
|
||||
|
||||
dayjs.extend(utc)
|
||||
|
||||
import { CronJobType } from './CreateCronJobSheet/CreateCronJobSheet.constants'
|
||||
import { CRON_TABLE_COLUMNS, HTTPHeader, secondsPattern } from './CronJobs.constants'
|
||||
import { CronJobTableCell } from './CronJobTableCell'
|
||||
@@ -250,22 +254,10 @@ export function calculateDuration(start: string, end: string): string {
|
||||
}
|
||||
|
||||
export function formatDate(dateString: string): string {
|
||||
const date = new Date(dateString)
|
||||
if (isNaN(date.getTime())) {
|
||||
return 'Invalid Date'
|
||||
}
|
||||
const options: Intl.DateTimeFormatOptions = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false,
|
||||
timeZone: 'UTC',
|
||||
timeZoneName: 'short',
|
||||
}
|
||||
return date.toLocaleString(undefined, options)
|
||||
if (!dateString) return 'Invalid Date'
|
||||
const parsed = dayjs.utc(dateString)
|
||||
if (!parsed.isValid()) return 'Invalid Date'
|
||||
return parsed.format('DD MMM YYYY, HH:mm:ss [UTC]')
|
||||
}
|
||||
|
||||
export function isSecondsFormat(schedule: string): boolean {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { screen } from '@testing-library/dom'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { render } from '@/tests/helpers'
|
||||
import { PreviousRunsTab } from './PreviousRunsTab'
|
||||
|
||||
const TEST_START = '2026-06-15T09:25:00.000Z'
|
||||
const TEST_END = '2026-06-15T09:25:05.000Z'
|
||||
|
||||
// Replace the virtualized DataGrid with a plain renderer so renderCell
|
||||
// functions are exercised without needing real DOM dimensions.
|
||||
vi.mock('react-data-grid', () => ({
|
||||
default: ({ rows, columns }: any) => (
|
||||
<div>
|
||||
{rows.map((row: any, rowIdx: number) =>
|
||||
columns.map((col: any) => (
|
||||
<div key={`${rowIdx}-${String(col.key)}`}>{col.renderCell?.({ row })}</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
Row: ({ children }: any) => <>{children}</>,
|
||||
}))
|
||||
|
||||
vi.mock('common', () => ({
|
||||
useParams: () => ({ childId: '1' }),
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/misc/useSelectedProject', () => ({
|
||||
useSelectedProjectQuery: () => ({
|
||||
data: { ref: 'test-ref', connectionString: 'test-conn' },
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/data/database-cron-jobs/database-cron-jobs-runs-infinite-query', () => ({
|
||||
useCronJobRunsInfiniteQuery: () => ({
|
||||
data: {
|
||||
pages: [
|
||||
[
|
||||
{
|
||||
runid: 1,
|
||||
job_pid: 123,
|
||||
jobid: 1,
|
||||
start_time: TEST_START,
|
||||
end_time: TEST_END,
|
||||
return_message: null,
|
||||
status: 'succeeded',
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
isPending: false,
|
||||
isFetching: false,
|
||||
isFetchingNextPage: false,
|
||||
hasNextPage: false,
|
||||
fetchNextPage: vi.fn(),
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/misc/useInfiniteScroll', () => ({
|
||||
useInfiniteScroll: () => vi.fn(),
|
||||
}))
|
||||
|
||||
describe('PreviousRunsTab timestamp display', () => {
|
||||
it('renders start_time and end_time columns in UTC', () => {
|
||||
render(<PreviousRunsTab />)
|
||||
// Both start_time and end_time should show timestamps ending in (UTC)
|
||||
const utcLabels = screen.getAllByText(/\(UTC\)/)
|
||||
expect(utcLabels.length).toBeGreaterThanOrEqual(2)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user