Files
Magent/scripts/review_repair_pipeline_ui.cjs
T
Assclaw 009bb35032
Magent CI/CD / verify (push) Successful in 10m47s
Magent CI/CD / deploy-prod (push) Skipped
Magent CI/CD / deploy-beta (push) Successful in 1m49s
Track repair collection cycles and reconcile request availability
2026-09-06 22:06:30 +12:00

93 lines
6.9 KiB
JavaScript

// Fixture-only regression: never sends repairs, deletes files, or starts downloads.
const assert = require('node:assert/strict')
const { chromium } = require(process.env.REVIEW_PLAYWRIGHT || 'playwright')
const base = process.env.REVIEW_BASE || 'http://127.0.0.1:3101'
const cycle = '2026-09-06T01:00:00+00:00'
const fixture = (state, partial = false) => {
const ready = state === 'complete'
const downloading = state === 'downloading'
const indexing = state === 'indexing'
const title = ready ? 'Available to watch' : indexing ? 'Replacement collected — updating Grizzlyflix' : downloading ? 'Replacement download in progress' : 'Waiting for a replacement'
const torrents = downloading ? [{ hash: 'new', name: 'Example replacement', state: 'downloading', progress: .32 }] : []
return {
request_id: '12', title: 'Repair review', request_type: partial ? 'tv' : 'movie',
state: ready ? 'COMPLETED' : downloading ? 'DOWNLOADING' : indexing ? 'IMPORTING' : 'ADDED_TO_ARR', timeline: [], actions: [],
presentation: {
repairCycle: cycle, status: { label: title, meaning: title },
download: { visible: downloading, state: downloading ? 'downloading' : 'not_started', torrents },
nextStep: { title: ready ? 'Ready to watch' : 'Tracking your replacement', description: 'This page updates automatically.', actionIds: [] },
repairActivity: { visible: !ready, state, headline: title, message: 'Tracking the affected content.', steps: [] },
pipeline: [
{ id: 'requested', label: 'Requested', state: 'complete', summary: 'Request received' },
{ id: 'approved', label: 'Approved', state: 'complete', summary: 'Approved for collection' },
{ id: 'library', label: 'Library collection', state: ready || indexing ? 'complete' : 'active', searchStatus: 'idle', summary: 'Checking the collector' },
{ id: 'search', label: 'Release search', state: ready || indexing || downloading ? 'complete' : 'waiting', summary: 'Tracking collection' },
{ id: 'download', label: 'Replacement download', state: ready || indexing ? 'complete' : downloading ? 'active' : 'waiting', stateLabel: downloading ? 'Active' : ready || indexing ? 'Complete' : 'Pending', visible: downloading, torrents, summary: ready || indexing ? 'The replacement has been imported.' : downloading ? 'Downloading (1 active).' : 'Waiting for a replacement download to start.' },
{ id: 'available', label: partial && !ready ? 'Partially available' : ready ? 'Available to watch' : indexing ? 'Updating Grizzlyflix' : 'Media server', state: ready ? 'complete' : partial ? 'partial' : indexing ? 'active' : 'waiting', stateLabel: ready ? 'Ready' : partial ? 'Repair in progress' : indexing ? 'Indexing' : 'Waiting', summary: partial && !ready ? 'Other episodes remain available. The selected episodes are being replaced.' : ready ? 'Ready to watch.' : 'Waiting for the updated file.', link: ready || partial ? 'https://media.test/web/index.html#!/details?id=example' : null },
],
},
}
}
;(async () => {
const browser = await chromium.launch({ headless: true })
try {
const context = await browser.newContext()
await context.addCookies([{ name: 'magent_logged_in', value: '1', url: base }])
let mode = 'waiting', partial = false, liveMode = 'old', livePolls = 0, snapshots = 0
const mutations = [], errors = []
await context.route('**/api/**', (route) => {
const req = route.request(), path = new URL(req.url()).pathname
if (req.method() !== 'GET') mutations.push(path)
const reply = (json) => route.fulfill({ json })
if (path === '/api/auth/me') return reply({ username: 'Member', role: 'user' })
if (path.endsWith('/snapshot')) { snapshots++; return reply(fixture(mode, partial)) }
if (path.endsWith('/download-progress')) {
livePolls++
return reply({ request_id: '12', repairCycle: liveMode === 'old' ? null : cycle, visible: true,
state: liveMode === 'old' ? 'completed' : 'downloading', summary: liveMode === 'old' ? 'Stale completed torrent' : 'Downloading (1 active).',
torrents: [{ hash: 'new', name: 'Example replacement', state: 'downloading', progress: liveMode === 'old' ? 1 : .48 }], updated_at: new Date().toISOString() })
}
if (path.includes('/events/stream')) return route.fulfill({ contentType: 'text/event-stream', body: ': fixture\n\n' })
if (path.includes('/branding/')) return route.fulfill({ status: 404 })
return reply({ navigation: { showRequests: true }, requests: [], services: [] })
})
const page = await context.newPage()
page.on('pageerror', (error) => errors.push(error.message))
const download = page.locator('.request-stage').filter({ has: page.getByRole('heading', { name: 'Replacement download', exact: true }) })
for (const width of [1440, 390]) {
await page.setViewportSize({ width, height: 1000 })
for (partial of [false, true]) {
for (mode of ['waiting', 'downloading', 'indexing', 'complete']) {
await page.goto(base + '/requests/12')
await download.waitFor()
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth), false)
if (mode === 'waiting') await download.getByText('Pending', { exact: true }).waitFor()
if (!partial && mode === 'waiting') assert.equal(await page.getByRole('link', { name: /Open on media server/ }).count(), 0)
if (partial && mode !== 'complete') await page.getByRole('heading', { name: 'Partially available', exact: true }).waitFor()
if (process.env.REVIEW_DIR) await page.screenshot({ path: `${process.env.REVIEW_DIR}/repair-${width}-${partial ? 'tv' : 'movie'}-${mode}.png` })
}
}
}
partial = false; mode = 'downloading'; liveMode = 'old'; livePolls = 0
await page.goto(base + '/requests/12')
// Wait for a real scheduled live poll, rather than a manual data injection.
await page.waitForResponse((response) => response.url().includes('/download-progress'), { timeout: 6000 })
assert.ok(livePolls > 0)
assert.equal(await download.getByText('Stale completed torrent', { exact: true }).count(), 0)
await download.getByText('32% complete', { exact: true }).waitFor()
liveMode = 'current'
await download.getByText('48% complete', { exact: true }).waitFor({ timeout: 6000 })
const before = snapshots
mode = 'indexing'
await page.getByRole('heading', { name: 'Updating Grizzlyflix', exact: true }).waitFor({ timeout: 9000 })
assert.ok(snapshots > before)
mode = 'complete'
await page.getByRole('heading', { name: 'Available to watch', exact: true }).waitFor({ timeout: 9000 })
assert.deepEqual(mutations, [])
assert.deepEqual(errors, [])
console.log('PASS: movie/TV desktop/mobile repair states; old-cycle polls ignored; real-time progress and automatic indexing → available transition; no API writes.')
} finally { await browser.close() }
})().catch((error) => { console.error(error); process.exitCode = 1 })