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

test(test): add social integration tests (#1721)

* test(test): add social integration tests

add social integration tests

* fix(test): align format

align format

* fix(test): cr update

cr update

* fix(test): cr update

cr update

* fix(test): cr update

cr update
This commit is contained in:
simeng-li 2022-08-03 13:43:28 +08:00 committed by GitHub
parent ff151b2010
commit f257e4deb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 202 additions and 3 deletions

View file

@ -10,6 +10,7 @@ import {
SocialConnectorInstance,
GetConnectorConfig,
} from '@logto/connector-types';
import { z } from 'zod';
import { defaultMetadata } from './constant';
import { mockSocialConfigGuard, MockSocialConfig } from './types';
@ -46,7 +47,17 @@ export default class MockSocialConnector implements SocialConnectorInstance<Mock
public getAccessToken = async () => randomUUID();
public getUserInfo: GetUserInfo = async () => ({
id: `mock-social-sub-${randomUUID()}`,
});
public getUserInfo: GetUserInfo = async (data) => {
const dataGuard = z.object({ code: z.string(), userId: z.optional(z.string()) });
const result = dataGuard.safeParse(data);
if (!result.success) {
throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, JSON.stringify(data));
}
// For mock use only. Use to track the created user entity
return {
id: result.data.userId ?? `mock-social-sub-${randomUUID()}`,
};
};
}

View file

@ -157,3 +157,42 @@ export const verifySignInUserWithSmsPasscode = (
},
})
.json<RedirectResponse>();
export const signInWithSocial = (
payload: {
connectorId: string;
state: string;
redirectUri: string;
},
interactionCookie: string
) =>
api
.post('session/sign-in/social', { headers: { cookie: interactionCookie }, json: payload })
.json<RedirectResponse>();
export const getAuthWithSocial = (
payload: { connectorId: string; data: unknown },
interactionCookie: string
) =>
api
.post('session/sign-in/social/auth', {
headers: { cookie: interactionCookie },
json: payload,
})
.json<RedirectResponse>();
export const registerWithSocial = (connectorId: string, interactionCookie: string) =>
api
.post('session/register/social', {
headers: { cookie: interactionCookie },
json: { connectorId },
})
.json<RedirectResponse>();
export const bindWithSocial = (connectorId: string, interactionCookie: string) =>
api
.post('session/bind-social', {
headers: { cookie: interactionCookie },
json: { connectorId },
})
.json<RedirectResponse>();

View file

@ -95,6 +95,10 @@ export default class MockClient {
return this.logto.isAuthenticated;
}
public getIdTokenClaims() {
return this.logto.getIdTokenClaims();
}
private readonly consent = async () => {
// Note: If sign in action completed successfully, we will get `_session.sig` in the cookie.
assert(this.interactionCookie, new Error('Session not found'));

View file

@ -0,0 +1,145 @@
import { assert } from '@silverhand/essentials';
import { HTTPError } from 'got';
import {
mockSocialConnectorId,
mockSocialConnectorTarget,
mockSocialConnectorConfig,
} from '@/__mocks__/connectors-mock';
import {
signInWithSocial,
getAuthWithSocial,
registerWithSocial,
bindWithSocial,
signInWithUsernameAndPassword,
getUser,
} from '@/api';
import MockClient from '@/client';
import { setUpConnector, createUserByAdmin } from '@/helpers';
import { generateUsername, generatePassword } from '@/utils';
const state = 'foo_state';
const redirectUri = 'http://foo.dev/callback';
const code = 'auth_code_foo';
describe('social sign-in and register', () => {
const socialUserId = crypto.randomUUID();
beforeAll(async () => {
await setUpConnector(mockSocialConnectorId, mockSocialConnectorConfig);
});
it('register with social', async () => {
const client = new MockClient();
await client.initSession();
assert(client.interactionCookie, new Error('Session not found'));
await expect(
signInWithSocial(
{ state, connectorId: mockSocialConnectorId, redirectUri },
client.interactionCookie
)
).resolves.toBeTruthy();
const response = await getAuthWithSocial(
{
connectorId: mockSocialConnectorId,
data: { state, redirectUri, code, userId: socialUserId },
},
client.interactionCookie
).catch((error: unknown) => error);
// User with social does not exist
expect(response instanceof HTTPError && response.response.statusCode === 422).toBe(true);
// Register with social
const { redirectTo } = await registerWithSocial(
mockSocialConnectorId,
client.interactionCookie
);
await client.processSession(redirectTo);
expect(client.isAuthenticated).toBeTruthy();
});
/*
* Note: As currently we can not prepare a social identities through admin api.
* The sign-in test case MUST run concurrently after the register test case
*/
it('Sign-In with social', async () => {
const client = new MockClient();
await client.initSession();
assert(client.interactionCookie, new Error('Session not found'));
await expect(
signInWithSocial(
{ state, connectorId: mockSocialConnectorId, redirectUri },
client.interactionCookie
)
).resolves.toBeTruthy();
const { redirectTo } = await getAuthWithSocial(
{
connectorId: mockSocialConnectorId,
data: { state, redirectUri, code, userId: socialUserId },
},
client.interactionCookie
);
await client.processSession(redirectTo);
expect(client.isAuthenticated).toBeTruthy();
});
});
describe('social bind account', () => {
const username = generateUsername();
const password = generatePassword();
beforeAll(async () => {
await createUserByAdmin(username, password);
});
it('bind new social account', async () => {
const client = new MockClient();
await client.initSession();
assert(client.interactionCookie, new Error('Session not found'));
await expect(
signInWithSocial(
{ state, connectorId: mockSocialConnectorId, redirectUri },
client.interactionCookie
)
).resolves.toBeTruthy();
const response = await getAuthWithSocial(
{ connectorId: mockSocialConnectorId, data: { state, redirectUri, code } },
client.interactionCookie
).catch((error: unknown) => error);
// User with social does not exist
expect(response instanceof HTTPError && response.response.statusCode === 422).toBe(true);
const { redirectTo } = await signInWithUsernameAndPassword(
username,
password,
client.interactionCookie
);
await expect(
bindWithSocial(mockSocialConnectorId, client.interactionCookie)
).resolves.not.toThrow();
await client.processSession(redirectTo);
// User should bind with social identities
const { sub } = client.getIdTokenClaims();
const user = await getUser(sub);
expect(user.identities).toHaveProperty(mockSocialConnectorTarget);
});
});