Files
Nico 1a2b691ddb Policies: Include/Exclude label targeting on edit policy page (#33441) (#47354)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #46583

Figma:
https://www.figma.com/design/0F1sw63SuYaKVWlcL7mnc6/-33441-Policies--Custom-targets-with-%22Include-any%22-and-%22Exclude-any%22?node-id=5319-2300&t=Fszpf83KhcZ7ViWh-0

## Testing

- [x] Added/updated automated tests

- [x] QA'd all new/changed functionality manually

Note: selecting `Exclude All` will fail since BE doesn't support it yet.
Will be tackled as part of
https://github.com/fleetdm/fleet/issues/46582.


https://github.com/user-attachments/assets/12316264-b5b0-4588-b714-8f0aea11c604




<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added support for excluding labels when targeting policy hosts,
enabling more granular control over which hosts receive specific policy
configurations.

* **Refactor**
* Streamlined label-targeting state management and UI components for
improved performance and maintainability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-11 10:18:05 -03:00

116 lines
3.6 KiB
TypeScript

import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { noop } from "lodash";
import { ILabelSummary } from "interfaces/label";
import TargetLabelSelector, { ILabelConfig } from "./TargetLabelSelector";
const LABELS: ILabelSummary[] = [
{ id: 1, name: "label 1", label_type: "regular" },
{ id: 2, name: "label 2", label_type: "regular" },
];
const makeTab = (overrides: Partial<ILabelConfig> = {}): ILabelConfig => ({
selectedLabels: {},
onSelectLabel: noop,
...overrides,
});
const renderSelector = (
props: Partial<React.ComponentProps<typeof TargetLabelSelector>> = {}
) =>
render(
<TargetLabelSelector
selectedTargetType="Custom"
onSelectTargetType={noop}
labels={LABELS}
includeConfig={makeTab({ showModeToggle: true, mode: "any" })}
excludeConfig={makeTab()}
emptyStateDescription="Add a label to target a group of hosts."
onAddLabel={noop}
{...props}
/>
);
describe("TargetLabelSelector (tabbed) component", () => {
it("renders Include and Exclude tabs with labels in Custom mode", () => {
renderSelector();
expect(screen.getByText("Include")).toBeVisible();
expect(screen.getByText("Exclude")).toBeVisible();
expect(screen.getByRole("checkbox", { name: "label 1" })).toBeVisible();
expect(screen.getByRole("checkbox", { name: "label 2" })).toBeVisible();
});
it("does not render the custom tabs when the target type is 'All hosts'", () => {
renderSelector({ selectedTargetType: "All hosts" });
expect(screen.queryByText("Include")).not.toBeInTheDocument();
expect(
screen.queryByRole("checkbox", { name: "label 1" })
).not.toBeInTheDocument();
});
it("renders the Any/All mode toggle on the include tab", () => {
renderSelector();
expect(screen.getByRole("radio", { name: "Any" })).toBeVisible();
expect(screen.getByRole("radio", { name: "All" })).toBeVisible();
});
it("does not render the mode toggle on the exclude tab when showModeToggle is false", () => {
renderSelector({ excludeConfig: makeTab({ showModeToggle: false }) });
fireEvent.click(screen.getByText("Exclude"));
expect(
screen.queryByRole("radio", { name: "Any" })
).not.toBeInTheDocument();
expect(
screen.queryByRole("radio", { name: "All" })
).not.toBeInTheDocument();
});
it("renders selected labels as checked", () => {
renderSelector({
includeConfig: makeTab({
showModeToggle: true,
mode: "any",
selectedLabels: { "label 1": true, "label 2": false },
}),
});
expect(screen.getByRole("checkbox", { name: "label 1" })).toBeChecked();
expect(screen.getByRole("checkbox", { name: "label 2" })).not.toBeChecked();
});
it("disables a label in the include tab when it is selected in the exclude tab", () => {
renderSelector({
excludeConfig: makeTab({ selectedLabels: { "label 1": true } }),
});
expect(screen.getByRole("checkbox", { name: "label 1" })).toHaveAttribute(
"aria-disabled",
"true"
);
expect(screen.getByRole("checkbox", { name: "label 2" })).toHaveAttribute(
"aria-disabled",
"false"
);
});
it("renders the empty state and triggers onAddLabel when there are no labels", () => {
const onAddLabel = jest.fn();
renderSelector({ labels: [], onAddLabel });
expect(screen.getByText("No labels")).toBeVisible();
expect(
screen.getByText("Add a label to target a group of hosts.")
).toBeVisible();
fireEvent.click(screen.getByRole("button", { name: "Add label" }));
expect(onAddLabel).toHaveBeenCalledTimes(1);
});
});