Skip to content

Commit

Permalink
chore: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gao-sun committed Jun 16, 2024
1 parent 942780f commit fe16e78
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 17 deletions.
20 changes: 9 additions & 11 deletions packages/core/src/__mocks__/connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,18 @@ export const mockGoogleConnector: LogtoConnector = {
dbEntry: {
...mockConnector,
id: 'google',
config: {
clientId: 'fake_client_id',
clientSecret: 'fake_client_secret',
oneTap: {
isEnabled: true,
autoSelect: true,
},
}
},
metadata: {
...mockMetadata,
id: 'google',
id: 'google-universal',
target: 'google',
platform: ConnectorPlatform.Web,
},
Expand All @@ -238,16 +246,6 @@ export const mockDemoSocialConnector: LogtoConnector = {
...mockLogtoConnector,
};

export const mockLogtoConnectors = [
mockAliyunDmConnector,
mockAliyunSmsConnector,
mockFacebookConnector,
mockGithubConnector,
mockGoogleConnector,
mockWechatConnector,
mockWechatNativeConnector,
];

export const socialTarget01 = 'socialTarget-id01';
export const socialTarget02 = 'socialTarget-id02';

Expand Down
44 changes: 44 additions & 0 deletions packages/core/src/libraries/sign-in-experience/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { builtInLanguages } from '@logto/phrases-experience';
import type { CreateSignInExperience, SignInExperience } from '@logto/schemas';

import {
mockGithubConnector,
mockGoogleConnector,
mockSignInExperience,
mockSocialConnectors,
socialTarget01,
Expand Down Expand Up @@ -170,6 +172,48 @@ describe('getFullSignInExperience()', () => {
googleOneTap: undefined,
});
});

it('should return full sign-in experience with google one tap', async () => {
findDefaultSignInExperience.mockResolvedValueOnce({
...mockSignInExperience,
socialSignInConnectorTargets: ['github', 'facebook', 'google'],
});
getLogtoConnectors.mockResolvedValueOnce([mockGoogleConnector, mockGithubConnector]);
ssoConnectorLibrary.getAvailableSsoConnectors.mockResolvedValueOnce([
wellConfiguredSsoConnector,
]);

const fullSignInExperience = await getFullSignInExperience('en');
const connectorFactory = ssoConnectorFactories[wellConfiguredSsoConnector.providerName];

expect(fullSignInExperience).toStrictEqual({
...mockSignInExperience,
socialConnectors: [
{ ...mockGithubConnector.metadata, id: mockGithubConnector.dbEntry.id },
{ ...mockGoogleConnector.metadata, id: mockGoogleConnector.dbEntry.id },
],
socialSignInConnectorTargets: ['github', 'facebook', 'google'],
forgotPassword: {
email: false,
phone: false,
},
ssoConnectors: [
{
id: wellConfiguredSsoConnector.id,
connectorName: connectorFactory.name.en,
logo: connectorFactory.logo,
darkLogo: connectorFactory.logoDark,
},
],
isDevelopmentTenant: false,
googleOneTap: {
isEnabled: true,
autoSelect: true,
clientId: 'fake_client_id',
connectorId: 'google',
},
});
});
});

describe('get sso connectors', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConnectorType } from '@logto/connector-kit';
import { ConnectorType, GoogleConnector } from '@logto/connector-kit';
import { createMockUtils } from '@logto/shared/esm';

import type { WithLogContext } from '#src/middleware/koa-audit-log.js';
Expand Down Expand Up @@ -27,8 +27,8 @@ mockEsm('#src/libraries/connector.js', () => ({

const { verifySocialIdentity } = await import('./social-verification.js');

describe('social-verification', () => {
it('verifySocialIdentity', async () => {
describe('verifySocialIdentity', () => {
it('should verify social identity', async () => {
// @ts-expect-error test mock context
const ctx: WithLogContext = {
...createMockContext(),
Expand All @@ -41,4 +41,37 @@ describe('social-verification', () => {
expect(getUserInfo).toBeCalledWith(connectorId, connectorData, expect.anything());
expect(userInfo).toEqual({ id: 'foo' });
});

it('should throw error if csrf token is not matched for Google One Tap verification', async () => {
const ctx: WithLogContext = {
...createMockContext(),
...createMockLogContext(),
// @ts-expect-error test mock context
cookies: { get: jest.fn().mockReturnValue('token') },
};
const connectorId = GoogleConnector.factoryId;
const connectorData = { credential: 'credential' };

await expect(verifySocialIdentity({ connectorId, connectorData }, ctx, tenant)).rejects.toThrow(
'CSRF token mismatch.'
);
});

it('should verify Google One Tap verification', async () => {
const ctx: WithLogContext = {
...createMockContext(),
...createMockLogContext(),
// @ts-expect-error test mock context
cookies: { get: jest.fn().mockReturnValue('token') },
};
const connectorId = GoogleConnector.factoryId;
const connectorData = {
[GoogleConnector.oneTapParams.credential]: 'credential',
[GoogleConnector.oneTapParams.csrfToken]: 'token',
};

await expect(
verifySocialIdentity({ connectorId, connectorData }, ctx, tenant)
).resolves.toEqual({ id: 'foo' });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,13 @@ export const verifySocialIdentity = async (
const log = ctx.createLog('Interaction.SignIn.Identifier.Social.Submit');
log.append({ connectorId, connectorData });

// Verify Google One Tap CSRF token, if it exists
const csrfToken = connectorData[GoogleConnector.oneTapParams.csrfToken];
if (csrfToken) {
// Verify the CSRF token if it's a Google connector and has credential (a Google One Tap
// verification)
if (
connectorId === GoogleConnector.factoryId &&
connectorData[GoogleConnector.oneTapParams.credential]
) {
const csrfToken = connectorData[GoogleConnector.oneTapParams.csrfToken];
const value = ctx.cookies.get(GoogleConnector.oneTapParams.csrfToken);
assertThat(value === csrfToken, 'session.csrf_token_mismatch');
}
Expand Down

0 comments on commit fe16e78

Please sign in to comment.