11import { renderToStaticMarkup } from "react-dom/server" ;
2- import { describe , expect , it , vi } from "vitest" ;
2+ import { afterEach , describe , expect , it , vi } from "vitest" ;
3+
4+ const systemStatus = {
5+ deployment : {
6+ dockerAvailable : true ,
7+ composeRendered : true ,
8+ hostControlConfigured : true ,
9+ maintenanceReady : true ,
10+ } ,
11+ images : [
12+ {
13+ id : "app-api" ,
14+ name : "OpenMapX API" ,
15+ image : "ghcr.io/openmapx/api:latest" ,
16+ containerState : "running" ,
17+ runningImageId : "sha256:old-image" ,
18+ localImageId : "sha256:new-image" ,
19+ updateAvailable : true ,
20+ status : "update-available" as "update-available" | "up-to-date" ,
21+ } ,
22+ ] ,
23+ } ;
324
425vi . mock ( "@/lib/EnvProvider" , ( ) => ( { useEnv : ( ) => ( { apiUrl : "http://api.test" } ) } ) ) ;
526vi . mock ( "../shared/AdminToast" , ( ) => ( { useAdminToast : ( ) => vi . fn ( ) } ) ) ;
@@ -9,31 +30,19 @@ vi.mock("@tanstack/react-query", () => ({
930 useQuery : ( options : { queryKey : unknown [ ] } ) =>
1031 options . queryKey [ 1 ] === "system"
1132 ? {
12- data : {
13- deployment : {
14- dockerAvailable : true ,
15- composeRendered : true ,
16- hostControlConfigured : true ,
17- maintenanceReady : true ,
18- } ,
19- images : [
20- {
21- id : "app-api" ,
22- name : "OpenMapX API" ,
23- image : "ghcr.io/openmapx/api:latest" ,
24- containerState : "running" ,
25- runningImageId : "sha256:old-image" ,
26- localImageId : "sha256:new-image" ,
27- updateAvailable : true ,
28- status : "update-available" ,
29- } ,
30- ] ,
31- } ,
33+ data : systemStatus ,
3234 isError : false ,
3335 }
3436 : { data : undefined , isError : false } ,
3537} ) ) ;
3638
39+ afterEach ( ( ) => {
40+ systemStatus . images [ 0 ] . runningImageId = "sha256:old-image" ;
41+ systemStatus . images [ 0 ] . localImageId = "sha256:new-image" ;
42+ systemStatus . images [ 0 ] . updateAvailable = true ;
43+ systemStatus . images [ 0 ] . status = "update-available" ;
44+ } ) ;
45+
3746describe ( "SystemMaintenance" , ( ) => {
3847 it ( "renders staged image state and safe operator actions" , async ( ) => {
3948 const { SystemMaintenance } = await import ( "./SystemMaintenance" ) ;
@@ -45,4 +54,35 @@ describe("SystemMaintenance", () => {
4554 expect ( markup ) . toContain ( "Deep diagnostics" ) ;
4655 expect ( markup ) . toContain ( "Host-control readiness" ) ;
4756 } ) ;
57+
58+ it ( "does not send a JSON content type for bodyless maintenance actions" , async ( ) => {
59+ const { buildSystemJobRequestInit } = await import ( "./SystemMaintenance" ) ;
60+
61+ expect ( buildSystemJobRequestInit ( ) ) . toEqual ( {
62+ method : "POST" ,
63+ credentials : "include" ,
64+ } ) ;
65+ expect ( buildSystemJobRequestInit ( { confirmation : "UPDATE OPENMAPX" } ) ) . toEqual ( {
66+ method : "POST" ,
67+ credentials : "include" ,
68+ headers : { "Content-Type" : "application/json" } ,
69+ body : JSON . stringify ( { confirmation : "UPDATE OPENMAPX" } ) ,
70+ } ) ;
71+ } ) ;
72+
73+ it ( "disables application updates when every core image is current" , async ( ) => {
74+ systemStatus . images [ 0 ] . runningImageId = "sha256:current-image" ;
75+ systemStatus . images [ 0 ] . localImageId = "sha256:current-image" ;
76+ systemStatus . images [ 0 ] . updateAvailable = false ;
77+ systemStatus . images [ 0 ] . status = "up-to-date" ;
78+
79+ const { SystemMaintenance } = await import ( "./SystemMaintenance" ) ;
80+ const markup = renderToStaticMarkup ( < SystemMaintenance /> ) ;
81+
82+ expect (
83+ / < b u t t o n [ ^ > ] * d i s a b l e d = " " [ ^ > ] * t i t l e = " A l l c o r e i m a g e s a r e u p t o d a t e " [ ^ > ] * > [ \s \S ] * ?U p d a t e O p e n M a p X / . test (
84+ markup ,
85+ ) ,
86+ ) . toBe ( true ) ;
87+ } ) ;
4888} ) ;
0 commit comments