mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
test: add ui tests for sign-up and sign-in settings (#4373)
This commit is contained in:
parent
e13107438c
commit
462f677cdc
8 changed files with 1443 additions and 138 deletions
|
@ -1,138 +0,0 @@
|
|||
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
|
||||
import { goToAdminConsole, trySaveChanges, waitForToaster } from '#src/ui-helpers/index.js';
|
||||
import { appendPathname, expectNavigation } from '#src/utils.js';
|
||||
|
||||
await page.setViewport({ width: 1920, height: 1080 });
|
||||
|
||||
const defaultPrimaryColor = '#6139F6';
|
||||
const testPrimaryColor = '#5B4D8E';
|
||||
|
||||
describe('sign-in experience', () => {
|
||||
const logtoConsoleUrl = new URL(logtoConsoleUrlString);
|
||||
|
||||
beforeAll(async () => {
|
||||
await goToAdminConsole();
|
||||
});
|
||||
|
||||
it('navigate to sign-in experience page', async () => {
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/sign-in-experience', logtoConsoleUrl).href)
|
||||
);
|
||||
|
||||
await expect(page).toMatchElement(
|
||||
'div[class$=main] div[class$=container] div[class$=cardTitle] div[class$=titleEllipsis]',
|
||||
{
|
||||
text: 'Sign-in experience',
|
||||
}
|
||||
);
|
||||
|
||||
// Start & finish guide
|
||||
await expect(page).toClick('div[class$=container] div[class$=content] button span', {
|
||||
text: 'Get Started',
|
||||
});
|
||||
|
||||
await expect(page).toClick(
|
||||
'div[class$=ReactModalPortal] div[class$=footerContent] > button span',
|
||||
{
|
||||
text: 'Done',
|
||||
}
|
||||
);
|
||||
|
||||
// Land on branding tab by default
|
||||
expect(page.url()).toBe(new URL(`console/sign-in-experience/branding`, logtoConsoleUrl).href);
|
||||
|
||||
// Wait for the branding tab to load
|
||||
await expect(page).toMatchElement('div[class$=tabContent] div[class$=card] div[class$=title]', {
|
||||
text: 'BRANDING AREA',
|
||||
});
|
||||
|
||||
await expect(page).toMatchElement('div[class$=tabContent] div[class$=card] div[class$=title]', {
|
||||
text: 'Custom CSS',
|
||||
});
|
||||
});
|
||||
|
||||
describe('update branding config', () => {
|
||||
it('update branding config', async () => {
|
||||
// Enabled dark mode
|
||||
await expect(page).toClick(
|
||||
'form div[class$=field] label[class$=switch]:has(input[name="color.isDarkModeEnabled"])'
|
||||
);
|
||||
|
||||
// Update brand color
|
||||
const brandColorField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] div[class$=title])',
|
||||
{
|
||||
text: 'Brand color',
|
||||
}
|
||||
);
|
||||
|
||||
await expect(brandColorField).toClick('div[role=button]');
|
||||
|
||||
await expect(page).toFill('input[id^=rc-editable-input]', testPrimaryColor);
|
||||
|
||||
// Close the color input
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
// Recalculate dark brand color
|
||||
await expect(page).toClick('div[class$=darkModeTip] button span', { text: 'Recalculate' });
|
||||
|
||||
// Wait for the recalculate to finish
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Fill in the custom CSS
|
||||
await expect(page).toFill(
|
||||
'div[class$=editor] textarea',
|
||||
'body { background-color: #5B4D8E; }'
|
||||
);
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await waitForToaster(page, {
|
||||
text: 'Saved',
|
||||
});
|
||||
});
|
||||
|
||||
it('reset branding config', async () => {
|
||||
// Reset branding config
|
||||
const brandColorField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] div[class$=title])',
|
||||
{
|
||||
text: 'Brand color',
|
||||
}
|
||||
);
|
||||
|
||||
await expect(brandColorField).toClick('div[role=button]');
|
||||
|
||||
await expect(page).toFill('input[id^=rc-editable-input]', defaultPrimaryColor);
|
||||
|
||||
// Close the color input
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
// Recalculate dark brand color
|
||||
await expect(page).toClick('div[class$=darkModeTip] button span', { text: 'Recalculate' });
|
||||
|
||||
// Wait for the recalculate to finish
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Fill in the custom CSS
|
||||
await expect(page).toFill('div[class$=editor] textarea', '');
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await waitForToaster(page, {
|
||||
text: 'Saved',
|
||||
});
|
||||
|
||||
// Disable dark mode
|
||||
await expect(page).toClick(
|
||||
'form div[class$=field] label[class$=switch]:has(input[name="color.isDarkModeEnabled"])'
|
||||
);
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await waitForToaster(page, {
|
||||
text: 'Saved',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,100 @@
|
|||
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
|
||||
import { goToAdminConsole } from '#src/ui-helpers/index.js';
|
||||
import { expectNavigation, appendPathname } from '#src/utils.js';
|
||||
|
||||
import { waitForFormCard, expectToSelectColor, expectToSaveSignInExperience } from './helpers.js';
|
||||
|
||||
const defaultPrimaryColor = '#6139F6';
|
||||
const testPrimaryColor = '#5B4D8E';
|
||||
|
||||
await page.setViewport({ width: 1920, height: 1080 });
|
||||
|
||||
describe('sign-in experience: branding', () => {
|
||||
const logtoConsoleUrl = new URL(logtoConsoleUrlString);
|
||||
|
||||
beforeAll(async () => {
|
||||
await goToAdminConsole();
|
||||
});
|
||||
|
||||
it('navigate to sign-in experience page', async () => {
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/sign-in-experience', logtoConsoleUrl).href)
|
||||
);
|
||||
|
||||
await expect(page).toMatchElement(
|
||||
'div[class$=main] div[class$=container] div[class$=cardTitle] div[class$=titleEllipsis]',
|
||||
{
|
||||
text: 'Sign-in experience',
|
||||
}
|
||||
);
|
||||
|
||||
// Start & finish guide
|
||||
await expect(page).toClick('div[class$=container] div[class$=content] button span', {
|
||||
text: 'Get Started',
|
||||
});
|
||||
|
||||
await expect(page).toClick(
|
||||
'div[class$=ReactModalPortal] div[class$=footerContent] > button span',
|
||||
{
|
||||
text: 'Done',
|
||||
}
|
||||
);
|
||||
|
||||
// Land on branding tab by default
|
||||
expect(page.url()).toBe(new URL(`console/sign-in-experience/branding`, logtoConsoleUrl).href);
|
||||
|
||||
// Wait for the branding tab to load
|
||||
await waitForFormCard(page, 'BRANDING AREA');
|
||||
await waitForFormCard(page, 'Custom CSS');
|
||||
});
|
||||
|
||||
it('update branding config', async () => {
|
||||
// Enabled dark mode
|
||||
await expect(page).toClick(
|
||||
'form div[class$=field] label[class$=switch]:has(input[name="color.isDarkModeEnabled"])'
|
||||
);
|
||||
|
||||
// Update brand color
|
||||
await expectToSelectColor(page, {
|
||||
field: 'Brand color',
|
||||
color: testPrimaryColor,
|
||||
});
|
||||
|
||||
// Recalculate dark brand color
|
||||
await expect(page).toClick('div[class$=darkModeTip] button span', { text: 'Recalculate' });
|
||||
|
||||
// Wait for the recalculate to finish
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Fill in the custom CSS
|
||||
await expect(page).toFill('div[class$=editor] textarea', 'body { background-color: #5B4D8E; }');
|
||||
|
||||
await expectToSaveSignInExperience(page);
|
||||
});
|
||||
|
||||
it('reset branding config', async () => {
|
||||
// Reset branding config
|
||||
await expectToSelectColor(page, {
|
||||
field: 'Brand color',
|
||||
color: defaultPrimaryColor,
|
||||
});
|
||||
|
||||
// Recalculate dark brand color
|
||||
await expect(page).toClick('div[class$=darkModeTip] button span', { text: 'Recalculate' });
|
||||
|
||||
// Wait for the recalculate to finish
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Fill in the custom CSS
|
||||
await expect(page).toFill('div[class$=editor] textarea', '');
|
||||
|
||||
await expectToSaveSignInExperience(page);
|
||||
|
||||
// Disable dark mode
|
||||
await expect(page).toClick(
|
||||
'form div[class$=field] label[class$=switch]:has(input[name="color.isDarkModeEnabled"])'
|
||||
);
|
||||
|
||||
await expectToSaveSignInExperience(page);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,58 @@
|
|||
import { type Page } from 'puppeteer';
|
||||
|
||||
import { trySaveChanges, expectConfirmModalAndAct, waitForToaster } from '#src/ui-helpers/index.js';
|
||||
|
||||
export const waitForFormCard = async (page: Page, title: string) => {
|
||||
await expect(page).toMatchElement('div[class$=tabContent] div[class$=card] div[class$=title]', {
|
||||
text: title,
|
||||
});
|
||||
};
|
||||
|
||||
type ExpectToSelectColorOptions = {
|
||||
field: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
export const expectToSelectColor = async (
|
||||
page: Page,
|
||||
{ field, color }: ExpectToSelectColorOptions
|
||||
) => {
|
||||
const colorField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] div[class$=title])',
|
||||
{
|
||||
text: field,
|
||||
}
|
||||
);
|
||||
|
||||
await expect(colorField).toClick('div[role=button]');
|
||||
|
||||
await expect(page).toFill('input[id^=rc-editable-input]', color);
|
||||
|
||||
// Close the color input
|
||||
await page.keyboard.press('Escape');
|
||||
};
|
||||
|
||||
type ExpectToSaveSignInExperienceOptions = {
|
||||
needToConfirmChanges?: boolean;
|
||||
};
|
||||
|
||||
export const expectToSaveSignInExperience = async (
|
||||
page: Page,
|
||||
options?: ExpectToSaveSignInExperienceOptions
|
||||
) => {
|
||||
const { needToConfirmChanges = false } = options ?? {};
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
if (needToConfirmChanges) {
|
||||
// Confirm changes
|
||||
await expectConfirmModalAndAct(page, {
|
||||
title: 'Reminder',
|
||||
actionText: 'Confirm',
|
||||
});
|
||||
}
|
||||
|
||||
await waitForToaster(page, {
|
||||
text: 'Saved',
|
||||
});
|
||||
};
|
|
@ -0,0 +1,161 @@
|
|||
import { ConnectorType } from '@logto/schemas';
|
||||
import { type Page } from 'puppeteer';
|
||||
|
||||
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
|
||||
import { expectToClickDetailsPageOption, waitForToaster } from '#src/ui-helpers/index.js';
|
||||
import { expectNavigation, appendPathname } from '#src/utils.js';
|
||||
|
||||
import {
|
||||
expectToConfirmConnectorDeletion,
|
||||
expectToSelectConnector,
|
||||
waitForConnectorCreationGuide,
|
||||
} from '../../connectors/helpers.js';
|
||||
|
||||
const logtoConsoleUrl = new URL(logtoConsoleUrlString);
|
||||
|
||||
type TestConnector = {
|
||||
factoryId: string;
|
||||
name: string;
|
||||
connectorType: ConnectorType;
|
||||
data: Record<string, string>;
|
||||
};
|
||||
|
||||
export const testSendgridConnector: TestConnector = {
|
||||
factoryId: 'sendgrid-email-service',
|
||||
name: 'SendGrid Email',
|
||||
connectorType: ConnectorType.Email,
|
||||
data: {
|
||||
'formConfig.apiKey': 'api-key',
|
||||
'formConfig.fromEmail': 'foo@example.com',
|
||||
'formConfig.fromName': 'Logto',
|
||||
},
|
||||
};
|
||||
|
||||
export const testTwilioConnector: TestConnector = {
|
||||
factoryId: 'twilio-short-message-service',
|
||||
name: 'Twilio SMS Service',
|
||||
connectorType: ConnectorType.Sms,
|
||||
data: {
|
||||
'formConfig.accountSID': 'account-sid',
|
||||
'formConfig.authToken': 'auth-token',
|
||||
'formConfig.fromMessagingServiceSID': 'from-messaging-service-sid',
|
||||
},
|
||||
};
|
||||
|
||||
export const testAppleConnector: TestConnector = {
|
||||
factoryId: 'apple-universal',
|
||||
name: 'Apple',
|
||||
connectorType: ConnectorType.Social,
|
||||
data: {
|
||||
'formConfig.clientId': 'client-id',
|
||||
},
|
||||
};
|
||||
|
||||
export const expectToSetupPasswordlessConnector = async (
|
||||
page: Page,
|
||||
{ factoryId, name, connectorType, data }: TestConnector
|
||||
) => {
|
||||
if (connectorType === ConnectorType.Social) {
|
||||
return;
|
||||
}
|
||||
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/connectors/passwordless', logtoConsoleUrl).href)
|
||||
);
|
||||
|
||||
const connectorItem = await expect(page).toMatchElement(
|
||||
'div[class$=item] div[class$=previewTitle]:has(>div)',
|
||||
{
|
||||
text: connectorType === ConnectorType.Email ? 'Email connector' : 'SMS connector',
|
||||
}
|
||||
);
|
||||
|
||||
const setupConnectorButton = await expect(connectorItem).toMatchElement('button span', {
|
||||
text: 'Set Up',
|
||||
});
|
||||
|
||||
await setupConnectorButton.click();
|
||||
|
||||
await setupConnectorButton.click();
|
||||
|
||||
await expectToSelectConnector(page, {
|
||||
factoryId,
|
||||
connectorType,
|
||||
});
|
||||
|
||||
await waitForConnectorCreationGuide(page, name);
|
||||
await expect(page).toFillForm('.ReactModalPortal form', data);
|
||||
|
||||
await expect(page).toClick('.ReactModalPortal form div[class$=footer] button[type=submit] span', {
|
||||
text: 'Save and Done',
|
||||
});
|
||||
|
||||
await waitForToaster(page, { text: 'Saved' });
|
||||
};
|
||||
|
||||
export const expectToSetupSocialConnector = async (
|
||||
page: Page,
|
||||
{ factoryId, name, connectorType, data }: TestConnector
|
||||
) => {
|
||||
if (connectorType !== ConnectorType.Social) {
|
||||
return;
|
||||
}
|
||||
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/connectors/social', logtoConsoleUrl).href)
|
||||
);
|
||||
|
||||
await expect(page).toClick('div[class$=headline] button[class$=withIcon] span', {
|
||||
text: 'Add Social Connector',
|
||||
});
|
||||
|
||||
await expectToSelectConnector(page, {
|
||||
factoryId,
|
||||
connectorType,
|
||||
});
|
||||
|
||||
await waitForConnectorCreationGuide(page, name);
|
||||
await expect(page).toFillForm('.ReactModalPortal form', data);
|
||||
|
||||
await expect(page).toClick('.ReactModalPortal form div[class$=footer] button[type=submit] span', {
|
||||
text: 'Save and Done',
|
||||
});
|
||||
|
||||
await waitForToaster(page, { text: 'Saved' });
|
||||
};
|
||||
|
||||
export const expectToDeletePasswordlessConnector = async (page: Page, { name }: TestConnector) => {
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/connectors/passwordless', logtoConsoleUrl).href)
|
||||
);
|
||||
|
||||
await expect(page).toClick('table tbody tr td div[class$=item] a[class$=title] span', {
|
||||
text: name,
|
||||
});
|
||||
|
||||
await expect(page).toMatchElement('div[class$=header] div[class$=name] span', {
|
||||
text: name,
|
||||
});
|
||||
|
||||
await expectToClickDetailsPageOption(page, 'Delete');
|
||||
|
||||
await expectToConfirmConnectorDeletion(page);
|
||||
};
|
||||
|
||||
export const expectToDeleteSocialConnector = async (page: Page, { name }: TestConnector) => {
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/connectors/social', logtoConsoleUrl).href)
|
||||
);
|
||||
|
||||
await expect(page).toClick('table tbody tr td div[class$=item] a[class$=title] span', {
|
||||
text: name,
|
||||
});
|
||||
|
||||
await expect(page).toMatchElement('div[class$=header] div[class$=name] span', {
|
||||
text: name,
|
||||
});
|
||||
|
||||
await expectToClickDetailsPageOption(page, 'Delete');
|
||||
|
||||
await expectToConfirmConnectorDeletion(page);
|
||||
};
|
|
@ -0,0 +1,577 @@
|
|||
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
|
||||
import { expectToClickNavTab, goToAdminConsole } from '#src/ui-helpers/index.js';
|
||||
import { expectNavigation, appendPathname } from '#src/utils.js';
|
||||
|
||||
import { expectToSaveSignInExperience, waitForFormCard } from '../helpers.js';
|
||||
|
||||
import {
|
||||
expectToDeletePasswordlessConnector,
|
||||
expectToSetupPasswordlessConnector,
|
||||
testSendgridConnector,
|
||||
testTwilioConnector,
|
||||
expectToSetupSocialConnector,
|
||||
testAppleConnector,
|
||||
expectToDeleteSocialConnector,
|
||||
} from './connector-setup-helpers.js';
|
||||
import {
|
||||
expectToAddSignInMethod,
|
||||
expectToAddSocialSignInConnector,
|
||||
expectToClickSignInMethodAuthnOption,
|
||||
expectToClickSignUpAuthnOption,
|
||||
expectToRemoveSignInMethod,
|
||||
expectToRemoveSocialSignInConnector,
|
||||
expectToResetSignUpAndSignInConfig,
|
||||
expectToSelectSignUpIdentifier,
|
||||
expectToSwapSignInMethodAuthnOption,
|
||||
} from './helpers.js';
|
||||
|
||||
await page.setViewport({ width: 1920, height: 1080 });
|
||||
|
||||
describe('sign-in experience(happy path): sign-up and sign-in', () => {
|
||||
const logtoConsoleUrl = new URL(logtoConsoleUrlString);
|
||||
|
||||
beforeAll(async () => {
|
||||
await goToAdminConsole();
|
||||
// Email connector
|
||||
await expectToSetupPasswordlessConnector(page, testSendgridConnector);
|
||||
// SMS connector
|
||||
await expectToSetupPasswordlessConnector(page, testTwilioConnector);
|
||||
// Social connector
|
||||
await expectToSetupSocialConnector(page, testAppleConnector);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await expectToDeletePasswordlessConnector(page, testSendgridConnector);
|
||||
await expectToDeletePasswordlessConnector(page, testTwilioConnector);
|
||||
await expectToDeleteSocialConnector(page, testAppleConnector);
|
||||
});
|
||||
|
||||
it('navigate to sign-in experience page', async () => {
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/sign-in-experience', logtoConsoleUrl).href)
|
||||
);
|
||||
|
||||
// Land on branding tab by default
|
||||
expect(page.url()).toBe(new URL(`console/sign-in-experience/branding`, logtoConsoleUrl).href);
|
||||
});
|
||||
|
||||
it('navigate to sign-up and sign-in tab', async () => {
|
||||
await expectToClickNavTab(page, 'Sign-up and Sign-in');
|
||||
|
||||
await waitForFormCard(page, 'SIGN UP');
|
||||
await waitForFormCard(page, 'SIGN IN');
|
||||
await waitForFormCard(page, 'SOCIAL SIGN-IN');
|
||||
});
|
||||
|
||||
describe('email as sign-up identifier (verify only)', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('select email as sign-in method and disable password settings for sign-up', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Email address');
|
||||
// Disable password settings for sign-up
|
||||
await expectToClickSignUpAuthnOption(page, 'Create your password');
|
||||
// Username will be added in later tests
|
||||
await expectToRemoveSignInMethod(page, 'Username');
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password + verification code
|
||||
*/
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('update email sign-in method', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSwapSignInMethodAuthnOption(page, 'Email address');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('add username sign-in method', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
* - Username: password
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('add & update phone number sign-in method', async () => {
|
||||
await expectToAddSignInMethod(page, 'Phone number');
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
* - Username: password
|
||||
* - Phone number: password + verification code
|
||||
*/
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
* - Username: password
|
||||
* - Phone number: verification code
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
* - Phone number: verification code
|
||||
*/
|
||||
await expectToRemoveSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
* - Phone number: password + verification code
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('email as sign-up identifier (password & verify)', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('select email as sign-in method and enable password settings for sign-up', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Email address');
|
||||
// Username will be added in later tests
|
||||
await expectToRemoveSignInMethod(page, 'Username');
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password + verification code
|
||||
*/
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('update email sign-in method', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
*/
|
||||
// Sign-in method: Email address + verification code + password
|
||||
await expectToSwapSignInMethodAuthnOption(page, 'Email address');
|
||||
await expectToSaveSignInExperience(page);
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('add phone number & username as sign-in method', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
* - Phone number: password + verification code
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Phone number');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
* - Phone number: password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
* - Phone number: password
|
||||
* - Username: password
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
* - Phone number: password + verification code
|
||||
* - Username: password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('phone as sign-up identifier (verify only)', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('select email as sign-in method and disable password settings for sign-up', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Phone number');
|
||||
// Disable password settings for sign-up
|
||||
await expectToClickSignUpAuthnOption(page, 'Create your password');
|
||||
// Username will be added in later tests
|
||||
await expectToRemoveSignInMethod(page, 'Username');
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: password + verification code
|
||||
*/
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('update sign-in methods', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: verification code + password
|
||||
*/
|
||||
await expectToSwapSignInMethodAuthnOption(page, 'Phone number');
|
||||
await expectToSaveSignInExperience(page);
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: verification code
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: verification code
|
||||
* - Email address: password + verification code
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Email address');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: verification code
|
||||
* - Email address: verification code
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: verification code
|
||||
* - Email address: verification code
|
||||
* - Username: password
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('phone as sign-up identifier (password & verify)', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('select email as sign-in method and enable password settings for sign-up', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Phone number');
|
||||
// Username will be added in later tests
|
||||
await expectToRemoveSignInMethod(page, 'Username');
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: password + verification code
|
||||
*/
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('update sign-in methods', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: verification code + password
|
||||
*/
|
||||
await expectToSwapSignInMethodAuthnOption(page, 'Phone number');
|
||||
await expectToSaveSignInExperience(page);
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Phone number: password
|
||||
* - Username: password
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('email or phone as sign-up identifier (verify only)', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('select email or phone as sign-up identifier and disable password settings for sign-up', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Email address or phone number');
|
||||
await expectToClickSignUpAuthnOption(page, 'Create your password');
|
||||
// Username will be added in later tests
|
||||
await expectToRemoveSignInMethod(page, 'Username');
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password + verification code
|
||||
* - Phone number: password + verification code
|
||||
*/
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('update sign-in method configs', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
* - Phone number: verification code + password
|
||||
*/
|
||||
await expectToSwapSignInMethodAuthnOption(page, 'Email address');
|
||||
await expectToSwapSignInMethodAuthnOption(page, 'Phone number');
|
||||
await expectToSaveSignInExperience(page);
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code
|
||||
* - Phone number: verification code + password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code
|
||||
* - Phone number: verification code
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code
|
||||
* - Phone number: verification code
|
||||
* - Username: password
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('email or phone as sign-up identifier (password & verify)', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('select email or phone as sign-up identifier and enable password settings for sign-up', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Email address or phone number');
|
||||
// Username will be added in later tests
|
||||
await expectToRemoveSignInMethod(page, 'Username');
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password + verification code
|
||||
* - Phone number: password + verification code
|
||||
*/
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('update sign-in method configs', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code + password
|
||||
* - Phone number: verification code + password
|
||||
*/
|
||||
await expectToSwapSignInMethodAuthnOption(page, 'Email address');
|
||||
await expectToSwapSignInMethodAuthnOption(page, 'Phone number');
|
||||
await expectToSaveSignInExperience(page);
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
* - Phone number: verification code + password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
* - Phone number: password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
* - Phone number: password
|
||||
* - Username: password
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('not applicable as sign-up identifier', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('select not applicable as sign-up identifier', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Not applicable');
|
||||
await expectToRemoveSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('update sign-in methods', async () => {
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password + verification code
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Email address', false);
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Password',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code
|
||||
* - Phone number: password verification code
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Phone number');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code
|
||||
* - Phone number: password
|
||||
*/
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Verification code',
|
||||
});
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
/**
|
||||
* Sign-in method
|
||||
* - Email address: verification code
|
||||
* - Phone number: password
|
||||
* - Username: password
|
||||
*/
|
||||
await expectToAddSignInMethod(page, 'Username');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('add social sign-in connector', async () => {
|
||||
await expectToAddSocialSignInConnector(page, 'Apple');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
|
||||
// Reset
|
||||
await expectToRemoveSocialSignInConnector(page, 'Apple');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('disable user registration', () => {
|
||||
it('navigate to others tab', async () => {
|
||||
await expectToClickNavTab(page, 'Others');
|
||||
|
||||
await waitForFormCard(page, 'TERMS');
|
||||
await waitForFormCard(page, 'LANGUAGES');
|
||||
await waitForFormCard(page, 'ADVANCED OPTIONS');
|
||||
});
|
||||
|
||||
it('disable user registration', async () => {
|
||||
const switchSelector = 'label[class$=switch]:has(input[name=createAccountEnabled])';
|
||||
await expect(page).toClick(switchSelector);
|
||||
await expectToSaveSignInExperience(page);
|
||||
|
||||
// Reset
|
||||
await expect(page).toClick(switchSelector);
|
||||
await expectToSaveSignInExperience(page);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,240 @@
|
|||
import { type Page } from 'puppeteer';
|
||||
|
||||
import { expectToSaveSignInExperience } from '../helpers.js';
|
||||
|
||||
export const expectToSelectSignUpIdentifier = async (page: Page, identifier: string) => {
|
||||
const signUpIdentifierField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] > div[class$=title])',
|
||||
{
|
||||
text: 'Sign-up identifier',
|
||||
}
|
||||
);
|
||||
|
||||
await expect(signUpIdentifierField).toClick('div[role=button][class*=select]');
|
||||
|
||||
// Wait for the dropdown to be rendered in the correct position
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await expect(page).toClick(
|
||||
'.ReactModalPortal div[class$=dropdownContainer] div[role=menuitem] div',
|
||||
{
|
||||
text: identifier,
|
||||
}
|
||||
);
|
||||
|
||||
await page.waitForSelector('.ReactModalPortal div[class$=dropdownContainer]', {
|
||||
hidden: true,
|
||||
});
|
||||
|
||||
await expect(signUpIdentifierField).toMatchElement('div[class*=select] div[class$=title] div', {
|
||||
text: identifier,
|
||||
});
|
||||
|
||||
// Wait for the config to update
|
||||
await page.waitForTimeout(500);
|
||||
};
|
||||
|
||||
export const expectToClickSignUpAuthnOption = async (page: Page, option: string) => {
|
||||
const signUpAuthnSettingsFiled = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] > div[class$=title])',
|
||||
{
|
||||
text: 'Authentication setting for sign-up',
|
||||
}
|
||||
);
|
||||
|
||||
await expect(signUpAuthnSettingsFiled).toClick('div[class$=selections] span[class$=label]', {
|
||||
text: option,
|
||||
});
|
||||
};
|
||||
|
||||
export const expectToAddSignInMethod = async (page: Page, method: string, isAddAnother = true) => {
|
||||
const signInMethodsField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] > div[class$=title])',
|
||||
{
|
||||
text: 'Identifier and authentication settings for sign-in',
|
||||
}
|
||||
);
|
||||
|
||||
// Click Add another
|
||||
await expect(signInMethodsField).toClick('button span', {
|
||||
text: isAddAnother ? 'Add Another' : 'Add Sign-in Method',
|
||||
});
|
||||
|
||||
// Wait for the dropdown to be rendered in the correct position
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await expect(page).toClick('.ReactModalPortal div[class$=dropdownContainer] div[role=menuitem]', {
|
||||
text: method,
|
||||
});
|
||||
|
||||
await page.waitForSelector('.ReactModalPortal div[class$=dropdownContainer]', {
|
||||
hidden: true,
|
||||
});
|
||||
};
|
||||
|
||||
type ExpectSignInMethodAuthnOptionOptions = {
|
||||
method: string;
|
||||
option: string;
|
||||
};
|
||||
|
||||
export const expectToClickSignInMethodAuthnOption = async (
|
||||
page: Page,
|
||||
{ method, option }: ExpectSignInMethodAuthnOptionOptions
|
||||
) => {
|
||||
const methodItem = await expect(page).toMatchElement(
|
||||
'div[class$=signInMethodItem]:has(div[class$=identifier])',
|
||||
{
|
||||
text: method,
|
||||
}
|
||||
);
|
||||
|
||||
await expect(methodItem).toClick('div[class*=authentication] span[class$=label]', {
|
||||
text: option,
|
||||
});
|
||||
|
||||
// Wait for the config to update
|
||||
await page.waitForTimeout(500);
|
||||
};
|
||||
|
||||
export const expectToSwapSignInMethodAuthnOption = async (page: Page, method: string) => {
|
||||
const methodItem = await expect(page).toMatchElement(
|
||||
'div[class$=signInMethodItem]:has(div[class$=identifier])',
|
||||
{
|
||||
text: method,
|
||||
}
|
||||
);
|
||||
|
||||
await expect(methodItem).toClick('div[class*=authentication] div[class$=swapButton] button');
|
||||
};
|
||||
|
||||
export const expectToRemoveSignInMethod = async (page: Page, method: string) => {
|
||||
const methodItem = await expect(page).toMatchElement(
|
||||
'div[class$=signInMethodItem]:has(div[class$=identifier])',
|
||||
{
|
||||
text: method,
|
||||
}
|
||||
);
|
||||
|
||||
await expect(methodItem).toClick('div[class$=anchor] button:last-of-type');
|
||||
|
||||
// Wait for the config to update
|
||||
await page.waitForTimeout(500);
|
||||
};
|
||||
|
||||
export const expectSignInMethodError = async (page: Page, method: string) => {
|
||||
await expect(page).toMatchElement(
|
||||
'div[class$=signInMethodItem] div[class$=error] div[class$=identifier]',
|
||||
{
|
||||
text: method,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
type ExpectNotificationOnFiledOptions = {
|
||||
field: string;
|
||||
content?: RegExp | string;
|
||||
};
|
||||
|
||||
export const expectNotificationInFiled = async (
|
||||
page: Page,
|
||||
{ field, content }: ExpectNotificationOnFiledOptions
|
||||
) => {
|
||||
const signInMethodsField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] > div[class$=title])',
|
||||
{
|
||||
text: field,
|
||||
}
|
||||
);
|
||||
|
||||
await expect(signInMethodsField).toMatchElement(
|
||||
'div[class*=inlineNotification] div[class$=content]',
|
||||
{
|
||||
text: content,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const expectSignUpIdentifierSelectorError = async (page: Page) => {
|
||||
const signUpIdentifierField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] > div[class$=title])',
|
||||
{
|
||||
text: 'Sign-up identifier',
|
||||
}
|
||||
);
|
||||
|
||||
await expect(signUpIdentifierField).toMatchElement('div[class*=select][class*=error]');
|
||||
};
|
||||
|
||||
export const expectToResetSignUpAndSignInConfig = async (page: Page, needSave = true) => {
|
||||
// Select 'Email address or phone number' first to ensure the sign-in method contains phone and email
|
||||
await expectToSelectSignUpIdentifier(page, 'Email address or phone number');
|
||||
await expectToSelectSignUpIdentifier(page, 'Username');
|
||||
await expectToRemoveSignInMethod(page, 'Email address');
|
||||
await expectToRemoveSignInMethod(page, 'Phone number');
|
||||
if (needSave) {
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
}
|
||||
};
|
||||
|
||||
export const expectToAddSocialSignInConnector = async (page: Page, name: string) => {
|
||||
const socialSignInField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] > div[class$=title])',
|
||||
{
|
||||
text: 'Social sign-in',
|
||||
}
|
||||
);
|
||||
|
||||
await expect(socialSignInField).toClick('button span', {
|
||||
text: 'Add Social Connector',
|
||||
});
|
||||
|
||||
// Wait for the dropdown to be rendered in the correct position
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await expect(page).toClick(
|
||||
'.ReactModalPortal div[class$=dropdownContainer] div[role=menuitem] span[class$=name]',
|
||||
{
|
||||
text: name,
|
||||
}
|
||||
);
|
||||
|
||||
await page.waitForSelector('.ReactModalPortal div[class$=dropdownContainer]', {
|
||||
hidden: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const expectToRemoveSocialSignInConnector = async (page: Page, name: string) => {
|
||||
const socialSignInField = await expect(page).toMatchElement(
|
||||
'div[class$=field]:has(div[class$=headline] > div[class$=title])',
|
||||
{
|
||||
text: 'Social sign-in',
|
||||
}
|
||||
);
|
||||
|
||||
const connectorItem = await expect(socialSignInField).toMatchElement(
|
||||
'div[class$=item]:has(span[class$=name])',
|
||||
{
|
||||
text: name,
|
||||
}
|
||||
);
|
||||
|
||||
await expect(connectorItem).toClick('button:last-of-type');
|
||||
};
|
||||
|
||||
type ExpectErrorsOnNavTabOptions = {
|
||||
tab: string;
|
||||
error?: RegExp | string;
|
||||
};
|
||||
|
||||
export const expectErrorsOnNavTab = async (
|
||||
page: Page,
|
||||
{ tab, error }: ExpectErrorsOnNavTabOptions
|
||||
) => {
|
||||
const signUpAndSignInTab = await expect(page).toMatchElement('nav div[class$=item]:has(a)', {
|
||||
text: tab,
|
||||
});
|
||||
|
||||
await expect(signUpAndSignInTab).toMatchElement('div[class$=errors]', {
|
||||
text: error,
|
||||
});
|
||||
};
|
|
@ -0,0 +1,301 @@
|
|||
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
|
||||
import { expectToClickNavTab, goToAdminConsole, trySaveChanges } from '#src/ui-helpers/index.js';
|
||||
import { expectNavigation, appendPathname } from '#src/utils.js';
|
||||
|
||||
import { expectToSaveSignInExperience, waitForFormCard } from '../helpers.js';
|
||||
|
||||
import {
|
||||
expectToDeletePasswordlessConnector,
|
||||
expectToSetupPasswordlessConnector,
|
||||
testSendgridConnector,
|
||||
testTwilioConnector,
|
||||
} from './connector-setup-helpers.js';
|
||||
import {
|
||||
expectToSelectSignUpIdentifier,
|
||||
expectNotificationInFiled,
|
||||
expectSignUpIdentifierSelectorError,
|
||||
expectToAddSignInMethod,
|
||||
expectSignInMethodError,
|
||||
expectErrorsOnNavTab,
|
||||
expectToClickSignUpAuthnOption,
|
||||
expectToClickSignInMethodAuthnOption,
|
||||
expectToResetSignUpAndSignInConfig,
|
||||
} from './helpers.js';
|
||||
|
||||
describe('sign-in experience(sad path): sign-up and sign-in', () => {
|
||||
const logtoConsoleUrl = new URL(logtoConsoleUrlString);
|
||||
|
||||
beforeAll(async () => {
|
||||
await goToAdminConsole();
|
||||
});
|
||||
|
||||
it('navigate to sign-in experience page', async () => {
|
||||
await expectNavigation(
|
||||
page.goto(appendPathname('/console/sign-in-experience', logtoConsoleUrl).href)
|
||||
);
|
||||
// Land on branding tab by default
|
||||
expect(page.url()).toBe(new URL(`console/sign-in-experience/branding`, logtoConsoleUrl).href);
|
||||
});
|
||||
|
||||
it('navigate to sign-up and sign-in tab', async () => {
|
||||
await expectToClickNavTab(page, 'Sign-up and Sign-in');
|
||||
|
||||
await waitForFormCard(page, 'SIGN UP');
|
||||
await waitForFormCard(page, 'SIGN IN');
|
||||
await waitForFormCard(page, 'SOCIAL SIGN-IN');
|
||||
});
|
||||
|
||||
describe('cases that no connector is setup', () => {
|
||||
describe('email address as sign-up identifier', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page, false);
|
||||
});
|
||||
|
||||
it('should fail to setup email as sign-up identifier', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Email address');
|
||||
// Disable password settings for sign-up settings
|
||||
await expectToClickSignUpAuthnOption(page, 'Create your password');
|
||||
|
||||
await expectNotificationInFiled(page, {
|
||||
field: 'Sign-up identifier',
|
||||
content: /No email connector set-up yet./,
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignUpIdentifierSelectorError(page);
|
||||
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '1 errors',
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail to add phone number sign-in method', async () => {
|
||||
await expectToAddSignInMethod(page, 'Phone number');
|
||||
await expectNotificationInFiled(page, {
|
||||
field: 'Identifier and authentication settings for sign-in',
|
||||
content: /No SMS connector set-up yet./,
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignInMethodError(page, 'Phone number');
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '2 errors',
|
||||
});
|
||||
|
||||
// Disable password option for sign-in method
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Password',
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignInMethodError(page, 'Phone number');
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '2 errors',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('phone number as sign-up identifier', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page, false);
|
||||
});
|
||||
|
||||
it('should fail to setup phone number as sign-up identifier', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Phone number');
|
||||
// Disable password settings for sign-up settings
|
||||
await expectToClickSignUpAuthnOption(page, 'Create your password');
|
||||
|
||||
await expectNotificationInFiled(page, {
|
||||
field: 'Sign-up identifier',
|
||||
content: /No SMS connector set-up yet./,
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignUpIdentifierSelectorError(page);
|
||||
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '1 errors',
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail to add email address sign-in method', async () => {
|
||||
await expectToAddSignInMethod(page, 'Email address');
|
||||
await expectNotificationInFiled(page, {
|
||||
field: 'Identifier and authentication settings for sign-in',
|
||||
content: /No email connector set-up yet./,
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignInMethodError(page, 'Email address');
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '2 errors',
|
||||
});
|
||||
|
||||
// Disable password option for sign-in method
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Password',
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignInMethodError(page, 'Email address');
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '2 errors',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('social sign-in', () => {
|
||||
it('should display no social connector notification in social sign-in field', async () => {
|
||||
await expectNotificationInFiled(page, {
|
||||
field: 'Social sign-in',
|
||||
content: /No social connector set-up yet./,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('cases that only Email connector is setup', () => {
|
||||
beforeAll(async () => {
|
||||
// Email connector
|
||||
await expectToSetupPasswordlessConnector(page, testSendgridConnector);
|
||||
// Nav back to sign-in experience page
|
||||
await expectNavigation(
|
||||
page.goto(
|
||||
appendPathname('/console/sign-in-experience/sign-up-and-sign-in', logtoConsoleUrl).href
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await expectToDeletePasswordlessConnector(page, testSendgridConnector);
|
||||
await expectNavigation(
|
||||
page.goto(
|
||||
appendPathname('/console/sign-in-experience/sign-up-and-sign-in', logtoConsoleUrl).href
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
describe('email address as sign-up identifier', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('should setup email as sign-up identifier', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Email address');
|
||||
// Disable password settings for sign-up settings
|
||||
await expectToClickSignUpAuthnOption(page, 'Create your password');
|
||||
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('should fail to add phone number sign-in method', async () => {
|
||||
await expectToAddSignInMethod(page, 'Phone number');
|
||||
await expectNotificationInFiled(page, {
|
||||
field: 'Identifier and authentication settings for sign-in',
|
||||
content: /No SMS connector set-up yet./,
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignInMethodError(page, 'Phone number');
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '1 errors',
|
||||
});
|
||||
|
||||
// Disable password option for sign-in method
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Phone number',
|
||||
option: 'Password',
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignInMethodError(page, 'Phone number');
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '1 errors',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('cases that only SMS connector is setup', () => {
|
||||
beforeAll(async () => {
|
||||
// SMS connector
|
||||
await expectToSetupPasswordlessConnector(page, testTwilioConnector);
|
||||
// Nav back to sign-in experience page
|
||||
await expectNavigation(
|
||||
page.goto(
|
||||
appendPathname('/console/sign-in-experience/sign-up-and-sign-in', logtoConsoleUrl).href
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await expectToDeletePasswordlessConnector(page, testTwilioConnector);
|
||||
await expectNavigation(
|
||||
page.goto(
|
||||
appendPathname('/console/sign-in-experience/sign-up-and-sign-in', logtoConsoleUrl).href
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
describe('phone number as sign-up identifier', () => {
|
||||
afterAll(async () => {
|
||||
await expectToResetSignUpAndSignInConfig(page);
|
||||
});
|
||||
|
||||
it('should setup phone number as sign-up identifier', async () => {
|
||||
await expectToSelectSignUpIdentifier(page, 'Phone number');
|
||||
// Disable password settings for sign-up settings
|
||||
await expectToClickSignUpAuthnOption(page, 'Create your password');
|
||||
await expectToSaveSignInExperience(page, { needToConfirmChanges: true });
|
||||
});
|
||||
|
||||
it('should fail to add email sign-in method', async () => {
|
||||
await expectToAddSignInMethod(page, 'Email address');
|
||||
await expectNotificationInFiled(page, {
|
||||
field: 'Identifier and authentication settings for sign-in',
|
||||
content: /No email connector set-up yet./,
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignInMethodError(page, 'Email address');
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '1 errors',
|
||||
});
|
||||
|
||||
// Disable password option for sign-in method
|
||||
await expectToClickSignInMethodAuthnOption(page, {
|
||||
method: 'Email address',
|
||||
option: 'Password',
|
||||
});
|
||||
|
||||
await trySaveChanges(page);
|
||||
|
||||
await expectSignInMethodError(page, 'Email address');
|
||||
await expectErrorsOnNavTab(page, {
|
||||
tab: 'Sign-up and Sign-in',
|
||||
error: '1 errors',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -105,3 +105,9 @@ export const expectConfirmModalAndAct = async (
|
|||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const expectToClickNavTab = async (page: Page, tab: string) => {
|
||||
await expect(page).toClick('nav div[class$=item] div[class$=link] a', {
|
||||
text: tab,
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue