From 949a0e198be68a1fd035eb5268e44d5dd3858801 Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Fri, 5 Mar 2021 14:47:59 +0100 Subject: [PATCH] added delete and cypress test --- cypress/integration/clients_test.spec.ts | 22 +++ .../pages/admin_console/ListingPage.ts | 10 +- .../manage/clients/InitialAccessTokenTab.ts | 38 +++++ package.json | 2 +- .../CreateInitialAccessToken.tsx | 10 +- .../initial-access/InitialAccessTokenList.tsx | 133 +++++++++++------- src/clients/messages.json | 4 + src/components/time-selector/TimeSelector.tsx | 5 +- src/realm-roles/UsersInRoleTab.tsx | 2 +- yarn.lock | 8 +- 10 files changed, 176 insertions(+), 58 deletions(-) create mode 100644 cypress/support/pages/admin_console/manage/clients/InitialAccessTokenTab.ts diff --git a/cypress/integration/clients_test.spec.ts b/cypress/integration/clients_test.spec.ts index 31fe8cf1be..4763f61bd9 100644 --- a/cypress/integration/clients_test.spec.ts +++ b/cypress/integration/clients_test.spec.ts @@ -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", () => { diff --git a/cypress/support/pages/admin_console/ListingPage.ts b/cypress/support/pages/admin_console/ListingPage.ts index 6c9cb580e5..5ee946dbe8 100644 --- a/cypress/support/pages/admin_console/ListingPage.ts +++ b/cypress/support/pages/admin_console/ListingPage.ts @@ -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; } diff --git a/cypress/support/pages/admin_console/manage/clients/InitialAccessTokenTab.ts b/cypress/support/pages/admin_console/manage/clients/InitialAccessTokenTab.ts new file mode 100644 index 0000000000..74b047cdc7 --- /dev/null +++ b/cypress/support/pages/admin_console/manage/clients/InitialAccessTokenTab.ts @@ -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; + } +} diff --git a/package.json b/package.json index 8a97229823..065e403d29 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/clients/initial-access/CreateInitialAccessToken.tsx b/src/clients/initial-access/CreateInitialAccessToken.tsx index 005764849a..9f179051b4 100644 --- a/src/clients/initial-access/CreateInitialAccessToken.tsx +++ b/src/clients/initial-access/CreateInitialAccessToken.tsx @@ -81,7 +81,11 @@ export const CreateInitialAccessToken = () => { defaultValue="" control={control} render={({ onChange, value }) => ( - + )} /> @@ -102,6 +106,7 @@ export const CreateInitialAccessToken = () => { control={control} render={({ onChange, value }) => ( { /> - - - } - columns={[ - { - name: "id", - displayKey: "clients:id", - }, - { - name: "timestamp", - displayKey: "clients:timestamp", - cellRenderer: (row) => moment(row.timestamp! * 1000).format("LLL"), - }, - { - name: "expiration", - displayKey: "clients:expires", - cellRenderer: (row) => - moment(row.timestamp! * 1000 + row.expiration! * 1000).fromNow(), - }, - { - name: "count", - displayKey: "clients:count", - }, - { - name: "remainingCount", - displayKey: "clients:remainingCount", - }, - ]} - emptyState={ - history.push(`${url}/create`)} - /> - } - /> + <> + + + + + } + actions={[ + { + title: t("common:delete"), + onRowClick: (token) => { + setToken(token); + toggleDeleteDialog(); + }, + }, + ]} + columns={[ + { + name: "id", + displayKey: "clients:id", + }, + { + name: "timestamp", + displayKey: "clients:timestamp", + cellRenderer: (row) => moment(row.timestamp! * 1000).format("LLL"), + }, + { + name: "expiration", + displayKey: "clients:expires", + cellRenderer: (row) => + moment(row.timestamp! * 1000 + row.expiration! * 1000).fromNow(), + }, + { + name: "count", + displayKey: "clients:count", + }, + { + name: "remainingCount", + displayKey: "clients:remainingCount", + }, + ]} + emptyState={ + history.push(`${url}/create`)} + /> + } + /> + ); }; diff --git a/src/clients/messages.json b/src/clients/messages.json index 1bae7eac85..4d83e6f6b5 100644 --- a/src/clients/messages.json +++ b/src/clients/messages.json @@ -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", diff --git a/src/components/time-selector/TimeSelector.tsx b/src/components/time-selector/TimeSelector.tsx index 76ea070c93..2e86d254b4 100644 --- a/src/components/time-selector/TimeSelector.tsx +++ b/src/components/time-selector/TimeSelector.tsx @@ -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 = ({ { name: role.name!, first: first!, max: max!, - } as any); + }); return usersWithRole; }; diff --git a/yarn.lock b/yarn.lock index 1ca1a2d3c0..b87d9de341 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"