fleet/frontend/test/test-utils.tsx

240 lines
6.5 KiB
TypeScript
Raw Normal View History

import React from "react";
import { InjectedRouter } from "react-router";
import { Location } from "history";
import {
render,
RenderOptions,
RenderResult,
waitFor,
} from "@testing-library/react";
import type { UserEvent } from "@testing-library/user-event/dist/types/setup/setup";
import userEvent from "@testing-library/user-event";
import { QueryClient, QueryClientProvider } from "react-query";
import { AppContext, IAppContext, initialState } from "context/app";
import {
INotificationContext,
NotificationContext,
} from "context/notification";
import { IPolicyContext, PolicyContext } from "context/policy";
import { IQueryContext, QueryContext } from "context/query";
UI: Conditional access - Microsoft Entra (#27982) _Note - currently feature flagged. Build frontend with `ALLOW_CONDITIONAL_ACCESS=true NODE_ENV=development yarn run webpack --progress --watch` to enable this feature. Also, all of this functionality depends on the new `config.license.managed_cloud` being true, so you'll need to mock that data somehow. [This branch](https://github.com/fleetdm/fleet/tree/27043-fake-data) has the appropriate fake data for testing_ ## For #27043, #27864 ### Build front end for Fleet's integration with Microsoft Entra, allowing conditional preventtion of single sign-on for hosts failing any policies on a team #### Trigger the integration ![trigger](https://github.com/user-attachments/assets/4578568a-f64a-4390-83d9-fbec751d4b14) #### Triggered, but configuration still not verified <img width="1348" alt="√ not-verified-return-to-prefilled-form" src="https://github.com/user-attachments/assets/44d0c21f-2554-40a8-9158-d1107cff2d09" /> #### Verified, short and long tenant ids: ![ezgif-75f82492180d28](https://github.com/user-attachments/assets/015f3605-81e8-463a-be74-07bab99d9724) #### Verified –> Deleted ![√ verified - delete - deleted](https://github.com/user-attachments/assets/44b8ba70-49c9-43e7-be54-8474756a5b50) #### Enable for policies of a team ![√ enable-for-team](https://github.com/user-attachments/assets/9454b0da-059d-4991-a3ff-14e74257a3a7) #### Activities <img width="886" alt="√ activities" src="https://github.com/user-attachments/assets/d21e6185-c2f2-40b2-9c69-9b92fab58766" /> #### Unavailable for self-hosted Fleet instances: ![no-access-self-hosted](https://github.com/user-attachments/assets/56213522-b721-472f-9174-c8dac0df61f3) #### Premium only ![√ premium-only](https://github.com/user-attachments/assets/97373960-6b38-458b-be37-4c3868469182) - [x] Changes file added for user-visible changes in `changes/` - [x] Added/updated automated tests - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [ ] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
2025-04-15 20:55:07 +00:00
import { IRouterLocation } from "interfaces/routing";
export const baseUrl = (path: string) => {
return `/api/latest/fleet${path}`;
};
type RenderOptionsWithProviderProps = RenderOptions & {
contextValue: Partial<IAppContext>;
};
/**
* A custom render method that provides a configurable App context when testing components
*/
// eslint-disable-next-line import/prefer-default-export
export const renderWithAppContext = (
component: React.ReactNode,
{ contextValue, ...renderOptions }: RenderOptionsWithProviderProps
) => {
const value: IAppContext = { ...initialState, ...contextValue };
return render(
<AppContext.Provider value={value}>{component}</AppContext.Provider>,
renderOptions
);
};
// recursively make all fields in T optional
type DeepPartial<T> = T extends object
? {
[P in keyof T]?: DeepPartial<T[P]>;
}
: T;
interface IContextOptions {
// DeepPartial allows inclusion of only fields needed for testing, even if such a partial type
// is not acceptable in actual application code
app?: DeepPartial<IAppContext>;
notification?: Partial<INotificationContext>;
policy?: Partial<IPolicyContext>;
query?: Partial<IQueryContext>;
}
interface ICustomRenderOptions {
context?: IContextOptions;
withBackendMock?: boolean;
}
const CONTEXT_PROVIDER_MAP = {
app: AppContext,
notification: NotificationContext,
policy: PolicyContext,
query: QueryContext,
};
type ContextProviderKeys = keyof typeof CONTEXT_PROVIDER_MAP;
interface IWrapperComponentProps {
client?: QueryClient;
value?: Partial<IAppContext> | Partial<INotificationContext>;
}
const createWrapperComponent = (
2024-03-13 19:09:16 +00:00
CurrentWrapper: React.FC<React.PropsWithChildren<any>>, // TODO: types
WrapperComponent: React.FC<React.PropsWithChildren<any>>, // TODO: types
props: IWrapperComponentProps
) => {
return ({ children }: IChildrenProp) => (
<WrapperComponent {...props}>
<CurrentWrapper>{children}</CurrentWrapper>
</WrapperComponent>
);
};
interface IChildrenProp {
children?: React.ReactNode;
}
type RenderResultWithUser = RenderResult & { user: UserEvent };
const addQueryProviderWrapper = (
CustomWrapperComponent: ({ children }: IChildrenProp) => JSX.Element
) => {
const client = new QueryClient();
CustomWrapperComponent = createWrapperComponent(
CustomWrapperComponent,
QueryClientProvider,
{ client }
);
return CustomWrapperComponent;
};
const addContextWrappers = (
contextObj: IContextOptions,
CustomWrapperComponent: ({ children }: IChildrenProp) => JSX.Element
) => {
Object.entries(contextObj).forEach(([key, value]) => {
CustomWrapperComponent = createWrapperComponent(
CustomWrapperComponent,
CONTEXT_PROVIDER_MAP[key as ContextProviderKeys].Provider,
{ value }
);
});
return CustomWrapperComponent;
};
/**
* Creates a custom testing-library render function based on a configuration object.
* It will help set up the react context and backend mock dependencies so that
* you can easily set up a component for testing.
*
* This will also set up the @testing-library/user-events and expose a user object
* you can use to perform user interactions.
*/
export const createCustomRenderer = (renderOptions?: ICustomRenderOptions) => {
let CustomWrapperComponent = ({ children }: IChildrenProp) => <>{children}</>;
if (renderOptions?.withBackendMock) {
CustomWrapperComponent = addQueryProviderWrapper(CustomWrapperComponent);
}
if (renderOptions?.context !== undefined) {
CustomWrapperComponent = addContextWrappers(
renderOptions.context,
CustomWrapperComponent
);
}
return (
component: React.ReactElement,
options?: Omit<RenderOptions, "wrapper">
): RenderResultWithUser => {
const renderResults: RenderResultWithUser = {
user: userEvent.setup(),
...render(component, { wrapper: CustomWrapperComponent, ...options }),
};
return renderResults;
};
};
2022-12-14 18:56:56 +00:00
/**
* This is a convenince method that calls the render method from `@testing-library/react` and also
* sets up the also `user-events`library and adds the user object to the returned object.
*/
2022-12-14 18:56:56 +00:00
export const renderWithSetup = (component: JSX.Element) => {
return {
user: userEvent.setup(),
...render(component),
};
};
const DEFAULT_MOCK_ROUTER: InjectedRouter = {
push: jest.fn(),
replace: jest.fn(),
goBack: jest.fn(),
goForward: jest.fn(),
go: jest.fn(),
setRouteLeaveHook: jest.fn(),
isActive: jest.fn(),
createHref: jest.fn(),
createPath: jest.fn(),
};
export const createMockRouter = (overrides?: Partial<InjectedRouter>) => {
return {
...DEFAULT_MOCK_ROUTER,
...overrides,
};
};
feat: enable multiple ABM and VPP tokens (#21693) > Related issue: #9956 # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [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/Committing-Changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated tests - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes - [x] If database migrations are included, checked table schema to confirm autoupdate - For database migrations: - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects. - [x] Ensured the correct collation is explicitly set for character columns (`COLLATE utf8mb4_unicode_ci`). - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Gabriel Hernandez <ghernandez345@gmail.com> Co-authored-by: Roberto Dip <rroperzh@gmail.com> Co-authored-by: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com> Co-authored-by: Dante Catalfamo <43040593+dantecatalfamo@users.noreply.github.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-08-29 22:51:46 +00:00
export const createMockLocation = (overrides?: Partial<Location>): Location => {
return {
pathname: "/",
search: "",
hash: "",
query: {},
state: undefined,
action: "POP",
key: "",
...overrides,
};
};
export const createMockLocationExperimental = (
UI: Conditional access - Microsoft Entra (#27982) _Note - currently feature flagged. Build frontend with `ALLOW_CONDITIONAL_ACCESS=true NODE_ENV=development yarn run webpack --progress --watch` to enable this feature. Also, all of this functionality depends on the new `config.license.managed_cloud` being true, so you'll need to mock that data somehow. [This branch](https://github.com/fleetdm/fleet/tree/27043-fake-data) has the appropriate fake data for testing_ ## For #27043, #27864 ### Build front end for Fleet's integration with Microsoft Entra, allowing conditional preventtion of single sign-on for hosts failing any policies on a team #### Trigger the integration ![trigger](https://github.com/user-attachments/assets/4578568a-f64a-4390-83d9-fbec751d4b14) #### Triggered, but configuration still not verified <img width="1348" alt="√ not-verified-return-to-prefilled-form" src="https://github.com/user-attachments/assets/44d0c21f-2554-40a8-9158-d1107cff2d09" /> #### Verified, short and long tenant ids: ![ezgif-75f82492180d28](https://github.com/user-attachments/assets/015f3605-81e8-463a-be74-07bab99d9724) #### Verified –> Deleted ![√ verified - delete - deleted](https://github.com/user-attachments/assets/44b8ba70-49c9-43e7-be54-8474756a5b50) #### Enable for policies of a team ![√ enable-for-team](https://github.com/user-attachments/assets/9454b0da-059d-4991-a3ff-14e74257a3a7) #### Activities <img width="886" alt="√ activities" src="https://github.com/user-attachments/assets/d21e6185-c2f2-40b2-9c69-9b92fab58766" /> #### Unavailable for self-hosted Fleet instances: ![no-access-self-hosted](https://github.com/user-attachments/assets/56213522-b721-472f-9174-c8dac0df61f3) #### Premium only ![√ premium-only](https://github.com/user-attachments/assets/97373960-6b38-458b-be37-4c3868469182) - [x] Changes file added for user-visible changes in `changes/` - [x] Added/updated automated tests - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [ ] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
2025-04-15 20:55:07 +00:00
overrides?: Partial<IRouterLocation>
): IRouterLocation => {
// Default values for the location object
const defaultLocation: IRouterLocation = {
pathname: "/",
host: "localhost:8080",
hostname: "localhost",
port: "8080",
protocol: "http:",
};
return {
...defaultLocation,
...overrides,
};
};
feat: enable multiple ABM and VPP tokens (#21693) > Related issue: #9956 # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [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/Committing-Changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Added/updated tests - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes - [x] If database migrations are included, checked table schema to confirm autoupdate - For database migrations: - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects. - [x] Ensured the correct collation is explicitly set for character columns (`COLLATE utf8mb4_unicode_ci`). - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com> Co-authored-by: Gabriel Hernandez <ghernandez345@gmail.com> Co-authored-by: Roberto Dip <rroperzh@gmail.com> Co-authored-by: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com> Co-authored-by: Dante Catalfamo <43040593+dantecatalfamo@users.noreply.github.com> Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-08-29 22:51:46 +00:00
/** helper method to generate a date "x" days ago. */
export const getPastDate = (days: number) => {
const targetDate = new Date();
targetDate.setDate(targetDate.getDate() - days);
return targetDate.toISOString();
};
/** helper method to generate a date "x" days from now */
export const getFutureDate = (days: number) => {
const targetDate = new Date();
targetDate.setDate(targetDate.getDate() + days);
return targetDate.toISOString();
};
export const waitForLoadingToFinish = async (container: HTMLElement) => {
await waitFor(() => {
expect(container.querySelector(".loading-overlay")).not.toBeInTheDocument();
});
};