mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
test: cover saveEach and schedule config normalization
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ViTUkt4czrvZdxdWwxqRAQ
This commit is contained in:
co-authored by
Claude Opus 5
parent
594475815f
commit
92a6ab6c4e
@@ -0,0 +1,40 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { normalizeScheduleCfg, scheduleCfgOf, scheduleFormOf } from './scheduleCfg'
|
||||
|
||||
// A deployed schedule as the API returns it: server fields the form never shows, a short cron.
|
||||
const deployed = {
|
||||
path: 'u/me/s',
|
||||
schedule: '0 0 12 * *',
|
||||
timezone: 'UTC',
|
||||
script_path: 'u/me/script',
|
||||
is_flow: false,
|
||||
args: { x: 'a' },
|
||||
enabled: true,
|
||||
on_failure: 'script/hub/1/workspace-or-schedule-error-handler-slack',
|
||||
on_failure_extra_args: { channel: '#alerts' },
|
||||
on_recovery: null,
|
||||
summary: '',
|
||||
extra_perms: {},
|
||||
edited_by: 'me',
|
||||
edited_at: '2026-09-11T00:00:00Z',
|
||||
workspace_id: 'w',
|
||||
email: 'me@example.com'
|
||||
}
|
||||
|
||||
describe('schedule config normalization', () => {
|
||||
// The deployed side is kept in this shape and compared with what the form hands back: if the
|
||||
// two drift, a schedule reads as edited the moment it is opened.
|
||||
it('is what the form hands back after loading it, and idempotent', () => {
|
||||
const once = normalizeScheduleCfg(deployed)
|
||||
expect(scheduleCfgOf(scheduleFormOf(once))).toEqual(once)
|
||||
expect(JSON.stringify(normalizeScheduleCfg(once))).toBe(JSON.stringify(once))
|
||||
expect(once).toMatchObject({
|
||||
schedule: '0 0 12 * * *',
|
||||
on_failure: 'script/hub/1/workspace-or-schedule-error-handler-slack',
|
||||
on_failure_extra_args: { channel: '#alerts' },
|
||||
on_recovery: undefined,
|
||||
summary: undefined
|
||||
})
|
||||
expect(once).not.toHaveProperty('edited_by')
|
||||
})
|
||||
})
|
||||
@@ -162,6 +162,37 @@ describe('item store: commands', () => {
|
||||
expect(a.writes).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('saves items in turn, all busy from the call, and stops at the first failure', async () => {
|
||||
const rows = fakeRows()
|
||||
const store = createItemStore(rows.port)
|
||||
const written: string[] = []
|
||||
const a = adapter({ deployed: deployedRes }, async (ctx) => {
|
||||
written.push(ctx.workspace)
|
||||
if (ctx.workspace === 'w1') throw new Error('refused')
|
||||
})
|
||||
const acquire = (ws: string) =>
|
||||
store.acquire(
|
||||
{ workspace: ws, kind: 'resource', path: 'u/me/r' },
|
||||
{ workspace: ws, path: 'u/me/r' },
|
||||
a
|
||||
).handle
|
||||
const [first, second] = [acquire('w1'), acquire('w2')]
|
||||
await settle()
|
||||
first.value = { ...deployedRes, description: 'one' }
|
||||
second.value = { ...deployedRes, description: 'two' }
|
||||
|
||||
const saving = store.saveEach([first, second])
|
||||
expect([first.busy, second.busy]).toEqual([true, true])
|
||||
const outcomes = await saving
|
||||
|
||||
expect(outcomes).toEqual([
|
||||
{ ok: false, error: 'refused' },
|
||||
{ ok: false, error: 'Not saved', skipped: true }
|
||||
])
|
||||
expect(written).toEqual(['w1'])
|
||||
expect([first.dirty, second.dirty, second.busy]).toEqual([true, true, false])
|
||||
})
|
||||
|
||||
it('holds a toggle behind a save, and keeps an unrelated edit through the toggle', async () => {
|
||||
type Sched = { path: string; enabled: boolean; summary: string }
|
||||
const rows = fakeRows()
|
||||
|
||||
Reference in New Issue
Block a user