mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 23:41:58 +00:00
触发历史不再给基准已过时的自动对比;对比页找不到默认基准时标题不再和「可在上方选择」打架,换基准的下拉和基准卡写明失败、取消的运行
- 中间失败的那次事后被接着运行成功之后,第 3 周存着的那份对比(比的是第 1 周,previous 为假)和运行详情「与上一次 对比」的默认基准(现在是第 2 周)又对不上,两处却都写「上一次成功的运行」。auto_compare.outdated 对基准当时就不是 紧挨着的上一次的那几份按 pick_base 现挑一遍,基准变了的算过时;api/schedules._fire_outs 对过时的给 null(不给链接、 不给旧计数),两个同名入口比的始终是同一对运行。基准没变的照旧给:中间那次还没结束、后来失败、被删掉都一样。紧挨着 的上一次不会过时(两次之间插不进新的运行),不核 - test_base_follows_launch_order_not_finish_time 补上:接着运行完之后第 3 周的触发记录不再带对比、任务列表的 last_fire 同样不带、运行详情的默认基准是第 2 周;另加一条基准仍是挑出来的那一次时照旧给出 - 对比页找不到默认基准:标题由「未找到可作为基准的运行」改为「没有默认基准」——失败、取消但封存了的运行不当默认基准, 却照样能在上方手动选;服务端的原因改成「没有找到上一次成功的运行:需要同一工作流、同一运行类别里比这次先发起、成功 结束并已封存的运行」,运行详情弹出的提示单独读也说得清 - 换基准的下拉给失败、已取消的运行写上状态,基准卡也标出来;下拉说明补一句默认基准只取成功结束的运行 - 运行详情「更多」的菜单项点之前不知道基准是哪一次,基准不是紧挨着的上一次时仍叫「与上一次对比」,和触发历史的叫法 不同:注释照实写明,留作后续
This commit is contained in:
@@ -11,7 +11,8 @@
|
||||
// 都不能出现对比页)。下一步的提示要和页面上真能做的事对得上:下拉里没有能换的运行就不叫人去上方换,本次的记录
|
||||
// 不存在时不给注定失败的「重试」。默认基准的说法照服务端的挑法(api/compare.py 的 pick_base)写「上一次成功的运行」
|
||||
// ——上一次失败了,基准是再往前成功的那一次;定时任务触发历史里的「与上一次对比」和运行详情里的同名入口打开同一对
|
||||
// 运行、写同一句来历,基准不是紧挨着的上一次时触发历史上看得见的字写明「上一次成功的运行」。
|
||||
// 运行、写同一句来历,基准不是紧挨着的上一次时触发历史上看得见的字写明「上一次成功的运行」;找不到默认基准时标题不说
|
||||
// 「没有可作为基准的运行」(失败、取消的照样能手动选),换基准的下拉和基准卡写明哪次失败、取消了。
|
||||
//
|
||||
// 全部用 page.route 假接口:虚构的「区域销售周报」三次已封存的正式运行和一次没封存的,运行详情、运行列表、
|
||||
// compare/base、compare、定时任务列表、发起它们的定时任务和触发历史都在浏览器层答掉,别的 GET 放行(外壳要的工作流、
|
||||
@@ -190,6 +191,8 @@ const REASON_WORKFLOW = '默认基准:同一工作流、同一运行类别上
|
||||
const FINDING = '正在查找上一次成功的运行'
|
||||
/** 409、422、缺基准的 404 时下拉里没有能换的运行:不叫人去上方换,照实说 */
|
||||
const NO_OTHER = '同一工作流没有其他可换作基准的已封存运行'
|
||||
/** 服务端(api/compare.py 的 NO_BASE_TEXT)找不到默认基准时的原话 */
|
||||
const NO_BASE_SERVER = '没有找到上一次成功的运行:需要同一工作流、同一运行类别里比这次先发起、成功结束并已封存的运行'
|
||||
|
||||
/**
|
||||
* 发起本次和基准的定时任务(RUNS 里的 schedule_id)和它的触发历史:本次那一行带服务端自动对比的计数,基准是 B、不是
|
||||
@@ -249,7 +252,7 @@ function defaults(opts) {
|
||||
if (m) {
|
||||
if (opts.base) return opts.base(m[1])
|
||||
return m[1] === T ? { json: { base_run_id: B, reason: 'same_schedule', base: refOf(B) } }
|
||||
: { status: 404, json: { detail: '没有找到可作为基准的运行' } }
|
||||
: { status: 404, json: { detail: NO_BASE_SERVER, code: 'compare_no_base' } }
|
||||
}
|
||||
m = p.match(/^\/api\/runs\/([^/]+)\/compare$/)
|
||||
if (m) {
|
||||
@@ -531,7 +534,8 @@ await section('默认基准的说法:上一次成功的运行', async () => {
|
||||
})
|
||||
|
||||
await section('运行详情与触发历史的「与上一次对比」:同一个基准、同一句来历', async () => {
|
||||
// 两处的基准由服务端用同一个函数挑(api/compare.py 的 pick_base):上一次失败了,两处都是再往前成功的 B
|
||||
// 两处的基准由服务端用同一个函数挑(api/compare.py 的 pick_base):上一次失败了,两处都是再往前成功的 B。两处真的
|
||||
// 一致由 backend/tests/test_scheduler_compare.py 守,这里守前端两个入口都原样用服务端给的基准
|
||||
const menu = await open(`/runs/${T}`)
|
||||
await viaMenu(menu.page)
|
||||
const hist = await open(`/schedules/${SCHEDULE_ID}?tab=history`)
|
||||
@@ -871,6 +875,41 @@ await section('换基准、互换', async () => {
|
||||
`${listsBefore} → ${lists()}`)
|
||||
})
|
||||
|
||||
await section('换基准:失败、取消的运行写明状态,默认基准只取成功结束的', async () => {
|
||||
// 默认基准跳过失败、取消的运行(服务端 pick_base),手动选不限:下拉和基准卡上得看得出哪次没成功,人读懂「上一次成功的
|
||||
// 运行」之后才挑得出成功的那一次。两次都封存过,都能选
|
||||
const F = 'c0ffee0failed0000000000000000005'
|
||||
const C = 'c0ffee0cancel0000000000000000006'
|
||||
RUNS[F] = runOf(F, { status: 'failed', version: 3, created_at: day('10-01'), started_at: day('10-01'), finished_at: '2026-10-01T01:01:00Z' })
|
||||
RUNS[C] = runOf(C, { status: 'cancelled', version: 3, created_at: day('10-02'), started_at: day('10-02'), finished_at: '2026-10-02T01:01:00Z' })
|
||||
try {
|
||||
const { page, errors } = await open(comparePath(T, F))
|
||||
await settled(page)
|
||||
const picker = page.locator('select[data-compare-base-picker]')
|
||||
await until(async () => (await picker.locator('option').count()) > 2)
|
||||
const options = Object.fromEntries(await picker.locator('option').evaluateAll((els) =>
|
||||
els.map((o) => [o.value, { text: o.textContent ?? '', disabled: o.disabled }])))
|
||||
check('下拉:失败的那次写「失败」,照样能选', !!options[F]?.text.includes('· 失败') && !options[F].disabled, JSON.stringify(options[F]))
|
||||
check('下拉:取消的那次写「已取消」,照样能选', !!options[C]?.text.includes('· 已取消') && !options[C].disabled, JSON.stringify(options[C]))
|
||||
check('下拉:成功结束的不另写状态', !!options[B] && !/失败|已取消|已完成/.test(options[B].text), options[B]?.text)
|
||||
const card = page.locator('[data-compare-run="base"]')
|
||||
check('下拉下面的说明写明默认基准只取成功结束的运行', (await card.innerText()).includes('默认基准只取成功结束的运行'),
|
||||
(await card.innerText()).replace(/\s+/g, ' '))
|
||||
const status = card.locator('[data-compare-run-status]')
|
||||
check('基准卡:失败的那次标出「失败」', await status.count() === 1 && (await status.innerText()).trim() === '失败',
|
||||
await status.innerText().catch(() => '没有'))
|
||||
check('本次卡:成功结束的不标状态', await page.locator('[data-compare-run="target"] [data-compare-run-status]').count() === 0)
|
||||
await picker.selectOption(B)
|
||||
await until(async () => new URL(page.url()).searchParams.get('base') === B)
|
||||
await settled(page)
|
||||
check('换成成功结束的那次:基准卡不再标状态', await until(async () => await card.locator('[data-compare-run-status]').count() === 0))
|
||||
check('页面没有报错', errors.length === 0, errors.join(';'))
|
||||
} finally {
|
||||
delete RUNS[F]
|
||||
delete RUNS[C]
|
||||
}
|
||||
})
|
||||
|
||||
await section('过时的答复不盖掉新的', async () => {
|
||||
let release
|
||||
const gate = new Promise((r) => { release = r })
|
||||
@@ -958,15 +997,18 @@ await section('出错与找不到基准', async () => {
|
||||
await settled(flaky.page)
|
||||
check('其他错误:给「重试」,重试后正常显示', await flaky.page.locator('tr[data-compare-metric]').count() === METRICS.length)
|
||||
|
||||
// 只带本次:页面自己找基准,找不到时写原因,下拉照样能选
|
||||
const lone = await open(comparePath(T), { base: () => ({ status: 404, json: { detail: '同一工作流没有其他已封存的正式运行' } }) })
|
||||
// 只带本次:页面自己找基准,找不到时写原因,下拉照样能选。标题只说没有默认基准:失败、取消但封存了的运行不当默认
|
||||
// 基准,却照样能手动选,写成「没有可作为基准的运行」就和下面「可在上方选择」打架
|
||||
const lone = await open(comparePath(T), { base: () => ({ status: 404, json: { detail: NO_BASE_SERVER, code: 'compare_no_base' } }) })
|
||||
await settled(lone.page, 'error')
|
||||
const noBase = lone.page.locator('[data-compare-error="no-base"]')
|
||||
check('找不到基准:写明原因', (await noBase.locator('[data-compare-error-title]').innerText()).includes('未找到可作为基准的运行')
|
||||
&& (await noBase.innerText()).includes('同一工作流没有其他已封存的正式运行'))
|
||||
check('找不到基准:标题写「没有默认基准」,后面跟服务端的原因', (await noBase.locator('[data-compare-error-title]').innerText()).trim() === '没有默认基准'
|
||||
&& (await noBase.innerText()).includes(NO_BASE_SERVER), (await noBase.innerText()).replace(/\s+/g, ' '))
|
||||
check('找不到基准:仍能手动选', await lone.page.locator('select[data-compare-base-picker]').isEnabled())
|
||||
check('找不到基准、下拉里有能选的:说可在上方选', await until(async () => (await noBase.innerText()).includes('可在上方选择')),
|
||||
(await noBase.innerText()).replace(/\s+/g, ' '))
|
||||
check('找不到基准:不说「没有可作为基准的运行」这类和「可在上方选择」矛盾的话', !/可作为基准的运行|没有可以对比/.test(await noBase.innerText()),
|
||||
(await noBase.innerText()).replace(/\s+/g, ' '))
|
||||
// 同一工作流只有一次没封存的:下拉里没有能选的,不能再叫人去上方选
|
||||
const bare = await open(comparePath(T), { base: () => ({ status: 404, json: { detail: '同一工作流没有其他已封存的正式运行', code: 'compare_no_base' } }),
|
||||
list: () => ({ json: [RUNS[T], RUNS[U]] }) })
|
||||
@@ -1071,8 +1113,7 @@ await section('不属于已保存工作流的运行:对比页的说明前后
|
||||
try {
|
||||
// 只带本次:服务端找不到基准(这种运行没有可比的)
|
||||
const lone = await open(comparePath(T), { base: () => ({ status: 404, json: {
|
||||
detail: '没有找到可以对比的上一次成功的运行:需要同一工作流、同一运行类别(定时任务发起的优先找同一定时任务)、比这次先发起、成功结束并已封存的运行',
|
||||
code: 'compare_no_base' } }) })
|
||||
detail: NO_BASE_SERVER, code: 'compare_no_base' } }) })
|
||||
await settled(lone.page, 'error')
|
||||
await until(async () => (await lone.page.locator('[data-compare-run="base"]').innerText()).includes('未保存或已删除'), 3000)
|
||||
const card = (await lone.page.locator('[data-compare-run="base"]').innerText()).replace(/\s+/g, ' ')
|
||||
|
||||
@@ -1509,7 +1509,8 @@ await section('详情:触发历史里的「与上一次对比」', async () =>
|
||||
|
||||
await section('详情:触发历史和运行详情的「与上一次对比」拿同一个基准', async () => {
|
||||
// f10 的上一次(f11)失败了,服务端两处都挑再往前成功的 f12:自动对比和运行详情的默认基准用的是同一个函数
|
||||
// (api/compare.py 的 pick_base)。这里守前端:两个入口都原样用服务端给的基准,打开同一对运行、写同一句来历
|
||||
// (api/compare.py 的 pick_base),基准事后变了的旧对比触发历史不再给,这些由 backend/tests/test_scheduler_compare.py
|
||||
// 守。这里守前端:两个入口都原样用服务端给的基准,打开同一对运行、写同一句来历
|
||||
const runOf = (id, at) => ({ ...RUNS[0], id, started_by: '定时任务:门店周报 · 每周', created_at: iso(at), started_at: iso(at),
|
||||
finished_at: iso(at + 4200), manifest_hash: 'ab'.repeat(32), manifest_seq: 2 })
|
||||
const f10 = runOf('run-f10', nextMonday9(-11))
|
||||
|
||||
Reference in New Issue
Block a user