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:
parent
7781d49667
commit
9f68a7a124
6 changed files with 41 additions and 104 deletions
|
@ -40,3 +40,5 @@ export const defaultMetadata: ConnectorMetadata = {
|
|||
};
|
||||
|
||||
export const defaultTimeout = 5000;
|
||||
|
||||
export const timestampFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -41,3 +41,5 @@ export const defaultMetadata: ConnectorMetadata = {
|
|||
};
|
||||
|
||||
export const defaultTimeout = 5000;
|
||||
|
||||
export const timestampFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue