import React from "react";
import { screen, waitFor } from "@testing-library/react";
import { createCustomRenderer } from "test/test-utils";
import createMockQuery from "__mocks__/queryMock";
import createMockUser from "__mocks__/userMock";
import createMockTeam from "__mocks__/teamMock";
import createMockConfig from "__mocks__/configMock";
import userEvent from "@testing-library/user-event";
import { http, HttpResponse } from "msw";
import mockServer from "test/mock-server";
import { QueryablePlatform } from "interfaces/platform";
import SaveNewQueryModal from "./SaveNewQueryModal";
const baseUrl = (path: string) => {
return `/api/latest/fleet${path}`;
};
const mockLabels = [
{
id: 1,
name: "Fun",
description: "Computers that like to have a good time",
label_type: "regular",
},
{
id: 2,
name: "Fresh",
description: "Laptops with dirty mouths",
label_type: "regular",
},
];
const labelSummariesHandler = http.get(baseUrl("/labels/summary"), () => {
return HttpResponse.json({
labels: mockLabels,
});
});
const mockQuery = createMockQuery();
describe("SaveNewQueryModal", () => {
const defaultProps = {
queryValue: "SELECT * FROM users",
apiTeamIdForQuery: 1,
isLoading: false,
saveQuery: jest.fn(),
toggleSaveNewQueryModal: jest.fn(),
backendValidators: {},
existingQuery: mockQuery,
queryReportsDisabled: false,
platformSelector: {
getSelectedPlatforms: () => ["linux"] as QueryablePlatform[],
setSelectedPlatforms: jest.fn(),
isAnyPlatformSelected: true,
render: () => <>>,
},
};
it("renders the modal with initial values and allows editing", async () => {
const render = createCustomRenderer({
withBackendMock: true,
context: {
app: {
currentUser: createMockUser(),
config: createMockConfig(),
isPremiumTier: false,
},
},
});
const { user } = render();
expect(screen.getByLabelText("Name")).toBeInTheDocument();
expect(screen.getByLabelText("Description")).toBeInTheDocument();
expect(screen.getByText("Interval")).toBeInTheDocument();
expect(screen.getByText("Observers can run")).toBeInTheDocument();
expect(screen.getByText("Automations off")).toBeInTheDocument();
expect(screen.getByText("Advanced options")).toBeInTheDocument();
const nameInput = screen.getByLabelText("Name");
await user.type(nameInput, "Test Query");
expect(nameInput).toHaveValue("Test Query");
});
it("toggles advanced options", async () => {
const render = createCustomRenderer({
withBackendMock: true,
context: {
app: {
currentUser: createMockUser(),
config: createMockConfig(),
isPremiumTier: false,
},
},
});
const { user } = render();
const advancedOptionsButton = screen.getByText("Advanced options");
await user.click(advancedOptionsButton);
expect(screen.getByText("Minimum osquery version")).toBeInTheDocument();
expect(screen.getByText("Logging")).toBeInTheDocument();
await user.click(advancedOptionsButton);
});
it("displays error when query name is empty", async () => {
const render = createCustomRenderer({
withBackendMock: true,
context: {
app: {
currentUser: createMockUser(),
config: createMockConfig(),
isPremiumTier: false,
},
},
});
const { user } = render();
await user.click(screen.getByText("Save"));
expect(screen.getByText("Report name must be present")).toBeInTheDocument();
});
it("should not show the target selector in the free tier", async () => {
const render = createCustomRenderer({
withBackendMock: true,
context: {
app: {
currentUser: createMockUser(),
config: createMockConfig(),
isPremiumTier: false,
},
},
});
render();
// Wait for any queries (that should not be happening) to finish.
await new Promise((resolve) => setTimeout(resolve, 500));
// Check that the target selector is not present.
expect(screen.queryByText("All hosts")).not.toBeInTheDocument();
});
it("should disable the save button in when no platforms are selected", async () => {
const render = createCustomRenderer({
withBackendMock: true,
context: {
app: {
currentUser: createMockUser(),
isGlobalObserver: false,
isGlobalAdmin: true,
isGlobalMaintainer: false,
isOnGlobalTeam: true,
isPremiumTier: false,
isSandboxMode: false,
config: createMockConfig(),
},
},
});
const props = {
...defaultProps,
platformSelector: {
getSelectedPlatforms: () => [] as QueryablePlatform[],
setSelectedPlatforms: jest.fn(),
isAnyPlatformSelected: false,
render: () => <>>,
},
};
render();
const saveButton = screen.getByRole("button", { name: "Save" });
expect(saveButton).toBeDisabled();
});
it("should send platforms when saving a new query", async () => {
const saveQuery = jest.fn();
const props = {
...defaultProps,
platformSelector: {
getSelectedPlatforms: () => ["linux", "macos"] as QueryablePlatform[],
setSelectedPlatforms: jest.fn(),
isAnyPlatformSelected: true,
render: () => <>>,
},
saveQuery,
};
const render = createCustomRenderer({
withBackendMock: true,
context: {
app: {
currentUser: createMockUser(),
isGlobalObserver: false,
isGlobalAdmin: true,
isGlobalMaintainer: false,
isOnGlobalTeam: true,
isPremiumTier: false,
isSandboxMode: false,
config: createMockConfig(),
},
},
});
render();
await waitFor(() => {
expect(screen.getByLabelText("Name")).toBeInTheDocument();
});
// Set a name.
await userEvent.type(screen.getByLabelText("Name"), "A Brand New Query!");
// Set a label.
await userEvent.click(screen.getByRole("button", { name: "Save" }));
expect(saveQuery.mock.calls[0][0].platform).toEqual("linux,macos");
});
describe("in premium tier", () => {
const render = createCustomRenderer({
withBackendMock: true,
context: {
app: {
currentUser: createMockUser(),
currentTeam: createMockTeam(),
isGlobalObserver: false,
isGlobalAdmin: true,
isGlobalMaintainer: false,
isOnGlobalTeam: true,
isPremiumTier: true,
isSandboxMode: false,
config: createMockConfig(),
},
},
});
beforeEach(() => {
mockServer.use(labelSummariesHandler);
});
it("should show the target selector in All hosts target mode when the query has no labels", async () => {
render();
await waitFor(() => {
expect(screen.getByLabelText("All hosts")).toBeInTheDocument();
expect(screen.getByLabelText("Custom")).toBeInTheDocument();
expect(screen.getByLabelText("All hosts")).toBeChecked();
});
});
it("should disable the save button in Custom target mode when no labels are selected, and enable it once labels are selected", async () => {
render();
let allHosts;
let custom;
await waitFor(() => {
allHosts = screen.getByLabelText("All hosts");
custom = screen.getByLabelText("Custom");
expect(allHosts).toBeInTheDocument();
expect(custom).toBeInTheDocument();
});
custom && (await userEvent.click(custom));
const saveButton = screen.getByRole("button", { name: "Save" });
expect(saveButton).toBeDisabled();
const funButton = await screen.findByRole("checkbox", {
name: "Fun",
});
expect(funButton).not.toBeChecked();
await userEvent.click(funButton);
expect(saveButton).toBeEnabled();
});
it("should send labels when saving a new query in Custom target mode", async () => {
const saveQuery = jest.fn();
const props = { ...defaultProps, saveQuery };
render();
await waitFor(() => {
expect(screen.getByLabelText("All hosts")).toBeInTheDocument();
});
// Set a name.
await userEvent.type(screen.getByLabelText("Name"), "A Brand New Query!");
// Set a label.
await userEvent.click(screen.getByLabelText("Custom"));
await userEvent.click(
await screen.findByRole("checkbox", { name: "Fun" })
);
await userEvent.click(screen.getByRole("button", { name: "Save" }));
expect(saveQuery.mock.calls[0][0].labels_include_any).toEqual(["Fun"]);
});
it("should clear labels when saving a new query in All hosts target mode", async () => {
const saveQuery = jest.fn();
const props = { ...defaultProps, saveQuery };
render();
await waitFor(() => {
expect(screen.getByLabelText("All hosts")).toBeInTheDocument();
});
// Set a name.
await userEvent.type(screen.getByLabelText("Name"), "A Brand New Query!");
await userEvent.click(screen.getByRole("button", { name: "Save" }));
expect(saveQuery.mock.calls[0][0].labels_include_any).toEqual([]);
});
});
});