|
1 | 1 | import assert from "node:assert/strict"; |
2 | | -import test from "node:test"; |
| 2 | +import test, { mock } from "node:test"; |
3 | 3 | import React from "react"; |
4 | 4 | import { act, create } from "react-test-renderer"; |
5 | 5 | import { AppRouterContext } from "next/dist/shared/lib/app-router-context.shared-runtime"; |
@@ -70,19 +70,68 @@ test("health screen exposes the failed service, fix hint, and safe env names", ( |
70 | 70 | act(() => renderer.unmount()); |
71 | 71 | }); |
72 | 72 |
|
73 | | -test("scan again refreshes the server data", () => { |
| 73 | +test("scan again runs once and recovers when fresh data arrives", () => { |
74 | 74 | let refreshes = 0; |
75 | 75 | const router = { refresh: () => refreshes++ }; |
| 76 | + const tree = (nextData: SystemHealthResponse) => ( |
| 77 | + <AppRouterContext.Provider value={router as never}> |
| 78 | + <HealthScreen data={nextData} /> |
| 79 | + </AppRouterContext.Provider> |
| 80 | + ); |
| 81 | + let renderer!: ReturnType<typeof create>; |
| 82 | + act(() => { |
| 83 | + renderer = create(tree(data)); |
| 84 | + }); |
| 85 | + const button = renderer.root.findByProps({ children: "Scan again" }); |
| 86 | + act(() => { |
| 87 | + button.props.onClick(); |
| 88 | + button.props.onClick(); |
| 89 | + }); |
| 90 | + assert.equal(refreshes, 1); |
| 91 | + assert.equal( |
| 92 | + renderer.root.findByProps({ children: "Scanning…" }).props.disabled, |
| 93 | + true, |
| 94 | + ); |
| 95 | + |
| 96 | + act(() => { |
| 97 | + renderer.update( |
| 98 | + tree({ |
| 99 | + ...data, |
| 100 | + generatedAt: "2026-08-20T12:00:01.000Z", |
| 101 | + }), |
| 102 | + ); |
| 103 | + }); |
| 104 | + assert.equal( |
| 105 | + renderer.root.findByProps({ children: "Scan again" }).props.disabled, |
| 106 | + false, |
| 107 | + ); |
| 108 | + act(() => renderer.unmount()); |
| 109 | +}); |
| 110 | + |
| 111 | +test("scan again recovers if a refresh never commits", (t) => { |
| 112 | + mock.timers.enable({ apis: ["setTimeout"] }); |
| 113 | + t.after(() => mock.timers.reset()); |
| 114 | + |
| 115 | + const router = { refresh() {} }; |
76 | 116 | let renderer!: ReturnType<typeof create>; |
77 | 117 | act(() => { |
78 | 118 | renderer = create( |
79 | 119 | <AppRouterContext.Provider value={router as never}> |
80 | | - <HealthScreen data={{ ...data, alerts: [], summary: { ...data.summary, down: 0, criticalDown: 0 } }} /> |
| 120 | + <HealthScreen data={data} /> |
81 | 121 | </AppRouterContext.Provider>, |
82 | 122 | ); |
83 | 123 | }); |
84 | | - const button = renderer.root.findByProps({ children: "Scan again" }); |
85 | | - act(() => button.props.onClick()); |
86 | | - assert.equal(refreshes, 1); |
| 124 | + act(() => renderer.root.findByProps({ children: "Scan again" }).props.onClick()); |
| 125 | + assert.equal( |
| 126 | + renderer.root.findByProps({ children: "Scanning…" }).props.disabled, |
| 127 | + true, |
| 128 | + ); |
| 129 | + |
| 130 | + act(() => mock.timers.tick(15_000)); |
| 131 | + |
| 132 | + assert.equal( |
| 133 | + renderer.root.findByProps({ children: "Scan again" }).props.disabled, |
| 134 | + false, |
| 135 | + ); |
87 | 136 | act(() => renderer.unmount()); |
88 | 137 | }); |
0 commit comments