From 289acef0926defd54745618515233b0f8fdd56cb Mon Sep 17 00:00:00 2001
From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com>
Date: Sat, 18 Apr 2026 10:17:39 +0200
Subject: [PATCH 1/8] 7203: Added spinner when retrieving bind key
---
CHANGELOG.md | 1 +
assets/client/app.jsx | 14 ++
assets/client/app.scss | 21 +++
assets/tests/client/app-reauth.test.jsx | 186 ++++++++++++++++++++++++
4 files changed, 222 insertions(+)
create mode 100644 assets/tests/client/app-reauth.test.jsx
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 02e22fdbb..673ae4714 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -35,6 +35,7 @@ All notable changes to this project will be documented in this file.
- Optimized list loading.
- Removed fixture length check from test.
- Added vitest for frontend unit tests.
+- Added spinner when retrieving bind key.
### NB! Prior to 3.x the project was split into separate repositories
diff --git a/assets/client/app.jsx b/assets/client/app.jsx
index 779f62bd3..698edf40f 100644
--- a/assets/client/app.jsx
+++ b/assets/client/app.jsx
@@ -28,6 +28,7 @@ function App({ preview, previewId }) {
const [bindKey, setBindKey] = useState(null);
const [displayFallback, setDisplayFallback] = useState(true);
const [debug, setDebug] = useState(false);
+ const [retrievingBindKey, setRetrievingBindKey] = useState(false);
const checkLoginTimeoutRef = useRef(null);
const contentServiceRef = useRef(null);
@@ -120,12 +121,18 @@ function App({ preview, previewId }) {
.checkLogin()
.then((data) => {
if (data.status === constants.LOGIN_STATUS_READY) {
+ setRetrievingBindKey(false);
startContent(data.screenId);
+ console.log("Login success");
} else if (data.status === constants.LOGIN_STATUS_AWAITING_BIND_KEY) {
+ setRetrievingBindKey(false);
+
if (data?.bindKey) {
setBindKey(data.bindKey);
}
+ restartLoginTimeout();
+ } else {
restartLoginTimeout();
}
})
@@ -162,7 +169,9 @@ function App({ preview, previewId }) {
}
setScreen(null);
+ setBindKey(null);
setRunning(false);
+ setRetrievingBindKey(true);
tokenService.stopRefreshing();
@@ -285,6 +294,11 @@ function App({ preview, previewId }) {
{displayFallback && !bindKey && (
)}
+ {retrievingBindKey && !bindKey && (
+
+ )}
);
}
diff --git a/assets/client/app.scss b/assets/client/app.scss
index 2f68c5a8e..06a2a81c5 100644
--- a/assets/client/app.scss
+++ b/assets/client/app.scss
@@ -52,6 +52,27 @@ body {
}
}
+.retrieving-bind-key-container {
+ position: absolute;
+ bottom: 10px;
+ right: 10px;
+
+ .retrieving-bind-key-spinner {
+ width: 2rem;
+ height: 2rem;
+ border: 0.25em solid rgba(255, 255, 255, 0.25);
+ border-top-color: white;
+ border-radius: 50%;
+ animation: spin 0.75s linear infinite;
+ }
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
.ql-editor {
min-height: 200px;
}
diff --git a/assets/tests/client/app-reauth.test.jsx b/assets/tests/client/app-reauth.test.jsx
new file mode 100644
index 000000000..2e09099f0
--- /dev/null
+++ b/assets/tests/client/app-reauth.test.jsx
@@ -0,0 +1,186 @@
+import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
+import { render, act, screen, cleanup } from "@testing-library/react";
+
+const { mockCheckLogin, mockRefreshToken } = vi.hoisted(() => ({
+ mockCheckLogin: vi.fn(),
+ mockRefreshToken: vi.fn(),
+}));
+
+vi.mock("../../client/logger/logger", () => ({
+ default: { info: vi.fn(), warn: vi.fn(), error: vi.fn() },
+}));
+
+vi.mock("../../client/util/app-storage", () => ({
+ default: {
+ getToken: vi.fn(() => null),
+ getRefreshToken: vi.fn(() => null),
+ getScreenId: vi.fn(() => null),
+ getTokenExpire: vi.fn(() => null),
+ getTokenIssueAt: vi.fn(() => null),
+ getFallbackImageUrl: vi.fn(() => null),
+ setToken: vi.fn(),
+ setRefreshToken: vi.fn(),
+ setScreenId: vi.fn(),
+ setTenant: vi.fn(),
+ setPreviousBoot: vi.fn(),
+ clearToken: vi.fn(),
+ clearRefreshToken: vi.fn(),
+ clearScreenId: vi.fn(),
+ clearTenant: vi.fn(),
+ clearFallbackImageUrl: vi.fn(),
+ clearAppStorage: vi.fn(),
+ },
+}));
+
+vi.mock("../../client/service/token-service", () => ({
+ default: {
+ checkLogin: mockCheckLogin,
+ refreshToken: mockRefreshToken,
+ startRefreshing: vi.fn(),
+ stopRefreshing: vi.fn(),
+ checkToken: vi.fn(),
+ },
+}));
+
+vi.mock("../../client/service/status-service", () => ({
+ default: {
+ setStatus: vi.fn(),
+ setError: vi.fn(),
+ setStatusInUrl: vi.fn(),
+ error: null,
+ },
+}));
+
+vi.mock("../../client/service/release-service", () => ({
+ default: {
+ checkForNewRelease: vi.fn(() => Promise.resolve()),
+ setPreviousBootInUrl: vi.fn(),
+ startReleaseCheck: vi.fn(),
+ stopReleaseCheck: vi.fn(),
+ setScreenIdInUrl: vi.fn(),
+ },
+}));
+
+vi.mock("../../client/service/tenant-service", () => ({
+ default: { loadTenantConfig: vi.fn() },
+}));
+
+vi.mock("../../client/util/client-config-loader.js", () => ({
+ default: {
+ loadConfig: vi.fn(() => Promise.resolve({ loginCheckTimeout: 50 })),
+ },
+}));
+
+vi.mock("../../client/service/content-service", () => {
+ return {
+ default: vi.fn().mockImplementation(() => ({
+ start: vi.fn(),
+ stop: vi.fn(),
+ })),
+ };
+});
+
+vi.mock("../../client/app.scss", () => ({}));
+vi.mock("../../client/assets/fallback.png", () => ({ default: "" }));
+vi.mock("../../client/components/screen.jsx", () => ({
+ default: () => ,
+}));
+
+import App from "../../client/app.jsx";
+
+/**
+ * Flush microtasks, advance timers, flush again.
+ * restartLoginTimeout creates setTimeout inside a .then() on loadConfig —
+ * microtasks must resolve first for the timer to exist.
+ */
+async function tick(ms) {
+ await act(async () => {});
+ await act(async () => {
+ vi.advanceTimersByTime(ms);
+ });
+ await act(async () => {});
+}
+
+describe("checkLogin retries on unknown status", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ mockCheckLogin.mockReset();
+ mockRefreshToken.mockReset();
+ });
+
+ afterEach(() => {
+ cleanup();
+ vi.useRealTimers();
+ });
+
+ it("continues login polling when checkLogin returns unknown status", async () => {
+ // The initial checkLogin (on mount) returns unknown status.
+ // Without the fix, the polling loop stops dead — no restartLoginTimeout.
+ // With the fix, unknown triggers restartLoginTimeout and the second
+ // call returns awaitingBindKey, showing the bind key.
+ mockCheckLogin
+ .mockResolvedValueOnce({ status: "unknown" })
+ .mockResolvedValueOnce({ status: "awaitingBindKey", bindKey: "BIND42" })
+ .mockResolvedValue({ status: "awaitingBindKey", bindKey: "BIND42" });
+
+ render();
+
+ // Mount: releaseService.checkForNewRelease resolves → checkLogin (call 1)
+ // → unknown status → with fix: restartLoginTimeout → 50ms timer.
+ await tick(0);
+
+ // Bind key should NOT be visible yet (unknown status, no bind key set).
+ expect(screen.queryByText("BIND42")).not.toBeInTheDocument();
+
+ // Advance past loginCheckTimeout to fire the retry timer.
+ // Call 2 → awaitingBindKey "BIND42".
+ await tick(60);
+
+ // With the fix, the login loop retried and the bind key is now shown.
+ expect(screen.getByText("BIND42")).toBeInTheDocument();
+ });
+});
+
+describe("reauthenticateHandler shows spinner while retrieving bind key", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ mockCheckLogin.mockReset();
+ mockRefreshToken.mockReset();
+ });
+
+ afterEach(() => {
+ cleanup();
+ vi.useRealTimers();
+ });
+
+ it("recovers from reauth failure and shows new bind key", async () => {
+ // Call 1 (mount): normal login with bind key.
+ // Call 2 (reauth → checkLogin): returns new bind key after refresh
+ // token failure triggers full re-login.
+ mockCheckLogin
+ .mockResolvedValueOnce({ status: "awaitingBindKey", bindKey: "INIT01" })
+ .mockResolvedValue({ status: "awaitingBindKey", bindKey: "REAUTH01" });
+
+ // refreshToken will fail when reauthenticate fires.
+ mockRefreshToken.mockRejectedValue(new Error("token expired"));
+
+ render();
+
+ // Let mount complete.
+ await tick(0);
+ expect(screen.getByText("INIT01")).toBeInTheDocument();
+
+ // Fire reauthenticate event — refreshToken rejects → catch block
+ // clears screen/bindKey, sets retrievingBindKey, calls checkLogin
+ // which resolves with new bind key.
+ await act(async () => {
+ document.dispatchEvent(new Event("reauthenticate"));
+ });
+ await tick(60);
+
+ // Old bind key gone, new bind key visible — proves the full reauth
+ // recovery flow works: clear state → checkLogin → new bind key.
+ expect(screen.queryByText("INIT01")).not.toBeInTheDocument();
+ expect(screen.getByText("REAUTH01")).toBeInTheDocument();
+ });
+});
From 9a3fb4ea8709117772fd846c90ad8dcb9a3dcfbc Mon Sep 17 00:00:00 2001
From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com>
Date: Sat, 18 Apr 2026 10:33:16 +0200
Subject: [PATCH 2/8] 7203: Default to retrieving bind key
---
assets/client/app.jsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/assets/client/app.jsx b/assets/client/app.jsx
index 698edf40f..96048b11c 100644
--- a/assets/client/app.jsx
+++ b/assets/client/app.jsx
@@ -28,7 +28,7 @@ function App({ preview, previewId }) {
const [bindKey, setBindKey] = useState(null);
const [displayFallback, setDisplayFallback] = useState(true);
const [debug, setDebug] = useState(false);
- const [retrievingBindKey, setRetrievingBindKey] = useState(false);
+ const [retrievingBindKey, setRetrievingBindKey] = useState(true);
const checkLoginTimeoutRef = useRef(null);
const contentServiceRef = useRef(null);
@@ -72,6 +72,7 @@ function App({ preview, previewId }) {
setBindKey(null);
setRunning(true);
+ setRetrievingBindKey(false);
contentServiceRef.current = new ContentService();
@@ -123,7 +124,6 @@ function App({ preview, previewId }) {
if (data.status === constants.LOGIN_STATUS_READY) {
setRetrievingBindKey(false);
startContent(data.screenId);
- console.log("Login success");
} else if (data.status === constants.LOGIN_STATUS_AWAITING_BIND_KEY) {
setRetrievingBindKey(false);
From 126414984a99105f79637b5fa7b074506ebcb524 Mon Sep 17 00:00:00 2001
From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com>
Date: Sat, 18 Apr 2026 10:44:16 +0200
Subject: [PATCH 3/8] 7203: Changed to switch for increased reability
---
assets/client/app.jsx | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/assets/client/app.jsx b/assets/client/app.jsx
index 96048b11c..108036f9c 100644
--- a/assets/client/app.jsx
+++ b/assets/client/app.jsx
@@ -121,19 +121,24 @@ function App({ preview, previewId }) {
tokenService
.checkLogin()
.then((data) => {
- if (data.status === constants.LOGIN_STATUS_READY) {
- setRetrievingBindKey(false);
- startContent(data.screenId);
- } else if (data.status === constants.LOGIN_STATUS_AWAITING_BIND_KEY) {
- setRetrievingBindKey(false);
-
- if (data?.bindKey) {
- setBindKey(data.bindKey);
- }
-
- restartLoginTimeout();
- } else {
- restartLoginTimeout();
+ switch (data.status) {
+ case constants.LOGIN_STATUS_READY:
+ setRetrievingBindKey(false);
+ startContent(data.screenId);
+ break;
+ case constants.LOGIN_STATUS_AWAITING_BIND_KEY:
+ setRetrievingBindKey(false);
+
+ if (data?.bindKey) {
+ setBindKey(data.bindKey);
+ }
+
+ restartLoginTimeout();
+ break;
+ case constants.LOGIN_STATUS_UNKNOWN:
+ default:
+ restartLoginTimeout();
+ break;
}
})
.catch(() => {
From f8699da3990528b4e19ab44e4a62ab0631321562 Mon Sep 17 00:00:00 2001
From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com>
Date: Thu, 30 Apr 2026 12:41:28 +0200
Subject: [PATCH 4/8] Update assets/client/app.scss
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Ture Gjørup
---
assets/client/app.scss | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/assets/client/app.scss b/assets/client/app.scss
index 06a2a81c5..3036e9626 100644
--- a/assets/client/app.scss
+++ b/assets/client/app.scss
@@ -63,11 +63,11 @@ body {
border: 0.25em solid rgba(255, 255, 255, 0.25);
border-top-color: white;
border-radius: 50%;
- animation: spin 0.75s linear infinite;
+ animation: bind-key-spin 0.75s linear infinite;
}
}
-@keyframes spin {
+@keyframes bind-key-spin {
to {
transform: rotate(360deg);
}
From a056a8990f42633a8e4647bd93e768f56ffa4273 Mon Sep 17 00:00:00 2001
From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com>
Date: Thu, 30 Apr 2026 12:41:45 +0200
Subject: [PATCH 5/8] Update assets/client/app.jsx
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Ture Gjørup
---
assets/client/app.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assets/client/app.jsx b/assets/client/app.jsx
index 108036f9c..071d5aebf 100644
--- a/assets/client/app.jsx
+++ b/assets/client/app.jsx
@@ -299,7 +299,7 @@ function App({ preview, previewId }) {
{displayFallback && !bindKey && (
)}
- {retrievingBindKey && !bindKey && (
+ {!preview && retrievingBindKey && !bindKey && (
From 672784fc8682d0b58ac1f73c4fdab8b47a537535 Mon Sep 17 00:00:00 2001
From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com>
Date: Thu, 30 Apr 2026 13:07:07 +0200
Subject: [PATCH 6/8] 7203: Fixed issues raised in code review
---
assets/client/app.jsx | 4 +
...-reauth.test.jsx => app-bind-key.test.jsx} | 94 +++++++++++++++++--
2 files changed, 92 insertions(+), 6 deletions(-)
rename assets/tests/client/{app-reauth.test.jsx => app-bind-key.test.jsx} (66%)
diff --git a/assets/client/app.jsx b/assets/client/app.jsx
index 071d5aebf..cc9d6bdef 100644
--- a/assets/client/app.jsx
+++ b/assets/client/app.jsx
@@ -137,11 +137,15 @@ function App({ preview, previewId }) {
break;
case constants.LOGIN_STATUS_UNKNOWN:
default:
+ // retrievingBindKey intentionally not reset — restartLoginTimeout
+ // retries checkLogin, so we are still retrieving.
restartLoginTimeout();
break;
}
})
.catch(() => {
+ // retrievingBindKey intentionally not reset — restartLoginTimeout
+ // retries checkLogin, so we are still retrieving.
restartLoginTimeout();
});
}
diff --git a/assets/tests/client/app-reauth.test.jsx b/assets/tests/client/app-bind-key.test.jsx
similarity index 66%
rename from assets/tests/client/app-reauth.test.jsx
rename to assets/tests/client/app-bind-key.test.jsx
index 2e09099f0..61ed2713a 100644
--- a/assets/tests/client/app-reauth.test.jsx
+++ b/assets/tests/client/app-bind-key.test.jsx
@@ -73,10 +73,10 @@ vi.mock("../../client/util/client-config-loader.js", () => ({
vi.mock("../../client/service/content-service", () => {
return {
- default: vi.fn().mockImplementation(() => ({
- start: vi.fn(),
- stop: vi.fn(),
- })),
+ default: vi.fn().mockImplementation(function () {
+ this.start = vi.fn();
+ this.stop = vi.fn();
+ }),
};
});
@@ -123,7 +123,7 @@ describe("checkLogin retries on unknown status", () => {
.mockResolvedValueOnce({ status: "awaitingBindKey", bindKey: "BIND42" })
.mockResolvedValue({ status: "awaitingBindKey", bindKey: "BIND42" });
- render();
+ const { container } = render();
// Mount: releaseService.checkForNewRelease resolves → checkLogin (call 1)
// → unknown status → with fix: restartLoginTimeout → 50ms timer.
@@ -131,6 +131,10 @@ describe("checkLogin retries on unknown status", () => {
// Bind key should NOT be visible yet (unknown status, no bind key set).
expect(screen.queryByText("BIND42")).not.toBeInTheDocument();
+ // Spinner should still be visible — we are still retrieving.
+ expect(
+ container.querySelector(".retrieving-bind-key-spinner")
+ ).toBeInTheDocument();
// Advance past loginCheckTimeout to fire the retry timer.
// Call 2 → awaitingBindKey "BIND42".
@@ -138,6 +142,10 @@ describe("checkLogin retries on unknown status", () => {
// With the fix, the login loop retried and the bind key is now shown.
expect(screen.getByText("BIND42")).toBeInTheDocument();
+ // Spinner gone — bind key received.
+ expect(
+ container.querySelector(".retrieving-bind-key-spinner")
+ ).not.toBeInTheDocument();
});
});
@@ -164,11 +172,15 @@ describe("reauthenticateHandler shows spinner while retrieving bind key", () =>
// refreshToken will fail when reauthenticate fires.
mockRefreshToken.mockRejectedValue(new Error("token expired"));
- render();
+ const { container } = render();
// Let mount complete.
await tick(0);
expect(screen.getByText("INIT01")).toBeInTheDocument();
+ // Spinner hidden — bind key is shown.
+ expect(
+ container.querySelector(".retrieving-bind-key-spinner")
+ ).not.toBeInTheDocument();
// Fire reauthenticate event — refreshToken rejects → catch block
// clears screen/bindKey, sets retrievingBindKey, calls checkLogin
@@ -182,5 +194,75 @@ describe("reauthenticateHandler shows spinner while retrieving bind key", () =>
// recovery flow works: clear state → checkLogin → new bind key.
expect(screen.queryByText("INIT01")).not.toBeInTheDocument();
expect(screen.getByText("REAUTH01")).toBeInTheDocument();
+ // Spinner gone after recovery.
+ expect(
+ container.querySelector(".retrieving-bind-key-spinner")
+ ).not.toBeInTheDocument();
+ });
+});
+
+describe("spinner persists during checkLogin retry on failure", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ mockCheckLogin.mockReset();
+ mockRefreshToken.mockReset();
+ });
+
+ afterEach(() => {
+ cleanup();
+ vi.useRealTimers();
+ });
+
+ it("keeps spinner visible when checkLogin rejects", async () => {
+ // First call rejects (network error), retry succeeds with bind key.
+ mockCheckLogin
+ .mockRejectedValueOnce(new Error("Network error"))
+ .mockResolvedValueOnce({ status: "awaitingBindKey", bindKey: "RETRY01" })
+ .mockResolvedValue({ status: "awaitingBindKey", bindKey: "RETRY01" });
+
+ const { container } = render();
+
+ await tick(0);
+
+ // checkLogin rejected → catch → restartLoginTimeout.
+ // retrievingBindKey was never reset, so spinner is still visible.
+ expect(
+ container.querySelector(".retrieving-bind-key-spinner")
+ ).toBeInTheDocument();
+
+ // Advance past the retry timeout.
+ await tick(60);
+
+ // Retry succeeded with bind key — spinner gone.
+ expect(
+ container.querySelector(".retrieving-bind-key-spinner")
+ ).not.toBeInTheDocument();
+ expect(screen.getByText("RETRY01")).toBeInTheDocument();
+ });
+});
+
+describe("spinner not shown in preview mode", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ mockCheckLogin.mockReset();
+ mockRefreshToken.mockReset();
+ });
+
+ afterEach(() => {
+ cleanup();
+ vi.useRealTimers();
+ });
+
+ it("does not show spinner when preview is set", async () => {
+ const { container } = render(
+
+ );
+
+ await tick(0);
+
+ // Even though retrievingBindKey starts true, preview mode suppresses it.
+ expect(
+ container.querySelector(".retrieving-bind-key-spinner")
+ ).not.toBeInTheDocument();
});
});
From 9db24c5e4fe3ed926b47f2e964b671c1c43b4e0c Mon Sep 17 00:00:00 2001
From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com>
Date: Thu, 30 Apr 2026 13:10:19 +0200
Subject: [PATCH 7/8] 7203: Applied coding standards
---
assets/tests/client/app-bind-key.test.jsx | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/assets/tests/client/app-bind-key.test.jsx b/assets/tests/client/app-bind-key.test.jsx
index 61ed2713a..ad19f64c0 100644
--- a/assets/tests/client/app-bind-key.test.jsx
+++ b/assets/tests/client/app-bind-key.test.jsx
@@ -133,7 +133,7 @@ describe("checkLogin retries on unknown status", () => {
expect(screen.queryByText("BIND42")).not.toBeInTheDocument();
// Spinner should still be visible — we are still retrieving.
expect(
- container.querySelector(".retrieving-bind-key-spinner")
+ container.querySelector(".retrieving-bind-key-spinner"),
).toBeInTheDocument();
// Advance past loginCheckTimeout to fire the retry timer.
@@ -144,7 +144,7 @@ describe("checkLogin retries on unknown status", () => {
expect(screen.getByText("BIND42")).toBeInTheDocument();
// Spinner gone — bind key received.
expect(
- container.querySelector(".retrieving-bind-key-spinner")
+ container.querySelector(".retrieving-bind-key-spinner"),
).not.toBeInTheDocument();
});
});
@@ -179,7 +179,7 @@ describe("reauthenticateHandler shows spinner while retrieving bind key", () =>
expect(screen.getByText("INIT01")).toBeInTheDocument();
// Spinner hidden — bind key is shown.
expect(
- container.querySelector(".retrieving-bind-key-spinner")
+ container.querySelector(".retrieving-bind-key-spinner"),
).not.toBeInTheDocument();
// Fire reauthenticate event — refreshToken rejects → catch block
@@ -196,7 +196,7 @@ describe("reauthenticateHandler shows spinner while retrieving bind key", () =>
expect(screen.getByText("REAUTH01")).toBeInTheDocument();
// Spinner gone after recovery.
expect(
- container.querySelector(".retrieving-bind-key-spinner")
+ container.querySelector(".retrieving-bind-key-spinner"),
).not.toBeInTheDocument();
});
});
@@ -227,7 +227,7 @@ describe("spinner persists during checkLogin retry on failure", () => {
// checkLogin rejected → catch → restartLoginTimeout.
// retrievingBindKey was never reset, so spinner is still visible.
expect(
- container.querySelector(".retrieving-bind-key-spinner")
+ container.querySelector(".retrieving-bind-key-spinner"),
).toBeInTheDocument();
// Advance past the retry timeout.
@@ -235,7 +235,7 @@ describe("spinner persists during checkLogin retry on failure", () => {
// Retry succeeded with bind key — spinner gone.
expect(
- container.querySelector(".retrieving-bind-key-spinner")
+ container.querySelector(".retrieving-bind-key-spinner"),
).not.toBeInTheDocument();
expect(screen.getByText("RETRY01")).toBeInTheDocument();
});
@@ -254,15 +254,13 @@ describe("spinner not shown in preview mode", () => {
});
it("does not show spinner when preview is set", async () => {
- const { container } = render(
-
- );
+ const { container } = render();
await tick(0);
// Even though retrievingBindKey starts true, preview mode suppresses it.
expect(
- container.querySelector(".retrieving-bind-key-spinner")
+ container.querySelector(".retrieving-bind-key-spinner"),
).not.toBeInTheDocument();
});
});
From f157e985dba6e4f76b1ddd0e27cc9324dc6486a9 Mon Sep 17 00:00:00 2001
From: Troels Ugilt Jensen <6103205+tuj@users.noreply.github.com>
Date: Thu, 30 Apr 2026 13:46:08 +0200
Subject: [PATCH 8/8] 7203: Fixed issue with test
---
assets/tests/client/app-bind-key.test.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assets/tests/client/app-bind-key.test.jsx b/assets/tests/client/app-bind-key.test.jsx
index ad19f64c0..654407c2a 100644
--- a/assets/tests/client/app-bind-key.test.jsx
+++ b/assets/tests/client/app-bind-key.test.jsx
@@ -254,7 +254,7 @@ describe("spinner not shown in preview mode", () => {
});
it("does not show spinner when preview is set", async () => {
- const { container } = render();
+ const { container } = render();
await tick(0);