From 4bb862ee7607180ba057b3832467f77b3d1cd459 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Mon, 3 Aug 2026 21:40:59 +0200 Subject: [PATCH] fix: stabilize advanced widget interactions --- .../board/advanced-focus/context.tsx | 3 +- e2e/shared/login.ts | 35 ++++++------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/apps/nextjs/src/components/board/advanced-focus/context.tsx b/apps/nextjs/src/components/board/advanced-focus/context.tsx index 5cf3135f0..50ac3dd65 100644 --- a/apps/nextjs/src/components/board/advanced-focus/context.tsx +++ b/apps/nextjs/src/components/board/advanced-focus/context.tsx @@ -3,6 +3,7 @@ import type { PropsWithChildren } from "react"; import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; import { Overlay, Portal } from "@mantine/core"; +import { useIsomorphicEffect } from "@mantine/hooks"; import { useEditMode } from "@homarr/boards/edit-mode"; @@ -229,7 +230,7 @@ export const BoardAdvancedFocusProvider = ({ children }: PropsWithChildren) => { if (isEditMode && activeRef.current) close(false); }, [close, isEditMode]); - useEffect(() => { + useIsomorphicEffect(() => { if (active?.activation !== "manual") return; const background = document.querySelectorAll("[data-advanced-focus-background]"); background.forEach((element) => { diff --git a/e2e/shared/login.ts b/e2e/shared/login.ts index 37684299b..7a3e3be1c 100644 --- a/e2e/shared/login.ts +++ b/e2e/shared/login.ts @@ -13,7 +13,7 @@ interface LoginInput { export const loginAsync = async ({ page, baseUrl, credentials, destination = "/" }: LoginInput) => { const destinationUrl = new URL(destination, baseUrl); const loginUrl = new URL("/auth/login", baseUrl); - loginUrl.searchParams.set("callbackUrl", destinationUrl.href); + loginUrl.searchParams.set("callbackUrl", `${destinationUrl.pathname}${destinationUrl.search}${destinationUrl.hash}`); await page.goto(loginUrl.href, { waitUntil: "load" }); await page.waitForFunction(() => { @@ -23,29 +23,14 @@ export const loginAsync = async ({ page, baseUrl, credentials, destination = "/" await page.getByLabel("Username").fill(credentials.username); await page.locator("#password").fill(credentials.password); + const destinationNavigation = page.waitForURL( + (url) => + url.origin === destinationUrl.origin && + url.pathname === destinationUrl.pathname && + url.search === destinationUrl.search && + url.hash === destinationUrl.hash, + { timeout: 60_000 }, + ); await page.locator("button[type='submit']").click(); - await waitForAuthenticatedSessionAsync(page, baseUrl); - - await page.goto(destinationUrl.href, { waitUntil: "domcontentloaded" }); - const currentUrl = new URL(page.url()); - if (currentUrl.origin !== destinationUrl.origin || currentUrl.pathname !== destinationUrl.pathname) { - throw new Error("Authenticated destination was not reached"); - } -}; - -const waitForAuthenticatedSessionAsync = async (page: Page, baseUrl: string) => { - const sessionUrl = new URL("/api/auth/session", baseUrl).href; - const deadline = Date.now() + 30_000; - - while (Date.now() < deadline) { - const response = await page.request.get(sessionUrl); - if (response.ok()) { - const session = (await response.json()) as { user?: unknown } | null; - if (session?.user !== undefined) return; - } - - await page.waitForTimeout(100); - } - - throw new Error("Authentication session was not established"); + await destinationNavigation; };