diff --git a/js/apps/account-ui/playwright.config.ts b/js/apps/account-ui/playwright.config.ts index d581bd76e6..eb4fef4479 100644 --- a/js/apps/account-ui/playwright.config.ts +++ b/js/apps/account-ui/playwright.config.ts @@ -36,6 +36,7 @@ export default defineConfig({ storageState: ".auth/user.json", }, dependencies: ["setup", "import realms"], + testIgnore: ["**/personal-info.spec.ts"], }, { name: "firefox", @@ -44,6 +45,15 @@ export default defineConfig({ storageState: ".auth/user.json", }, dependencies: ["setup", "import realms"], + testIgnore: ["**/personal-info.spec.ts"], + }, + { + name: "personal-info", + use: { + ...devices["Desktop Chrome"], + }, + dependencies: ["import realms"], + testMatch: ["**/personal-info.spec.ts"], }, ], }); diff --git a/js/apps/account-ui/src/personal-info/components/UserProfileGroup.tsx b/js/apps/account-ui/src/personal-info/components/UserProfileGroup.tsx index cc1ed71502..671b859acc 100644 --- a/js/apps/account-ui/src/personal-info/components/UserProfileGroup.tsx +++ b/js/apps/account-ui/src/personal-info/components/UserProfileGroup.tsx @@ -12,9 +12,15 @@ import { TFuncKey } from "../../i18n"; export type UserProfileFieldsProps = UserProfileAttributeMetadata; +type LengthValidator = + | { + min: number; + } + | undefined; + const isRequired = (attribute: UserProfileAttributeMetadata) => Object.keys(attribute.required || {}).length !== 0 || - ((attribute.validators?.length?.min as number) || 0) > 0; + (((attribute.validators.length as LengthValidator)?.min as number) || 0) > 0; export const UserProfileGroup = ({ children, @@ -47,7 +53,7 @@ export const UserProfileGroup = ({ labelIcon={ helpText ? ( - + ) : undefined } diff --git a/js/apps/account-ui/test/admin-client.ts b/js/apps/account-ui/test/admin-client.ts index b44a1cc44f..7b6ffb2c8d 100644 --- a/js/apps/account-ui/test/admin-client.ts +++ b/js/apps/account-ui/test/admin-client.ts @@ -1,6 +1,7 @@ import KeycloakAdminClient from "@keycloak/keycloak-admin-client"; import RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import type UserProfileConfig from "@keycloak/keycloak-admin-client/lib/defs/userProfileConfig"; +import UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation"; const adminClient = new KeycloakAdminClient({ baseUrl: process.env.KEYCLOAK_SERVER || "http://127.0.0.1:8180", @@ -36,3 +37,33 @@ export async function importUserProfile( ) { await adminClient.users.updateProfile({ ...userProfile, realm }); } + +export async function enableLocalization(realm: string) { + const realmRepresentation = await adminClient.realms.findOne({ realm }); + await adminClient.realms.update( + { realm }, + { + ...realmRepresentation, + internationalizationEnabled: true, + supportedLocales: ["en", "nl", "de"], + }, + ); +} + +export async function createUser(user: UserRepresentation, realm: string) { + try { + await adminClient.users.create({ ...user, realm }); + } catch (error) { + console.error(error); + } +} + +export async function deleteUser(username: string, realm: string) { + try { + const users = await adminClient.users.find({ username, realm }); + const { id } = users[0]; + await adminClient.users.del({ id: id!, realm }); + } catch (error) { + console.error(error); + } +} diff --git a/js/apps/account-ui/test/personal-info/personal-info.spec.ts b/js/apps/account-ui/test/personal-info/personal-info.spec.ts index 6297fa2fe8..66daa00a18 100644 --- a/js/apps/account-ui/test/personal-info/personal-info.spec.ts +++ b/js/apps/account-ui/test/personal-info/personal-info.spec.ts @@ -1,12 +1,19 @@ import type UserProfileConfig from "@keycloak/keycloak-admin-client/lib/defs/userProfileConfig"; import { expect, test } from "@playwright/test"; -import { importUserProfile } from "../admin-client"; +import { + enableLocalization, + importUserProfile, + createUser, + deleteUser, +} from "../admin-client"; import { login } from "../login"; import userProfileConfig from "./user-profile.json" assert { type: "json" }; +const realm = "user-profile"; + test.describe("Personal info page", () => { test("sets basic information", async ({ page }) => { - await page.goto("./"); + await login(page, "admin", "admin", "master"); await page.getByTestId("email").fill("edewit@somewhere.com"); await page.getByTestId("firstName").fill("Erik"); await page.getByTestId("lastName").fill("de Wit"); @@ -18,15 +25,79 @@ test.describe("Personal info page", () => { }); test.describe("Personal info with userprofile enabled", async () => { - const realm = "user-profile"; - test.beforeAll(async () => { await importUserProfile(userProfileConfig as UserProfileConfig, realm); + await createUser( + { + username: "jdoe", + enabled: true, + email: "jdoe@keycloak.org", + firstName: "John", + lastName: "Doe", + credentials: [ + { + type: "password", + value: "jdoe", + }, + ], + realmRoles: [], + clientRoles: { + account: ["manage-account"], + }, + }, + realm, + ); }); + test.afterAll(async () => await deleteUser("jdoe", realm)); + test("render user profile fields", async ({ page }) => { await login(page, "jdoe", "jdoe", realm); await expect(page.locator("#select")).toBeVisible(); + await expect(page.getByTestId("select-help")).toBeVisible(); + expect(page.getByText("Alternative email")).toBeDefined(); + }); + + test("save user profile", async ({ page }) => { + await login(page, "jdoe", "jdoe", realm); + + await page.locator("#select").click(); + await page.getByRole("option", { name: "two" }).click(); + await page.getByTestId("email2").type("non-valid"); + await page.getByTestId("save").click(); + await expect(page.getByTestId("alerts")).toHaveText( + "Could not update account due to validation errors", + ); + + await expect(page.locator("#email2-helper")).toHaveText( + "Invalid email address.", + ); + + await page.getByTestId("email2").clear(); + await page.getByTestId("email2").type("valid@email.com"); + await page.getByTestId("save").click(); + + await page.reload(); + await expect(page.getByTestId("email2")).toHaveValue("valid@email.com"); + }); +}); + +// skip currently the locale is not part of the response +test.describe.skip("Realm localization", async () => { + test.beforeAll(() => enableLocalization("master")); + + test("change locale", async ({ page }) => { + await login(page, "admin", "admin", "master"); + await page + .locator("div") + .filter({ hasText: /^Deutsch$/ }) + .nth(2) + .click(); + await page.getByRole("option", { name: "English" }).click(); + await page.getByTestId("save").click(); + await page.reload(); + + expect(page.locator("div").filter({ hasText: /^English$/ })).toBeDefined(); }); }); diff --git a/js/apps/account-ui/test/realms/user-profile-realm.json b/js/apps/account-ui/test/realms/user-profile-realm.json index a68f1850fa..f820721e5e 100644 --- a/js/apps/account-ui/test/realms/user-profile-realm.json +++ b/js/apps/account-ui/test/realms/user-profile-realm.json @@ -12,27 +12,6 @@ "attributes": { "userProfileEnabled": "true" }, - "users": [ - { - "username": "jdoe", - "enabled": true, - "email": "jdoe@keycloak.org", - "firstName": "John", - "lastName": "Doe", - "credentials": [ - { - "type": "password", - "value": "jdoe" - } - ], - "realmRoles": [], - "clientRoles": { - "account": [ - "manage-account" - ] - } - } - ], "clients": [ { "clientId": "security-admin-console-v2",