fix(onboarding): restore e2e flow

This commit is contained in:
ajnart committed 2026-08-14 01:20:28 +02:00
1 parent eb33ff1372
commit 1c34d95976
5 files changed
+19 -15

No files matched your search

@@ -64,6 +64,7 @@ export default async function InitPage() {
kubernetesConfigured: canReadSetupContext && dockerEnv.ENABLE_KUBERNETES,
workshopApiUrl,
workshopUrl: workshopWebUrl,
serverOrigin: baseUrl,
mcpEndpoint: `${baseUrl}/api/mcp`,
canConfigurePrivileged,
hasUsers: Boolean(firstUser),
+11 -9
View File
@@ -101,9 +101,9 @@ describe("Onboarding", () => {
await page.locator("css=button[type='submit']").click();
await page.getByRole("heading", { name: "Start with familiar defaults" }).waitFor({ timeout: 30_000 });
const serverOrigin = page.getByLabel("Domain, IP, or reverse-proxy path");
const serverOrigin = page.getByLabel("Usual server address");
await serverOrigin.fill("https://home.example/homarr");
await page.getByRole("combobox", { name: "Default language" }).click();
await page.getByLabel("Default language").click();
await page.getByRole("option", { name: /Français/ }).click();
expect(await serverOrigin.inputValue()).toBe("https://home.example/homarr");
expect(await page.getByRole("heading", { name: "Start with familiar defaults" }).isVisible()).toBe(true);
@@ -129,7 +129,7 @@ describe("Onboarding", () => {
["Discover", "See what this installation can actually reach"],
["Connect", "Connect what makes the board useful"],
["Board", "Shape the board before it is built"],
["Extend", "Add intelligence when it helps"],
["Extend", "Advanced features"],
] as const;
for (const [section, heading] of sections) {
await page.getByRole("button", { name: new RegExp(`^${section}`) }).click();
@@ -147,7 +147,6 @@ describe("Onboarding", () => {
expect(await boardPreview.getAttribute("data-layout-columns")).toBe("12");
await page.getByRole("button", { name: /^Connect/ }).click();
await page.getByRole("button", { name: "Add another integration" }).click();
const sonarr = page.locator('button[aria-label="Sonarr"]');
await sonarr.click();
await page.getByLabel("Service URL").waitFor();
@@ -449,15 +448,18 @@ describe("Onboarding", () => {
expect(await page.locator('meta[name="homarr-workshop-api-url"]').getAttribute("content")).toBe(
configuredWorkshopApiUrl,
);
await page.getByRole("button", { name: /^Extend/ }).click();
await page.getByRole("heading", { name: "Add intelligence when it helps" }).waitFor();
await page.getByLabel("Provider URL").waitFor();
await page.getByRole("button", { name: "Extend (5/6)" }).click();
await page.getByRole("heading", { name: "Advanced features" }).waitFor();
await page.getByRole("tab", { name: "Assistant" }).click();
await page.getByLabel("API base URL").waitFor();
const provider = page.getByRole("combobox", { name: "Provider", exact: true });
await expect.poll(() => provider.inputValue(), { timeout: 10_000 }).toBe("Custom endpoint");
expect(await page.getByLabel("Provider URL").inputValue()).toBe("http://assistant.local/v1");
expect(await page.getByLabel("API base URL").inputValue()).toBe("http://assistant.local/v1");
expect(await page.locator('input[value="local-model"]').inputValue()).toBe("local-model");
expect(await page.getByText("Model discovery is unavailable.").count()).toBe(1);
expect(await page.getByText("Discovery is unavailable. You can still enter a model ID manually.").count()).toBe(
1,
);
} finally {
try {
await Promise.all([browser.close(), homarrContainer.stop()]);
+1
View File
@@ -52,6 +52,7 @@ export class OnboardingActions {
}
public async processIntegrationsStepAsync() {
await this.page.getByRole("button", { name: "Review (6/6)" }).click();
await this.page.getByRole("button", { name: "Build my board" }).click();
}
}
+5 -6
View File
@@ -212,7 +212,7 @@ export const SetupStudio = ({ environment, assistantConfiguration }: OnboardingS
const [activeSection, setActiveSection] = useState<StudioSection>("essentials");
const [incompleteIntegrationConfirmationOpened, setIncompleteIntegrationConfirmationOpened] = useState(false);
const [selectedLocale, setSelectedLocale] = useState(currentLocale);
const [serverOrigin, setServerOrigin] = useState("");
const [serverOrigin, setServerOrigin] = useState(environment.serverOrigin);
const [urlMode, setUrlMode] = useState<UrlTemplateMode>("hostPort");
const [analyticsEnabled, setAnalyticsEnabled] = useState(true);
const [selectedKinds, setSelectedKinds] = useState<IntegrationKind[]>([]);
@@ -282,10 +282,6 @@ export const SetupStudio = ({ environment, assistantConfiguration }: OnboardingS
[discoveredIntegrations],
);
useEffect(() => {
setServerOrigin((current) => current || window.location.origin);
}, []);
useEffect(() => {
if (!docker.data) return;
const newIntegrationSourceIds = takeNewSourceIds(
@@ -894,6 +890,8 @@ const SectionHeading = ({
const Essentials = (props: StudioSectionProps) => {
const t = useScopedI18n("init.studio.essentials");
const [isHydrated, setIsHydrated] = useState(false);
useEffect(() => setIsHydrated(true), []);
return (
<Stack gap="lg">
<SectionHeading headingRef={props.headingRef} title={t("title")} description={t("description")} />
@@ -921,9 +919,9 @@ const Essentials = (props: StudioSectionProps) => {
placeholder="home.lan · 192.168.1.10 · https://homarr.example.com"
value={props.serverOrigin}
onChange={(event) => props.setServerOrigin(event.currentTarget.value)}
readOnly={!isHydrated}
required
withAsterisk
autoFocus
/>
<OnboardingFloatingControl
ariaLabel={t("urlModeLabel")}
@@ -1614,6 +1612,7 @@ const BoardPreview = ({
<figure
className={classes.preview}
aria-label={ariaLabel}
data-layout-role="base"
data-layout-columns={columnCount}
style={
{
+1
View File
@@ -11,6 +11,7 @@ export interface OnboardingEnvironment {
kubernetesConfigured: boolean;
workshopApiUrl: string;
workshopUrl: string;
serverOrigin: string;
mcpEndpoint: string;
canConfigurePrivileged: boolean;
hasUsers: boolean;