Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WD-17070 - chore(tests): add provider form tests #497

Merged
merged 2 commits into from
Dec 4, 2024
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
188 changes: 188 additions & 0 deletions ui/src/pages/providers/ProviderForm/ProviderForm.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { screen } from "@testing-library/dom";
import { faker } from "@faker-js/faker";
import userEvent from "@testing-library/user-event";
import { Formik } from "formik";
import MockAdapter from "axios-mock-adapter";

import { axiosInstance } from "api/axios";
import { renderComponent } from "test/utils";

import ProviderForm from "./ProviderForm";
import { ProviderFormTypes } from "./ProviderForm";
import { Label } from "./types";

const mock = new MockAdapter(axiosInstance);

const initialValues = {
id: "",
client_id: "",
client_secret: "",
auth_url: "",
issuer_url: "",
token_url: "",
subject_source: "userinfo",
microsoft_tenant: "",
provider: "",
mapper_url: "",
scope: "",
apple_team_id: "",
apple_private_key_id: "",
apple_private_key: "",
requested_claims: "",
} as const;

beforeEach(() => {
mock.reset();
});

test("submits field data", async () => {
const values = {
provider: "auth0",
id: faker.word.sample(),
client_id: faker.word.sample(),
client_secret: faker.word.sample(),
scope: faker.word.sample(),
requested_claims: faker.word.sample(),
mapper_url: faker.word.sample(),
};
const onSubmit = vi.fn();
renderComponent(
<Formik<ProviderFormTypes>
initialValues={initialValues}
onSubmit={onSubmit}
>
{(formik) => (
<>
<ProviderForm formik={formik} />
<button onClick={() => void formik.submitForm()}>Submit</button>
</>
)}
</Formik>,
);
await userEvent.selectOptions(
screen.getByRole("combobox", { name: Label.PROVIDER }),
values.provider,
);
await userEvent.type(
screen.getByRole("textbox", { name: Label.NAME }),
values.id,
);
await userEvent.type(
screen.getByRole("textbox", { name: Label.CLIENT_ID }),
values.client_id,
);
await userEvent.type(
screen.getByRole("textbox", { name: Label.CLIENT_SECRET }),
values.client_secret,
);
await userEvent.type(
screen.getByRole("textbox", { name: Label.SCOPES }),
values.scope,
);
await userEvent.type(
screen.getByRole("textbox", { name: Label.REQUESTED_CLAIMS }),
values.requested_claims,
);
await userEvent.type(
screen.getByRole("textbox", { name: Label.MAPPER }),
values.mapper_url,
);
await userEvent.click(screen.getByRole("button"));
expect(onSubmit.mock.calls[0][0]).toMatchObject(values);
});

test("displays fields for apple form", async () => {
renderComponent(
<Formik<ProviderFormTypes> initialValues={initialValues} onSubmit={vi.fn()}>
{(formik) => <ProviderForm formik={formik} />}
</Formik>,
);
await userEvent.selectOptions(
screen.getByRole("combobox", { name: Label.PROVIDER }),
"apple",
);
expect(
screen.queryByRole("textbox", { name: Label.CLIENT_SECRET }),
).not.toBeInTheDocument();
expect(
screen.getByRole("textbox", { name: Label.PRIVATE_KEY }),
).toBeInTheDocument();
expect(
screen.getByRole("textbox", { name: Label.DEVELOPER_TEAM_ID }),
).toBeInTheDocument();
expect(
screen.getByRole("textbox", { name: Label.PRIVATE_KEY_ID }),
).toBeInTheDocument();
});

test("displays fields for microsoft form", async () => {
renderComponent(
<Formik<ProviderFormTypes> initialValues={initialValues} onSubmit={vi.fn()}>
{(formik) => <ProviderForm formik={formik} />}
</Formik>,
);
await userEvent.selectOptions(
screen.getByRole("combobox", { name: Label.PROVIDER }),
"microsoft",
);
expect(
screen.getByRole("textbox", { name: Label.TENANT }),
).toBeInTheDocument();
expect(
screen.getByRole("radio", { name: Label.USERINFO }),
).toBeInTheDocument();
expect(screen.getByRole("radio", { name: Label.ME })).toBeInTheDocument();
});

