feat: sites and authors integration into existing screens (& formated all frontend files kinda accidentally)

This commit is contained in:
Florian Sylvain committed 2026-10-15 05:25:44 +02:00
1 parent 3d81d2c717
commit 6b8990c55e
239 files changed
+9194 -1354

No files matched your search

+111 -26
View File
@@ -40,7 +40,9 @@ beforeEach(() => {
describe('load', () => {
it('shares one request between concurrent callers', async () => {
const store = setup('owner', { [STATUS_PATH]: () => Promise.resolve(upToDate()) })
const store = setup('owner', {
[STATUS_PATH]: () => Promise.resolve(upToDate()),
})
await Promise.all([store.load(), store.load()])
@@ -50,11 +52,15 @@ describe('load', () => {
})
it('reports an error when nothing was ever loaded, and keeps the last status otherwise', async () => {
const store = setup('owner', { [STATUS_PATH]: () => Promise.reject(new ApiError(500)) })
const store = setup('owner', {
[STATUS_PATH]: () => Promise.reject(new ApiError(500)),
})
await store.load()
expect(store.loadState).toBe('error')
const kept = setup('owner', { [STATUS_PATH]: () => Promise.resolve(upToDate()) })
const kept = setup('owner', {
[STATUS_PATH]: () => Promise.resolve(upToDate()),
})
await kept.load()
requestMock.mockImplementation(() => Promise.reject(new NetworkError()))
await kept.load()
@@ -65,7 +71,9 @@ describe('load', () => {
describe('check', () => {
it('stores the result and returns to idle', async () => {
const store = setup('owner', { [CHECK_PATH]: () => Promise.resolve(newerAvailable()) })
const store = setup('owner', {
[CHECK_PATH]: () => Promise.resolve(newerAvailable()),
})
const result = await store.check()
@@ -76,7 +84,9 @@ describe('check', () => {
})
it('answers busy and sends nothing while a check is running', async () => {
const store = setup('owner', { [CHECK_PATH]: () => new Promise(() => undefined) })
const store = setup('owner', {
[CHECK_PATH]: () => new Promise(() => undefined),
})
store.check()
expect(await store.check()).toBe('busy')
@@ -98,8 +108,20 @@ describe('check', () => {
phase: 'limited',
retry: 60,
},
{ name: '403', error: new ApiError(403), result: 'forbidden', phase: 'idle', retry: 0 },
{ name: '500', error: new ApiError(500), result: 'failed', phase: 'failed', retry: 0 },
{
name: '403',
error: new ApiError(403),
result: 'forbidden',
phase: 'idle',
retry: 0,
},
{
name: '500',
error: new ApiError(500),
result: 'failed',
phase: 'failed',
retry: 0,
},
{
name: 'a network failure',
error: new NetworkError(),
@@ -108,7 +130,9 @@ describe('check', () => {
retry: 0,
},
])('maps $name', async ({ error, result, phase, retry }) => {
const store = setup('owner', { [CHECK_PATH]: () => Promise.reject(error) })
const store = setup('owner', {
[CHECK_PATH]: () => Promise.reject(error),
})
expect(await store.check()).toBe(result)
expect(store.phase).toBe(phase)
@@ -118,7 +142,9 @@ describe('check', () => {
describe('banner dismissal', () => {
it('hides the banner for the dismissed version only and keeps the cue', async () => {
const store = setup('owner', { [STATUS_PATH]: () => Promise.resolve(newerAvailable()) })
const store = setup('owner', {
[STATUS_PATH]: () => Promise.resolve(newerAvailable()),
})
await store.load()
expect(store.bannerVisible).toBe(true)
@@ -131,14 +157,18 @@ describe('banner dismissal', () => {
it('reads the remembered version when created', async () => {
localStorage.setItem(DISMISSED_VERSION_KEY, 'v2.3.0-beta')
const store = setup('owner', { [STATUS_PATH]: () => Promise.resolve(newerAvailable()) })
const store = setup('owner', {
[STATUS_PATH]: () => Promise.resolve(newerAvailable()),
})
await store.load()
expect(store.bannerVisible).toBe(false)
})
it('shows no cue for an admin', async () => {
const store = setup('admin', { [STATUS_PATH]: () => Promise.resolve(newerAvailable()) })
const store = setup('admin', {
[STATUS_PATH]: () => Promise.resolve(newerAvailable()),
})
await store.load()
expect(store.showCue).toBe(false)
@@ -148,7 +178,9 @@ describe('banner dismissal', () => {
describe('startDownload', () => {
it('stores the 202 body and returns to idle', async () => {
const store = setup('owner', { [DOWNLOAD_PATH]: () => Promise.resolve(downloading()) })
const store = setup('owner', {
[DOWNLOAD_PATH]: () => Promise.resolve(downloading()),
})
const result = await store.startDownload()
@@ -156,11 +188,15 @@ describe('startDownload', () => {
expect(store.applyPhase).toBe('idle')
expect(store.status?.state).toBe('downloading')
expect(store.jobRunning).toBe(true)
expect(requestMock).toHaveBeenCalledWith(DOWNLOAD_PATH, { method: 'POST' })
expect(requestMock).toHaveBeenCalledWith(DOWNLOAD_PATH, {
method: 'POST',
})
})
it('answers busy and sends nothing while a start is in flight', async () => {
const store = setup('owner', { [DOWNLOAD_PATH]: () => new Promise(() => undefined) })
const store = setup('owner', {
[DOWNLOAD_PATH]: () => new Promise(() => undefined),
})
store.startDownload()
expect(await store.startDownload()).toBe('busy')
@@ -169,9 +205,27 @@ describe('startDownload', () => {
})
it.each([
{ name: '400', error: new ApiError(400), result: 'nothing', phase: 'idle', retry: 0 },
{ name: '403', error: new ApiError(403), result: 'forbidden', phase: 'idle', retry: 0 },
{ name: '409', error: new ApiError(409), result: 'conflict', phase: 'idle', retry: 0 },
{
name: '400',
error: new ApiError(400),
result: 'nothing',
phase: 'idle',
retry: 0,
},
{
name: '403',
error: new ApiError(403),
result: 'forbidden',
phase: 'idle',
retry: 0,
},
{
name: '409',
error: new ApiError(409),
result: 'conflict',
phase: 'idle',
retry: 0,
},
{
name: '422',
error: new ApiError(422),
@@ -193,7 +247,13 @@ describe('startDownload', () => {
phase: 'limited',
retry: 60,
},
{ name: '500', error: new ApiError(500), result: 'failed', phase: 'failed', retry: 0 },
{
name: '500',
error: new ApiError(500),
result: 'failed',
phase: 'failed',
retry: 0,
},
{
name: 'a network failure',
error: new NetworkError(),
@@ -202,7 +262,9 @@ describe('startDownload', () => {
retry: 0,
},
])('maps $name', async ({ error, result, phase, retry }) => {
const store = setup('owner', { [DOWNLOAD_PATH]: () => Promise.reject(error) })
const store = setup('owner', {
[DOWNLOAD_PATH]: () => Promise.reject(error),
})
expect(await store.startDownload()).toBe(result)
expect(store.applyPhase).toBe(phase)
@@ -224,7 +286,9 @@ describe('startDownload', () => {
describe('poll', () => {
it('replaces the status and keeps it when a poll fails', async () => {
const store = setup('owner', { [STATUS_PATH]: () => Promise.resolve(downloading(60)) })
const store = setup('owner', {
[STATUS_PATH]: () => Promise.resolve(downloading(60)),
})
await store.poll()
expect(store.status?.progress?.percent).toBe(60)
@@ -236,7 +300,9 @@ describe('poll', () => {
})
it('skips a poll while another is in flight', async () => {
const store = setup('owner', { [STATUS_PATH]: () => new Promise(() => undefined) })
const store = setup('owner', {
[STATUS_PATH]: () => new Promise(() => undefined),
})
store.poll()
await store.poll()
@@ -247,9 +313,24 @@ describe('poll', () => {
describe('job state', () => {
it.each([
{ name: 'downloading', status: downloading(), running: true, readyToInstall: false },
{ name: 'ready', status: ready(), running: false, readyToInstall: true },
{ name: 'idle', status: startable(), running: false, readyToInstall: false },
{
name: 'downloading',
status: downloading(),
running: true,
readyToInstall: false,
},
{
name: 'ready',
status: ready(),
running: false,
readyToInstall: true,
},
{
name: 'idle',
status: startable(),
running: false,
readyToInstall: false,
},
{
name: 'downloading without the helper',
status: { ...downloading(), can_apply: false },
@@ -257,7 +338,9 @@ describe('job state', () => {
readyToInstall: false,
},
])('reads $name', async ({ status, running, readyToInstall }) => {
const store = setup('owner', { [STATUS_PATH]: () => Promise.resolve(status) })
const store = setup('owner', {
[STATUS_PATH]: () => Promise.resolve(status),
})
await store.load()
expect(store.jobRunning).toBe(running)
@@ -265,7 +348,9 @@ describe('job state', () => {
})
it('shows no ready state to an admin', async () => {
const store = setup('admin', { [STATUS_PATH]: () => Promise.resolve(ready()) })
const store = setup('admin', {
[STATUS_PATH]: () => Promise.resolve(ready()),
})
await store.load()
expect(store.readyToInstall).toBe(false)