keycloak_theme/src/login/KcContext/kcContextMocks.ts

572 lines
17 KiB
TypeScript
Raw Normal View History

import "keycloakify/tools/Object.fromEntries";
2023-03-18 18:27:50 +01:00
import type { KcContext, Attribute } from "./KcContext";
2024-05-20 15:48:51 +02:00
import {
resources_common,
keycloak_resources,
type LoginThemePageId
} from "keycloakify/bin/shared/constants";
2023-02-26 15:36:52 +01:00
import { id } from "tsafe/id";
2023-04-20 20:51:46 +02:00
import { assert, type Equals } from "tsafe/assert";
import { BASE_URL } from "keycloakify/lib/BASE_URL";
2023-02-26 15:36:52 +01:00
const attributesByName = Object.fromEntries(
id<Attribute[]>([
{
validators: {
length: {
"ignore.empty.value": true,
min: "3",
max: "255"
}
2023-02-26 15:36:52 +01:00
},
displayName: "${username}",
annotations: {},
required: true,
autocomplete: "username",
readOnly: false,
2024-06-04 04:06:29 +02:00
name: "username"
2023-02-26 15:36:52 +01:00
},
{
validators: {
length: {
max: "255",
"ignore.empty.value": true
},
email: {
"ignore.empty.value": true
},
pattern: {
"ignore.empty.value": true,
pattern: "gmail\\.com$"
}
},
displayName: "${email}",
annotations: {},
required: true,
autocomplete: "email",
readOnly: false,
name: "email"
2023-02-26 15:36:52 +01:00
},
{
validators: {
length: {
max: "255",
"ignore.empty.value": true
}
},
displayName: "${firstName}",
annotations: {},
required: true,
readOnly: false,
name: "firstName"
2023-02-26 15:36:52 +01:00
},
{
validators: {
length: {
max: "255",
"ignore.empty.value": true
}
},
displayName: "${lastName}",
annotations: {},
required: true,
readOnly: false,
name: "lastName"
}
]).map(attribute => [attribute.name, attribute])
);
2023-02-26 15:36:52 +01:00
const resourcesPath = `${BASE_URL}${keycloak_resources}/login/resources`;
2023-03-18 18:27:50 +01:00
export const kcContextCommonMock: KcContext.Common = {
2024-05-20 15:48:51 +02:00
themeVersion: "0.0.0",
keycloakifyVersion: "0.0.0",
themeType: "login",
themeName: "my-theme-name",
url: {
loginAction: "#",
resourcesPath,
2024-05-20 15:48:51 +02:00
resourcesCommonPath: `${resourcesPath}/${resources_common}`,
loginRestartFlowUrl: "#",
loginUrl: "#",
ssoLoginInOtherTabsUrl: "#"
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
realm: {
name: "myrealm",
displayName: "myrealm",
displayNameHtml: "myrealm",
internationalizationEnabled: true,
registrationEmailAsUsername: false
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
messagesPerField: {
printIfExists: () => {
2023-02-26 15:36:52 +01:00
return undefined;
},
2024-05-20 15:48:51 +02:00
existsError: () => false,
get: fieldName => `Fake error for ${fieldName}`,
exists: () => false,
getFirstError: fieldName => `Fake error for ${fieldName}`
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
locale: {
supported: [
2023-02-26 15:36:52 +01:00
/* spell-checker: disable */
2024-06-04 04:06:29 +02:00
["de", "Deutsch"],
["no", "Norsk"],
["ru", "Русский"],
["sv", "Svenska"],
["pt-BR", "Português (Brasil)"],
["lt", "Lietuvių"],
["en", "English"],
["it", "Italiano"],
["fr", "Français"],
["zh-CN", "中文简体"],
["es", "Español"],
["cs", "Čeština"],
["ja", "日本語"],
["sk", "Slovenčina"],
["pl", "Polski"],
["ca", "Català"],
["nl", "Nederlands"],
["tr", "Türkçe"]
2023-02-26 15:36:52 +01:00
/* spell-checker: enable */
2024-06-04 04:06:29 +02:00
].map(
([languageTag, label]) =>
({
languageTag,
label,
url: "https://gist.github.com/garronej/52baaca1bb925f2296ab32741e062b8e"
}) as const
),
2024-05-20 15:48:51 +02:00
currentLanguageTag: "en"
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
auth: {
showUsername: false,
showResetCredentials: false,
showTryAnotherWayLink: false
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
client: {
clientId: "myApp",
attributes: {}
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
scripts: [],
isAppInitiatedAction: false,
2024-05-27 17:18:06 +02:00
properties: {},
__localizationRealmOverridesUserProfile: {}
2023-02-26 15:36:52 +01:00
};
const loginUrl = {
...kcContextCommonMock.url,
loginResetCredentialsUrl: "#",
registrationUrl: "#",
oauth2DeviceVerificationAction: "#",
oauthAction: "#"
2023-02-26 15:36:52 +01:00
};
2023-04-20 20:51:46 +02:00
export const kcContextMocks = [
2023-03-18 18:27:50 +01:00
id<KcContext.Login>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login.ftl",
url: loginUrl,
realm: {
2023-02-26 15:36:52 +01:00
...kcContextCommonMock.realm,
2024-05-20 15:48:51 +02:00
loginWithEmailAllowed: true,
rememberMe: true,
password: true,
resetPasswordAllowed: true,
registrationAllowed: true
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
auth: kcContextCommonMock.auth!,
social: {
displayInfo: true
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
usernameHidden: false,
login: {},
registrationDisabled: false
2023-02-26 15:36:52 +01:00
}),
2024-05-11 21:38:48 +02:00
id<KcContext.Register>({
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
url: {
2024-05-11 21:38:48 +02:00
...loginUrl,
registrationAction: "#"
2024-05-11 21:38:48 +02:00
},
2024-05-20 15:48:51 +02:00
isAppInitiatedAction: false,
passwordRequired: true,
recaptchaRequired: false,
pageId: "register.ftl",
profile: {
attributesByName
2024-05-11 21:38:48 +02:00
},
2024-05-20 15:48:51 +02:00
scripts: [
2024-05-11 21:38:48 +02:00
//"https://www.google.com/recaptcha/api.js"
]
}),
2023-03-18 18:27:50 +01:00
id<KcContext.Info>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "info.ftl",
messageHeader: "<Message header>",
requiredActions: undefined,
skipLink: false,
actionUri: "#",
client: {
clientId: "myApp",
baseUrl: "#",
attributes: {}
},
message: {
type: "info",
summary:
"This is the info message from the Keycloak server (in real environment, this message is localized)"
2023-02-26 15:36:52 +01:00
}
}),
2023-03-18 18:27:50 +01:00
id<KcContext.Error>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "error.ftl",
client: {
clientId: "myApp",
baseUrl: "#",
attributes: {}
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
message: {
type: "error",
summary:
"This is the error message from the Keycloak server (in real environment, this message is localized)"
2023-02-26 15:36:52 +01:00
}
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginResetPassword>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-reset-password.ftl",
realm: {
2023-02-26 15:36:52 +01:00
...kcContextCommonMock.realm,
2024-05-20 15:48:51 +02:00
loginWithEmailAllowed: false,
duplicateEmailsAllowed: false
},
2024-05-20 15:48:51 +02:00
url: loginUrl,
auth: {}
2023-02-26 15:36:52 +01:00
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginVerifyEmail>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-verify-email.ftl",
user: {
email: "john.doe@gmail.com"
2023-02-26 15:36:52 +01:00
}
}),
2023-03-18 18:27:50 +01:00
id<KcContext.Terms>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "terms.ftl"
2023-02-26 15:36:52 +01:00
}),
id<KcContext.LoginDeviceVerifyUserCode>({
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-oauth2-device-verify-user-code.ftl",
url: loginUrl
}),
id<KcContext.LoginOauthGrant>({
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-oauth-grant.ftl",
oauth: {
code: "5-1N4CIzfi1aprIQjmylI-9e3spLCWW9i5d-GDcs-Sw",
clientScopesRequested: [
{ consentScreenText: "${profileScopeConsentText}" },
{ consentScreenText: "${rolesScopeConsentText}" },
{ consentScreenText: "${emailScopeConsentText}" }
],
client: "account"
},
url: loginUrl
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginOtp>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-otp.ftl",
otpLogin: {
userOtpCredentials: [
2023-02-26 15:36:52 +01:00
{
2024-05-20 15:48:51 +02:00
id: "id1",
userLabel: "label1"
2023-02-26 15:36:52 +01:00
},
{
2024-05-20 15:48:51 +02:00
id: "id2",
userLabel: "label2"
2023-02-26 15:36:52 +01:00
}
]
}
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginUsername>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-username.ftl",
url: loginUrl,
realm: {
2023-02-26 15:36:52 +01:00
...kcContextCommonMock.realm,
2024-05-20 15:48:51 +02:00
loginWithEmailAllowed: true,
rememberMe: true,
password: true,
resetPasswordAllowed: true,
registrationAllowed: true
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
social: {
displayInfo: true
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
usernameHidden: false,
login: {},
registrationDisabled: false
2023-02-26 15:36:52 +01:00
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginPassword>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-password.ftl",
url: loginUrl,
realm: {
2023-02-26 15:36:52 +01:00
...kcContextCommonMock.realm,
2024-05-20 15:48:51 +02:00
resetPasswordAllowed: true
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
social: {
displayInfo: false
2024-05-11 21:38:48 +02:00
}
2023-02-26 15:36:52 +01:00
}),
2023-03-18 18:27:50 +01:00
id<KcContext.WebauthnAuthenticate>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "webauthn-authenticate.ftl",
url: loginUrl,
authenticators: {
authenticators: []
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
realm: {
2024-05-11 21:38:48 +02:00
...kcContextCommonMock.realm,
2024-05-20 15:48:51 +02:00
password: true,
registrationAllowed: true
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
challenge: "",
userVerification: "not specified",
rpId: "",
createTimeout: "0",
isUserIdentified: "false",
shouldDisplayAuthenticators: false,
social: {
displayInfo: false
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
login: {}
2023-02-26 15:36:52 +01:00
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginUpdatePassword>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-update-password.ftl"
2023-02-26 15:36:52 +01:00
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginUpdateProfile>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-update-profile.ftl",
profile: {
attributesByName
2023-02-26 15:36:52 +01:00
}
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginIdpLinkConfirm>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-idp-link-confirm.ftl",
idpAlias: "FranceConnect"
2023-02-26 15:36:52 +01:00
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginIdpLinkEmail>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-idp-link-email.ftl",
idpAlias: "FranceConnect",
brokerContext: {
username: "anUsername"
2023-02-26 15:36:52 +01:00
}
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LoginConfigTotp>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "login-config-totp.ftl",
totp: {
totpSecretEncoded: "KVVF G2BY N4YX S6LB IUYT K2LH IFYE 4SBV",
qrUrl: "#",
totpSecretQrCode:
2023-02-26 15:36:52 +01:00
"iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2AQAAAADNaUdlAAACM0lEQVR4Xu3OIZJgOQwDUDFd2UxiurLAVnnbHw4YGDKtSiWOn4Gxf81//7r/+q8b4HfLGBZDK9d85NmNR+sB42sXvOYrN5P1DcgYYFTGfOlbzE8gzwy3euweGizw7cfdl34/GRhlkxjKNV+5AebPXPORX1JuB9x8ZfbyyD2y1krWAKsbMq1HnqQDaLfa77p4+MqvzEGSqvSAD/2IHW2yHaigR9tX3m8dDIYGcNf3f+gDpVBZbZU77zyJ6Rlcy+qoTMG887KAPD9hsh6a1Sv3gJUHGHUAxSMzj7zqDDe7Phmt2eG+8UsMxjRGm816MAO+8VMl1R1jGHOrZB/5Zo/WXAPgxixm9Mo96vDGrM1eOto8c4Ax4wF437mifOXlpiPzCnN7Y9l95NnEMxgMY9AAGA8fucH14Y1aVb6N/cqrmyh0BVht7k1e+bU8LK0Cg5vmVq9c5vHIjOfqxDIfeTraNVTwewa4wVe+SW5N+uP1qACeudUZbqGOfA6VZV750Noq2Xx3kpveV44ZelSV1V7KFHzkWyVrrlUwG0Pl9pWnoy3vsQoME6vKI69i5osVgwWzHT7zjmJtMcNUSVn1oYMd7ZodbgowZl45VG0uVuLPUr1yc79uaQBag/mqR34xhlWyHm1prplHboCWdZ4TeZjsK8+dI+jbz1C5hl65mcpgB5dhcj8+dGO+0Ko68+lD37JDD83dpDLzzK+TrQyaVwGj6pUboGV+7+AyN8An/pf84/7rv/4/1l4OCc/1BYMAAAAASUVORK5CYII=",
2024-05-20 15:48:51 +02:00
manualUrl: "#",
totpSecret: "G4nsI8lQagRMUchH8jEG",
otpCredentials: [],
supportedApplications: ["FreeOTP", "Google Authenticator"],
policy: {
algorithm: "HmacSHA1",
digits: 6,
lookAheadWindow: 1,
type: "totp",
period: 30,
getAlgorithmKey: () => "SHA1"
2023-02-26 15:36:52 +01:00
}
}
}),
2023-03-18 18:27:50 +01:00
id<KcContext.LogoutConfirm>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "logout-confirm.ftl",
url: {
2023-02-26 15:36:52 +01:00
...kcContextCommonMock.url,
2024-05-20 15:48:51 +02:00
logoutConfirmAction: "Continuer?"
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
client: {
clientId: "myApp",
baseUrl: "#",
attributes: {}
2023-02-26 15:36:52 +01:00
},
2024-05-20 15:48:51 +02:00
logoutConfirm: { code: "123", skipLink: false }
2023-02-26 15:36:52 +01:00
}),
2023-03-18 18:27:50 +01:00
id<KcContext.IdpReviewUserProfile>({
2023-02-26 15:36:52 +01:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "idp-review-user-profile.ftl",
profile: {
attributesByName
2023-02-26 15:36:52 +01:00
}
2023-03-27 13:02:44 +03:00
}),
id<KcContext.UpdateEmail>({
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
pageId: "update-email.ftl",
profile: {
attributesByName: {
email: attributesByName["email"]
}
2023-03-27 13:02:44 +03:00
}
2023-03-31 17:38:22 +02:00
}),
id<KcContext.SelectAuthenticator>({
...kcContextCommonMock,
pageId: "select-authenticator.ftl",
auth: {
authenticationSelections: [
{
authExecId: "f607f83c-537e-42b7-99d7-c52d459afe84",
displayName: "otp-display-name",
helpText: "otp-help-text",
iconCssClass: "kcAuthenticatorOTPClass"
},
{
authExecId: "5ed881b1-84cd-4e9b-b4d9-f329ea61a58c",
displayName: "webauthn-display-name",
helpText: "webauthn-help-text",
iconCssClass: "kcAuthenticatorWebAuthnClass"
}
]
}
2023-04-20 20:51:46 +02:00
}),
id<KcContext.SamlPostForm>({
...kcContextCommonMock,
pageId: "saml-post-form.ftl",
2024-05-20 15:48:51 +02:00
samlPost: {
url: "#"
2023-04-20 20:51:46 +02:00
}
}),
id<KcContext.LoginPageExpired>({
...kcContextCommonMock,
pageId: "login-page-expired.ftl"
2024-05-11 00:05:58 +02:00
}),
id<KcContext.FrontchannelLogout>({
...kcContextCommonMock,
pageId: "frontchannel-logout.ftl",
2024-05-20 15:48:51 +02:00
logout: {
clients: [
2024-05-11 00:05:58 +02:00
{
2024-05-20 15:48:51 +02:00
name: "myApp",
frontChannelLogoutUrl: "#"
2024-05-11 00:05:58 +02:00
},
{
2024-05-20 15:48:51 +02:00
name: "myApp2",
frontChannelLogoutUrl: "#"
2024-05-11 00:05:58 +02:00
}
]
}
2024-05-11 21:38:48 +02:00
}),
id<KcContext.WebauthnRegister>({
2024-05-20 15:48:51 +02:00
pageId: "webauthn-register.ftl",
...kcContextCommonMock,
challenge: "random-challenge-string",
userid: "user123",
username: "johndoe",
signatureAlgorithms: ["ES256", "RS256"],
rpEntityName: "Example Corp",
rpId: "example.com",
attestationConveyancePreference: "direct",
authenticatorAttachment: "platform",
requireResidentKey: "required",
userVerificationRequirement: "preferred",
createTimeout: 60000,
excludeCredentialIds: "credId123,credId456",
isSetRetry: false,
isAppInitiatedAction: true
2024-05-11 21:38:48 +02:00
}),
id<KcContext.DeleteCredential>({
2024-05-20 15:48:51 +02:00
pageId: "delete-credential.ftl",
2024-05-11 21:38:48 +02:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
credentialLabel: "myCredential"
2024-05-11 21:38:48 +02:00
}),
id<KcContext.Code>({
2024-05-20 15:48:51 +02:00
pageId: "code.ftl",
2024-05-11 21:38:48 +02:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
code: {
success: true,
code: "123456"
2024-05-11 21:38:48 +02:00
}
}),
id<KcContext.DeleteAccountConfirm>({
2024-05-20 15:48:51 +02:00
pageId: "delete-account-confirm.ftl",
2024-05-11 21:38:48 +02:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
triggered_from_aia: true
2024-05-11 21:38:48 +02:00
}),
id<KcContext.LoginRecoveryAuthnCodeConfig>({
2024-05-20 15:48:51 +02:00
pageId: "login-recovery-authn-code-config.ftl",
2024-05-11 21:38:48 +02:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
recoveryAuthnCodesConfigBean: {
generatedRecoveryAuthnCodesList: ["code123", "code456", "code789"],
generatedRecoveryAuthnCodesAsString: "code123, code456, code789",
generatedAt: new Date().getTime()
2024-05-11 21:38:48 +02:00
}
}),
id<KcContext.LoginRecoveryAuthnCodeInput>({
2024-05-20 15:48:51 +02:00
pageId: "login-recovery-authn-code-input.ftl",
2024-05-11 21:38:48 +02:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
recoveryAuthnCodesInputBean: {
codeNumber: 1234
2024-05-11 21:38:48 +02:00
}
}),
id<KcContext.LoginResetOtp>({
2024-05-20 15:48:51 +02:00
pageId: "login-reset-otp.ftl",
2024-05-11 21:38:48 +02:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
configuredOtpCredentials: {
userOtpCredentials: [
2024-05-11 21:38:48 +02:00
{
2024-05-20 15:48:51 +02:00
id: "otpId1",
userLabel: "OTP Device 1"
2024-05-11 21:38:48 +02:00
},
{
2024-05-20 15:48:51 +02:00
id: "otpId2",
userLabel: "OTP Device 2"
2024-05-11 21:38:48 +02:00
},
{
2024-05-20 15:48:51 +02:00
id: "otpId3",
userLabel: "Backup OTP"
2024-05-11 21:38:48 +02:00
}
],
2024-05-20 15:48:51 +02:00
selectedCredentialId: "otpId2"
2024-05-11 21:38:48 +02:00
}
}),
id<KcContext.LoginX509Info>({
2024-05-20 15:48:51 +02:00
pageId: "login-x509-info.ftl",
2024-05-11 21:38:48 +02:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
x509: {
formData: {
subjectDN: "CN=John Doe, O=Example Corp, C=US",
isUserEnabled: true,
username: "johndoe"
2024-05-11 21:38:48 +02:00
}
}
}),
id<KcContext.WebauthnError>({
2024-05-20 15:48:51 +02:00
pageId: "webauthn-error.ftl",
2024-05-11 21:38:48 +02:00
...kcContextCommonMock,
2024-05-20 15:48:51 +02:00
isAppInitiatedAction: true
2023-02-26 15:36:52 +01:00
})
];
2023-04-20 20:51:46 +02:00
{
type Got = (typeof kcContextMocks)[number]["pageId"];
type Expected = LoginThemePageId;
type OnlyInGot = Exclude<Got, Expected>;
type OnlyInExpected = Exclude<Expected, Got>;
assert<Equals<OnlyInGot, never>>();
assert<Equals<OnlyInExpected, never>>();
}