test("generic form displays auto discovery fields", async () => {
renderComponent(
<Formik<ProviderFormTypes> initialValues={initialValues} onSubmit={vi.fn()}>
{(formik) => <ProviderForm formik={formik} />}
</Formik>,
);
await userEvent.selectOptions(
screen.getByRole("combobox", { name: Label.PROVIDER }),
"generic",
);
await userEvent.click(screen.getByRole("radio", { name: Label.YES }));
expect(
screen.getByRole("textbox", { name: Label.OIDC_SERVER_URL }),
).toBeInTheDocument();
expect(
screen.queryByRole("textbox", { name: Label.AUTH_URL }),
).not.toBeInTheDocument();
expect(
screen.queryByRole("textbox", { name: Label.TOKEN_URL }),
).not.toBeInTheDocument();
});

test("generic form displays non auto discovery fields", async () => {
renderComponent(
<Formik<ProviderFormTypes> initialValues={initialValues} onSubmit={vi.fn()}>
{(formik) => <ProviderForm formik={formik} />}
</Formik>,
);
await userEvent.selectOptions(
screen.getByRole("combobox", { name: Label.PROVIDER }),
"generic",
);
await userEvent.click(screen.getByRole("radio", { name: Label.NO }));
expect(
screen.queryByRole("textbox", { name: Label.OIDC_SERVER_URL }),
).not.toBeInTheDocument();
expect(
screen.getByRole("textbox", { name: Label.AUTH_URL }),
).toBeInTheDocument();
expect(
screen.getByRole("textbox", { name: Label.TOKEN_URL }),
).toBeInTheDocument();
});

test("disables the mapper URL field when editing", () => {
renderComponent(
<Formik<ProviderFormTypes> initialValues={initialValues} onSubmit={vi.fn()}>
{(formik) => <ProviderForm isEdit formik={formik} />}
</Formik>,
);
expect(screen.getByRole("textbox", { name: Label.MAPPER })).toBeDisabled();
});
37 changes: 19 additions & 18 deletions ui/src/pages/providers/ProviderForm/ProviderForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FC, useState } from "react";
import { Form, Input, Select, Textarea } from "@canonical/react-components";
import { FormikProps } from "formik";
import { Label } from "./types";

