Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions web/package/agama-web-ui.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
-------------------------------------------------------------------
Mon Mar 9 09:19:30 UTC 2026 - David Diaz <dgonzalez@suse.com>

- Allow downloading the user config (jsc#PED-15453).

-------------------------------------------------------------------
Thu Mar 5 11:46:24 UTC 2026 - Imobach Gonzalez Sosa <igonzalezsosa@suse.com>

Expand Down
101 changes: 101 additions & 0 deletions web/src/components/core/InstallerOptionsMenu.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) [2026] SUSE LLC
*
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, contact SUSE LLC.
*
* To contact SUSE LLC about this file by physical or electronic mail, you may
* find current contact information at www.suse.com.
*/

import React from "react";
import { screen } from "@testing-library/react";
import { plainRender } from "~/test-utils";
import InstallerOptionsMenu from "./InstallerOptionsMenu";

jest.mock("~/components/core/ChangeProductOption", () => () => (
<a role="menuitem">Change product</a>
));

describe("InstallerOptionsMenu", () => {
describe("toggle button", () => {
it("renders a toggle with 'More installer options' aria-label", () => {
plainRender(<InstallerOptionsMenu />);
screen.getByRole("button", { name: /More installer options/i });
});

it("renders the 'More' label by default", () => {
plainRender(<InstallerOptionsMenu />);
expect(screen.getByRole("button", { name: /More installer options/i })).toHaveTextContent(
"More",
);
});

it("hides the 'More' label when hideLabel is true", () => {
plainRender(<InstallerOptionsMenu hideLabel />);
const toggle = screen.getByRole("button", { name: /More installer options/i });
expect(toggle).not.toHaveTextContent("More");
});
});

describe("dropdown open/close behavior", () => {
it("is closed by default", () => {
plainRender(<InstallerOptionsMenu />);
expect(screen.queryByRole("menu")).toBeNull();
});

it("opens the dropdown when the toggle is clicked", async () => {
const { user } = plainRender(<InstallerOptionsMenu />);
await user.click(screen.getByRole("button", { name: /More installer options/i }));
screen.getByRole("menu");
});

it("closes the dropdown after selecting an item", async () => {
const { user } = plainRender(<InstallerOptionsMenu />);
await user.click(screen.getByRole("button", { name: /More installer options/i }));
const menu = screen.getByRole("menu");
await user.click(screen.getByRole("menuitem", { name: /Download config/i }));
expect(menu).not.toBeVisible();
});
});

describe("dropdown items", () => {
it("renders the 'Change product' option when showChangeProductOption is true", async () => {
const { user } = plainRender(<InstallerOptionsMenu showChangeProductOption />);
await user.click(screen.getByRole("button", { name: /More installer options/i }));
screen.getByRole("menuitem", { name: /Change product/i });
});

it("does not render the 'Change product' option by default", async () => {
const { user } = plainRender(<InstallerOptionsMenu />);
await user.click(screen.getByRole("button", { name: /More installer options/i }));
expect(screen.queryByRole("menuitem", { name: /Change product/i })).not.toBeInTheDocument();
});

it("renders the 'Download config' link", async () => {
const { user } = plainRender(<InstallerOptionsMenu />);
await user.click(screen.getByRole("button", { name: /More installer options/i }));
const link = screen.getByRole("menuitem", { name: /Download config/i });
expect(link).toHaveAttribute("download", "agama-config.json");
});

it("renders the 'Download logs' link", async () => {
const { user } = plainRender(<InstallerOptionsMenu />);
await user.click(screen.getByRole("button", { name: /More installer options/i }));
const link = screen.getByRole("menuitem", { name: /Download logs/i });
expect(link).toHaveAttribute("download", "agama-logs.tar.gz");
});
});
});
3 changes: 3 additions & 0 deletions web/src/components/core/InstallerOptionsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ export default function InstallerOptionsMenu({
>
<DropdownList>
{showChangeProductOption && <ChangeProductOption component="dropdownitem" />}
<DropdownItem key="download-config" to={ROOT.config} download="agama-config.json">
{_("Download config")}
</DropdownItem>
<DropdownItem key="download-logs" to={ROOT.logs} download="agama-logs.tar.gz">
{_("Download logs")}
</DropdownItem>
Expand Down
1 change: 1 addition & 0 deletions web/src/routes/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const ROOT = {
installationFinished: "/installation/finished",
installationExit: "/installation/exit",
logs: "/api/v2/private/download_logs",
config: "/api/v2/config",
};

const USER = {
Expand Down