0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-31 22:51:25 -05:00

refactor(test): add modal ui test helpers (#4412)

This commit is contained in:
Xiao Yijun 2023-08-31 12:14:19 +08:00 committed by GitHub
parent 0007c75df1
commit 4f5881304e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 93 additions and 186 deletions

View file

@ -1,7 +1,11 @@
import { ConnectorType } from '@logto/connector-kit';
import { type Page } from 'puppeteer';
import { expectConfirmModalAndAct, waitForToast } from '#src/ui-helpers/index.js';
import {
expectConfirmModalAndAct,
expectModalWithTitle,
waitForToast,
} from '#src/ui-helpers/index.js';
import {
passwordlessConnectorTestCases,
@ -38,16 +42,13 @@ export const expectToSelectConnector = async (
page: Page,
{ groupFactoryId, factoryId, connectorType }: SelectConnectorOption
) => {
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text:
connectorType === ConnectorType.Email
? 'Set up email connector'
: connectorType === ConnectorType.Sms
? 'Set up SMS connector'
: 'Add Social Connector',
}
await expectModalWithTitle(
page,
connectorType === ConnectorType.Email
? 'Set up email connector'
: connectorType === ConnectorType.Sms
? 'Set up SMS connector'
: 'Add Social Connector'
);
if (groupFactoryId) {

View file

@ -7,6 +7,7 @@ import {
goToAdminConsole,
expectToSaveChanges,
waitForToast,
expectModalWithTitle,
} from '#src/ui-helpers/index.js';
import { expectNavigation, appendPathname } from '#src/utils.js';
@ -53,12 +54,7 @@ describe('social connectors', () => {
text: 'Add Social Connector',
});
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Add Social Connector',
}
);
await expectModalWithTitle(page, 'Add Social Connector');
// Close modal
await page.keyboard.press('Escape');

View file

@ -1,7 +1,9 @@
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
import {
expectConfirmModalAndAct,
expectModalWithTitle,
expectToClickDetailsPageOption,
expectToClickModalAction,
goToAdminConsole,
waitForToast,
} from '#src/ui-helpers/index.js';
@ -49,21 +51,14 @@ describe('RBAC', () => {
text: 'Create API Resource',
});
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Create API Resource',
}
);
await expectModalWithTitle(page, 'Create API Resource');
await expect(page).toFillForm('.ReactModalPortal form', {
name: apiResourceName,
indicator: apiResourceIndicator,
});
await expect(page).toClick('.ReactModalPortal div[class$=footer] button[type=submit] span', {
text: 'Create API Resource',
});
await expectToClickModalAction(page, 'Create API Resource');
await waitForToast(page, {
text: `The API resource ${apiResourceName} has been successfully created`,
@ -83,21 +78,14 @@ describe('RBAC', () => {
text: 'Create Permission',
});
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Create permission',
}
);
await expectModalWithTitle(page, 'Create permission');
await expect(page).toFillForm('.ReactModalPortal form', {
name: permissionName,
description: permissionDescription,
});
await expect(page).toClick('.ReactModalPortal div[class$=footer] button[type=submit] span', {
text: 'Create permission',
});
await expectToClickModalAction(page, 'Create permission');
await waitForToast(page, {
text: `The permission ${permissionName} has been successfully created`,
@ -121,25 +109,15 @@ describe('RBAC', () => {
it('create a user for rbac testing', async () => {
await expect(page).toClick('div[class$=headline] button span', { text: 'Add User' });
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Add User',
}
);
await expectModalWithTitle(page, 'Add User');
await expect(page).toFillForm('.ReactModalPortal form', {
username: rbacTestUsername,
});
await expect(page).toClick('.ReactModalPortal div[class$=footer] button[type=submit] span', {
text: 'Add User',
});
await expectToClickModalAction(page, 'Add User');
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{ text: 'This user has been successfully created' }
);
await expectModalWithTitle(page, 'This user has been successfully created');
await page.keyboard.press('Escape');
});
@ -160,12 +138,7 @@ describe('RBAC', () => {
text: 'Create Role',
});
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Create Role',
}
);
await expectModalWithTitle(page, 'Create Role');
await expect(page).toFillForm('.ReactModalPortal form', {
name: roleName,
@ -187,24 +160,14 @@ describe('RBAC', () => {
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button[type=submit] span', {
text: 'Create Role',
});
await expectToClickModalAction(page, 'Create Role');
await waitForToast(page, {
text: `The role ${roleName} has been successfully created.`,
});
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Assign users',
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: 'Skip for now',
});
await expectModalWithTitle(page, 'Assign users');
await expectToClickModalAction(page, 'Skip for now');
await expect(page).toMatchElement('div[class$=header] div[class$=info] div[class$=name]', {
text: roleName,
@ -222,15 +185,9 @@ describe('RBAC', () => {
);
await expect(permissionRow).toClick('td[class$=deleteColumn] button');
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Reminder',
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: 'Remove',
await expectConfirmModalAndAct(page, {
title: 'Reminder',
actionText: 'Remove',
});
await waitForToast(page, {
@ -243,12 +200,7 @@ describe('RBAC', () => {
text: 'Assign Permissions',
});
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Assign permissions',
}
);
await expectModalWithTitle(page, 'Assign permissions');
await expect(page).toClick(
'.ReactModalPortal div[class$=resourceItem] div[class$=title] div[class$=name]',
@ -264,9 +216,7 @@ describe('RBAC', () => {
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: 'Assign Permissions',
});
await expectToClickModalAction(page, 'Assign Permissions');
await waitForToast(page, {
text: 'The selected permissions were successfully assigned to this role',
@ -286,12 +236,7 @@ describe('RBAC', () => {
text: 'Assign Users',
});
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Assign users',
}
);
await expectModalWithTitle(page, 'Assign users');
await expect(page).toClick(
'.ReactModalPortal div[class$=roleUsersTransfer] div[class$=item] div[class$=title]',
@ -299,10 +244,7 @@ describe('RBAC', () => {
text: rbacTestUsername,
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: 'Assign users',
});
await expectToClickModalAction(page, 'Assign users');
await waitForToast(page, {
text: 'The selected users were successfully assigned to this role',
@ -338,15 +280,9 @@ describe('RBAC', () => {
// Click remove button
await expect(roleRow).toClick('td:last-of-type button');
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Reminder',
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: 'Remove',
await expectConfirmModalAndAct(page, {
title: 'Reminder',
actionText: 'Remove',
});
await waitForToast(page, {
@ -359,12 +295,7 @@ describe('RBAC', () => {
text: 'Assign Roles',
});
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: `Assign roles to ${rbacTestUsername}`,
}
);
await expectModalWithTitle(page, `Assign roles to ${rbacTestUsername}`);
await expect(page).toClick(
'.ReactModalPortal div[class$=rolesTransfer] div[class$=item] div[class$=name]',
@ -373,9 +304,7 @@ describe('RBAC', () => {
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: 'Assign roles',
});
await expectToClickModalAction(page, 'Assign roles');
await waitForToast(page, {
text: 'Successfully assigned role(s)',
@ -458,16 +387,7 @@ describe('RBAC', () => {
);
await expect(permissionRow).toClick('td[class$=deleteColumn] button');
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Reminder',
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: 'Delete',
});
await expectConfirmModalAndAct(page, { title: 'Reminder', actionText: 'Delete' });
await waitForToast(page, {
text: `The permission "${permissionName}" was successfully deleted.`,
@ -477,18 +397,11 @@ describe('RBAC', () => {
it('delete api resource', async () => {
await expectToClickDetailsPageOption(page, 'Delete');
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'Reminder',
}
);
await expectModalWithTitle(page, 'Reminder');
await expect(page).toFill('.ReactModalPortal input', apiResourceName);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: 'Delete',
});
await expectToClickModalAction(page, 'Delete');
await waitForToast(page, {
text: `The API Resource ${apiResourceName} has been successfully deleted`,

View file

@ -4,6 +4,8 @@ import {
expectToSaveChanges,
waitForToast,
expectToDiscardChanges,
expectModalWithTitle,
expectToClickModalAction,
} from '#src/ui-helpers/index.js';
import {
appendPathname,
@ -44,14 +46,10 @@ describe('user management', () => {
});
await expect(page).toClick('button[type=submit]');
await page.waitForSelector('div[class$=infoLine');
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: 'This user has been successfully created',
}
);
await expectModalWithTitle(page, 'This user has been successfully created');
// Go to user details page
await expect(page).toClick('div.ReactModalPortal div[class$=footer] button:first-of-type');
await expectToClickModalAction(page, 'Check user detail');
await expect(page).toMatchElement('div[class$=main] div[class$=metadata] div[class$=title]', {
text: 'jdoe@gmail.com',
});
@ -131,7 +129,7 @@ describe('user management', () => {
await page.waitForSelector('div[class$=infoLine');
// Go to the user details page
await expect(page).toClick('div.ReactModalPortal div[class$=footer] button:nth-of-type(1)');
await expectToClickModalAction(page, 'Check user detail');
await expect(page).toMatchElement('div[class$=main] div[class$=metadata] div[class$=title]', {
text: username,
});
@ -183,7 +181,7 @@ describe('user management', () => {
await expect(page).toMatchElement('.ReactModalPortal div[class$=medium] div[class$=content]', {
text: 'User needs to have at least one of the sign-in identifiers (username, email, phone number or social) to sign in. Are you sure you want to continue?',
});
await expect(page).toClick('div.ReactModalPortal div[class$=footer] button:nth-of-type(2)');
await expectToClickModalAction(page, 'Confirm');
// After all identifiers, top userinfo card shows 'Unnamed' as the title
await expect(page).toMatchElement('div[class$=main] div[class$=metadata] div[class$=title]', {
text: 'Unnamed',

View file

@ -1,5 +1,13 @@
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
import { goToAdminConsole, expectToSaveChanges, waitForToast } from '#src/ui-helpers/index.js';
import {
goToAdminConsole,
expectToSaveChanges,
waitForToast,
expectToClickModalAction,
expectToClickDetailsPageOption,
expectModalWithTitle,
expectConfirmModalAndAct,
} from '#src/ui-helpers/index.js';
import { appendPathname, expectNavigation } from '#src/utils.js';
await page.setViewport({ width: 1280, height: 720 });
@ -93,38 +101,28 @@ describe('webhooks', () => {
await createWebhookFromWebhooksPage();
// Disable webhook
await expect(page).toClick('div[class$=header] >div:nth-of-type(2) button');
// Wait for the menu to be opened
await page.waitForTimeout(500);
await expect(page).toClick(
'.ReactModalPortal div[class$=dropdownContainer] div[role=menuitem]:nth-of-type(1)'
);
await expectToClickDetailsPageOption(page, 'Disable webhook');
await expectModalWithTitle(page, 'Reminder');
await expect(page).toMatchElement('.ReactModalPortal div[class$=content] div[class$=content]', {
text: 'Are you sure you want to reactivate this webhook? Doing so will not send HTTP request to endpoint URL.',
});
await expect(page).toClick('.ReactModalPortal div[class$=footer] button:last-of-type');
// Wait for the state to be updated
await page.waitForTimeout(500);
await expectToClickModalAction(page, 'Disable webhook');
await expect(page).toMatchElement(
'div[class$=header] div[class$=metadata] div:nth-of-type(2) div[class$=outlined] div:nth-of-type(2)',
{
text: 'Not in use',
timeout: 1000,
}
);
// Enable webhook
await expect(page).toClick('div[class$=header] >div:nth-of-type(2) button');
// Wait for the menu to be opened
await page.waitForTimeout(500);
await expect(page).toClick(
'.ReactModalPortal div[class$=dropdownContainer] div[role=menuitem]:nth-of-type(1)'
);
// Wait for the state to be updated
await page.waitForTimeout(500);
const stateDiv = await page.waitForSelector(
// Reactivate webhook
await expectToClickDetailsPageOption(page, 'Reactivate webhook');
// Wait for the active webhook state info to appear
await page.waitForSelector(
'div[class$=header] div[class$=metadata] div:nth-of-type(2) div[class$=state]'
);
expect(stateDiv).toBeTruthy();
});
it('can regenerate signing key for a webhook', async () => {
@ -132,13 +130,11 @@ describe('webhooks', () => {
await createWebhookFromWebhooksPage();
await expect(page).toClick('button[class$=regenerateButton]');
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=content] div[class$=titleEllipsis]',
{
text: 'Regenerate signing key',
}
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button:last-of-type');
await expectConfirmModalAndAct(page, {
title: 'Regenerate signing key',
actionText: 'Regenerate',
});
await waitForToast(page, { text: 'Signing key has been regenerated.' });
});
});

View file

@ -45,9 +45,7 @@ export const expectUnsavedChangesAlert = async (page: Page) => {
'.ReactModalPortal div[class$=content]::-p-text(You have made some changes. Are you sure you want to leave this page?)'
);
await expect(page).toClick('.ReactModalPortal div[class$=footer] button', {
text: 'Stay on Page',
});
await expectToClickModalAction(page, 'Stay on Page');
};
export const expectToSaveChanges = async (page: Page) => {
@ -89,27 +87,32 @@ export const expectToClickDetailsPageOption = async (page: Page, optionText: str
);
};
type ExpectConfirmModalAndActOptions = {
title?: string | RegExp;
actionText?: string | RegExp;
};
export const expectConfirmModalAndAct = async (
page: Page,
{ title, actionText }: ExpectConfirmModalAndActOptions
) => {
export const expectModalWithTitle = async (page: Page, title: string | RegExp) => {
await expect(page).toMatchElement(
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
{
text: title,
}
);
};
if (actionText) {
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: actionText,
});
}
export const expectToClickModalAction = async (page: Page, actionText: string | RegExp) => {
await expect(page).toClick('.ReactModalPortal div[class$=footer] button span', {
text: actionText,
});
};
type ExpectConfirmModalAndActOptions = {
title: string | RegExp;
actionText: string | RegExp;
};
export const expectConfirmModalAndAct = async (
page: Page,
{ title, actionText }: ExpectConfirmModalAndActOptions
) => {
await expectModalWithTitle(page, title);
await expectToClickModalAction(page, actionText);
};
export const expectToClickNavTab = async (page: Page, tab: string) => {