added delete and cypress test
This commit is contained in:
parent
5a8762b3fa
commit
949a0e198b
10 changed files with 176 additions and 58 deletions
|
@ -6,6 +6,7 @@ import CreateClientPage from "../support/pages/admin_console/manage/clients/Crea
|
|||
import ModalUtils from "../support/util/ModalUtils";
|
||||
import AdvancedTab from "../support/pages/admin_console/manage/clients/AdvancedTab";
|
||||
import AdminClient from "../support/util/AdminClient";
|
||||
import InitialAccessTokenTab from "../support/pages/admin_console/manage/clients/InitialAccessTokenTab";
|
||||
|
||||
let itemId = "client_crud";
|
||||
const loginPage = new LoginPage();
|
||||
|
@ -78,6 +79,27 @@ describe("Clients test", function () {
|
|||
|
||||
listingPage.itemExist(itemId, false);
|
||||
});
|
||||
|
||||
it("Initial access token", () => {
|
||||
const initialAccessTokenTab = new InitialAccessTokenTab();
|
||||
listingPage.goToInitialAccessTokenTab();
|
||||
initialAccessTokenTab.shouldBeEmpty();
|
||||
initialAccessTokenTab.createNewToken(1, 1).save();
|
||||
|
||||
modalUtils.checkModalTitle("Initial access token details").closeModal();
|
||||
|
||||
initialAccessTokenTab.shouldNotBeEmpty();
|
||||
|
||||
initialAccessTokenTab.getFistId((id) => {
|
||||
listingPage.deleteItem(id);
|
||||
modalUtils
|
||||
.checkModalTitle("Delete initial access token?")
|
||||
.confirmModal();
|
||||
masthead.checkNotificationMessage(
|
||||
"initial access token created successfully"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Advanced tab test", () => {
|
||||
|
|
|
@ -7,6 +7,7 @@ export default class ListingPage {
|
|||
searchBtn: string;
|
||||
createBtn: string;
|
||||
importBtn: string;
|
||||
initialAccessTokenTab = "initialAccessToken";
|
||||
|
||||
constructor() {
|
||||
this.searchInput = '.pf-c-toolbar__item [type="search"]';
|
||||
|
@ -34,15 +35,20 @@ export default class ListingPage {
|
|||
return this;
|
||||
}
|
||||
|
||||
goToInitialAccessTokenTab() {
|
||||
cy.getId(this.initialAccessTokenTab).click();
|
||||
return this;
|
||||
}
|
||||
|
||||
searchItem(searchValue: string, wait = true) {
|
||||
if (wait) {
|
||||
const searchUrl = `/admin/realms/master/*${searchValue}*`;
|
||||
cy.intercept(searchUrl).as("searchClients");
|
||||
cy.intercept(searchUrl).as("search");
|
||||
}
|
||||
cy.get(this.searchInput).type(searchValue);
|
||||
cy.get(this.searchBtn).click();
|
||||
if (wait) {
|
||||
cy.wait(["@searchClients"]);
|
||||
cy.wait(["@search"]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
export default class InitialAccessTokenTab {
|
||||
private emptyAction = "empty-primary-action";
|
||||
|
||||
private expirationInput = "expiration";
|
||||
private countInput = "count";
|
||||
private saveBtn = "save";
|
||||
|
||||
shouldBeEmpty() {
|
||||
cy.getId(this.emptyAction).should("exist");
|
||||
return this;
|
||||
}
|
||||
|
||||
shouldNotBeEmpty() {
|
||||
cy.getId(this.emptyAction).should("not.exist");
|
||||
return this;
|
||||
}
|
||||
|
||||
getFistId(callback: (id: string) => void) {
|
||||
cy.get('tbody > tr > [data-label="ID"]')
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
callback(text);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
createNewToken(expiration: number, count: number) {
|
||||
cy.getId(this.emptyAction).click();
|
||||
cy.getId(this.expirationInput).type(`${expiration}`);
|
||||
cy.getId(this.countInput).type(`${count}`);
|
||||
return this;
|
||||
}
|
||||
|
||||
save() {
|
||||
cy.getId(this.saveBtn).click();
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@
|
|||
"@patternfly/react-table": "4.23.0",
|
||||
"file-saver": "^2.0.2",
|
||||
"i18next": "^19.6.2",
|
||||
"keycloak-admin": "1.14.9",
|
||||
"keycloak-admin": "1.14.10",
|
||||
"lodash": "^4.17.20",
|
||||
"moment": "^2.29.1",
|
||||
"react": "^16.8.5",
|
||||
|
|
|
@ -81,7 +81,11 @@ export const CreateInitialAccessToken = () => {
|
|||
defaultValue=""
|
||||
control={control}
|
||||
render={({ onChange, value }) => (
|
||||
<TimeSelector value={value} onChange={onChange} />
|
||||
<TimeSelector
|
||||
data-testid="expiration"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
@ -102,6 +106,7 @@ export const CreateInitialAccessToken = () => {
|
|||
control={control}
|
||||
render={({ onChange, value }) => (
|
||||
<NumberInput
|
||||
data-testid="count"
|
||||
inputName="count"
|
||||
inputAriaLabel={t("count")}
|
||||
min={1}
|
||||
|
@ -116,10 +121,11 @@ export const CreateInitialAccessToken = () => {
|
|||
/>
|
||||
</FormGroup>
|
||||
<ActionGroup>
|
||||
<Button variant="primary" type="submit">
|
||||
<Button variant="primary" type="submit" data-testid="save">
|
||||
{t("common:save")}
|
||||
</Button>
|
||||
<Button
|
||||
data-testid="cancel"
|
||||
variant="link"
|
||||
onClick={() =>
|
||||
history.push(`/${realm}/clients/initialAccessToken`)
|
||||
|
|
|
@ -1,27 +1,56 @@
|
|||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { useHistory, useRouteMatch } from "react-router-dom";
|
||||
import moment from "moment";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@patternfly/react-core";
|
||||
import { AlertVariant, Button, ButtonVariant } from "@patternfly/react-core";
|
||||
|
||||
import ClientInitialAccessPresentation from "keycloak-admin/lib/defs/clientInitialAccessPresentation";
|
||||
import { KeycloakDataTable } from "../../components/table-toolbar/KeycloakDataTable";
|
||||
import { useAdminClient } from "../../context/auth/AdminClient";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState";
|
||||
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
|
||||
import { useAlerts } from "../../components/alert/Alerts";
|
||||
|
||||
export const InitialAccessTokenList = () => {
|
||||
const { t } = useTranslation("clients");
|
||||
|
||||
const adminClient = useAdminClient();
|
||||
const { addAlert } = useAlerts();
|
||||
const { realm } = useRealm();
|
||||
|
||||
const history = useHistory();
|
||||
const { url } = useRouteMatch();
|
||||
|
||||
const [token, setToken] = useState<ClientInitialAccessPresentation>();
|
||||
|
||||
const loader = async () =>
|
||||
await adminClient.realms.getClientsInitialAccess({ realm });
|
||||
|
||||
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
|
||||
titleKey: "clients:tokenDeleteConfirmTitle",
|
||||
messageKey: t("tokenDeleteConfirm", token),
|
||||
continueButtonLabel: "common:delete",
|
||||
continueButtonVariant: ButtonVariant.danger,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
await adminClient.realms.delClientsInitialAccess({
|
||||
realm,
|
||||
id: token!.id!,
|
||||
});
|
||||
addAlert(t("tokenDeleteSuccess"), AlertVariant.success);
|
||||
setToken(undefined);
|
||||
} catch (error) {
|
||||
addAlert(t("tokenDeleteError", { error }), AlertVariant.danger);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<DeleteConfirm />
|
||||
<KeycloakDataTable
|
||||
key={token?.id}
|
||||
ariaLabelKey="clients:initialAccessToken"
|
||||
searchPlaceholderKey="clients:searchInitialAccessToken"
|
||||
loader={loader}
|
||||
|
@ -32,6 +61,15 @@ export const InitialAccessTokenList = () => {
|
|||
</Button>
|
||||
</>
|
||||
}
|
||||
actions={[
|
||||
{
|
||||
title: t("common:delete"),
|
||||
onRowClick: (token) => {
|
||||
setToken(token);
|
||||
toggleDeleteDialog();
|
||||
},
|
||||
},
|
||||
]}
|
||||
columns={[
|
||||
{
|
||||
name: "id",
|
||||
|
@ -66,5 +104,6 @@ export const InitialAccessTokenList = () => {
|
|||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -75,6 +75,10 @@
|
|||
"clientDeleteConfirm": "If you delete this client, all associated data will be removed.",
|
||||
"searchInitialAccessToken": "Search token",
|
||||
"createToken": "Create initial access token",
|
||||
"tokenDeleteConfirm": "Are you sure you want to permanently delete the initial access token {{id}}",
|
||||
"tokenDeleteConfirmTitle": "Delete initial access token?",
|
||||
"tokenDeleteSuccess": "initial access token created successfully",
|
||||
"tokenDeleteError": "Could not delete initial access token: '{{error}}'",
|
||||
"id": "ID",
|
||||
"timestamp": "Created date",
|
||||
"expires": "Expires",
|
||||
|
|
|
@ -5,13 +5,14 @@ import {
|
|||
Split,
|
||||
SplitItem,
|
||||
TextInput,
|
||||
TextInputProps,
|
||||
} from "@patternfly/react-core";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export type Unit = "seconds" | "minutes" | "hours" | "days";
|
||||
|
||||
export type TimeSelectorProps = {
|
||||
export type TimeSelectorProps = TextInputProps & {
|
||||
value: number;
|
||||
units?: Unit[];
|
||||
onChange: (time: number | string) => void;
|
||||
|
@ -21,6 +22,7 @@ export const TimeSelector = ({
|
|||
value,
|
||||
units = ["seconds", "minutes", "hours", "days"],
|
||||
onChange,
|
||||
...rest
|
||||
}: TimeSelectorProps) => {
|
||||
const { t } = useTranslation("common");
|
||||
|
||||
|
@ -73,6 +75,7 @@ export const TimeSelector = ({
|
|||
<Split hasGutter>
|
||||
<SplitItem>
|
||||
<TextInput
|
||||
{...rest}
|
||||
type="number"
|
||||
id={`kc-time-${new Date().getTime()}`}
|
||||
min="0"
|
||||
|
|
|
@ -26,7 +26,7 @@ export const UsersInRoleTab = () => {
|
|||
name: role.name!,
|
||||
first: first!,
|
||||
max: max!,
|
||||
} as any);
|
||||
});
|
||||
return usersWithRole;
|
||||
};
|
||||
|
||||
|
|
|
@ -13477,10 +13477,10 @@ junk@^3.1.0:
|
|||
resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1"
|
||||
integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==
|
||||
|
||||
keycloak-admin@1.14.9:
|
||||
version "1.14.9"
|
||||
resolved "https://registry.yarnpkg.com/keycloak-admin/-/keycloak-admin-1.14.9.tgz#f068e8580714c3b92987901cfe6c83bfba669a2a"
|
||||
integrity sha512-VaS6unTYLWuEkqb+FAY+c0Oo+ta505OxhOntCHLcgysMwRmL5pz6taVK8lUZ1ir/6QVto62adVQjmN5fMkpSWg==
|
||||
keycloak-admin@1.14.10:
|
||||
version "1.14.10"
|
||||
resolved "https://registry.yarnpkg.com/keycloak-admin/-/keycloak-admin-1.14.10.tgz#e44903826896262b3655303db46795b84a5f9b08"
|
||||
integrity sha512-WhEA+FkcPikN/Oqh7L0puVkPU1cm3bB+15VOoPdESZknQ9poS0Ohz3Rg1flRfmMdqoMgcy+prigUPtHy6gOAUg==
|
||||
dependencies:
|
||||
axios "^0.21.0"
|
||||
camelize "^1.0.0"
|
||||
|
|
Loading…
Reference in a new issue