Created more tests for the authentication flow (#2633)
This commit is contained in:
parent
cc7ec1cf7f
commit
d8d28e1d7c
7 changed files with 125 additions and 89 deletions
|
@ -8,38 +8,57 @@ import FlowDetails from "../support/pages/admin_console/manage/authentication/Fl
|
||||||
import RequiredActions from "../support/pages/admin_console/manage/authentication/RequiredActions";
|
import RequiredActions from "../support/pages/admin_console/manage/authentication/RequiredActions";
|
||||||
import adminClient from "../support/util/AdminClient";
|
import adminClient from "../support/util/AdminClient";
|
||||||
import PasswordPolicies from "../support/pages/admin_console/manage/authentication/PasswordPolicies";
|
import PasswordPolicies from "../support/pages/admin_console/manage/authentication/PasswordPolicies";
|
||||||
|
import ModalUtils from "../support/util/ModalUtils";
|
||||||
|
|
||||||
|
const loginPage = new LoginPage();
|
||||||
|
const masthead = new Masthead();
|
||||||
|
const sidebarPage = new SidebarPage();
|
||||||
|
const listingPage = new ListingPage();
|
||||||
|
|
||||||
describe("Authentication test", () => {
|
describe("Authentication test", () => {
|
||||||
const loginPage = new LoginPage();
|
|
||||||
const masthead = new Masthead();
|
|
||||||
const sidebarPage = new SidebarPage();
|
|
||||||
const listingPage = new ListingPage();
|
|
||||||
|
|
||||||
const detailPage = new FlowDetails();
|
const detailPage = new FlowDetails();
|
||||||
|
const duplicateFlowModal = new DuplicateFlowModal();
|
||||||
|
const modalUtil = new ModalUtils();
|
||||||
|
|
||||||
beforeEach(() => {
|
before(() => {
|
||||||
keycloakBefore();
|
keycloakBefore();
|
||||||
loginPage.logIn();
|
loginPage.logIn();
|
||||||
sidebarPage.waitForPageLoad();
|
sidebarPage.waitForPageLoad();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
sidebarPage.goToAuthentication();
|
sidebarPage.goToAuthentication();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create duplicate of existing flow", () => {
|
it("should create duplicate of existing flow", () => {
|
||||||
const modalDialog = new DuplicateFlowModal();
|
|
||||||
listingPage.clickRowDetails("Browser").clickDetailMenu("Duplicate");
|
listingPage.clickRowDetails("Browser").clickDetailMenu("Duplicate");
|
||||||
modalDialog.fill("Copy of browser");
|
duplicateFlowModal.fill("Copy of browser");
|
||||||
|
|
||||||
masthead.checkNotificationMessage("Flow successfully duplicated");
|
masthead.checkNotificationMessage("Flow successfully duplicated");
|
||||||
listingPage.itemExist("Copy of browser");
|
listingPage.itemExist("Copy of browser");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should fail duplicate with empty flow name", () => {
|
||||||
|
listingPage.clickRowDetails("Browser").clickDetailMenu("Duplicate");
|
||||||
|
duplicateFlowModal.fill().shouldShowError("Required field");
|
||||||
|
modalUtil.cancelModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should fail duplicate with duplicated name", () => {
|
||||||
|
listingPage.clickRowDetails("Browser").clickDetailMenu("Duplicate");
|
||||||
|
duplicateFlowModal.fill("browser");
|
||||||
|
masthead.checkNotificationMessage(
|
||||||
|
"Could not duplicate flow: New flow alias name already exists"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("should show the details of a flow as a table", () => {
|
it("should show the details of a flow as a table", () => {
|
||||||
listingPage.goToItemDetails("Copy of browser");
|
listingPage.goToItemDetails("Copy of browser");
|
||||||
|
|
||||||
detailPage.executionExists("Cookie");
|
detailPage.executionExists("Cookie");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should move kerberos down", () => {
|
it.skip("should move kerberos down", () => {
|
||||||
listingPage.goToItemDetails("Copy of browser");
|
listingPage.goToItemDetails("Copy of browser");
|
||||||
|
|
||||||
detailPage.moveRowTo("Kerberos", "Identity Provider Redirector");
|
detailPage.moveRowTo("Kerberos", "Identity Provider Redirector");
|
||||||
|
@ -94,6 +113,13 @@ describe("Authentication test", () => {
|
||||||
detailPage.flowExists(flowName);
|
detailPage.flowExists(flowName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should remove an execution", () => {
|
||||||
|
listingPage.goToItemDetails("Copy of browser");
|
||||||
|
detailPage.executionExists("Cookie").clickRowDelete("Cookie");
|
||||||
|
modalUtil.confirmModal();
|
||||||
|
detailPage.executionExists("Cookie", false);
|
||||||
|
});
|
||||||
|
|
||||||
it("should create flow from scratch", () => {
|
it("should create flow from scratch", () => {
|
||||||
const flowName = "Flow";
|
const flowName = "Flow";
|
||||||
listingPage.goToCreateItem();
|
listingPage.goToCreateItem();
|
||||||
|
@ -109,78 +135,76 @@ describe("Authentication test", () => {
|
||||||
|
|
||||||
detailPage.flowExists(flowName);
|
detailPage.flowExists(flowName);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("Required actions", () => {
|
describe("Required actions", () => {
|
||||||
const requiredActionsPage = new RequiredActions();
|
const requiredActionsPage = new RequiredActions();
|
||||||
beforeEach(() => {
|
|
||||||
keycloakBefore();
|
|
||||||
loginPage.logIn();
|
|
||||||
sidebarPage.goToRealm("Test");
|
|
||||||
sidebarPage.goToAuthentication();
|
|
||||||
requiredActionsPage.goToTab();
|
|
||||||
});
|
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
adminClient.createRealm("Test");
|
cy.wrap(adminClient.createRealm("Test"));
|
||||||
});
|
keycloakBefore();
|
||||||
|
loginPage.logIn();
|
||||||
after(() => {
|
sidebarPage.goToRealm("Test");
|
||||||
adminClient.deleteRealm("Test");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should enable delete account", () => {
|
|
||||||
const action = "Delete Account";
|
|
||||||
requiredActionsPage.enableAction(action);
|
|
||||||
masthead.checkNotificationMessage("Updated required action successfully");
|
|
||||||
requiredActionsPage.isChecked(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register an unregistered action", () => {
|
|
||||||
const action = "Verify Profile";
|
|
||||||
requiredActionsPage.enableAction(action);
|
|
||||||
masthead.checkNotificationMessage("Updated required action successfully");
|
|
||||||
requiredActionsPage.isChecked(action).isDefaultEnabled(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set action as default", () => {
|
|
||||||
const action = "Configure OTP";
|
|
||||||
requiredActionsPage.setAsDefault(action);
|
|
||||||
masthead.checkNotificationMessage("Updated required action successfully");
|
|
||||||
requiredActionsPage.isDefaultChecked(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should reorder required actions", () => {
|
|
||||||
const action = "Terms and Conditions";
|
|
||||||
requiredActionsPage.moveRowTo(action, "Update Profile");
|
|
||||||
masthead.checkNotificationMessage("Updated required action successfully");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Password policies tab", () => {
|
beforeEach(() => {
|
||||||
const passwordPoliciesPage = new PasswordPolicies();
|
sidebarPage.goToAuthentication();
|
||||||
beforeEach(() => {
|
requiredActionsPage.goToTab();
|
||||||
keycloakBefore();
|
});
|
||||||
loginPage.logIn();
|
|
||||||
sidebarPage.goToAuthentication();
|
|
||||||
passwordPoliciesPage.goToTab();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should add password policies", () => {
|
after(() => {
|
||||||
passwordPoliciesPage
|
adminClient.deleteRealm("Test");
|
||||||
.shouldShowEmptyState()
|
});
|
||||||
.addPolicy("Not Recently Used")
|
|
||||||
.save();
|
|
||||||
masthead.checkNotificationMessage(
|
|
||||||
"Password policies successfully updated"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should remove password policies", () => {
|
it("should enable delete account", () => {
|
||||||
passwordPoliciesPage.removePolicy("remove-passwordHistory").save();
|
const action = "Delete Account";
|
||||||
masthead.checkNotificationMessage(
|
requiredActionsPage.enableAction(action);
|
||||||
"Password policies successfully updated"
|
masthead.checkNotificationMessage("Updated required action successfully");
|
||||||
);
|
requiredActionsPage.isChecked(action);
|
||||||
passwordPoliciesPage.shouldShowEmptyState();
|
});
|
||||||
});
|
|
||||||
|
it("should register an unregistered action", () => {
|
||||||
|
const action = "Verify Profile";
|
||||||
|
requiredActionsPage.enableAction(action);
|
||||||
|
masthead.checkNotificationMessage("Updated required action successfully");
|
||||||
|
requiredActionsPage.isChecked(action).isDefaultEnabled(action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set action as default", () => {
|
||||||
|
const action = "Configure OTP";
|
||||||
|
requiredActionsPage.setAsDefault(action);
|
||||||
|
masthead.checkNotificationMessage("Updated required action successfully");
|
||||||
|
requiredActionsPage.isDefaultChecked(action);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should reorder required actions", () => {
|
||||||
|
const action = "Terms and Conditions";
|
||||||
|
requiredActionsPage.moveRowTo(action, "Update Profile");
|
||||||
|
masthead.checkNotificationMessage("Updated required action successfully");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Password policies tab", () => {
|
||||||
|
const passwordPoliciesPage = new PasswordPolicies();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
keycloakBefore();
|
||||||
|
loginPage.logIn();
|
||||||
|
sidebarPage.goToAuthentication();
|
||||||
|
passwordPoliciesPage.goToTab();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should add password policies", () => {
|
||||||
|
passwordPoliciesPage
|
||||||
|
.shouldShowEmptyState()
|
||||||
|
.addPolicy("Not Recently Used")
|
||||||
|
.save();
|
||||||
|
masthead.checkNotificationMessage("Password policies successfully updated");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove password policies", () => {
|
||||||
|
passwordPoliciesPage.removePolicy("remove-passwordHistory").save();
|
||||||
|
masthead.checkNotificationMessage("Password policies successfully updated");
|
||||||
|
passwordPoliciesPage.shouldShowEmptyState();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,14 +2,20 @@ export default class DuplicateFlowModal {
|
||||||
private aliasInput = "alias";
|
private aliasInput = "alias";
|
||||||
private descriptionInput = "description";
|
private descriptionInput = "description";
|
||||||
private confirmButton = "confirm";
|
private confirmButton = "confirm";
|
||||||
|
private errorText = ".pf-m-error";
|
||||||
|
|
||||||
fill(name?: string, description?: string) {
|
fill(name?: string, description?: string) {
|
||||||
|
cy.findByTestId(this.aliasInput).clear();
|
||||||
if (name) {
|
if (name) {
|
||||||
cy.findByTestId(this.aliasInput).clear().type(name);
|
cy.findByTestId(this.aliasInput).type(name);
|
||||||
if (description) cy.get(this.descriptionInput).type(description);
|
if (description) cy.get(this.descriptionInput).type(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
cy.findByTestId(this.confirmButton).click();
|
cy.findByTestId(this.confirmButton).click();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldShowError(message: string) {
|
||||||
|
cy.get(this.errorText).invoke("text").should("contain", message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
type RequirementType = "Required" | "Alternative" | "Disabled" | "Conditional";
|
type RequirementType = "Required" | "Alternative" | "Disabled" | "Conditional";
|
||||||
|
|
||||||
export default class FlowDetails {
|
export default class FlowDetails {
|
||||||
executionExists(name: string) {
|
executionExists(name: string, exist = true) {
|
||||||
this.getExecution(name).should("exist");
|
this.getExecution(name).should((!exist ? "not." : "") + "exist");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,12 @@ export default class FlowDetails {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clickRowDelete(name: string) {
|
||||||
|
cy.findByTestId(`${name}-delete`).click();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private fillSubFlowModal(subFlowName: string, name: string) {
|
private fillSubFlowModal(subFlowName: string, name: string) {
|
||||||
cy.get(".pf-c-modal-box__title-text").contains(
|
cy.get(".pf-c-modal-box__title-text").contains(
|
||||||
"Add step to " + subFlowName
|
"Add step to " + subFlowName
|
||||||
|
|
|
@ -41,7 +41,7 @@ export const DuplicateFlowModal = ({
|
||||||
}, [name, description, setValue]);
|
}, [name, description, setValue]);
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
await trigger();
|
if (!(await trigger())) return;
|
||||||
const form = getValues();
|
const form = getValues();
|
||||||
try {
|
try {
|
||||||
await adminClient.authenticationManagement.copyFlow({
|
await adminClient.authenticationManagement.copyFlow({
|
||||||
|
|
|
@ -130,13 +130,13 @@ export default function FlowDetails() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const update = async (
|
const update = async (execution: ExpandableExecution) => {
|
||||||
execution: AuthenticationExecutionInfoRepresentation
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
) => {
|
const { executionList, isCollapsed, ...ex } = execution;
|
||||||
try {
|
try {
|
||||||
await adminClient.authenticationManagement.updateExecution(
|
await adminClient.authenticationManagement.updateExecution(
|
||||||
{ flow: flow?.alias! },
|
{ flow: flow?.alias! },
|
||||||
execution
|
ex
|
||||||
);
|
);
|
||||||
refresh();
|
refresh();
|
||||||
addAlert(t("updateFlowSuccess"), AlertVariant.success);
|
addAlert(t("updateFlowSuccess"), AlertVariant.success);
|
||||||
|
|
|
@ -2,11 +2,11 @@ import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Select, SelectOption, SelectVariant } from "@patternfly/react-core";
|
import { Select, SelectOption, SelectVariant } from "@patternfly/react-core";
|
||||||
|
|
||||||
import type AuthenticationExecutionInfoRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationExecutionInfoRepresentation";
|
import type { ExpandableExecution } from "../execution-model";
|
||||||
|
|
||||||
type FlowRequirementDropdownProps = {
|
type FlowRequirementDropdownProps = {
|
||||||
flow: AuthenticationExecutionInfoRepresentation;
|
flow: ExpandableExecution;
|
||||||
onChange: (flow: AuthenticationExecutionInfoRepresentation) => void;
|
onChange: (flow: ExpandableExecution) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FlowRequirementDropdown = ({
|
export const FlowRequirementDropdown = ({
|
||||||
|
|
|
@ -15,7 +15,6 @@ import {
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { TrashIcon } from "@patternfly/react-icons";
|
import { TrashIcon } from "@patternfly/react-icons";
|
||||||
|
|
||||||
import type AuthenticationExecutionInfoRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationExecutionInfoRepresentation";
|
|
||||||
import type { AuthenticationProviderRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigRepresentation";
|
import type { AuthenticationProviderRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigRepresentation";
|
||||||
import type { ExpandableExecution } from "../execution-model";
|
import type { ExpandableExecution } from "../execution-model";
|
||||||
import type { Flow } from "./modals/AddSubFlowModal";
|
import type { Flow } from "./modals/AddSubFlowModal";
|
||||||
|
@ -30,7 +29,7 @@ type FlowRowProps = {
|
||||||
builtIn: boolean;
|
builtIn: boolean;
|
||||||
execution: ExpandableExecution;
|
execution: ExpandableExecution;
|
||||||
onRowClick: (execution: ExpandableExecution) => void;
|
onRowClick: (execution: ExpandableExecution) => void;
|
||||||
onRowChange: (execution: AuthenticationExecutionInfoRepresentation) => void;
|
onRowChange: (execution: ExpandableExecution) => void;
|
||||||
onAddExecution: (
|
onAddExecution: (
|
||||||
execution: ExpandableExecution,
|
execution: ExpandableExecution,
|
||||||
type: AuthenticationProviderRepresentation
|
type: AuthenticationProviderRepresentation
|
||||||
|
@ -115,6 +114,7 @@ export const FlowRow = ({
|
||||||
<Tooltip content={t("common:delete")}>
|
<Tooltip content={t("common:delete")}>
|
||||||
<Button
|
<Button
|
||||||
variant="plain"
|
variant="plain"
|
||||||
|
data-testid={`${execution.displayName}-delete`}
|
||||||
aria-label={t("common:delete")}
|
aria-label={t("common:delete")}
|
||||||
onClick={() => onDelete(execution)}
|
onClick={() => onDelete(execution)}
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in a new issue