mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
test: add ui tests for passwordless connectors (#4331)
This commit is contained in:
parent
d0f91d5d37
commit
8354fa87ad
5 changed files with 580 additions and 80 deletions
|
@ -0,0 +1,92 @@
|
|||
import { ConnectorType } from '@logto/connector-kit';
|
||||
import { type Page } from 'puppeteer';
|
||||
|
||||
import { expectConfirmModalAndAct, waitForToaster } from '#src/ui-helpers/index.js';
|
||||
|
||||
import {
|
||||
passwordlessConnectorTestCases,
|
||||
type PasswordlessConnectorCase,
|
||||
} from './passwordless-connector-test-cases.js';
|
||||
|
||||
/**
|
||||
* Finds the next connector of the same type adjacent to the current connector, which will be selected
|
||||
* as the new connector when changing the current connector.
|
||||
*/
|
||||
export const findNextCompatibleConnector = (currentConnector: PasswordlessConnectorCase) => {
|
||||
const sameTypeConnectors = passwordlessConnectorTestCases.filter(
|
||||
(connector) => connector.isEmailConnector === currentConnector.isEmailConnector
|
||||
);
|
||||
|
||||
const currentIndex = sameTypeConnectors.findIndex(
|
||||
(connector) => connector.factoryId === currentConnector.factoryId
|
||||
);
|
||||
|
||||
if (currentIndex === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
return sameTypeConnectors[(currentIndex + 1) % sameTypeConnectors.length];
|
||||
};
|
||||
|
||||
type SelectConnectorOption = {
|
||||
groupFactoryId?: string;
|
||||
factoryId: string;
|
||||
connectorType: ConnectorType;
|
||||
};
|
||||
|
||||
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',
|
||||
}
|
||||
);
|
||||
|
||||
if (groupFactoryId) {
|
||||
// Platform selector
|
||||
await page.click(
|
||||
`.ReactModalPortal div[role=radio]:has(input[name=group][value=${groupFactoryId}])`
|
||||
);
|
||||
|
||||
await page.waitForSelector('.ReactModalPortal div[class$=platforms] div[class$=radioGroup]');
|
||||
|
||||
await page.click(
|
||||
`.ReactModalPortal div[class$=platforms] div[role=radio]:has(input[name=connector][value=${factoryId}])`
|
||||
);
|
||||
} else {
|
||||
await page.click(
|
||||
`.ReactModalPortal div[role=radio]:has(input[name=group][value=${factoryId}])`
|
||||
);
|
||||
}
|
||||
|
||||
await expect(page).toClick('.ReactModalPortal div[class$=footer] button:not(disabled) span', {
|
||||
text: 'Next',
|
||||
});
|
||||
};
|
||||
|
||||
export const waitForConnectorCreationGuide = async (page: Page, connectorName: string) => {
|
||||
await expect(page).toMatchElement('.ReactModalPortal div[class$=titleEllipsis] span', {
|
||||
text: connectorName,
|
||||
});
|
||||
|
||||
await expect(page).toMatchElement('.ReactModalPortal div[class$=subtitle] span', {
|
||||
text: 'A step by step guide to configure your connector',
|
||||
});
|
||||
};
|
||||
|
||||
export const expectToConfirmConnectorDeletion = async (page: Page) => {
|
||||
await expectConfirmModalAndAct(page, {
|
||||
title: 'Reminder',
|
||||
actionText: 'Delete',
|
||||
});
|
||||
|
||||
await waitForToaster(page, { text: 'The connector has been successfully deleted' });
|
||||
};
|
|
@ -0,0 +1,234 @@
|
|||
export type PasswordlessConnectorCase = {
|
||||
factoryId: string;
|
||||
isEmailConnector: boolean;
|
||||
name: string;
|
||||
initialFormData: Record<string, string>;
|
||||
updateFormData: Record<string, string>;
|
||||
errorFormData: Record<string, string>;
|
||||
};
|
||||
|
||||
const awsSesMail: PasswordlessConnectorCase = {
|
||||
factoryId: 'aws-ses-mail',
|
||||
isEmailConnector: true,
|
||||
name: 'AWS Direct Mail',
|
||||
initialFormData: {
|
||||
'formConfig.accessKeyId': 'access-key-id',
|
||||
'formConfig.accessKeySecret': 'access-key-config',
|
||||
'formConfig.region': 'region',
|
||||
'formConfig.emailAddress': 'email-address',
|
||||
'formConfig.emailAddressIdentityArn': 'email-address-identity-arn',
|
||||
'formConfig.feedbackForwardingEmailAddress': 'feedback-forwarding-email-address',
|
||||
'formConfig.feedbackForwardingEmailAddressIdentityArn':
|
||||
'feedback-forwarding-email-address-identity-arn',
|
||||
'formConfig.configurationSetName': 'configuration-set-name',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.accessKeyId': 'new-access-key-id',
|
||||
'formConfig.accessKeySecret': 'new-access-key-config',
|
||||
'formConfig.region': 'new-region',
|
||||
'formConfig.emailAddress': 'new-email-address',
|
||||
'formConfig.emailAddressIdentityArn': 'new-email-address-identity-arn',
|
||||
'formConfig.feedbackForwardingEmailAddress': 'new-feedback-forwarding-email-address',
|
||||
'formConfig.feedbackForwardingEmailAddressIdentityArn':
|
||||
'new-feedback-forwarding-email-address-identity-arn',
|
||||
'formConfig.configurationSetName': 'new-configuration-set-name',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.accessKeyId': '',
|
||||
'formConfig.accessKeySecret': '',
|
||||
'formConfig.region': '',
|
||||
},
|
||||
};
|
||||
|
||||
const sendGrid: PasswordlessConnectorCase = {
|
||||
factoryId: 'sendgrid-email-service',
|
||||
isEmailConnector: true,
|
||||
name: 'SendGrid Email',
|
||||
initialFormData: {
|
||||
'formConfig.apiKey': 'api-key',
|
||||
'formConfig.fromEmail': 'foo@example.com',
|
||||
'formConfig.fromName': 'Logto',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.apiKey': 'new-api-key',
|
||||
'formConfig.fromEmail': 'new-foo@example.com',
|
||||
'formConfig.fromName': 'new-Logto',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.apiKey': '',
|
||||
'formConfig.fromEmail': '',
|
||||
},
|
||||
};
|
||||
|
||||
const aliyunDirectMail: PasswordlessConnectorCase = {
|
||||
factoryId: 'aliyun-direct-mail',
|
||||
isEmailConnector: true,
|
||||
name: 'Aliyun Direct Mail',
|
||||
initialFormData: {
|
||||
'formConfig.accessKeyId': 'access-key-id',
|
||||
'formConfig.accessKeySecret': 'access-key-config',
|
||||
'formConfig.accountName': 'account-name',
|
||||
'formConfig.fromAlias': 'from-alias',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.accessKeyId': 'new-access-key-id',
|
||||
'formConfig.accessKeySecret': 'new-access-key-config',
|
||||
'formConfig.accountName': 'new-account-name',
|
||||
'formConfig.fromAlias': 'new-from-alias',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.accessKeyId': '',
|
||||
'formConfig.accessKeySecret': '',
|
||||
'formConfig.accountName': '',
|
||||
},
|
||||
};
|
||||
|
||||
const mailgun: PasswordlessConnectorCase = {
|
||||
factoryId: 'mailgun-email',
|
||||
isEmailConnector: true,
|
||||
name: 'Mailgun',
|
||||
initialFormData: {
|
||||
'formConfig.endpoint': 'https://fake.mailgun.net',
|
||||
'formConfig.domain': 'mailgun-domain.com',
|
||||
'formConfig.apiKey': 'api-key',
|
||||
'formConfig.from': 'from',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.endpoint': 'https://new-fake.mailgun.net',
|
||||
'formConfig.domain': 'new-mailgun-domain.com',
|
||||
'formConfig.apiKey': 'new-api-key',
|
||||
'formConfig.from': 'new-from',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.domain': '',
|
||||
'formConfig.apiKey': '',
|
||||
'formConfig.from': '',
|
||||
},
|
||||
};
|
||||
|
||||
const smpt: PasswordlessConnectorCase = {
|
||||
factoryId: 'simple-mail-transfer-protocol',
|
||||
isEmailConnector: true,
|
||||
name: 'SMTP',
|
||||
initialFormData: {
|
||||
'formConfig.host': 'host',
|
||||
'formConfig.port': '25',
|
||||
'formConfig.fromEmail': 'from',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.host': 'new-host',
|
||||
'formConfig.port': '26',
|
||||
'formConfig.fromEmail': 'new-from',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.host': '',
|
||||
'formConfig.port': '',
|
||||
'formConfig.fromEmail': '',
|
||||
},
|
||||
};
|
||||
|
||||
const twilio: PasswordlessConnectorCase = {
|
||||
factoryId: 'twilio-short-message-service',
|
||||
isEmailConnector: false,
|
||||
name: 'Twilio SMS Service',
|
||||
initialFormData: {
|
||||
'formConfig.accountSID': 'account-sid',
|
||||
'formConfig.authToken': 'auth-token',
|
||||
'formConfig.fromMessagingServiceSID': 'from-messaging-service-sid',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.accountSID': 'new-account-sid',
|
||||
'formConfig.authToken': 'new-auth-token',
|
||||
'formConfig.fromMessagingServiceSID': 'new-from-messaging-service-sid',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.accountSID': '',
|
||||
'formConfig.authToken': '',
|
||||
'formConfig.fromMessagingServiceSID': '',
|
||||
},
|
||||
};
|
||||
|
||||
const aliyunShortMessage: PasswordlessConnectorCase = {
|
||||
factoryId: 'aliyun-short-message-service',
|
||||
isEmailConnector: false,
|
||||
name: 'Aliyun Short Message Service',
|
||||
initialFormData: {
|
||||
'formConfig.accessKeyId': 'access-key-id',
|
||||
'formConfig.accessKeySecret': 'access-key-config',
|
||||
'formConfig.signName': 'sign-name',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.accessKeyId': 'new-access-key-id',
|
||||
'formConfig.accessKeySecret': 'new-access-key-config',
|
||||
'formConfig.signName': 'new-sign-name',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.accessKeyId': '',
|
||||
'formConfig.accessKeySecret': '',
|
||||
'formConfig.signName': '',
|
||||
},
|
||||
};
|
||||
|
||||
// Tencent-short-message-service
|
||||
const tencentShortMessage: PasswordlessConnectorCase = {
|
||||
factoryId: 'tencent-short-message-service',
|
||||
isEmailConnector: false,
|
||||
name: 'Tencent Short Message Service',
|
||||
initialFormData: {
|
||||
'formConfig.accessKeyId': 'access-key-id',
|
||||
'formConfig.accessKeySecret': 'access-key-config',
|
||||
'formConfig.signName': 'sign-name',
|
||||
'formConfig.sdkAppId': 'sdk-app-id',
|
||||
'formConfig.region': 'region',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.accessKeyId': 'new-access-key-id',
|
||||
'formConfig.accessKeySecret': 'new-access-key-config',
|
||||
'formConfig.signName': 'new-sign-name',
|
||||
'formConfig.sdkAppId': 'new-sdk-app-id',
|
||||
'formConfig.region': 'new-region',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.accessKeyId': '',
|
||||
'formConfig.accessKeySecret': '',
|
||||
'formConfig.signName': '',
|
||||
'formConfig.sdkAppId': '',
|
||||
'formConfig.region': '',
|
||||
},
|
||||
};
|
||||
|
||||
// Smsaero-short-message-service
|
||||
const smsaeroShortMessage: PasswordlessConnectorCase = {
|
||||
factoryId: 'smsaero-short-message-service',
|
||||
isEmailConnector: false,
|
||||
name: 'SMS Aero service',
|
||||
initialFormData: {
|
||||
'formConfig.email': 'fake@email.com',
|
||||
'formConfig.apiKey': 'api-key',
|
||||
'formConfig.senderName': 'sender-name',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.email': 'new-fake@email.com',
|
||||
'formConfig.apiKey': 'new-api-key',
|
||||
'formConfig.senderName': 'new-sender-name',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.email': '',
|
||||
'formConfig.apiKey': '',
|
||||
'formConfig.senderName': '',
|
||||
},
|
||||
};
|
||||
|
||||
export const passwordlessConnectorTestCases = [
|
||||
// Email
|
||||
awsSesMail,
|
||||
sendGrid,
|
||||
aliyunDirectMail,
|
||||
mailgun,
|
||||
smpt,
|
||||
// SMS
|
||||
twilio,
|
||||
aliyunShortMessage,
|
||||
tencentShortMessage,
|
||||
smsaeroShortMessage,
|
||||
];
|
|
@ -0,0 +1,174 @@
|
|||
import { ConnectorType } from '@logto/connector-kit';
|
||||
|
||||
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
|
||||
import {
|
||||
expectToClickDetailsPageOption,
|
||||
expectUnsavedChangesAlert,
|
||||
goToAdminConsole,
|
||||
trySaveChanges,
|
||||
waitForToaster,
|
||||
} from '#src/ui-helpers/index.js';
|
||||
import { expectNavigation, appendPathname } from '#src/utils.js';
|
||||
|
||||
import {
|
||||
expectToConfirmConnectorDeletion,
|
||||
expectToSelectConnector,
|
||||
findNextCompatibleConnector,
|
||||
waitForConnectorCreationGuide,
|
||||
} from './helpers.js';
|
||||
import {
|
||||
type PasswordlessConnectorCase,
|
||||
passwordlessConnectorTestCases,
|
||||
} from './passwordless-connector-test-cases.js';
|
||||
|
||||
await page.setViewport({ width: 1920, height: 1080 });
|
||||
|
||||
describe('passwordless connectors', () => {
|
||||
const logtoConsoleUrl = new URL(logtoConsoleUrlString);
|
||||
|
||||
beforeAll(async () => {
|
||||
await goToAdminConsole();
|
||||
});
|
||||
|
||||
it('navigate to passwordless connector page', async () => {
|
||||
// Should navigate to passwordless page when visit '/console/connectors'
|
||||
await expectNavigation(page.goto(appendPathname('/console/connectors', logtoConsoleUrl).href));
|
||||
expect(page.url()).toBe(new URL('/console/connectors/passwordless', logtoConsoleUrl).href);
|
||||
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/connectors/passwordless', logtoConsoleUrl).href)
|
||||
);
|
||||
expect(page.url()).toBe(new URL('/console/connectors/passwordless', logtoConsoleUrl).href);
|
||||
});
|
||||
|
||||
it.each(passwordlessConnectorTestCases)(
|
||||
'can setup and modify a(n) $factoryId connector',
|
||||
async (connector: PasswordlessConnectorCase) => {
|
||||
const { factoryId, isEmailConnector, name, initialFormData, updateFormData, errorFormData } =
|
||||
connector;
|
||||
|
||||
const connectorItem = await expect(page).toMatchElement(
|
||||
'div[class$=item] div[class$=previewTitle]:has(>div)',
|
||||
{
|
||||
text: isEmailConnector ? 'Email connector' : 'SMS connector',
|
||||
}
|
||||
);
|
||||
|
||||
const setupConnectorButton = await expect(connectorItem).toMatchElement('button span', {
|
||||
text: 'Set Up',
|
||||
});
|
||||
|
||||
await setupConnectorButton.click();
|
||||
|
||||
await expectToSelectConnector(page, {
|
||||
factoryId,
|
||||
connectorType: isEmailConnector ? ConnectorType.Email : ConnectorType.Sms,
|
||||
});
|
||||
|
||||
await waitForConnectorCreationGuide(page, name);
|
||||
|
||||
await expect(page).toClick(
|
||||
'.ReactModalPortal form div[class$=footer] button[type=submit] span',
|
||||
{
|
||||
text: 'Save and Done',
|
||||
}
|
||||
);
|
||||
|
||||
// Display error input
|
||||
await page.waitForSelector('form div[class$=field] div[class$=error]');
|
||||
|
||||
await expect(page).toFillForm('.ReactModalPortal form', initialFormData);
|
||||
|
||||
// Try click test button
|
||||
await expect(page).toClick('.ReactModalPortal div[class$=send] button span', {
|
||||
text: 'Send',
|
||||
});
|
||||
|
||||
// Display test input error
|
||||
await page.waitForSelector('.ReactModalPortal div[class$=error]:has(input[name=sendTo])');
|
||||
|
||||
await expect(page).toClick(
|
||||
'.ReactModalPortal form div[class$=footer] button[type=submit] span',
|
||||
{
|
||||
text: 'Save and Done',
|
||||
}
|
||||
);
|
||||
|
||||
await waitForToaster(page, { text: 'Saved' });
|
||||
|
||||
await expect(page).toMatchElement('div[class$=header] div[class$=name] span', {
|
||||
text: name,
|
||||
});
|
||||
|
||||
// Try send test
|
||||
await expect(page).toFill(
|
||||
'input[name=sendTo]',
|
||||
isEmailConnector ? 'fake@email.com' : '+1 555-123-4567'
|
||||
);
|
||||
|
||||
await expect(page).toClick('div[class$=fields] div[class$=send] button span', {
|
||||
text: 'Send',
|
||||
});
|
||||
|
||||
await waitForToaster(page, {
|
||||
text: /error/i,
|
||||
isError: true,
|
||||
});
|
||||
|
||||
// Fill incorrect form
|
||||
await expect(page).toFillForm('form', errorFormData);
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await page.waitForSelector('form div[class$=field] div[class$=error]');
|
||||
|
||||
// Update form
|
||||
await expect(page).toFillForm('form', updateFormData);
|
||||
|
||||
await expectUnsavedChangesAlert(page);
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await waitForToaster(page, { text: 'Saved' });
|
||||
|
||||
// Change to next connector
|
||||
const nextConnector = findNextCompatibleConnector(connector);
|
||||
|
||||
if (nextConnector) {
|
||||
await expectToClickDetailsPageOption(
|
||||
page,
|
||||
isEmailConnector ? 'Change email connector' : 'Change SMS connector'
|
||||
);
|
||||
|
||||
await expectToSelectConnector(page, {
|
||||
factoryId: nextConnector.factoryId,
|
||||
connectorType: isEmailConnector ? ConnectorType.Email : ConnectorType.Sms,
|
||||
});
|
||||
|
||||
await waitForConnectorCreationGuide(page, nextConnector.name);
|
||||
|
||||
await expect(page).toFillForm('.ReactModalPortal form', nextConnector.initialFormData);
|
||||
|
||||
await expect(page).toClick(
|
||||
'.ReactModalPortal form div[class$=footer] button[type=submit] span',
|
||||
{
|
||||
text: 'Save and Done',
|
||||
}
|
||||
);
|
||||
|
||||
await waitForToaster(page, { text: 'Saved' });
|
||||
|
||||
await expect(page).toMatchElement('div[class$=header] div[class$=name] span', {
|
||||
text: nextConnector.name,
|
||||
});
|
||||
}
|
||||
|
||||
// Delete email connector
|
||||
await expectToClickDetailsPageOption(page, 'Delete');
|
||||
|
||||
await expectToConfirmConnectorDeletion(page);
|
||||
|
||||
expect(page.url()).toBe(new URL(`console/connectors/passwordless`, logtoConsoleUrl).href);
|
||||
}
|
||||
);
|
||||
});
|
|
@ -1,12 +1,20 @@
|
|||
import { ConnectorType } from '@logto/connector-kit';
|
||||
|
||||
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
|
||||
import {
|
||||
expectToClickDetailsPageOption,
|
||||
expectUnsavedChangesAlert,
|
||||
goToAdminConsole,
|
||||
trySaveChanges,
|
||||
waitForSuccessToast,
|
||||
waitForToaster,
|
||||
} from '#src/ui-helpers/index.js';
|
||||
import { expectNavigation, appendPathname } from '#src/utils.js';
|
||||
|
||||
import {
|
||||
expectToConfirmConnectorDeletion,
|
||||
expectToSelectConnector,
|
||||
waitForConnectorCreationGuide,
|
||||
} from './helpers.js';
|
||||
import {
|
||||
socialConnectorTestCases,
|
||||
type SocialConnectorCase,
|
||||
|
@ -71,44 +79,15 @@ describe('social connectors', () => {
|
|||
text: 'Add Social Connector',
|
||||
});
|
||||
|
||||
await expect(page).toMatchElement(
|
||||
'.ReactModalPortal div[class$=header] div[class$=titleEllipsis]',
|
||||
{
|
||||
text: 'Add Social Connector',
|
||||
}
|
||||
);
|
||||
|
||||
if (groupFactoryId) {
|
||||
// Platform selector
|
||||
await page.click(
|
||||
`.ReactModalPortal div[role=radio]:has(input[name=group][value=${groupFactoryId}])`
|
||||
);
|
||||
|
||||
await page.waitForSelector(
|
||||
'.ReactModalPortal div[class$=platforms] div[class$=radioGroup]'
|
||||
);
|
||||
|
||||
await page.click(
|
||||
`.ReactModalPortal div[class$=platforms] div[role=radio]:has(input[name=connector][value=${factoryId}])`
|
||||
);
|
||||
} else {
|
||||
await page.click(
|
||||
`.ReactModalPortal div[role=radio]:has(input[name=group][value=${factoryId}])`
|
||||
);
|
||||
}
|
||||
|
||||
await expect(page).toClick('.ReactModalPortal div[class$=footer] button:not(disabled) span', {
|
||||
text: 'Next',
|
||||
await expectToSelectConnector(page, {
|
||||
groupFactoryId,
|
||||
factoryId,
|
||||
connectorType: ConnectorType.Social,
|
||||
});
|
||||
|
||||
await expect(page).toMatchElement('.ReactModalPortal div[class$=titleEllipsis] span', {
|
||||
text: name,
|
||||
});
|
||||
|
||||
await expect(page).toMatchElement('.ReactModalPortal div[class$=subtitle] span', {
|
||||
text: 'A step by step guide to configure your connector',
|
||||
});
|
||||
await waitForConnectorCreationGuide(page, name);
|
||||
|
||||
// Save with empty form
|
||||
await expect(page).toClick(
|
||||
'.ReactModalPortal form div[class$=footer] button[type=submit] span',
|
||||
{
|
||||
|
@ -131,7 +110,7 @@ describe('social connectors', () => {
|
|||
}
|
||||
);
|
||||
|
||||
await waitForSuccessToast(page, 'Saved');
|
||||
await waitForToaster(page, { text: 'Saved' });
|
||||
|
||||
await expect(page).toMatchElement('div[class$=header] div[class$=name] span', {
|
||||
text: name,
|
||||
|
@ -151,47 +130,12 @@ describe('social connectors', () => {
|
|||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await waitForSuccessToast(page, 'Saved');
|
||||
await waitForToaster(page, { text: 'Saved' });
|
||||
|
||||
// Delete connector
|
||||
await expect(page).toClick(
|
||||
'div[class$=header] div[class$=operations] button[class$=withIcon]:has(span[class$=icon] > svg[class$=moreIcon])'
|
||||
);
|
||||
await expectToClickDetailsPageOption(page, 'Delete');
|
||||
|
||||
await expect(page).toMatchElement(
|
||||
'.ReactModalPortal div[class$=dropdownContainer] div[class$=dropdownTitle]',
|
||||
{
|
||||
text: 'MORE OPTIONS',
|
||||
}
|
||||
);
|
||||
|
||||
// Wait for the dropdown menu to be rendered in the correct position
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await expect(page).toClick(
|
||||
'.ReactModalPortal div[class$=dropdownContainer] div[role=menuitem]',
|
||||
{ text: 'Delete' }
|
||||
);
|
||||
|
||||
await page.waitForSelector(
|
||||
'.ReactModalPortal div[class$=dropdownContainer] div[class$=dropdownTitle]',
|
||||
{
|
||||
hidden: true,
|
||||
}
|
||||
);
|
||||
|
||||
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 waitForSuccessToast(page, 'The connector has been successfully deleted');
|
||||
await expectToConfirmConnectorDeletion(page);
|
||||
|
||||
expect(page.url()).toBe(new URL(`console/connectors/social`, logtoConsoleUrl).href);
|
||||
}
|
||||
|
|
|
@ -20,13 +20,19 @@ export const goToAdminConsole = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
export const waitForSuccessToast = async (page: Page, text: string) => {
|
||||
const successToastHandle = await page.waitForSelector('div[class*=toast][class*=success]');
|
||||
await expect(successToastHandle).toMatchElement('div[class$=message]', {
|
||||
type WaitToasterOptions = {
|
||||
text?: string | RegExp;
|
||||
isError?: boolean;
|
||||
};
|
||||
|
||||
export const waitForToaster = async (page: Page, { text, isError }: WaitToasterOptions) => {
|
||||
const toastStyleClass = isError ? 'error' : 'success';
|
||||
const toastHandle = await page.waitForSelector(`div[class*=toast][class*=${toastStyleClass}]`);
|
||||
await expect(toastHandle).toMatchElement('div[class$=message]', {
|
||||
text,
|
||||
});
|
||||
// Wait the success toast to disappear so that the next time we call this function we will match the brand new toast
|
||||
await page.waitForSelector('div[class*=toast][class*=success]', {
|
||||
// Wait the toast to disappear so that the next time we call this function we will match the brand new toast
|
||||
await page.waitForSelector(`div[class*=toast][class*=${toastStyleClass}]`, {
|
||||
hidden: true,
|
||||
});
|
||||
};
|
||||
|
@ -49,3 +55,53 @@ export const trySaveChanges = async (page: Page) => {
|
|||
await page.waitForTimeout(500);
|
||||
await expect(page).toClick('div[class$=actionBar] button span', { text: 'Save Changes' });
|
||||
};
|
||||
|
||||
export const expectToClickDetailsPageOption = async (page: Page, optionText: string) => {
|
||||
await expect(page).toClick(
|
||||
'div[class$=header] button[class$=withIcon]:last-of-type span[class$=icon]:has(svg)'
|
||||
);
|
||||
|
||||
await expect(page).toMatchElement(
|
||||
'.ReactModalPortal div[class$=dropdownContainer] div[class$=dropdownTitle]',
|
||||
{
|
||||
text: 'MORE OPTIONS',
|
||||
}
|
||||
);
|
||||
|
||||
// Wait for the dropdown menu to be rendered in the correct position
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await expect(page).toClick('.ReactModalPortal div[class$=dropdownContainer] div[role=menuitem]', {
|
||||
text: optionText,
|
||||
});
|
||||
|
||||
await page.waitForSelector(
|
||||
'.ReactModalPortal div[class$=dropdownContainer] div[class$=dropdownTitle]',
|
||||
{
|
||||
hidden: true,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
type ExpectConfirmModalAndActOptions = {
|
||||
title?: string | RegExp;
|
||||
actionText?: string | RegExp;
|
||||
};
|
||||
|
||||
export const expectConfirmModalAndAct = async (
|
||||
page: Page,
|
||||
{ title, actionText }: ExpectConfirmModalAndActOptions
|
||||
) => {
|
||||
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,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue