feat: signed releases, release feed, notification (read-only)
This commit is contained in:
1 parent
a49eec909c
commit
834493a4f5
49 files changed
+4191
-18
No files matched your search
+134
-4
@@ -164,6 +164,65 @@ const verifiedSession: ApiMock = {
|
||||
},
|
||||
}
|
||||
|
||||
const updateRunningVersion = 'v2.2.0-beta'
|
||||
const updateLatestTag = 'v2.3.0'
|
||||
const updateReleaseUrl = 'https://git.floriansylvain.fr/fsylvain/RenewCMS/releases/tag/v2.3.0'
|
||||
const updateReleasedAt = '2026-09-24T08:00:00Z'
|
||||
|
||||
const adminSession: ApiMock = {
|
||||
status: 200,
|
||||
body: { ...(verifiedSession.body as object), role: 'admin' },
|
||||
}
|
||||
|
||||
function updateStatusBody(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
current: updateRunningVersion,
|
||||
latest: updateRunningVersion,
|
||||
available: false,
|
||||
release_url: updateReleaseUrl,
|
||||
notes: { version: updateRunningVersion, released_at: updateReleasedAt, items: [] },
|
||||
checked_at: new Date().toISOString(),
|
||||
can_apply: false,
|
||||
state: 'idle',
|
||||
progress: null,
|
||||
error: null,
|
||||
started_at: null,
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
function updateNeverChecked() {
|
||||
return updateStatusBody({
|
||||
latest: '',
|
||||
release_url: null,
|
||||
notes: null,
|
||||
checked_at: null,
|
||||
})
|
||||
}
|
||||
|
||||
function updateAvailable() {
|
||||
return updateStatusBody({
|
||||
latest: updateLatestTag,
|
||||
available: true,
|
||||
notes: { version: updateLatestTag, released_at: updateReleasedAt, items: [] },
|
||||
})
|
||||
}
|
||||
|
||||
const updateCheckHangs: ApiMock = { status: 200, hang: true }
|
||||
|
||||
function updateApi(
|
||||
role: 'owner' | 'admin',
|
||||
status: unknown,
|
||||
check: ApiMock = { status: 200, body: updateStatusBody() },
|
||||
): Record<string, ApiMock> {
|
||||
return {
|
||||
'GET /v1/auth/me': role === 'owner' ? verifiedSession : adminSession,
|
||||
'GET /v1/settings/': { status: 200, body: { version: updateRunningVersion } },
|
||||
'GET /v1/system/update': { status: 200, body: status },
|
||||
'POST /v1/system/update/check': check,
|
||||
}
|
||||
}
|
||||
|
||||
const editorNow = '2026-09-26T11:02:00Z'
|
||||
|
||||
const bathroomBody =
|
||||
@@ -1981,13 +2040,71 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
'Invite sent': { path: '/users', skip: 'clock-sensitive' },
|
||||
},
|
||||
settings: {
|
||||
Default: {
|
||||
'Up to date': { path: '/settings', skip: 'clock-sensitive' },
|
||||
Checking: {
|
||||
path: '/settings',
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/settings/': { status: 200, body: { version: 'v2.2.0-beta' } },
|
||||
api: updateApi('owner', updateNeverChecked(), updateCheckHangs),
|
||||
},
|
||||
'Check failed': { path: '/settings', skip: 'clock-sensitive' },
|
||||
'Update available': { path: '/settings', skip: 'pending' },
|
||||
'Update available, notes open': { path: '/settings', skip: 'pending' },
|
||||
Downloading: { path: '/settings', skip: 'pending' },
|
||||
Verifying: { path: '/settings', skip: 'pending' },
|
||||
'Ready to install': { path: '/settings', skip: 'pending' },
|
||||
'Restart: confirm': { path: '/settings', skip: 'pending' },
|
||||
'Restart: request failed': { path: '/settings', skip: 'pending' },
|
||||
'Restarting to install': { path: '/settings', skip: 'pending' },
|
||||
'Restarting, taking longer': { path: '/settings', skip: 'pending' },
|
||||
'Update done': { path: '/settings', skip: 'pending' },
|
||||
'Update failed, rolled back': { path: '/settings', skip: 'pending' },
|
||||
'Download failed': { path: '/settings', skip: 'pending' },
|
||||
'Verification failed': { path: '/settings', skip: 'pending' },
|
||||
'Too many requests (429)': {
|
||||
path: '/settings',
|
||||
api: updateApi('owner', updateNeverChecked(), {
|
||||
status: 429,
|
||||
headers: { 'Retry-After': '42' },
|
||||
}),
|
||||
},
|
||||
'Not prepared': {
|
||||
path: '/settings',
|
||||
api: updateApi('owner', updateAvailable()),
|
||||
},
|
||||
'Not prepared: command copied': {
|
||||
path: '/settings',
|
||||
origin: integrationOrigin,
|
||||
api: updateApi('owner', updateAvailable()),
|
||||
steps: async (page) => {
|
||||
await page.getByRole('button', { name: 'Copy', exact: true }).click()
|
||||
await page.mouse.move(0, 0)
|
||||
},
|
||||
},
|
||||
'Plain restart: confirm': { path: '/settings', skip: 'pending' },
|
||||
'Plain restart: restarting': { path: '/settings', skip: 'pending' },
|
||||
'Plain restart: done': { path: '/settings', skip: 'pending' },
|
||||
'Admin view': {
|
||||
path: '/settings',
|
||||
api: updateApi('admin', updateAvailable()),
|
||||
},
|
||||
'Role changed (403)': {
|
||||
path: '/settings',
|
||||
api: {
|
||||
...updateApi('owner', updateNeverChecked(), { status: 403 }),
|
||||
'GET /v1/auth/me': {
|
||||
status: 200,
|
||||
bodyFor: (_url, call) => ({
|
||||
...(verifiedSession.body as object),
|
||||
role: call === 1 ? 'owner' : 'admin',
|
||||
}),
|
||||
},
|
||||
'GET /v1/system/update': {
|
||||
status: 200,
|
||||
bodyFor: (_url, call) =>
|
||||
call === 1 ? updateNeverChecked() : updateAvailable(),
|
||||
},
|
||||
},
|
||||
},
|
||||
'Update already running (409)': { path: '/settings', skip: 'pending' },
|
||||
},
|
||||
integration: {
|
||||
Default: {
|
||||
@@ -2222,6 +2339,7 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture },
|
||||
},
|
||||
},
|
||||
@@ -2230,6 +2348,7 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture, hang: true },
|
||||
},
|
||||
},
|
||||
@@ -2238,6 +2357,7 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
'GET /v1/article/': { status: 200, body: [] },
|
||||
},
|
||||
},
|
||||
@@ -2246,9 +2366,19 @@ export const visualStates: Record<string, Record<string, VisualState>> = {
|
||||
now: boardNow,
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/system/update': { status: 200, body: updateStatusBody() },
|
||||
'GET /v1/article/': { status: 500 },
|
||||
},
|
||||
},
|
||||
'Update available (owner)': {
|
||||
path: '/home',
|
||||
api: {
|
||||
'GET /v1/auth/me': verifiedSession,
|
||||
'GET /v1/article/': { status: 200, body: sixArticlesFixture },
|
||||
'GET /v1/system/update': { status: 200, body: updateAvailable() },
|
||||
},
|
||||
},
|
||||
'Update ready to install (owner)': { path: '/home', skip: 'pending' },
|
||||
},
|
||||
'log-in': {
|
||||
Default: { path: '/login', api: { 'GET /v1/auth/registration': registrationClosed } },
|
||||
|
||||
Reference in new issue
Block a user