diff --git a/packages/connector-wechat-native/src/index.test.ts b/packages/connector-wechat-native/src/index.test.ts index 827673cfe..8e023f1f5 100644 --- a/packages/connector-wechat-native/src/index.test.ts +++ b/packages/connector-wechat-native/src/index.test.ts @@ -57,15 +57,25 @@ describe('getAccessToken', () => { expect(openid).toEqual('openid'); }); - it('throws SocialAuthCodeInvalid error if accessToken not found in response', async () => { + it('throws SocialAuthCodeInvalid error if errcode is 40029', async () => { nock(accessTokenEndpointUrl.origin) .get(accessTokenEndpointUrl.pathname) .query(parameters) - .reply(200, {}); + .reply(200, { errcode: 40_029, errmsg: 'invalid code' }); await expect(weChatNativeMethods.getAccessToken('code')).rejects.toMatchError( new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid) ); }); + + it('throws error if errcode is neither 40029 nor undefined', async () => { + nock(accessTokenEndpointUrl.origin) + .get(accessTokenEndpointUrl.pathname) + .query(true) + .reply(200, { errcode: 40_163, errmsg: 'invalid code' }); + await expect(weChatNativeMethods.getAccessToken('wrong_code')).rejects.toMatchError( + new Error('invalid code') + ); + }); }); describe('validateConfig', () => { @@ -140,15 +150,16 @@ describe('getUserInfo', () => { }); it('throws error if `openid` is missing', async () => { - nock.cleanAll(); - nock(userInfoEndpointUrl.origin).get(userInfoEndpointUrl.pathname).query(parameters).reply(0, { - unionid: 'this_is_an_arbitrary_wechat_union_id', - headimgurl: 'https://github.com/images/error/octocat_happy.gif', - nickname: 'wechat bot', - }); nockNoOpenIdAccessTokenResponse(); + nock(userInfoEndpointUrl.origin) + .get(userInfoEndpointUrl.pathname) + .query(parameters) + .reply(200, { + errcode: 41_009, + errmsg: 'missing openid', + }); await expect(weChatNativeMethods.getUserInfo({ code: 'code' })).rejects.toMatchError( - new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid) + new Error('missing openid') ); }); @@ -156,7 +167,7 @@ describe('getUserInfo', () => { nock(userInfoEndpointUrl.origin) .get(userInfoEndpointUrl.pathname) .query(parameters) - .reply(200, { errcode: 40_001 }); + .reply(200, { errcode: 40_001, errmsg: 'invalid credential' }); await expect(weChatNativeMethods.getUserInfo({ code: 'code' })).rejects.toMatchError( new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid) ); diff --git a/packages/connector-wechat-native/src/index.ts b/packages/connector-wechat-native/src/index.ts index c23bcccf8..c8c11fcfd 100644 --- a/packages/connector-wechat-native/src/index.ts +++ b/packages/connector-wechat-native/src/index.ts @@ -31,9 +31,6 @@ import { WeChatNativeConfig, } from './types'; -// As creating a WeChat Web/Mobile application needs a real App or Website record, the real test is temporarily not finished. -// TODO: test with our own wechat mobile/web application (LOG-1910), already tested with other verified wechat web application - export default class WeChatNativeConnector implements SocialConnector { public metadata: ConnectorMetadata = defaultMetadata; @@ -68,6 +65,7 @@ export default class WeChatNativeConnector implements SocialConnector { access_token: accessToken, openid, errcode, + errmsg, } = await got .get(accessTokenEndpoint, { searchParams: { appid, secret, code, grant_type: 'authorization_code' }, @@ -75,10 +73,8 @@ export default class WeChatNativeConnector implements SocialConnector { }) .json(); - assert( - errcode !== 40_029 && accessToken && openid, - new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid) - ); + assert(errcode !== 40_029, new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)); + assert(!errcode && accessToken && openid, new Error(errmsg ?? '')); return { accessToken, openid }; }; @@ -87,15 +83,6 @@ export default class WeChatNativeConnector implements SocialConnector { const { code } = codeDataGuard.parse(data); const { accessToken, openid } = await this.getAccessToken(code); - // TO-DO: @Darcy refactor this - // 'openid' is defined as a required input argument in WeChat API doc, but it does not necessarily have to - // be the return value from getAccessToken per testing. - // In other words, 'openid' is required but the response of getUserInfo is consistent as long as - // access_token is valid. - // We are expecting to get 41009 'missing openid' response according to the developers doc, but the - // fact is that we still got 40001 'invalid credentials' response. - assert(openid, new Error('`openid` is required by WeChat API.')); - try { const { unionid, headimgurl, nickname, errcode, errmsg } = await got .get(userInfoEndpoint, { diff --git a/packages/connector-wechat-native/src/types.ts b/packages/connector-wechat-native/src/types.ts index fec54ed7f..55412d6ac 100644 --- a/packages/connector-wechat-native/src/types.ts +++ b/packages/connector-wechat-native/src/types.ts @@ -15,6 +15,7 @@ export type AccessTokenResponse = { refresh_token?: string; scope?: string; errcode?: number; + errmsg?: string; }; export type UserInfoResponse = { diff --git a/packages/connector-wechat/src/index.test.ts b/packages/connector-wechat/src/index.test.ts index d9630f533..72c19892f 100644 --- a/packages/connector-wechat/src/index.test.ts +++ b/packages/connector-wechat/src/index.test.ts @@ -57,15 +57,25 @@ describe('getAccessToken', () => { expect(openid).toEqual('openid'); }); - it('throws SocialAuthCodeInvalid error if accessToken not found in response', async () => { + it('throws SocialAuthCodeInvalid error if errcode is 40029', async () => { nock(accessTokenEndpointUrl.origin) .get(accessTokenEndpointUrl.pathname) .query(parameters) - .reply(200, {}); + .reply(200, { errcode: 40_029, errmsg: 'invalid code' }); await expect(weChatMethods.getAccessToken('code')).rejects.toMatchError( new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid) ); }); + + it('throws error if errcode is neither 40029 nor undefined', async () => { + nock(accessTokenEndpointUrl.origin) + .get(accessTokenEndpointUrl.pathname) + .query(true) + .reply(200, { errcode: 40_163, errmsg: 'invalid code' }); + await expect(weChatMethods.getAccessToken('wrong_code')).rejects.toMatchError( + new Error('invalid code') + ); + }); }); describe('validateConfig', () => { @@ -84,18 +94,9 @@ describe('validateConfig', () => { const nockNoOpenIdAccessTokenResponse = () => { const accessTokenEndpointUrl = new URL(accessTokenEndpoint); - const parameters = new URLSearchParams({ - appid: '', - secret: '', - code: 'code', - grant_type: 'authorization_code', + nock(accessTokenEndpointUrl.origin).get(accessTokenEndpointUrl.pathname).query(true).reply(200, { + access_token: 'access_token', }); - nock(accessTokenEndpointUrl.origin) - .get(accessTokenEndpointUrl.pathname) - .query(parameters) - .reply(200, { - access_token: 'access_token', - }); }; describe('getUserInfo', () => { @@ -107,6 +108,7 @@ describe('getUserInfo', () => { code: 'code', grant_type: 'authorization_code', }); + nock(accessTokenEndpointUrl.origin) .get(accessTokenEndpointUrl.pathname) .query(parameters) @@ -141,15 +143,16 @@ describe('getUserInfo', () => { }); it('throws error if `openid` is missing', async () => { - nock.cleanAll(); - nock(userInfoEndpointUrl.origin).get(userInfoEndpointUrl.pathname).query(parameters).reply(0, { - unionid: 'this_is_an_arbitrary_wechat_union_id', - headimgurl: 'https://github.com/images/error/octocat_happy.gif', - nickname: 'wechat bot', - }); nockNoOpenIdAccessTokenResponse(); + nock(userInfoEndpointUrl.origin) + .get(userInfoEndpointUrl.pathname) + .query(parameters) + .reply(200, { + errcode: 41_009, + errmsg: 'missing openid', + }); await expect(weChatMethods.getUserInfo({ code: 'code' })).rejects.toMatchError( - new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid) + new Error('missing openid') ); }); @@ -157,7 +160,7 @@ describe('getUserInfo', () => { nock(userInfoEndpointUrl.origin) .get(userInfoEndpointUrl.pathname) .query(parameters) - .reply(200, { errcode: 40_001 }); + .reply(200, { errcode: 40_001, errmsg: 'invalid credential' }); await expect(weChatMethods.getUserInfo({ code: 'code' })).rejects.toMatchError( new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid) ); diff --git a/packages/connector-wechat/src/index.ts b/packages/connector-wechat/src/index.ts index 51012a0c5..9564833dd 100644 --- a/packages/connector-wechat/src/index.ts +++ b/packages/connector-wechat/src/index.ts @@ -28,7 +28,7 @@ import { import { weChatConfigGuard, AccessTokenResponse, UserInfoResponse, WeChatConfig } from './types'; // As creating a WeChat Web/Mobile application needs a real App or Website record, the real test is temporarily not finished. -// TODO: test with our own wechat mobile/web application (LOG-1910), already tested with other verified wechat web application +// TODO: test with our own WeChat web application (LOG-2719), already tested with other verified WeChat web application export default class WeChatConnector implements SocialConnector { public metadata: ConnectorMetadata = defaultMetadata; @@ -64,6 +64,7 @@ export default class WeChatConnector implements SocialConnector { access_token: accessToken, openid, errcode, + errmsg, } = await got .get(accessTokenEndpoint, { searchParams: { appid, secret, code, grant_type: 'authorization_code' }, @@ -71,10 +72,8 @@ export default class WeChatConnector implements SocialConnector { }) .json(); - assert( - errcode !== 40_029 && accessToken && openid, - new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid) - ); + assert(errcode !== 40_029, new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid)); + assert(!errcode && accessToken && openid, new Error(errmsg ?? '')); return { accessToken, openid }; }; @@ -83,15 +82,6 @@ export default class WeChatConnector implements SocialConnector { const { code } = codeDataGuard.parse(data); const { accessToken, openid } = await this.getAccessToken(code); - // TO-DO: @Darcy refactor this - // 'openid' is defined as a required input argument in WeChat API doc, but it does not necessarily have to - // be the return value from getAccessToken per testing. - // In other words, 'openid' is required but the response of getUserInfo is consistent as long as - // access_token is valid. - // We are expecting to get 41009 'missing openid' response according to the developers doc, but the - // fact is that we still got 40001 'invalid credentials' response. - assert(openid, new Error('`openid` is required by WeChat API.')); - try { const { unionid, headimgurl, nickname, errcode, errmsg } = await got .get(userInfoEndpoint, { @@ -105,7 +95,7 @@ export default class WeChatConnector implements SocialConnector { // 'errmsg' and 'errcode' turn to non-empty values or empty values at the same time. Hence, if 'errmsg' is non-empty then 'errcode' should be non-empty. assert(errcode !== 40_001, new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid)); - assert(!errcode, new Error(errmsg)); + assert(!errcode, new Error(errmsg ?? '')); return { id: unionid ?? openid, avatar: headimgurl, name: nickname }; } catch (error: unknown) { diff --git a/packages/connector-wechat/src/types.ts b/packages/connector-wechat/src/types.ts index ef41cbaa6..ce1858489 100644 --- a/packages/connector-wechat/src/types.ts +++ b/packages/connector-wechat/src/types.ts @@ -11,6 +11,7 @@ export type AccessTokenResponse = { refresh_token?: string; scope?: string; errcode?: number; + errmsg?: string; }; export type UserInfoResponse = {