mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
chore: add integration tests
This commit is contained in:
parent
92625e5019
commit
9c59102f97
4 changed files with 131 additions and 4 deletions
|
@ -7,12 +7,17 @@ import type {
|
|||
|
||||
import { authedAdminApi } from './api.js';
|
||||
|
||||
export const createApplication = async (name: string, type: ApplicationType) =>
|
||||
export const createApplication = async (
|
||||
name: string,
|
||||
type: ApplicationType,
|
||||
rest?: Partial<CreateApplication>
|
||||
) =>
|
||||
authedAdminApi
|
||||
.post('applications', {
|
||||
json: {
|
||||
name,
|
||||
type,
|
||||
...rest,
|
||||
},
|
||||
})
|
||||
.json<Application>();
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
import { Prompt } from '@logto/js';
|
||||
import { ApplicationType, InteractionEvent } from '@logto/schemas';
|
||||
|
||||
import { createApplication, deleteApplication, putInteraction } from '#src/api/index.js';
|
||||
import MockClient from '#src/client/index.js';
|
||||
import { demoAppRedirectUri } from '#src/constants.js';
|
||||
import { processSession } from '#src/helpers/client.js';
|
||||
import { createUserByAdmin } from '#src/helpers/index.js';
|
||||
import { enableAllPasswordSignInMethods } from '#src/helpers/sign-in-experience.js';
|
||||
import { generateUsername, generatePassword } from '#src/utils.js';
|
||||
|
||||
describe('always issue Refresh Token config', () => {
|
||||
const username = generateUsername();
|
||||
const password = generatePassword();
|
||||
|
||||
const validateRefreshToken = async (appId: string, redirectUri: string, expectToken: boolean) => {
|
||||
const client = new MockClient({
|
||||
appId,
|
||||
prompt: Prompt.Login,
|
||||
});
|
||||
await client.initSession(redirectUri);
|
||||
await client.successSend(putInteraction, {
|
||||
event: InteractionEvent.SignIn,
|
||||
identifier: { username, password },
|
||||
});
|
||||
const { redirectTo } = await client.submitInteraction();
|
||||
await processSession(client, redirectTo);
|
||||
|
||||
if (expectToken) {
|
||||
expect(await client.getRefreshToken()).not.toBeNull();
|
||||
} else {
|
||||
expect(await client.getRefreshToken()).toBeNull();
|
||||
}
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
await createUserByAdmin(username, password);
|
||||
await enableAllPasswordSignInMethods();
|
||||
});
|
||||
|
||||
it('can sign in and fetch Refresh Token without `prompt=consent` when always issue Refresh Token is set', async () => {
|
||||
const app = await createApplication('Integration test app', ApplicationType.SPA, {
|
||||
oidcClientMetadata: { redirectUris: [demoAppRedirectUri], postLogoutRedirectUris: [] },
|
||||
customClientMetadata: { alwaysIssueRefreshToken: true },
|
||||
});
|
||||
await validateRefreshToken(app.id, demoAppRedirectUri, true);
|
||||
await deleteApplication(app.id);
|
||||
});
|
||||
|
||||
it('cannot fetch Refresh Token if alwaysIssueRefreshToken is false and prompt is not consent', async () => {
|
||||
const app = await createApplication('Integration test app', ApplicationType.SPA, {
|
||||
oidcClientMetadata: { redirectUris: [demoAppRedirectUri], postLogoutRedirectUris: [] },
|
||||
customClientMetadata: { alwaysIssueRefreshToken: false },
|
||||
});
|
||||
await validateRefreshToken(app.id, demoAppRedirectUri, false);
|
||||
await deleteApplication(app.id);
|
||||
});
|
||||
|
||||
it('cannot fetch Refresh Token for non-web apps', async () => {
|
||||
const redirectUri = 'io.logto://callback';
|
||||
const app = await createApplication('Integration test app', ApplicationType.Native, {
|
||||
oidcClientMetadata: { redirectUris: [redirectUri], postLogoutRedirectUris: [] },
|
||||
customClientMetadata: { alwaysIssueRefreshToken: true },
|
||||
});
|
||||
await validateRefreshToken(app.id, redirectUri, false);
|
||||
await deleteApplication(app.id);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
import { demoAppApplicationId } from '@logto/schemas';
|
||||
import { trySafe } from '@silverhand/essentials';
|
||||
import { HTTPError, type Headers, got } from 'got';
|
||||
|
||||
import { logtoUrl } from '#src/constants.js';
|
||||
|
||||
describe('content-type: application/json compatibility', () => {
|
||||
const api = got.extend({
|
||||
prefixUrl: new URL('/oidc', logtoUrl),
|
||||
});
|
||||
|
||||
const expectErrorMessageForPayload = async (
|
||||
payload: Record<string, unknown>,
|
||||
errorMessage: string,
|
||||
headers?: Headers
|
||||
) => {
|
||||
return trySafe(
|
||||
api.post('token', {
|
||||
headers,
|
||||
json: payload,
|
||||
}),
|
||||
(error) => {
|
||||
if (!(error instanceof HTTPError)) {
|
||||
return fail('Error is not a HTTPError instance.');
|
||||
}
|
||||
expect(JSON.parse(String(error.response.body))).toHaveProperty(
|
||||
'error_description',
|
||||
errorMessage
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
it('recognizes `application/json` content-type in OIDC token endpoints', async () => {
|
||||
await Promise.all([
|
||||
expectErrorMessageForPayload(
|
||||
{ client_id: demoAppApplicationId },
|
||||
"missing required parameter 'grant_type'"
|
||||
),
|
||||
expectErrorMessageForPayload(
|
||||
{ client_id: demoAppApplicationId, grant_type: 'refresh_token' },
|
||||
"missing required parameter 'refresh_token'"
|
||||
),
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not recognize `application/json1` content-type', async () => {
|
||||
await expectErrorMessageForPayload(
|
||||
{ client_id: demoAppApplicationId },
|
||||
'only application/x-www-form-urlencoded content-type bodies are supported on POST /token',
|
||||
{ 'content-type': 'application/json1' }
|
||||
);
|
||||
});
|
||||
});
|
|
@ -26,7 +26,7 @@ describe('get access token', () => {
|
|||
await enableAllPasswordSignInMethods();
|
||||
});
|
||||
|
||||
it('sign-in and getAccessToken with admin user', async () => {
|
||||
it('can sign in and getAccessToken with admin user', async () => {
|
||||
const client = new MockClient({
|
||||
resources: [defaultManagementApi.resource.indicator],
|
||||
scopes: [defaultManagementApi.scope.name],
|
||||
|
@ -49,7 +49,7 @@ describe('get access token', () => {
|
|||
void expect(client.getAccessToken('api.foo.com')).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('sign-in and getAccessToken with guest user', async () => {
|
||||
it('can sign in and getAccessToken with guest user', async () => {
|
||||
const client = new MockClient({
|
||||
resources: [defaultManagementApi.resource.indicator],
|
||||
scopes: [defaultManagementApi.scope.name],
|
||||
|
@ -69,7 +69,7 @@ describe('get access token', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('sign-in and get multiple Access Token by the same Refresh Token within refreshTokenReuseInterval', async () => {
|
||||
it('can sign in and get multiple Access Tokens by the same Refresh Token within refreshTokenReuseInterval', async () => {
|
||||
const client = new MockClient({ resources: [defaultManagementApi.resource.indicator] });
|
||||
|
||||
await client.initSession();
|
Loading…
Reference in a new issue