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

fix(core,test): fix integration test (#5438)

* fix(core,test): fix integration test

fix integration tests

* fix(test): remove api timeout

remove api timeout
This commit is contained in:
simeng-li 2024-02-28 14:04:29 +08:00 committed by GitHub
parent 50bf70891d
commit db6e761490
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 92 additions and 59 deletions

View file

@ -72,7 +72,7 @@ export default function singleSignOnConnectorsRoutes<T extends AuthedRouter>(
koaGuard({
body: ssoConnectorCreateGuard,
response: SsoConnectors.guard,
status: [200, 409, 422],
status: [200, 400, 409, 422],
}),
async (ctx, next) => {
const { body } = ctx.guard;
@ -212,7 +212,7 @@ export default function singleSignOnConnectorsRoutes<T extends AuthedRouter>(
params: z.object({ id: z.string().min(1) }),
body: ssoConnectorPatchGuard,
response: ssoConnectorWithProviderConfigGuard,
status: [200, 404, 409, 422],
status: [200, 400, 404, 409, 422],
}),
async (ctx, next) => {
const {

File diff suppressed because one or more lines are too long

View file

@ -4,7 +4,6 @@ import { logtoConsoleUrl, logtoUrl, logtoCloudUrl } from '#src/constants.js';
const api = got.extend({
prefixUrl: new URL('/api', logtoUrl),
timeout: { response: 5000 }, // The default is 60s which is way too long for tests.
});
export default api;

View file

@ -7,6 +7,7 @@ import {
import { appendPath, getEnv } from '@silverhand/essentials';
export const logtoUrl = getEnv('INTEGRATION_TESTS_LOGTO_URL', 'http://localhost:3001');
export const logtoOidcUrl = appendPath(new URL(logtoUrl), 'oidc').toString();
export const logtoConsoleUrl = getEnv(
'INTEGRATION_TESTS_LOGTO_CONSOLE_URL',
'http://localhost:3002'

View file

@ -1,6 +1,9 @@
import fs from 'node:fs';
import { conditional, conditionalString } from '@silverhand/essentials';
import { type Page } from 'puppeteer';
import { metadataXml } from '#src/__mocks__/sso-connectors-mock.js';
import { expectToSaveChanges, waitForToast } from '#src/ui-helpers/index.js';
import { dcls, cls } from '#src/utils.js';
@ -115,7 +118,8 @@ const configureSsoConnectorConnection = async (
protocol: Protocol,
previewResults: Record<string, string>
) => {
await expect(page).toFillForm(dcls('form'), formData);
await fillSsoConnectorConnectionForm(page, formData, protocol);
await expectToSaveChanges(page);
await waitForToast(page, { text: 'Saved' });
@ -128,6 +132,58 @@ const configureSsoConnectorConnection = async (
}
};
const fillSsoConnectorConnectionForm = async (
page: Page,
formData: Record<string, string>,
protocol: Protocol
) => {
if (protocol === 'OIDC') {
await expect(page).toFillForm(dcls('form'), formData);
return;
}
// Click on the switch config method link
await expect(page).toClick([dcls('form'), 'button'].join(' '));
// Click on the "Upload the metadata XML file" option
const dropdownMenu = await page.waitForSelector(
['.ReactModalPortal', dcls('dropdownContainer')].join(' ')
);
await page.evaluate((dropdownMenu) => {
if (dropdownMenu) {
const optionElement = dropdownMenu.querySelectorAll('div[role=menuitem] div');
const uploadMetadataXmlOption = Array.from(optionElement).find(
(element) => element.textContent === 'Upload the metadata XML file'
);
if (uploadMetadataXmlOption) {
const clickEvent = new MouseEvent('click', { bubbles: true });
uploadMetadataXmlOption.dispatchEvent(clickEvent);
}
}
}, dropdownMenu);
await uploadMetadataXml(page);
};
export const uploadMetadataXml = async (page: Page) => {
const fileInputElement = await page.waitForSelector('form input[type=file]');
expect(fileInputElement).toBeTruthy();
if (!fileInputElement) {
throw new Error('File input element is not found.');
}
const metadataFilePath = './metadata.xml';
fs.writeFileSync(metadataFilePath, metadataXml);
await fileInputElement.uploadFile(metadataFilePath);
// Delete the mock file
fs.unlinkSync(metadataFilePath);
};
export const findModalFooterButton = async (isButtonDisabled = false) => {
return page.waitForSelector(
`.ReactModalPortal div[class$=footer] button${conditionalString(

View file

@ -1,3 +1,5 @@
import { logtoIssuer, metadataXml } from '#src/__mocks__/sso-connectors-mock.js';
// Will extend this type definition later since we are going to configure the SSO connectors with specific values.
export type Protocol = 'SAML' | 'OIDC';
@ -12,66 +14,39 @@ export type SsoConnectorTestCase = {
const oidcFormData = {
clientId: 'client-id',
clientSecret: 'client-secret',
issuer: logtoIssuer,
};
const samlFormData = {
// This is a real metadata URL from Microsoft Entra ID test application.
metadataUrl:
'https://login.microsoftonline.com/ac016212-4f8d-46c6-892c-57c90a255a02/federationmetadata/2007-06/federationmetadata.xml?appid=f562b098-dc8c-4e20-8c4b-ea55554fbd8c',
metadata: metadataXml,
};
export const oidcPreviewResults = {
'Authorization endpoint': 'https://accounts.google.com/o/oauth2/v2/auth',
'Token endpoint': 'https://oauth2.googleapis.com/token',
'User information endpoint': 'https://openidconnect.googleapis.com/v1/userinfo',
'JSON web key set endpoint': 'https://www.googleapis.com/oauth2/v3/certs',
Issuer: 'https://accounts.google.com',
};
export const samlPreviewResults = {
'Sign on URL': 'https://login.microsoftonline.com/ac016212-4f8d-46c6-892c-57c90a255a02/saml2',
Issuer: 'https://sts.windows.net/ac016212-4f8d-46c6-892c-57c90a255a02/',
'Signing certificate': 'Expiring Sunday, October 25, 2026',
};
const microsoftEntraIdName = 'Microsoft Entra ID';
const microsoftEntraID: SsoConnectorTestCase = {
connectorName: microsoftEntraIdName,
connectorFactoryName: microsoftEntraIdName,
protocol: 'SAML',
formData: samlFormData,
previewResults: samlPreviewResults,
};
const googleWorkspaceName = 'Google Workspace';
const googleWorkspace: SsoConnectorTestCase = {
connectorName: googleWorkspaceName,
connectorFactoryName: googleWorkspaceName,
protocol: 'OIDC',
formData: oidcFormData,
previewResults: oidcPreviewResults,
};
const oktaName = 'Okta';
const okta: SsoConnectorTestCase = {
connectorName: oktaName,
connectorFactoryName: oktaName,
protocol: 'OIDC',
// Google Workspace connector have `issuer` predefined, for other OIDC-protocol-based connectors, we use Google's issuer to test the config fetcher and preview.
formData: { ...oidcFormData, issuer: 'https://accounts.google.com' },
previewResults: oidcPreviewResults,
'Authorization endpoint': `${logtoIssuer}/auth`,
'Token endpoint': `${logtoIssuer}/token`,
'User information endpoint': `${logtoIssuer}/me`,
'JSON web key set endpoint': `${logtoIssuer}/jwks`,
Issuer: logtoIssuer,
};
const oidcName = 'OIDC';
const oidc: SsoConnectorTestCase = {
connectorName: oidcName,
connectorFactoryName: oidcName,
protocol: 'OIDC',
// Google Workspace connector have `issuer` predefined, for other OIDC-protocol-based connectors, we use Google's issuer to test the config fetcher and preview.
formData: { ...oidcFormData, issuer: 'https://accounts.google.com' },
// To avoid external dependencies we use local logtoOidcUrl as the issuer for all the OIDC based connectors.
formData: { ...oidcFormData },
previewResults: oidcPreviewResults,
};
// These values are decoded from the metadataXml string.
export const samlPreviewResults = {
'Sign on URL': 'https://login.microsoftonline.com/ac016212-4f8d-46c6-892c-57c90a255a02/saml2',
Issuer: 'https://sts.windows.net/ac016212-4f8d-46c6-892c-57c90a255a02/',
'Signing certificate': 'Expiring Sunday, October 25, 2026',
};
const samlName = 'SAML';
const saml: SsoConnectorTestCase = {
connectorName: samlName,
@ -81,10 +56,4 @@ const saml: SsoConnectorTestCase = {
previewResults: samlPreviewResults,
};
export const ssoConnectorTestCases: SsoConnectorTestCase[] = [
microsoftEntraID,
googleWorkspace,
okta,
oidc,
saml,
];
export const ssoConnectorTestCases: SsoConnectorTestCase[] = [oidc, saml];

View file

@ -1,15 +1,16 @@
import { getSsoConnectors, deleteSsoConnectorById } from '#src/api/sso-connector.js';
import { logtoConsoleUrl as logtoConsoleUrlString } from '#src/constants.js';
import {
goToAdminConsole,
expectModalWithTitle,
expectToClickDetailsPageOption,
expectConfirmModalAndAct,
expectToClickDetailsPageOption,
expectToSaveChanges,
waitForToast,
} from '#src/ui-helpers/index.js';
import { expectNavigation, appendPathname, dcls, cls } from '#src/utils.js';
import { findModalFooterButton, fillSsoConnectorCreationModal } from './helpers.js';
import { fillSsoConnectorCreationModal, findModalFooterButton } from './helpers.js';
import { ssoConnectorTestCases } from './sso-connectors-test-cases.js';
await page.setViewport({ width: 1920, height: 1080 });
@ -32,6 +33,12 @@ describe('create SSO connectors', () => {
await goToAdminConsole();
});
afterAll(async () => {
// Delete all SSO connectors
const connectors = await getSsoConnectors();
await Promise.all(connectors.map(async ({ id }) => deleteSsoConnectorById(id)));
});
it('navigate to Enterprise SSO connectors listing page', async () => {
await expectNavigation(
page.goto(appendPathname('/console/enterprise-sso', logtoConsoleUrl).href)