Created more tests for the authentication flow (#2633)

This commit is contained in:
Erik Jan de Wit 2022-05-18 11:16:47 +02:00 committed by GitHub
parent cc7ec1cf7f
commit d8d28e1d7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 125 additions and 89 deletions

View file

@ -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();
}); });
}); });

View file

@ -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);
}
} }

View file

@ -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

View file

@ -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({

View file

@ -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);

View file

@ -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 = ({

View file

@ -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)}
> >