Event listeners (#1533)

* fixed a breadcrum for edit profile

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* edit executor - wip

* executor details - wip

* fixed executors list

* fixed multivaluedList and List components

* fixed displaying default vals for global profile executors, fixed unclicking executors without congigs for global profiles

* added edit executor

* improved edit executor

* added tests for editing executors

* renamed obj

* skipping client policies tests as unstable

* feedback fixes

* fix multiValuedlist defaults - wip

* fixed defaultValues for multiValuedList

* resolved and fixed conflict for test

* added event listeners

* added event listeners

* added success and error mssgs for event listeners saving

* added tests for event listeners

* added tests for event listeners

* improved error mssg

* fixed events tests as LOGIN type no longer available

* uncommented test, but using .skip

Co-authored-by: Agnieszka Gancarczyk <agancarc@redhat.com>
This commit is contained in:
agagancarczyk 2021-11-11 12:18:50 +00:00 committed by GitHub
parent 7786e6d463
commit 2b45a83109
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 262 additions and 24 deletions

View file

@ -24,10 +24,11 @@ describe("Events tests", () => {
it("Check search dropdown display", () => {
sidebarPage.goToRealmSettings();
cy.findByTestId("rs-realm-events-tab").click();
cy.findByTestId("rs-events-tab").click();
realmSettingsPage
.toggleSwitch(realmSettingsPage.enableEvents)
.save(realmSettingsPage.eventsUserSave);
.save(realmSettingsPage.modalConfirm);
masthead.signOut();
loginPage.logIn();
@ -77,7 +78,7 @@ describe("Events tests", () => {
realmSettingsPage
.toggleSwitch(realmSettingsPage.enableAdminEvents)
.save(realmSettingsPage.eventsAdminSave);
.save(realmSettingsPage.modalConfirm);
sidebarPage.goToEvents();
cy.findByTestId("admin-events-tab").click();

View file

@ -118,8 +118,7 @@ describe("Realm settings tests", () => {
masthead.checkNotificationMessage("Realm successfully updated");
});
/*
it("Go to login tab", () => {
it.skip("Go to login tab", () => {
sidebarPage.goToRealmSettings();
cy.findByTestId("rs-login-tab").click();
realmSettingsPage.toggleSwitch(realmSettingsPage.userRegSwitch);
@ -127,7 +126,7 @@ describe("Realm settings tests", () => {
realmSettingsPage.toggleSwitch(realmSettingsPage.rememberMeSwitch);
});
it("Check login tab values", () => {
it.skip("Check login tab values", () => {
sidebarPage.goToRealmSettings();
cy.findByTestId("rs-login-tab").click();
@ -135,7 +134,6 @@ describe("Realm settings tests", () => {
cy.get("#kc-forgot-pw-switch-off").should("be.visible");
cy.get("#kc-remember-me-switch-off").should("not.be.visible");
});
*/
it("Go to email tab", () => {
sidebarPage.goToRealmSettings();
@ -178,30 +176,24 @@ describe("Realm settings tests", () => {
describe("Events tab", () => {
const listingPage = new ListingPage();
it("Enable user events", () => {
cy.intercept("GET", `/auth/admin/realms/${realmName}/keys`).as("load");
sidebarPage.goToRealmSettings();
cy.findByTestId("rs-realm-events-tab").click();
cy.findByTestId("rs-events-tab").click();
cy.wait(["@load"]);
realmSettingsPage
.toggleSwitch(realmSettingsPage.enableEvents)
.save(realmSettingsPage.eventsUserSave);
masthead.checkNotificationMessage("Successfully saved configuration");
realmSettingsPage.clearEvents("user");
modalUtils
.checkModalMessage(
"If you clear all events of this realm, all records will be permanently cleared in the database"
)
.confirmModal();
masthead.checkNotificationMessage("The user events have been cleared");
const events = ["Client info", "Client info error"];
cy.intercept("GET", `/auth/admin/realms/${realmName}/events/config`).as(
"fetchConfig"
);
@ -209,7 +201,6 @@ describe("Realm settings tests", () => {
masthead.checkNotificationMessage("Successfully saved configuration");
cy.wait(["@fetchConfig"]);
sidebarPage.waitForPageLoad();
for (const event of events) {
listingPage.searchItem(event, false).itemExist(event);
}
@ -439,6 +430,38 @@ describe("Realm settings tests", () => {
});
});
describe("Realm settings events tab tests", () => {
beforeEach(() => {
keycloakBefore();
loginPage.logIn();
sidebarPage.goToRealmSettings();
cy.findByTestId("rs-realm-events-tab").click();
cy.findByTestId("rs-event-listeners-tab").click();
});
it("Should display event listeners form", () => {
realmSettingsPage.shouldDisplayEventListenersForm();
});
it("Should revert saving event listener", () => {
realmSettingsPage.shouldRevertSavingEventListener();
});
it("Should save event listener", () => {
realmSettingsPage.shouldSaveEventListener();
});
it("Should remove event from event listener", () => {
realmSettingsPage.shouldRemoveEventFromEventListener();
});
it("Should remove all events from event listener and re-save original", () => {
realmSettingsPage.shouldSaveEventListener();
realmSettingsPage.shouldRemoveAllEventListeners();
realmSettingsPage.shouldReSaveEventListener();
});
});
describe("Realm settings client profiles tab tests", () => {
beforeEach(() => {
keycloakBefore();

View file

@ -40,14 +40,14 @@ export default class UserEventsTab {
shouldDoSearchAndRemoveChips() {
cy.findByTestId(this.searchEventDrpDwnBtn).click();
cy.get(this.eventTypeInputFld).type("LOGIN");
cy.get(this.eventTypeOption).contains("LOGIN").click();
cy.get(this.eventTypeInputFld).type("LOGOUT");
cy.get(this.eventTypeOption).contains("LOGOUT").click();
cy.intercept("/auth/admin/realms/master/events*").as("eventsFetch");
cy.findByTestId(this.searchEventsBtn).click();
cy.wait("@eventsFetch");
cy.get("table").contains("td", "LOGIN");
cy.get("table").contains("td", "LOGOUT");
cy.get("table").should("not.have.text", "CODE_TO_TOKEN");
cy.get("table").should("not.have.text", "CODE_TO_TOKEN_ERROR");
cy.get("table").should("not.have.text", "LOGIN_ERROR");
@ -55,7 +55,7 @@ export default class UserEventsTab {
cy.get("[id^=remove_group]").click();
cy.wait("@eventsFetch");
cy.get("table").should("be.visible").contains("td", "LOGIN");
cy.get("table").should("be.visible").contains("td", "LOGOUT");
}
shouldHaveSearchBtnEnabled() {

View file

@ -196,6 +196,16 @@ export default class RealmSettingsPage {
private addConditionSaveBtn = "addCondition-saveBtn";
private conditionTypeLink = "condition-type-link";
private addValue = "addValue";
private eventListenersFormLabel = ".pf-c-form__label-text";
private eventListenersDrpDwn = ".pf-c-select.kc_eventListeners_select";
private eventListenersSaveBtn = "saveEventListenerBtn";
private eventListenersRevertBtn = "revertEventListenerBtn";
private eventListenersInputFld =
".pf-c-form-control.pf-c-select__toggle-typeahead";
private eventListenersDrpDwnOption = ".pf-c-select__menu-item";
private eventListenersDrwDwnSelect =
".pf-c-button.pf-c-select__toggle-button.pf-m-plain";
private eventListenerRemove = '[data-ouia-component-id="Remove"]';
selectLoginThemeType(themeType: string) {
cy.get(this.selectLoginTheme).click();
@ -505,6 +515,58 @@ export default class RealmSettingsPage {
return this;
}
shouldDisplayEventListenersForm() {
cy.get(this.eventListenersFormLabel)
.should("be.visible")
.contains("Event listeners");
cy.get(this.eventListenersDrpDwn).should("exist");
cy.findByTestId(this.eventListenersSaveBtn).should("exist");
cy.findAllByTestId(this.eventListenersRevertBtn).should("exist");
}
shouldRevertSavingEventListener() {
cy.get(this.eventListenersInputFld).click().type("email");
cy.get(this.eventListenersDrpDwnOption).click();
cy.get(this.eventListenersDrwDwnSelect).click();
cy.findByTestId(this.eventListenersRevertBtn).click();
cy.get(this.eventListenersDrpDwn).should("not.have.text", "email");
}
shouldSaveEventListener() {
cy.get(this.eventListenersInputFld).click().type("email");
cy.get(this.eventListenersDrpDwnOption).click();
cy.get(this.eventListenersDrwDwnSelect).click();
cy.findByTestId(this.eventListenersSaveBtn).click();
cy.get(this.alertMessage).should(
"be.visible",
"Event listener has been updated."
);
}
shouldRemoveEventFromEventListener() {
cy.get(this.eventListenerRemove).first().click();
cy.findByTestId(this.eventListenersSaveBtn).click();
cy.get(this.alertMessage).should(
"be.visible",
"Event listener has been updated."
);
cy.get(this.eventListenersDrpDwn).should("not.have.text", "jboss-logging");
}
shouldRemoveAllEventListeners() {
cy.get(".pf-c-button.pf-m-plain.pf-c-select__toggle-clear").click();
cy.findByTestId(this.eventListenersSaveBtn).click();
cy.get(this.eventListenersDrpDwn).should("not.have.text", "jboss-logging");
cy.get(this.eventListenersDrpDwn).should("not.have.text", "email");
}
shouldReSaveEventListener() {
cy.get(this.eventListenersInputFld).click().type("jboss-logging");
cy.get(this.eventListenersDrpDwnOption).click();
cy.get(this.eventListenersDrwDwnSelect).click();
cy.findByTestId(this.eventListenersSaveBtn).click();
}
shouldDisplayProfilesTab() {
cy.findByTestId(this.createProfileBtn).should("exist");
cy.findByTestId(this.formViewSelect).should("exist");

View file

@ -248,3 +248,7 @@ article.pf-c-card.pf-m-flat.kc-login-settings-template
.kc-conditionType-trash-icon:hover {
filter: brightness(55%);
}
.kc_eventListeners_select {
width: 35rem;
}

View file

@ -0,0 +1,113 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Controller, UseFormMethods } from "react-hook-form";
import {
ActionGroup,
Button,
FormGroup,
Select,
SelectOption,
SelectVariant,
} from "@patternfly/react-core";
import { HelpItem } from "../../components/help-enabler/HelpItem";
import { useServerInfo } from "../../context/server-info/ServerInfoProvider";
type EventListenersFormProps = {
form: UseFormMethods;
reset: () => void;
};
export const EventListenersForm = ({
form,
reset,
}: EventListenersFormProps) => {
const { t } = useTranslation("realm-settings");
const {
control,
formState: { isDirty },
} = form;
const [selectEventListenerOpen, setSelectEventListenerOpen] = useState(false);
const serverInfo = useServerInfo();
const eventListeners = serverInfo.providers?.eventsListener.providers;
return (
<>
<FormGroup
hasNoPaddingTop
label={t("eventListeners")}
fieldId={"kc-eventListeners"}
labelIcon={
<HelpItem
helpText={t("eventListenersHelpText")}
forLabel={t("eventListeners")}
forID={t(`common:helpLabel`, { label: t("eventListeners") })}
/>
}
>
<Controller
name="eventsListeners"
defaultValue=""
control={control}
render={({
onChange,
value,
}: {
onChange: (newValue: string[]) => void;
value: string[];
}) => (
<Select
name="eventsListeners"
className="kc_eventListeners_select"
data-testid="eventListeners-select"
chipGroupProps={{
numChips: 3,
expandedText: t("common:hide"),
collapsedText: t("common:showRemaining"),
}}
variant={SelectVariant.typeaheadMulti}
typeAheadAriaLabel="Select"
onToggle={(isOpen) => setSelectEventListenerOpen(isOpen)}
selections={value}
onSelect={(_, selectedValue) => {
const option = selectedValue.toString();
const changedValue = value.includes(option)
? value.filter((item) => item !== option)
: [...value, option];
onChange(changedValue);
}}
onClear={(operation) => {
operation.stopPropagation();
onChange([]);
}}
isOpen={selectEventListenerOpen}
aria-labelledby={"eventsListeners"}
>
{Object.keys(eventListeners!).map((event) => (
<SelectOption key={event} value={event} />
))}
</Select>
)}
/>
</FormGroup>
<ActionGroup>
<Button
variant="primary"
type="submit"
data-testid={"saveEventListenerBtn"}
isDisabled={!isDirty}
>
{t("common:save")}
</Button>
<Button
variant="link"
data-testid={"revertEventListenerBtn"}
onClick={reset}
>
{t("common:revert")}
</Button>
</ActionGroup>
</>
);
};

View file

@ -20,6 +20,7 @@ import { EventConfigForm, EventsType } from "./EventConfigForm";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { EventsTypeTable, EventType } from "./EventsTypeTable";
import { AddEventTypesDialog } from "./AddEventTypesDialog";
import { EventListenersForm } from "./EventListenersForm";
export const EventsTab = () => {
const { t } = useTranslation("realm-settings");
@ -31,7 +32,7 @@ export const EventsTab = () => {
const [tableKey, setTableKey] = useState(0);
const reload = () => setTableKey(new Date().getTime());
const [activeTab, setActiveTab] = useState("user");
const [activeTab, setActiveTab] = useState("event");
const [events, setEvents] = useState<RealmEventsConfigRepresentation>();
const [type, setType] = useState<EventsType>();
const [addEventType, setAddEventType] = useState(false);
@ -85,12 +86,25 @@ export const EventsTab = () => {
);
const save = async (eventConfig: RealmEventsConfigRepresentation) => {
const updatedEventListener =
events?.eventsListeners !== eventConfig.eventsListeners;
try {
await adminClient.realms.updateConfigEvents({ realm }, eventConfig);
setupForm({ ...events, ...eventConfig });
addAlert(t("eventConfigSuccessfully"), AlertVariant.success);
addAlert(
updatedEventListener
? t("realm-settings:saveEventListenersSuccess")
: t("realm-settings:eventConfigSuccessfully"),
AlertVariant.success
);
} catch (error) {
addError("realm-settings:eventConfigError", error);
addError(
updatedEventListener
? t("realm-settings:saveEventListenersError")
: t("realm-settings:eventConfigError"),
error
);
}
};
@ -122,6 +136,21 @@ export const EventsTab = () => {
activeKey={activeTab}
onSelect={(_, key) => setActiveTab(key as string)}
>
<Tab
eventKey="event"
title={<TabTitleText>{t("eventListeners")}</TabTitleText>}
data-testid="rs-event-listeners-tab"
>
<PageSection>
<FormAccess
role="manage-events"
isHorizontal
onSubmit={handleSubmit(save)}
>
<EventListenersForm form={form} reset={() => setupForm(events)} />
</FormAccess>
</PageSection>
</Tab>
<Tab
eventKey="user"
title={<TabTitleText>{t("userEventsSettings")}</TabTitleText>}

View file

@ -32,6 +32,12 @@ export default {
login: "Login",
themes: "Themes",
events: "Events",
eventListeners: "Event listeners",
eventListenersHelpText:
"Configure what listeners receive events for the realm.",
saveEventListeners: "Save Event Listeners",
saveEventListenersSuccess: "Event listener has been updated.",
saveEventListenersError: "Error saving event listener: {{error}}",
userEventsConfig: "User events configuration",
userEventsSettings: "User events settings",
adminEventsConfig: "Admin events configuration",