mirror of
https://github.com/logto-io/logto.git
synced 2025-01-27 21:39:16 -05:00
fix(console,test): should clear error message and add console integration test (#5081)
* fix(console,test): should clear error message and add console integration test * refactor(test): refactor code using cls and dcls methods if possible
This commit is contained in:
parent
08489334dd
commit
9870ddeff0
3 changed files with 132 additions and 13 deletions
|
@ -32,12 +32,14 @@ function DomainsInput({ className, values, onChange: rawOnChange, error, placeho
|
|||
const [focusedValueId, setFocusedValueId] = useState<Nullable<string>>(null);
|
||||
const [currentValue, setCurrentValue] = useState('');
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { setError } = useFormContext<DomainsFormType>();
|
||||
const { setError, clearErrors } = useFormContext<DomainsFormType>();
|
||||
|
||||
const onChange = (values: Option[]) => {
|
||||
const { values: parsedValues, errorMessage } = domainOptionsParser(values);
|
||||
if (errorMessage) {
|
||||
setError('domains', { type: 'custom', message: errorMessage });
|
||||
} else {
|
||||
clearErrors('domains');
|
||||
}
|
||||
rawOnChange(parsedValues);
|
||||
};
|
||||
|
|
|
@ -97,7 +97,6 @@ function Experience({ data, isDeleted, onUpdated, isDarkModeEnabled }: Props) {
|
|||
watch,
|
||||
setValue,
|
||||
setError,
|
||||
clearErrors,
|
||||
handleSubmit,
|
||||
register,
|
||||
formState: { defaultValues, isDirty, isSubmitting, errors },
|
||||
|
|
|
@ -4,14 +4,24 @@ import {
|
|||
expectModalWithTitle,
|
||||
expectToClickDetailsPageOption,
|
||||
expectConfirmModalAndAct,
|
||||
expectToSaveChanges,
|
||||
waitForToast,
|
||||
} from '#src/ui-helpers/index.js';
|
||||
import { expectNavigation, appendPathname } from '#src/utils.js';
|
||||
import { expectNavigation, appendPathname, dcls, cls } from '#src/utils.js';
|
||||
|
||||
import { findModalFooterButton, fillSsoConnectorCreationModal } from './helpers.js';
|
||||
import { ssoConnectorTestCases } from './sso-connectors-test-cases.js';
|
||||
|
||||
await page.setViewport({ width: 1920, height: 1080 });
|
||||
|
||||
const emailDomainInputFieldSelector = [
|
||||
'form',
|
||||
`${dcls('input')}${cls('multiple')}[role=button]`,
|
||||
'input',
|
||||
].join(' ');
|
||||
|
||||
const emailDomainErrorMessageSelector = ['form', dcls('field'), dcls('errorMessage')].join(' ');
|
||||
|
||||
describe('create SSO connectors', () => {
|
||||
const logtoConsoleUrl = new URL(logtoConsoleUrlString);
|
||||
|
||||
|
@ -26,7 +36,7 @@ describe('create SSO connectors', () => {
|
|||
);
|
||||
|
||||
await expect(page).toMatchElement(
|
||||
'div[class$=main] div[class$=headline] div[class$=titleEllipsis]',
|
||||
[dcls('main'), dcls('headline'), dcls('titleEllipsis')].join(' '),
|
||||
{
|
||||
text: 'Enterprise SSO',
|
||||
}
|
||||
|
@ -37,7 +47,7 @@ describe('create SSO connectors', () => {
|
|||
|
||||
it('can open create SSO connector modal from table placeholder and create the first SSO connector', async () => {
|
||||
// When no SSO connector is created, use the create button in placeholder.
|
||||
await expect(page).toClick('table div[class$=placeholder] button span', {
|
||||
await expect(page).toClick(['table', dcls('placeholder'), 'button', 'span'].join(' '), {
|
||||
text: 'Add enterprise connector',
|
||||
});
|
||||
|
||||
|
@ -57,9 +67,12 @@ describe('create SSO connectors', () => {
|
|||
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||
|
||||
// When there are existing SSO connector(s), use the create button in page header.
|
||||
await expect(page).toClick('div[class$=main] div[class$=headline] button[type=button] span', {
|
||||
text: 'Add enterprise connector',
|
||||
});
|
||||
await expect(page).toClick(
|
||||
[dcls('main'), dcls('headline'), 'button[type=button]', 'span'].join(' '),
|
||||
{
|
||||
text: 'Add enterprise connector',
|
||||
}
|
||||
);
|
||||
|
||||
await expectModalWithTitle(page, 'Add enterprise connector');
|
||||
|
||||
|
@ -76,9 +89,12 @@ describe('create SSO connectors', () => {
|
|||
await page.waitForNavigation({ waitUntil: 'networkidle0' });
|
||||
|
||||
// When there are existing SSO connector(s), use the create button in page header.
|
||||
await expect(page).toClick('div[class$=main] div[class$=headline] button[type=button] span', {
|
||||
text: 'Add enterprise connector',
|
||||
});
|
||||
await expect(page).toClick(
|
||||
[dcls('main'), dcls('headline'), 'button[type=button]', 'span'].join(' '),
|
||||
{
|
||||
text: 'Add enterprise connector',
|
||||
}
|
||||
);
|
||||
|
||||
await expectModalWithTitle(page, 'Add enterprise connector');
|
||||
|
||||
|
@ -95,7 +111,7 @@ describe('create SSO connectors', () => {
|
|||
|
||||
// Error message should be shown.
|
||||
await expect(page).toMatchElement(
|
||||
'.ReactModalPortal div[class$=field] div[class$=errorMessage]',
|
||||
['.ReactModalPortal', dcls('field'), dcls('errorMessage')].join(' '),
|
||||
{
|
||||
text: 'Connector name already exists. Please choose a different name.',
|
||||
}
|
||||
|
@ -104,7 +120,7 @@ describe('create SSO connectors', () => {
|
|||
await expect(findModalFooterButton(true)).resolves.toBeTruthy();
|
||||
|
||||
await expect(page).toFill(
|
||||
'.ReactModalPortal input[type=text][name=connectorName]',
|
||||
['.ReactModalPortal', 'input[type=text][name=connectorName]'].join(' '),
|
||||
`${connectorName} (1)`
|
||||
);
|
||||
|
||||
|
@ -125,6 +141,108 @@ describe('create SSO connectors', () => {
|
|||
expect(page.url().endsWith('/connection')).toBeTruthy();
|
||||
});
|
||||
|
||||
it("can go to SSO connector's 'SSO Experience' tab", async () => {
|
||||
// Navigate to "SSO Experience" tab
|
||||
await expect(page).toClick(['nav', dcls('item'), dcls('link'), 'a'].join(' '), {
|
||||
text: 'SSO Experience',
|
||||
});
|
||||
|
||||
// Confirm the current path is for "SSO Experience".
|
||||
expect(page.url().endsWith('/experience')).toBeTruthy();
|
||||
// Confirm the current tab is "SSO Experience".
|
||||
await expect(page).toMatchElement(['nav', dcls('item'), dcls('selected'), 'a'].join(' '), {
|
||||
text: 'SSO Experience',
|
||||
});
|
||||
});
|
||||
|
||||
it("can configure SSO connectors's 'SSO Experience' GENERAL setup", async () => {
|
||||
// Expect to see inline notification alert to configure email domain.
|
||||
await expect(page).toMatchElement(
|
||||
['form', `${dcls('alert')}${cls('inlineNotification')}`, dcls('content')].join(' '),
|
||||
{
|
||||
text: 'Add email domain to guide enterprise users to their identity provider for Single Sign-on.',
|
||||
}
|
||||
);
|
||||
|
||||
// Configure email domain
|
||||
await expect(page).toFill(emailDomainInputFieldSelector, 'svhd.io');
|
||||
|
||||
// Press enter to add email domain
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
// Input email domain with invalid format
|
||||
await expect(page).toFill(emailDomainInputFieldSelector, 'abc');
|
||||
|
||||
// Press space to add email domain
|
||||
await page.keyboard.press('Space');
|
||||
await expect(page).toMatchElement(emailDomainErrorMessageSelector, {
|
||||
text: 'Invalid domain format.',
|
||||
});
|
||||
|
||||
// Input public email domain (e.g., 'gmail.com', 'yahoo.com' etc)
|
||||
await expect(page).toFill(emailDomainInputFieldSelector, 'gmail.com');
|
||||
|
||||
// Press tab to add email domain
|
||||
await page.keyboard.press('Tab');
|
||||
await expect(page).toMatchElement(emailDomainErrorMessageSelector, {
|
||||
text: 'Public email domains are not allowed. Invalid domain format.',
|
||||
});
|
||||
|
||||
// Remove last added email domain (which is `gmail.com` in this case). CSS selector can not specify the text content of the component.
|
||||
await expect(page).toClick(
|
||||
[
|
||||
'form',
|
||||
`${dcls('input')}${cls('multiple')}[role=button]`,
|
||||
`${dcls('info')}${cls('tag')}:last-of-type`,
|
||||
'button',
|
||||
].join(' ')
|
||||
);
|
||||
|
||||
// Error message got updated, since forbidden email domain is removed.
|
||||
await expect(page).toMatchElement(emailDomainErrorMessageSelector, {
|
||||
text: 'Invalid domain format.',
|
||||
});
|
||||
await expect(page).toFill(emailDomainInputFieldSelector, 'abc');
|
||||
|
||||
// Input field blurred to input email domain.
|
||||
await page.$eval(
|
||||
// Can not use `emailDomainInputFieldSelector` here since it could break the type inference.
|
||||
'form div[class*=input][class*=multiple][role=button] input',
|
||||
(element: HTMLInputElement) => {
|
||||
element.blur();
|
||||
}
|
||||
);
|
||||
|
||||
// Does not allow duplicate email domain.
|
||||
await expect(page).toMatchElement(emailDomainErrorMessageSelector, {
|
||||
text: 'There are duplicate domains. Invalid domain format.',
|
||||
});
|
||||
|
||||
// Remove last two added email domains (which are two `abc` in this case).
|
||||
await expect(page).toClick(
|
||||
[
|
||||
'form',
|
||||
`${dcls('input')}${cls('multiple')}[role=button]`,
|
||||
`${dcls('info')}${cls('tag')}:last-of-type`,
|
||||
'button',
|
||||
].join(' ')
|
||||
);
|
||||
|
||||
// Focus on email domain input field component (at this time, the input field is empty).
|
||||
const inputField = await page.$(emailDomainInputFieldSelector);
|
||||
await inputField?.focus();
|
||||
// Should remove the last input email domain with double backspace when the input box is empty.
|
||||
await inputField?.press('Backspace');
|
||||
await inputField?.press('Backspace');
|
||||
|
||||
// Since incorrect email domains are removed, error message no longer exists.
|
||||
const errorMessage = await page.$(emailDomainErrorMessageSelector);
|
||||
expect(errorMessage).toBeNull();
|
||||
|
||||
await expectToSaveChanges(page);
|
||||
await waitForToast(page, { text: 'Saved' });
|
||||
});
|
||||
|
||||
it('can delete an SSO connector from details page', async () => {
|
||||
// Delete connector
|
||||
await expectToClickDetailsPageOption(page, 'Delete');
|
||||
|
|
Loading…
Add table
Reference in a new issue