const providerOptions = [
{
Expand Down Expand Up @@ -120,22 +121,22 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("provider")}
id="provider"
options={providerOptions}
label="Provider"
label={Label.PROVIDER}
error={formik.touched.provider ? formik.errors.provider : null}
/>
<Input
{...formik.getFieldProps("id")}
id="id"
type="text"
label="Name"
label={Label.NAME}
error={formik.touched.id ? formik.errors.id : null}
disabled={isEdit}
/>
<Input
{...formik.getFieldProps("client_id")}
id="client_id"
type="text"
label="Client ID"
label={Label.CLIENT_ID}
error={formik.touched.client_id ? formik.errors.client_id : null}
disabled={isEdit}
/>
Expand All @@ -144,7 +145,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("client_secret")}
id="client_secret"
type="text"
label="Client secret"
label={Label.CLIENT_SECRET}
error={
formik.touched.client_secret ? formik.errors.client_secret : null
}
Expand All @@ -159,7 +160,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("microsoft_tenant")}
id="microsoft_tenant"
type="text"
label="Tenant"
label={Label.TENANT}
help={
<>
The Azure AD Tenant to use for authentication. Can either be{" "}
Expand All @@ -178,7 +179,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
<Input
name="subject_source"
type="radio"
label="Userinfo"
label={Label.USERINFO}
help="The subject identifier is taken from sub field of userifo standard endpoint response"
checked={formik.values.subject_source === "userinfo"}
onChange={() =>
Expand All @@ -188,7 +189,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
<Input
name="subject_source"
type="radio"
label="Me"
label={Label.ME}
help={
<>
The <code>id</code> field of https://graph.microsoft.com/v1.0/me
Expand All @@ -208,7 +209,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
<Textarea
{...formik.getFieldProps("apple_private_key")}
id="apple_private_key"
label="Private Key"
label={Label.PRIVATE_KEY}
error={
formik.touched.apple_private_key
? formik.errors.apple_private_key
Expand All @@ -219,7 +220,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("apple_team_id")}
id="apple_team_id"
type="text"
label="Developer Team ID"
label={Label.DEVELOPER_TEAM_ID}
help={
<>
The Apple Developer Team ID can be found at{" "}
Expand All @@ -240,7 +241,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("apple_private_key_id")}
id="apple_private_key_id"
type="text"
label="Private Key ID"
label={Label.PRIVATE_KEY_ID}
error={
formik.touched.apple_private_key_id
? formik.errors.apple_private_key_id
Expand Down Expand Up @@ -269,7 +270,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
<Input
type="radio"
id="discovery_on"
label="Yes"
label={Label.YES}
name="oidc_discovery"
checked={hasAutoDiscovery}
onChange={() => setAutoDiscovery(true)}
Expand All @@ -280,7 +281,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("issuer_url")}
id="issuer_url"
type="text"
label="OIDC server URL"
label={Label.OIDC_SERVER_URL}
error={
formik.touched.issuer_url ? formik.errors.issuer_url : null
}
Expand All @@ -290,7 +291,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
<Input
type="radio"
id="discovery_off"
label="No"
label={Label.NO}
name="oidc_discovery"
checked={!hasAutoDiscovery}
onChange={() => setAutoDiscovery(false)}
Expand All @@ -301,15 +302,15 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("auth_url")}
id="auth_url"
type="text"
label="Auth URL"
label={Label.AUTH_URL}
help="I.e. https://example.org/oauth2/auth"
error={formik.touched.auth_url ? formik.errors.auth_url : null}
/>
<Input
{...formik.getFieldProps("token_url")}
id="token_url"
type="text"
label="Token URL"
label={Label.TOKEN_URL}
help="I.e. https://example.org/oauth2/token"
error={
formik.touched.token_url ? formik.errors.token_url : null
Expand All @@ -326,7 +327,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("scope")}
id="scope"
type="text"
label="Scopes"
label={Label.SCOPES}
help={
<>
Comma seperated list of optional requested permissions. Common
Expand All @@ -341,7 +342,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("requested_claims")}
id="requested_claims"
type="text"
label="Requested claims"
label={Label.REQUESTED_CLAIMS}
error={
formik.touched.requested_claims
? formik.errors.requested_claims
Expand All @@ -352,7 +353,7 @@ const ProviderForm: FC<Props> = ({ formik, isEdit = false }) => {
{...formik.getFieldProps("mapper_url")}
id="mapper_url"
type="text"
label="Mapper"
label={Label.MAPPER}
help="Mapper specifies the JSONNet code snippet which uses the OpenID Connect Provider's data to hydrate the identity's data. Supported file types are .jsonnet"
error={formik.touched.mapper_url ? formik.errors.mapper_url : null}
disabled={isEdit}
Expand Down
20 changes: 20 additions & 0 deletions ui/src/pages/providers/ProviderForm/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export enum Label {
AUTH_URL = "Auth URL",
CLIENT_ID = "Client ID",
CLIENT_SECRET = "Client secret",
DEVELOPER_TEAM_ID = "Developer Team ID",
MAPPER = "Mapper",
ME = "Me",
NAME = "Name",
NO = "No",
OIDC_SERVER_URL = "OIDC server URL",
PRIVATE_KEY = "Private Key",
PRIVATE_KEY_ID = "Private Key ID",
PROVIDER = "Provider",
REQUESTED_CLAIMS = "Requested claims",
SCOPES = "Scopes",
TENANT = "Tenant",
TOKEN_URL = "Token URL",
USERINFO = "Userinfo",
YES = "Yes",
}
Loading