0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-06 20:40:08 -05:00

chore(test): add test cases for SSO connection info (#5092)

This commit is contained in:
Darcy Ye 2024-01-02 11:37:57 +08:00 committed by GitHub
parent 86ce940dff
commit 3861bcac36
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 10 deletions

View file

@ -1,7 +1,72 @@
import { conditionalString } from '@silverhand/essentials';
import { type Page } from 'puppeteer';
import { type SsoConnectorTestCase } from './sso-connectors-test-cases.js';
import { dcls, cls } from '#src/utils.js';
import { type SsoConnectorTestCase, type Protocol } from './sso-connectors-test-cases.js';
const getAndCheckValueByFieldName = async (page: Page, fieldName: string, expectSuffix: string) => {
const valueField = await expect(page).toMatchElement(
[dcls('form'), `${dcls('field')}:has(${dcls('headline')} > ${dcls('title')})`].join(' '),
{ text: fieldName }
);
const value = await valueField.$eval(
[dcls('copyToClipboard'), dcls('row'), dcls('content')].join(' '),
(element) => element.textContent
);
expect(value?.endsWith(expectSuffix)).toBeTruthy();
};
// Check the correctness of automatically generated connection info on the `Connection` tab.
const checkSsoConnectorConnectionTabInfo = async (page: Page, protocol: Protocol) => {
// Wait for the details page redirect to default tab (which is `Connection` tab).
await page.waitForNavigation({ waitUntil: 'networkidle0' });
// eslint-disable-next-line prefer-regex-literals
const regExpForDetailsPageUrl = new RegExp('enterprise-sso\\/([^/]+)\\/connection');
expect(regExpForDetailsPageUrl.test(page.url())).toBe(true);
const ssoConnectorIdFromUrl = regExpForDetailsPageUrl.exec(page.url())?.[1];
if (!ssoConnectorIdFromUrl) {
throw new Error('SSO connector ID is not found in URL.');
}
// The SSO connector ID shown on the page should match the ID of the SSO connector in URL.
await expect(page).toMatchElement(
[
dcls('metadata'),
dcls('row'),
`${dcls('container')}${cls('copyId')}`,
dcls('row'),
dcls('content'),
].join(' '),
{ text: ssoConnectorIdFromUrl }
);
if (protocol === 'SAML') {
await getAndCheckValueByFieldName(
page,
'Assertion consumer service URL (Reply URL)',
`api/authn/single-sign-on/saml/${ssoConnectorIdFromUrl}`
);
await getAndCheckValueByFieldName(
page,
'Audience URI (SP Entity ID)',
`enterprise-sso/${ssoConnectorIdFromUrl}`
);
}
if (protocol === 'OIDC') {
await getAndCheckValueByFieldName(
page,
'Redirect URI (Callback URL)',
`callback/${ssoConnectorIdFromUrl}`
);
}
};
export const findModalFooterButton = async (isButtonDisabled = false) => {
return page.waitForSelector(
@ -13,14 +78,22 @@ export const findModalFooterButton = async (isButtonDisabled = false) => {
export const fillSsoConnectorCreationModal = async (
page: Page,
{ connectorFactoryName, connectorName }: SsoConnectorTestCase
{ connectorFactoryName, connectorName, protocol }: SsoConnectorTestCase,
checkConnectionInfo = false
) => {
// Button should be disabled util form is filled.
await expect(findModalFooterButton(true)).resolves.toBeTruthy();
// Select connector factory
await expect(page).toClick(
`.ReactModalPortal div[role=radio] div[class$=ssoConnector] div[class$=content] div[class$=name] span`,
[
'.ReactModalPortal',
'div[role=radio]',
dcls('ssoConnector'),
dcls('content'),
dcls('name'),
'span',
].join(' '),
{ text: connectorFactoryName }
);
@ -35,4 +108,11 @@ export const fillSsoConnectorCreationModal = async (
// Button should enabled.
const createButton = await findModalFooterButton();
await createButton?.click();
if (checkConnectionInfo) {
// Wait for the page redirect to details page.
await page.waitForNavigation({ waitUntil: 'networkidle0' });
await checkSsoConnectorConnectionTabInfo(page, protocol);
}
};

View file

@ -1,37 +1,45 @@
// Will extend this type definition later since we are going to configure the SSO connectors with specific values.
export type Protocol = 'SAML' | 'OIDC';
export type SsoConnectorTestCase = {
connectorName: string;
connectorFactoryName: string;
protocol: Protocol;
};
const microsoftEntraIdName = 'Microsoft Entra ID';
const microsoftEntraID: SsoConnectorTestCase = {
connectorName: microsoftEntraIdName,
connectorFactoryName: microsoftEntraIdName,
protocol: 'SAML',
};
const googleWorkspaceName = 'Google Workspace';
const googleWorkspace: SsoConnectorTestCase = {
connectorName: googleWorkspaceName,
connectorFactoryName: googleWorkspaceName,
protocol: 'OIDC',
};
const oktaName = 'Okta';
const okta: SsoConnectorTestCase = {
connectorName: oktaName,
connectorFactoryName: oktaName,
protocol: 'OIDC',
};
const oidcName = 'OIDC';
const oidc: SsoConnectorTestCase = {
connectorName: oidcName,
connectorFactoryName: oidcName,
protocol: 'OIDC',
};
const samlName = 'SAML';
const saml: SsoConnectorTestCase = {
connectorName: samlName,
connectorFactoryName: samlName,
protocol: 'SAML',
};
export const ssoConnectorTestCases: SsoConnectorTestCase[] = [

View file

@ -55,9 +55,7 @@ describe('create SSO connectors', () => {
await expectModalWithTitle(page, 'Add enterprise connector');
await fillSsoConnectorCreationModal(page, ssoConnectorTestCases[0]!);
await page.waitForNavigation({ waitUntil: 'networkidle0' });
await fillSsoConnectorCreationModal(page, ssoConnectorTestCases[0]!, true);
// Come back to Enterprise SSO listing page.
await page.goto(appendPathname('/console/enterprise-sso', logtoConsoleUrl).href);
@ -78,9 +76,7 @@ describe('create SSO connectors', () => {
await expectModalWithTitle(page, 'Add enterprise connector');
await fillSsoConnectorCreationModal(page, ssoConnector);
await page.waitForNavigation({ waitUntil: 'networkidle0' });
await fillSsoConnectorCreationModal(page, ssoConnector, true);
// Come back to Enterprise SSO listing page.
await page.goto(appendPathname('/console/enterprise-sso', logtoConsoleUrl).href);
@ -104,11 +100,13 @@ describe('create SSO connectors', () => {
* To check only the `duplicated connector name` is blocked, even if the
* existing SSO connector (with the occupied name) is created with a different connector factory.
*/
const { connectorFactoryName } = ssoConnectorTestCases[0]!;
const { connectorFactoryName, protocol } = ssoConnectorTestCases[0]!;
const { connectorName } = ssoConnectorTestCases[1]!;
// Since the creation process is expected to be blocked in this test case, we do not want to check the connection info on details page.
await fillSsoConnectorCreationModal(page, {
connectorFactoryName,
connectorName,
protocol,
});
// Error message should be shown.