mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35459 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [ ] Added/updated automated tests working on these - [X] QA'd all new/changed functionality manually ## Screenshots | Option does not appear for FMA apps | | --- | | <img width="723" height="419" alt="image" src="https://github.com/user-attachments/assets/f9f1328e-e38c-452c-b06e-337a69c13e71" /> | | Option does not appear for custom packages | | --- | | <img width="731" height="416" alt="image" src="https://github.com/user-attachments/assets/3de78f15-d7ce-45c7-875f-a250fc00a160" /> | | Option does not appear for macOS VPP apps | | --- | | <img width="725" height="454" alt="image" src="https://github.com/user-attachments/assets/07dcb074-f57d-4cc4-a746-20b80c821fb6" /> | | Option appears iOS VPP apps | | --- | | <img width="727" height="420" alt="image" src="https://github.com/user-attachments/assets/ec4ce503-0300-437c-b3f2-248928fcfe7b" /> | | Option appears iPadOS VPP apps | | --- | | <img width="727" height="422" alt="image" src="https://github.com/user-attachments/assets/0030c6cc-3d93-480c-af93-740fca4d5b57" /> | | Form with auto-updates disabled | | --- | | <img width="668" height="517" alt="image" src="https://github.com/user-attachments/assets/d59a7ba4-dc83-4a80-ba94-0befc7635f05" /> | | Start / end time validation | | --- | | <img width="668" height="679" alt="image" src="https://github.com/user-attachments/assets/939fd09a-76f6-42de-9c71-fe4982f3f84b" /> | | Maintenance window length validation | | --- | | <img width="664" height="681" alt="image" src="https://github.com/user-attachments/assets/a2eab676-5166-42a9-9043-2565014e33cb" /> | | Badge and banner appears after saving | | --- | | <img width="766" height="529" alt="image" src="https://github.com/user-attachments/assets/48d89e1d-4430-4dd7-b8e6-d5b04ebad47f" /> | --------- Co-authored-by: Gabriel Hernandez <ghernandez345@gmail.com> Co-authored-by: Nico <32375741+nulmete@users.noreply.github.com>
187 lines
6.7 KiB
TypeScript
187 lines
6.7 KiB
TypeScript
import React from "react";
|
|
import { screen } from "@testing-library/react";
|
|
import { createCustomRenderer } from "test/test-utils";
|
|
import {
|
|
createMockSoftwarePackage,
|
|
createMockSoftwareTitle,
|
|
} from "__mocks__/softwareMock";
|
|
import { InstallerType } from "interfaces/software";
|
|
import softwareAPI from "services/entities/software";
|
|
import EditIconModal from "./EditIconModal";
|
|
|
|
const software = createMockSoftwareTitle();
|
|
const softwarePackage = createMockSoftwarePackage();
|
|
const MOCK_PROPS = {
|
|
softwareId: 123,
|
|
teamIdForApi: 456,
|
|
software: softwarePackage,
|
|
onExit: jest.fn(),
|
|
refetchSoftwareTitle: jest.fn(),
|
|
iconUploadedAt: "2025-09-03T12:00:00Z",
|
|
setIconUploadedAt: jest.fn(),
|
|
installerType: "package" as InstallerType,
|
|
previewInfo: {
|
|
type: "apps",
|
|
versions: software.versions?.length,
|
|
source: software.source,
|
|
currentIconUrl: null,
|
|
name: software.name,
|
|
titleName: software.name,
|
|
countsUpdatedAt: "2025-09-03T12:00:00Z",
|
|
},
|
|
};
|
|
|
|
describe("EditIconModal", () => {
|
|
it("renders with the correct modal title for software, FileUploader, Preview tabs, save button", () => {
|
|
const render = createCustomRenderer({ withBackendMock: true });
|
|
render(<EditIconModal {...MOCK_PROPS} />);
|
|
|
|
expect(screen.getByText(/edit appearance/i)).toBeInTheDocument();
|
|
expect(screen.getByText("Choose file")).toBeInTheDocument();
|
|
expect(screen.getByText("Preview")).toBeInTheDocument();
|
|
expect(screen.getByText("Fleet")).toBeInTheDocument();
|
|
expect(screen.getByText("Self-service")).toBeInTheDocument();
|
|
const save = screen.getByRole("button", { name: "Save" });
|
|
expect(save).toBeInTheDocument();
|
|
});
|
|
|
|
it("shows the correct software name and preview info in Fleet card", () => {
|
|
const render = createCustomRenderer({ withBackendMock: true });
|
|
render(<EditIconModal {...MOCK_PROPS} />);
|
|
expect(screen.getAllByText(software.name).length).toBeGreaterThan(0);
|
|
expect(screen.getByText("Version")).toBeInTheDocument();
|
|
expect(screen.getByText("Vulnerabilities")).toBeInTheDocument();
|
|
expect(screen.getByText("88.0.1")).toBeInTheDocument();
|
|
expect(screen.getByText("20 vulnerabilities")).toBeInTheDocument();
|
|
});
|
|
|
|
it("calls onExit handler when modal close is triggered", async () => {
|
|
const render = createCustomRenderer({ withBackendMock: true });
|
|
const { user } = render(<EditIconModal {...MOCK_PROPS} />);
|
|
|
|
await user.keyboard("{Escape}");
|
|
|
|
expect(MOCK_PROPS.onExit).toHaveBeenCalled();
|
|
});
|
|
|
|
// Note: Rely on QA Wolf for E2e testing of file upload, preview, save, and remove icon
|
|
|
|
describe("Display name tests", () => {
|
|
it("shows the Display name input with correct default value", () => {
|
|
const render = createCustomRenderer({ withBackendMock: true });
|
|
render(<EditIconModal {...MOCK_PROPS} />);
|
|
// Should default to blank if previewInfo.titleName === previewInfo.name
|
|
const displayNameInput = screen.getByLabelText("Display name");
|
|
expect(displayNameInput).toBeInTheDocument();
|
|
expect(displayNameInput).toHaveValue("");
|
|
});
|
|
|
|
it("pre-fills Display name if previewInfo.name has been modified", () => {
|
|
const MODIFIED_PROPS = {
|
|
...MOCK_PROPS,
|
|
previewInfo: {
|
|
...MOCK_PROPS.previewInfo,
|
|
name: "New Custom Name",
|
|
titleName: "Original Title Name",
|
|
},
|
|
};
|
|
const render = createCustomRenderer({ withBackendMock: true });
|
|
render(<EditIconModal {...MODIFIED_PROPS} />);
|
|
const displayNameInput = screen.getByLabelText("Display name");
|
|
expect(displayNameInput).toBeInTheDocument();
|
|
expect(displayNameInput).toHaveValue("New Custom Name");
|
|
const helpText = screen.getByText(
|
|
/Optional. If left blank, Fleet will use/
|
|
);
|
|
|
|
expect(helpText).toHaveTextContent(MODIFIED_PROPS.previewInfo.titleName);
|
|
});
|
|
|
|
it("only edits the display name when icon is not changed", async () => {
|
|
const editSoftwarePackageSpy = jest
|
|
.spyOn(softwareAPI, "editSoftwarePackage")
|
|
.mockResolvedValue({} as any);
|
|
const deleteSoftwareIconSpy = jest.spyOn(
|
|
softwareAPI,
|
|
"deleteSoftwareIcon"
|
|
);
|
|
const editSoftwareIconSpy = jest.spyOn(softwareAPI, "editSoftwareIcon");
|
|
|
|
const render = createCustomRenderer({ withBackendMock: true });
|
|
const { user } = render(<EditIconModal {...MOCK_PROPS} />);
|
|
|
|
const displayNameInput = screen.getByLabelText("Display name");
|
|
await user.type(displayNameInput, "New Name ");
|
|
|
|
const saveButton = screen.getByRole("button", { name: "Save" });
|
|
await user.click(saveButton);
|
|
|
|
expect(editSoftwarePackageSpy).toHaveBeenCalledWith({
|
|
data: { displayName: "New Name" }, // whitespace was trimmed
|
|
softwareId: 123,
|
|
teamId: 456,
|
|
});
|
|
|
|
expect(deleteSoftwareIconSpy).not.toHaveBeenCalled();
|
|
expect(editSoftwareIconSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("only edits the display name when removing a custom name", async () => {
|
|
const editSoftwarePackageSpy = jest
|
|
.spyOn(softwareAPI, "editSoftwarePackage")
|
|
.mockResolvedValue({} as any);
|
|
|
|
const MODIFIED_PROPS = {
|
|
...MOCK_PROPS,
|
|
previewInfo: {
|
|
...MOCK_PROPS.previewInfo,
|
|
name: "Custom Display Name",
|
|
titleName: "Original Software Name",
|
|
},
|
|
};
|
|
|
|
const render = createCustomRenderer({ withBackendMock: true });
|
|
const { user } = render(<EditIconModal {...MODIFIED_PROPS} />);
|
|
|
|
const displayNameInput = screen.getByLabelText("Display name");
|
|
await user.clear(displayNameInput);
|
|
|
|
const saveButton = screen.getByRole("button", { name: "Save" });
|
|
await user.click(saveButton);
|
|
|
|
expect(editSoftwarePackageSpy).toHaveBeenCalledWith({
|
|
data: { displayName: "" },
|
|
softwareId: 123,
|
|
teamId: 456,
|
|
});
|
|
});
|
|
|
|
it("handles name update error properly", async () => {
|
|
const editSoftwarePackageSpy = jest
|
|
.spyOn(softwareAPI, "editSoftwarePackage")
|
|
.mockRejectedValue(new Error("Name update failed"));
|
|
|
|
const CUSTOM_ICON_PROPS = {
|
|
...MOCK_PROPS,
|
|
previewInfo: {
|
|
...MOCK_PROPS.previewInfo,
|
|
currentIconUrl: null,
|
|
},
|
|
};
|
|
|
|
const render = createCustomRenderer({ withBackendMock: true });
|
|
const { user } = render(<EditIconModal {...CUSTOM_ICON_PROPS} />);
|
|
|
|
const displayNameInput = screen.getByLabelText("Display name");
|
|
await user.type(displayNameInput, "New Name");
|
|
|
|
const saveButton = screen.getByRole("button", { name: "Save" });
|
|
await user.click(saveButton);
|
|
|
|
expect(editSoftwarePackageSpy).toHaveBeenCalled();
|
|
await expect(editSoftwarePackageSpy).rejects.toThrow(
|
|
"Name update failed"
|
|
);
|
|
});
|
|
});
|
|
});
|