0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-24 22:41:28 -05:00

refactor(connector-alipay*): refactor Alipay UTs and pass config into getAccessToken (#1002)

* refactor(connector-alipay): remove unnecessary method and db query, fix UT

* refactor(connector-alipay-native): remove unnecessary db query, fix UTs

* refactor(connector-alipay*): extract timestamp format as const
This commit is contained in:
Darcy Ye 2022-06-01 15:30:00 +08:00 committed by GitHub
parent 7781d49667
commit 9f68a7a124
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 41 additions and 104 deletions

View file

@ -40,3 +40,5 @@ export const defaultMetadata: ConnectorMetadata = {
};
export const defaultTimeout = 5000;
export const timestampFormat = 'YYYY-MM-DD HH:mm:ss';

View file

@ -56,9 +56,6 @@ describe('getAccessToken', () => {
const alipayEndpointUrl = new URL(alipayEndpoint);
it('should get an accessToken by exchanging with code', async () => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -73,15 +70,15 @@ describe('getAccessToken', () => {
sign: '<signature>',
});
const response = await alipayNativeMethods.getAccessToken('code');
const response = await alipayNativeMethods.getAccessToken(
'code',
mockedAlipayNativeConfigWithValidPrivateKey
);
const { accessToken } = response;
expect(accessToken).toEqual('access_token');
});
it('should throw when accessToken is empty', async () => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -96,15 +93,12 @@ describe('getAccessToken', () => {
sign: '<signature>',
});
await expect(alipayNativeMethods.getAccessToken('code')).rejects.toMatchError(
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
);
await expect(
alipayNativeMethods.getAccessToken('code', mockedAlipayNativeConfigWithValidPrivateKey)
).rejects.toMatchError(new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid));
});
it('should fail with wrong code', async () => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -117,7 +111,9 @@ describe('getAccessToken', () => {
sign: '<signature>',
});
await expect(alipayNativeMethods.getAccessToken('wrong_code')).rejects.toMatchError(
await expect(
alipayNativeMethods.getAccessToken('wrong_code', mockedAlipayNativeConfigWithValidPrivateKey)
).rejects.toMatchError(
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid, 'Invalid code')
);
});
@ -127,22 +123,10 @@ describe('getUserInfo', () => {
beforeEach(() => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
const alipayEndpointUrl = new URL(alipayEndpoint);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
.reply(200, {
alipay_system_oauth_token_response: {
user_id: '2088000000000000',
access_token: 'access_token',
expires_in: '3600',
refresh_token: 'refresh_token',
re_expires_in: '7200', // Expiring time of refresh token, in seconds
},
sign: '<signature>',
});
.mockResolvedValue(mockedAlipayNativeConfigWithValidPrivateKey);
jest
.spyOn(alipayNativeMethods, 'getAccessToken')
.mockResolvedValue({ accessToken: 'access_token' });
});
afterEach(() => {
@ -153,9 +137,6 @@ describe('getUserInfo', () => {
const alipayEndpointUrl = new URL(alipayEndpoint);
it('should get userInfo with accessToken', async () => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -177,9 +158,6 @@ describe('getUserInfo', () => {
});
it('should throw with wrong accessToken', async () => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -198,9 +176,6 @@ describe('getUserInfo', () => {
});
it('should throw General error with other response error codes', async () => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -219,9 +194,6 @@ describe('getUserInfo', () => {
});
it('should throw with right accessToken but empty userInfo', async () => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -242,9 +214,6 @@ describe('getUserInfo', () => {
});
it('should throw with other request errors', async () => {
jest
.spyOn(alipayNativeMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayNativeConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin).post(alipayEndpointUrl.pathname).query(true).reply(500);
await expect(alipayNativeMethods.getUserInfo({ auth_code: 'wrong_code' })).rejects.toThrow();

View file

@ -29,6 +29,7 @@ import {
methodForUserInfo,
defaultMetadata,
defaultTimeout,
timestampFormat,
} from './constant';
import {
alipayNativeConfigGuard,
@ -65,12 +66,11 @@ export default class AlipayNativeConnector implements SocialConnector {
return `${authorizationEndpoint}?${queryParameters.toString()}`;
};
public getAccessToken = async (code: string) => {
const config = await this.getConfig(this.metadata.id);
public getAccessToken = async (code: string, config: AlipayNativeConfig) => {
const initSearchParameters = {
method: methodForAccessToken,
format: 'JSON',
timestamp: dayjs().format('YYYY-MM-DD HH:mm:ss'),
timestamp: dayjs().format(timestampFormat),
version: '1.0',
grant_type: 'authorization_code',
code,
@ -101,7 +101,8 @@ export default class AlipayNativeConnector implements SocialConnector {
public getUserInfo: GetUserInfo = async (data) => {
const { auth_code } = dataGuard.parse(data);
const config = await this.getConfig(this.metadata.id);
const { accessToken } = await this.getAccessToken(auth_code);
const { accessToken } = await this.getAccessToken(auth_code, config);
assert(
accessToken && config,
new ConnectorError(ConnectorErrorCodes.InsufficientRequestParameters)
@ -110,7 +111,7 @@ export default class AlipayNativeConnector implements SocialConnector {
const initSearchParameters = {
method: methodForUserInfo,
format: 'JSON',
timestamp: dayjs().format('YYYY-MM-DD HH:mm:ss'),
timestamp: dayjs().format(timestampFormat),
version: '1.0',
grant_type: 'authorization_code',
auth_token: accessToken,

View file

@ -41,3 +41,5 @@ export const defaultMetadata: ConnectorMetadata = {
};
export const defaultTimeout = 5000;
export const timestampFormat = 'YYYY-MM-DD HH:mm:ss';

View file

@ -56,9 +56,6 @@ describe('getAccessToken', () => {
const alipayEndpointUrl = new URL(alipayEndpoint);
it('should get an accessToken by exchanging with code', async () => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -73,15 +70,15 @@ describe('getAccessToken', () => {
sign: '<signature>',
});
const response = await alipayMethods.getAccessToken('code');
const response = await alipayMethods.getAccessToken(
'code',
mockedAlipayConfigWithValidPrivateKey
);
const { accessToken } = response;
expect(accessToken).toEqual('access_token');
});
it('should throw when accessToken is empty', async () => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -96,15 +93,12 @@ describe('getAccessToken', () => {
sign: '<signature>',
});
await expect(alipayMethods.getAccessToken('code')).rejects.toMatchError(
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)
);
await expect(
alipayMethods.getAccessToken('code', mockedAlipayConfigWithValidPrivateKey)
).rejects.toMatchError(new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid));
});
it('should fail with wrong code', async () => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -117,7 +111,9 @@ describe('getAccessToken', () => {
sign: '<signature>',
});
await expect(alipayMethods.getAccessToken('wrong_code')).rejects.toMatchError(
await expect(
alipayMethods.getAccessToken('wrong_code', mockedAlipayConfigWithValidPrivateKey)
).rejects.toMatchError(
new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid, 'Invalid code')
);
});
@ -125,24 +121,8 @@ describe('getAccessToken', () => {
describe('getUserInfo', () => {
beforeEach(() => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
const alipayEndpointUrl = new URL(alipayEndpoint);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
.reply(200, {
alipay_system_oauth_token_response: {
user_id: '2088000000000000',
access_token: 'access_token',
expires_in: '3600',
refresh_token: 'refresh_token',
re_expires_in: '7200', // Expiring time of refresh token, in seconds
},
sign: '<signature>',
});
jest.spyOn(alipayMethods, 'getConfig').mockResolvedValue(mockedAlipayConfigWithValidPrivateKey);
jest.spyOn(alipayMethods, 'getAccessToken').mockResolvedValue({ accessToken: 'access_token' });
});
afterEach(() => {
@ -153,9 +133,6 @@ describe('getUserInfo', () => {
const alipayEndpointUrl = new URL(alipayEndpoint);
it('should get userInfo with accessToken', async () => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -177,9 +154,6 @@ describe('getUserInfo', () => {
});
it('should throw with wrong accessToken', async () => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -198,9 +172,6 @@ describe('getUserInfo', () => {
});
it('should throw General error with other response error codes', async () => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -219,9 +190,6 @@ describe('getUserInfo', () => {
});
it('should throw with right accessToken but empty userInfo', async () => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin)
.post(alipayEndpointUrl.pathname)
.query(true)
@ -242,9 +210,6 @@ describe('getUserInfo', () => {
});
it('should throw with other request errors', async () => {
jest
.spyOn(alipayMethods, 'getConfig')
.mockResolvedValueOnce(mockedAlipayConfigWithValidPrivateKey);
nock(alipayEndpointUrl.origin).post(alipayEndpointUrl.pathname).query(true).reply(500);
await expect(alipayMethods.getUserInfo({ code: 'code' })).rejects.toThrow();

View file

@ -28,6 +28,7 @@ import {
scope,
defaultMetadata,
defaultTimeout,
timestampFormat,
} from './constant';
import { alipayConfigGuard, AlipayConfig, AccessTokenResponse, UserInfoResponse } from './types';
import { signingParameters } from './utils';
@ -78,12 +79,11 @@ export default class AlipayConnector implements SocialConnector {
return `${authorizationEndpoint}?${queryParameters.toString()}`;
};
public getAccessToken = async (code: string) => {
const config = await this.getConfig(this.metadata.id);
public getAccessToken = async (code: string, config: AlipayConfig) => {
const initSearchParameters = {
method: methodForAccessToken,
format: 'JSON',
timestamp: this.getTimestamp(),
timestamp: dayjs().format(timestampFormat),
version: '1.0',
grant_type: 'authorization_code',
code: parseCodeFromJson(code),
@ -114,7 +114,7 @@ export default class AlipayConnector implements SocialConnector {
public getUserInfo: GetUserInfo = async (data) => {
const { code } = codeDataGuard.parse(data);
const config = await this.getConfig(this.metadata.id);
const { accessToken } = await this.getAccessToken(code);
const { accessToken } = await this.getAccessToken(code, config);
assert(
accessToken && config,
@ -124,7 +124,7 @@ export default class AlipayConnector implements SocialConnector {
const initSearchParameters = {
method: methodForUserInfo,
format: 'JSON',
timestamp: this.getTimestamp(),
timestamp: dayjs().format(timestampFormat),
version: '1.0',
grant_type: 'authorization_code',
auth_token: accessToken,
@ -163,6 +163,4 @@ export default class AlipayConnector implements SocialConnector {
return { id, avatar, name };
};
private readonly getTimestamp = (): string => dayjs().format('YYYY-MM-DD HH:mm:ss');
}