Add initial test for the resources tab (#21334)
This commit is contained in:
parent
4517ef5d7e
commit
f06d7f8eb6
15 changed files with 344 additions and 62 deletions
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"name": "account-ui",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "wireit",
|
||||
"build": "wireit",
|
||||
|
@ -29,6 +30,7 @@
|
|||
"@types/react": "^18.2.14",
|
||||
"@types/react-dom": "^18.2.6",
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"@keycloak/keycloak-admin-client": "workspace:*",
|
||||
"vite": "^4.4.1",
|
||||
"vite-plugin-checker": "^0.6.1"
|
||||
},
|
||||
|
@ -38,7 +40,8 @@
|
|||
"dependencies": [
|
||||
"../../libs/ui-shared:build",
|
||||
"../../libs/keycloak-masthead:build",
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
},
|
||||
"preview": {
|
||||
|
@ -46,7 +49,8 @@
|
|||
"dependencies": [
|
||||
"../../libs/ui-shared:build",
|
||||
"../../libs/keycloak-masthead:build",
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
|
@ -54,7 +58,8 @@
|
|||
"dependencies": [
|
||||
"../../libs/ui-shared:build",
|
||||
"../../libs/keycloak-masthead:build",
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
},
|
||||
"lint": {
|
||||
|
@ -62,7 +67,8 @@
|
|||
"dependencies": [
|
||||
"../../libs/ui-shared:build",
|
||||
"../../libs/keycloak-masthead:build",
|
||||
"../../libs/keycloak-js:build"
|
||||
"../../libs/keycloak-js:build",
|
||||
"../../libs/keycloak-admin-client:build"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,32 @@
|
|||
import { defineConfig, devices } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// require('dotenv').config();
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: "./test",
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: "html",
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: "http://localhost:8080/",
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{ name: "setup", testMatch: /.*\.setup\.ts/ },
|
||||
{ name: "setup", testMatch: /.auth\.setup\.ts/ },
|
||||
{
|
||||
name: "import realm",
|
||||
testMatch: /import\.setup\.ts/,
|
||||
teardown: "del realm",
|
||||
},
|
||||
{
|
||||
name: "del realm",
|
||||
testMatch: /import\.teardown\.ts/,
|
||||
},
|
||||
{
|
||||
name: "chromium",
|
||||
use: {
|
||||
|
@ -40,6 +34,7 @@ export default defineConfig({
|
|||
storageState: ".auth/user.json",
|
||||
},
|
||||
dependencies: ["setup"],
|
||||
testIgnore: ["**/*my-resources.spec.ts"],
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -49,38 +44,14 @@ export default defineConfig({
|
|||
storageState: ".auth/user.json",
|
||||
},
|
||||
dependencies: ["setup"],
|
||||
testIgnore: ["**/*my-resources.spec.ts"],
|
||||
},
|
||||
|
||||
// {
|
||||
// name: "webkit",
|
||||
// use: { ...devices["Desktop Safari"] },
|
||||
// },
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
{
|
||||
name: "photoz realm chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
dependencies: ["import realm"],
|
||||
testMatch: ["**/*my-resources.spec.ts"],
|
||||
},
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: 'npm run start',
|
||||
// url: 'http://127.0.0.1:3000',
|
||||
// reuseExistingServer: !process.env.CI,
|
||||
// },
|
||||
});
|
||||
|
|
|
@ -28,9 +28,10 @@ export type Environment = {
|
|||
};
|
||||
|
||||
// The default environment, used during development.
|
||||
const realm = new URLSearchParams(window.location.search).get("realm");
|
||||
const defaultEnvironment: Environment = {
|
||||
authUrl: "http://localhost:8180",
|
||||
realm: "master",
|
||||
realm: realm || "master",
|
||||
clientId: "security-admin-console-v2",
|
||||
resourceUrl: "http://localhost:8080",
|
||||
logo: "/logo.svg",
|
||||
|
|
|
@ -200,6 +200,7 @@ export const ResourcesTab = () => {
|
|||
<OverflowMenuGroup groupType="button">
|
||||
<OverflowMenuItem>
|
||||
<Button
|
||||
data-testid={`share-${resource.name}`}
|
||||
variant="link"
|
||||
onClick={() =>
|
||||
toggleOpen(resource._id, "shareDialogOpen", true)
|
||||
|
|
22
js/apps/account-ui/test/admin-client.ts
Normal file
22
js/apps/account-ui/test/admin-client.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
|
||||
import RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
||||
|
||||
const adminClient = new KeycloakAdminClient({
|
||||
baseUrl: "http://127.0.0.1:8180",
|
||||
realmName: "master",
|
||||
});
|
||||
|
||||
await adminClient.auth({
|
||||
username: "admin",
|
||||
password: "admin",
|
||||
grantType: "password",
|
||||
clientId: "admin-cli",
|
||||
});
|
||||
|
||||
export async function importRealm(realm: RealmRepresentation) {
|
||||
await adminClient.realms.create(realm);
|
||||
}
|
||||
|
||||
export async function deleteRealm(realm: string) {
|
||||
await adminClient.realms.del({ realm });
|
||||
}
|
|
@ -1,15 +1,12 @@
|
|||
import { test as setup } from "@playwright/test";
|
||||
import { login } from "./login";
|
||||
|
||||
const authFile = ".auth/user.json";
|
||||
|
||||
setup("authenticate", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByRole("link", { name: "Personal info" }).click();
|
||||
const userName = page.getByLabel("Username or email");
|
||||
await userName.fill("admin");
|
||||
await page.getByLabel("Password").fill("admin");
|
||||
await page.getByRole("button", { name: "Sign In" }).click();
|
||||
await page.waitForURL("/#/personal-info");
|
||||
await login(page, "admin", "admin");
|
||||
await page.waitForURL("/");
|
||||
|
||||
await page.context().storageState({ path: authFile });
|
||||
});
|
||||
|
|
7
js/apps/account-ui/test/import.setup.ts
Normal file
7
js/apps/account-ui/test/import.setup.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
|
||||
import { test as setup } from "@playwright/test";
|
||||
|
||||
import { importRealm } from "./admin-client";
|
||||
import testRealm from "./test-realm.json" assert { type: "json" };
|
||||
|
||||
setup("import realm", () => importRealm(testRealm as RealmRepresentation));
|
4
js/apps/account-ui/test/import.teardown.ts
Normal file
4
js/apps/account-ui/test/import.teardown.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { test as setup } from "@playwright/test";
|
||||
import { deleteRealm } from "./admin-client";
|
||||
|
||||
setup("delete realm", () => deleteRealm("photoz"));
|
7
js/apps/account-ui/test/login.ts
Normal file
7
js/apps/account-ui/test/login.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { Page } from "@playwright/test";
|
||||
|
||||
export const login = async (page: Page, username: string, password: string) => {
|
||||
await page.getByLabel("Username or email").fill(username);
|
||||
await page.getByLabel("Password").fill(password);
|
||||
await page.getByRole("button", { name: "Sign In" }).click();
|
||||
};
|
12
js/apps/account-ui/test/my-resources.spec.ts
Normal file
12
js/apps/account-ui/test/my-resources.spec.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { login } from "./login";
|
||||
|
||||
test.describe("My resources page", () => {
|
||||
test("List my resources", async ({ page }) => {
|
||||
await page.goto("/?realm=photoz");
|
||||
login(page, "jdoe", "jdoe");
|
||||
await page.waitForURL("/?realm=photoz");
|
||||
await page.getByTestId("resources").click();
|
||||
await expect(page.getByRole("gridcell", { name: "one" })).toBeVisible();
|
||||
});
|
||||
});
|
|
@ -1,9 +1,9 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("Personal info page", () => {
|
||||
test("Setting last and first name", async ({ page }) => {
|
||||
test("sets basic information", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.getByTestId("personal-info").click();
|
||||
await page.getByTestId("email").fill("edewit@example.com");
|
||||
await page.getByTestId("firstName").fill("Erik");
|
||||
await page.getByTestId("lastName").fill("de Wit");
|
||||
await page.getByTestId("save").click();
|
||||
|
|
242
js/apps/account-ui/test/test-realm.json
Normal file
242
js/apps/account-ui/test/test-realm.json
Normal file
|
@ -0,0 +1,242 @@
|
|||
{
|
||||
"realm": "photoz",
|
||||
"enabled": true,
|
||||
"userManagedAccessAllowed": true,
|
||||
"sslRequired": "external",
|
||||
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
|
||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"requiredCredentials": [
|
||||
"password"
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"username": "alice",
|
||||
"enabled": true,
|
||||
"email": "alice@keycloak.org",
|
||||
"firstName": "Alice",
|
||||
"lastName": "In Chains",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "alice"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"user", "uma_authorization"
|
||||
],
|
||||
"clientRoles": {
|
||||
"photoz-restful-api": [
|
||||
"manage-albums"
|
||||
],
|
||||
"account": [
|
||||
"manage-account"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "jdoe",
|
||||
"enabled": true,
|
||||
"email": "jdoe@keycloak.org",
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "jdoe"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"user", "uma_authorization"
|
||||
],
|
||||
"clientRoles": {
|
||||
"photoz-restful-api": [
|
||||
"manage-albums"
|
||||
],
|
||||
"account": [
|
||||
"manage-account"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "admin",
|
||||
"enabled": true,
|
||||
"email": "admin@admin.com",
|
||||
"firstName": "Admin",
|
||||
"lastName": "Istrator",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "admin"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"admin", "uma_authorization"
|
||||
],
|
||||
"clientRoles": {
|
||||
"realm-management": [
|
||||
"realm-admin"
|
||||
],
|
||||
"photoz-restful-api": [
|
||||
"manage-albums"
|
||||
],
|
||||
"account": [
|
||||
"manage-account"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "service-account-photoz-restful-api",
|
||||
"enabled": true,
|
||||
"email": "service-account-photoz-restful-api@placeholder.org",
|
||||
"serviceAccountClientId": "photoz-restful-api",
|
||||
"clientRoles": {
|
||||
"photoz-restful-api" : ["uma_protection"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"roles": {
|
||||
"realm": [
|
||||
{
|
||||
"name": "user",
|
||||
"description": "User privileges"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"description": "Administrator privileges"
|
||||
}
|
||||
]
|
||||
},
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "photoz-html5-client",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8080/photoz-html5-client",
|
||||
"baseUrl": "http://localhost:8080/photoz-html5-client",
|
||||
"publicClient": true,
|
||||
"consentRequired" : true,
|
||||
"fullScopeAllowed" : true,
|
||||
"redirectUris": [
|
||||
"http://localhost:8080/photoz-html5-client/*"
|
||||
],
|
||||
"webOrigins": ["http://localhost:8080"]
|
||||
},
|
||||
{
|
||||
"clientId": "photoz-restful-api",
|
||||
"secret": "secret",
|
||||
"enabled": true,
|
||||
"baseUrl": "http://localhost:8080/photoz-restful-api",
|
||||
"authorizationServicesEnabled" : true,
|
||||
"redirectUris": [
|
||||
"http://localhost:8080/photoz-html5-client"
|
||||
],
|
||||
"webOrigins" : ["http://localhost:8080"],
|
||||
"authorizationSettings": {
|
||||
"allowRemoteResourceManagement": true,
|
||||
"policyEnforcementMode": "ENFORCING",
|
||||
"resources": [
|
||||
{
|
||||
"name": "one",
|
||||
"type": "http://photoz.com/album",
|
||||
"owner": {
|
||||
"name": "jdoe"
|
||||
},
|
||||
"ownerManagedAccess": true,
|
||||
"attributes": {},
|
||||
"_id": "3fba8c0d-c388-4177-8808-18f2b1917ec9",
|
||||
"uris": [
|
||||
"/album/20277be2-548b-49dd-9dbe-95fe1fe80830"
|
||||
],
|
||||
"scopes": [
|
||||
{
|
||||
"name": "album:view"
|
||||
},
|
||||
{
|
||||
"name": "album:delete"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mine",
|
||||
"type": "http://photoz.com/album",
|
||||
"owner": {
|
||||
"name": "alice"
|
||||
},
|
||||
"ownerManagedAccess": true,
|
||||
"attributes": {},
|
||||
"_id": "575da73f-cc0c-482f-ac2a-47c9dd70c390",
|
||||
"uris": [
|
||||
"/album/5fc8c73d-40e0-4682-b555-7b9f56ede273"
|
||||
],
|
||||
"scopes": [
|
||||
{
|
||||
"name": "album:view"
|
||||
},
|
||||
{
|
||||
"name": "album:delete"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"policies": [],
|
||||
"scopes": [
|
||||
{
|
||||
"id": "0b4de4d2-b173-415f-9071-20f866e879ab",
|
||||
"name": "album:view"
|
||||
},
|
||||
{
|
||||
"id": "3b7cf7ed-46c7-4133-b15b-66d05b1f2afe",
|
||||
"name": "album:delete"
|
||||
}
|
||||
],
|
||||
"decisionStrategy": "UNANIMOUS"
|
||||
}
|
||||
},
|
||||
{
|
||||
"clientId": "security-admin-console-v2",
|
||||
"rootUrl": "http://localhost:8080/",
|
||||
"adminUrl": "http://localhost:8080/",
|
||||
"surrogateAuthRequired": false,
|
||||
"enabled": true,
|
||||
"alwaysDisplayInConsole": false,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"redirectUris": [
|
||||
"http://localhost:8080/*"
|
||||
],
|
||||
"webOrigins": [
|
||||
"http://localhost:8080"
|
||||
],
|
||||
"notBefore": 0,
|
||||
"bearerOnly": false,
|
||||
"consentRequired": false,
|
||||
"standardFlowEnabled": true,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": true,
|
||||
"serviceAccountsEnabled": false,
|
||||
"publicClient": true,
|
||||
"frontchannelLogout": false,
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {},
|
||||
"authenticationFlowBindingOverrides": {},
|
||||
"fullScopeAllowed": true,
|
||||
"nodeReRegistrationTimeout": -1,
|
||||
"defaultClientScopes": [
|
||||
"web-origins",
|
||||
"role_list",
|
||||
"roles",
|
||||
"profile",
|
||||
"email"
|
||||
],
|
||||
"optionalClientScopes": [
|
||||
"address",
|
||||
"phone",
|
||||
"offline_access",
|
||||
"microprofile-jwt"
|
||||
],
|
||||
"access": {
|
||||
"view": true,
|
||||
"configure": true,
|
||||
"manage": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
import { ReactNode, useState } from "react";
|
||||
import { Dropdown, DropdownToggle, KebabToggle } from "@patternfly/react-core";
|
||||
import {
|
||||
Dropdown,
|
||||
DropdownProps,
|
||||
DropdownToggle,
|
||||
KebabToggle,
|
||||
} from "@patternfly/react-core";
|
||||
|
||||
type KeycloakDropdownProps = {
|
||||
type KeycloakDropdownProps = Omit<DropdownProps, "toggle"> & {
|
||||
isKebab?: boolean;
|
||||
title?: ReactNode;
|
||||
dropDownItems: ReactNode[];
|
||||
|
@ -11,11 +16,13 @@ export const KeycloakDropdown = ({
|
|||
isKebab = false,
|
||||
title,
|
||||
dropDownItems,
|
||||
...rest
|
||||
}: KeycloakDropdownProps) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
{...rest}
|
||||
isPlain
|
||||
position="right"
|
||||
toggle={
|
||||
|
|
|
@ -85,6 +85,7 @@ const KeycloakMasthead = ({
|
|||
}}
|
||||
>
|
||||
<KeycloakDropdown
|
||||
data-testid="options-kebab"
|
||||
isKebab
|
||||
dropDownItems={[
|
||||
...(kebabDropdownItems || dropdownItems),
|
||||
|
@ -100,6 +101,7 @@ const KeycloakMasthead = ({
|
|||
}}
|
||||
>
|
||||
<KeycloakDropdown
|
||||
data-testid="options"
|
||||
dropDownItems={[...dropdownItems, extraItems]}
|
||||
title={
|
||||
hasUsername && keycloak
|
||||
|
|
|
@ -114,6 +114,9 @@ importers:
|
|||
specifier: workspace:*
|
||||
version: link:../../libs/ui-shared
|
||||
devDependencies:
|
||||
'@keycloak/keycloak-admin-client':
|
||||
specifier: workspace:*
|
||||
version: link:../../libs/keycloak-admin-client
|
||||
'@playwright/test':
|
||||
specifier: ^1.35.1
|
||||
version: 1.35.1
|
||||
|
|
Loading…
Reference in a new issue