@zohodesk/testinglibrary 0.0.64-n20-experimental → 0.0.66-n20-experimental
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/common/data-generator/steps/DataGenerator.spec.js +8 -4
- package/build/common/data-generator/steps/DataGeneratorStepsHelper.js +2 -2
- package/build/core/dataGenerator/DataGenerator.js +9 -4
- package/build/core/dataGenerator/authenticator/Authenticator.js +35 -0
- package/build/core/dataGenerator/authenticator/CookieAuthenticator.js +41 -0
- package/build/core/dataGenerator/authenticator/JWTauthenticator.js +71 -0
- package/build/core/dataGenerator/authenticator/OAuthAuthenticator.js +31 -0
- package/build/core/dataGenerator/authenticator/OrgOAuthAuthenticator.js +29 -0
- package/build/core/playwright/builtInFixtures/context.js +3 -33
- package/build/core/playwright/readConfigFile.js +1 -3
- package/build/core/playwright/runner/SpawnRunner.js +1 -1
- package/build/core/playwright/setup/custom-reporter.js +1 -87
- package/build/test/core/dataGenerator/authenticator/__test__/Authenticator.test.js +89 -0
- package/build/test/core/dataGenerator/authenticator/__test__/JWTauthenticator.test.js +134 -0
- package/build/test/core/dataGenerator/authenticator/__test__/OAuthAuthenticator.test.js +46 -0
- package/build/test/core/dataGenerator/authenticator/__test__/OrgOAuthAuthenticator.test.js +46 -0
- package/build/test/core/dataGenerator/authenticator/__tests__/JWTauthenticator.test.js +165 -0
- package/jest.config.js +1 -1
- package/npm-shrinkwrap.json +2419 -1360
- package/package.json +1 -1
- package/unit_reports/unit-report.html +277 -0
- package/build/core/playwright/helpers/logCollector.js +0 -154
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _JWTauthenticator = _interopRequireDefault(require("../../../../../../src/core/dataGenerator/authenticator/JWTauthenticator"));
|
|
5
|
+
describe('JWTauthenticator', () => {
|
|
6
|
+
let fetchMock;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
fetchMock = jest.fn();
|
|
9
|
+
global.fetch = fetchMock;
|
|
10
|
+
process.env.DG_JWT_AUTH_URL = 'https://jwt-auth.example.com';
|
|
11
|
+
process.env.DG_JWT_TOKEN_URL = 'https://token.example.com/{ZSOID}/oauth';
|
|
12
|
+
process.env.DG_DOMAIN_URL = 'https://domain.example.com';
|
|
13
|
+
process.env.DG_JWT_AUTHENTICATOR_API = 'https://authenticator.example.com/jwtToken';
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
delete global.fetch;
|
|
17
|
+
delete process.env.DG_JWT_AUTH_URL;
|
|
18
|
+
delete process.env.DG_JWT_TOKEN_URL;
|
|
19
|
+
delete process.env.DG_DOMAIN_URL;
|
|
20
|
+
delete process.env.DG_JWT_AUTHENTICATOR_API;
|
|
21
|
+
});
|
|
22
|
+
it('should return unchanged payload when jwt config is missing', async () => {
|
|
23
|
+
const jwtAuthenticator = new _JWTauthenticator.default();
|
|
24
|
+
const apiPayload = {
|
|
25
|
+
account: {}
|
|
26
|
+
};
|
|
27
|
+
const actorInfo = {
|
|
28
|
+
email: 'user@example.com',
|
|
29
|
+
'data-generator': {
|
|
30
|
+
account: {}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const result = await jwtAuthenticator.constructPayload(apiPayload, actorInfo);
|
|
34
|
+
expect(result).toEqual(apiPayload);
|
|
35
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
36
|
+
});
|
|
37
|
+
it('should fetch jwt access token and attach it to payload', async () => {
|
|
38
|
+
fetchMock.mockResolvedValue({
|
|
39
|
+
ok: true,
|
|
40
|
+
json: async () => ({
|
|
41
|
+
access_token: 'access-token-123'
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
const jwtAuthenticator = new _JWTauthenticator.default();
|
|
45
|
+
const apiPayload = {
|
|
46
|
+
account: {}
|
|
47
|
+
};
|
|
48
|
+
const actorInfo = {
|
|
49
|
+
email: 'user.one@example.com',
|
|
50
|
+
'data-generator': {
|
|
51
|
+
account: {
|
|
52
|
+
jwt: {
|
|
53
|
+
jwt_secret: 'jwt-secret',
|
|
54
|
+
response_type: 'token',
|
|
55
|
+
client_id: '12345.client-id'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const result = await jwtAuthenticator.constructPayload(apiPayload, actorInfo);
|
|
61
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
62
|
+
expect(fetchMock).toHaveBeenCalledWith('https://authenticator.example.com/jwtToken', expect.objectContaining({
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: {
|
|
65
|
+
'Content-Type': 'application/json'
|
|
66
|
+
}
|
|
67
|
+
}));
|
|
68
|
+
const requestBody = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
69
|
+
expect(requestBody).toEqual(expect.objectContaining({
|
|
70
|
+
user_token: encodeURIComponent('user.one@example.com'),
|
|
71
|
+
jwt_secret: 'jwt-secret',
|
|
72
|
+
jwt_auth_url: 'https://jwt-auth.example.com',
|
|
73
|
+
response_type: 'token',
|
|
74
|
+
client_id: '12345.client-id',
|
|
75
|
+
token_url: 'https://token.example.com/12345/oauth',
|
|
76
|
+
domain_url: 'https://domain.example.com'
|
|
77
|
+
}));
|
|
78
|
+
expect(result.account.jwt).toEqual(expect.objectContaining({
|
|
79
|
+
jwt_secret: 'jwt-secret',
|
|
80
|
+
response_type: 'token',
|
|
81
|
+
client_id: '12345.client-id',
|
|
82
|
+
access_token: 'access-token-123'
|
|
83
|
+
}));
|
|
84
|
+
});
|
|
85
|
+
it('should throw a descriptive error when authenticator API returns non-ok response', async () => {
|
|
86
|
+
fetchMock.mockResolvedValue({
|
|
87
|
+
ok: false,
|
|
88
|
+
status: 500,
|
|
89
|
+
text: async () => 'internal error'
|
|
90
|
+
});
|
|
91
|
+
const jwtAuthenticator = new _JWTauthenticator.default();
|
|
92
|
+
const apiPayload = {
|
|
93
|
+
account: {}
|
|
94
|
+
};
|
|
95
|
+
const actorInfo = {
|
|
96
|
+
email: 'user@example.com',
|
|
97
|
+
'data-generator': {
|
|
98
|
+
account: {
|
|
99
|
+
jwt: {
|
|
100
|
+
jwt_secret: 'jwt-secret',
|
|
101
|
+
response_type: 'token',
|
|
102
|
+
client_id: '12345.client-id'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
await expect(jwtAuthenticator.constructPayload(apiPayload, actorInfo)).rejects.toThrow('JWT authenticator error! status: 500, body: internal error');
|
|
108
|
+
});
|
|
109
|
+
it('should throw when authenticator response has no access_token', async () => {
|
|
110
|
+
fetchMock.mockResolvedValue({
|
|
111
|
+
ok: true,
|
|
112
|
+
json: async () => ({
|
|
113
|
+
token_type: 'Bearer'
|
|
114
|
+
})
|
|
115
|
+
});
|
|
116
|
+
const jwtAuthenticator = new _JWTauthenticator.default();
|
|
117
|
+
const apiPayload = {
|
|
118
|
+
account: {}
|
|
119
|
+
};
|
|
120
|
+
const actorInfo = {
|
|
121
|
+
email: 'user@example.com',
|
|
122
|
+
'data-generator': {
|
|
123
|
+
account: {
|
|
124
|
+
jwt: {
|
|
125
|
+
jwt_secret: 'jwt-secret',
|
|
126
|
+
response_type: 'token',
|
|
127
|
+
client_id: '12345.client-id'
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
await expect(jwtAuthenticator.constructPayload(apiPayload, actorInfo)).rejects.toThrow('JWT authenticator did not return access_token');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _OAuthAuthenticator = _interopRequireDefault(require("../../../../../../src/core/dataGenerator/authenticator/OAuthAuthenticator"));
|
|
5
|
+
describe('OAuthAuthenticator', () => {
|
|
6
|
+
it('should merge oauth2 from actor info into payload account', async () => {
|
|
7
|
+
const oauthAuthenticator = new _OAuthAuthenticator.default();
|
|
8
|
+
const apiPayload = {
|
|
9
|
+
account: {
|
|
10
|
+
oauth2: {
|
|
11
|
+
existing_key: 'existing-value'
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const actorInfo = {
|
|
16
|
+
'data-generator': {
|
|
17
|
+
account: {
|
|
18
|
+
oauth2: {
|
|
19
|
+
client_id: 'new-client',
|
|
20
|
+
scope: 'tickets.read'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const result = await oauthAuthenticator.constructPayload(apiPayload, actorInfo);
|
|
26
|
+
expect(result.account.oauth2).toEqual({
|
|
27
|
+
existing_key: 'existing-value',
|
|
28
|
+
client_id: 'new-client',
|
|
29
|
+
scope: 'tickets.read'
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
it('should initialize account when missing and keep payload unchanged if oauth2 is absent', async () => {
|
|
33
|
+
const oauthAuthenticator = new _OAuthAuthenticator.default();
|
|
34
|
+
const apiPayload = {};
|
|
35
|
+
const actorInfo = {
|
|
36
|
+
'data-generator': {
|
|
37
|
+
account: {}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const result = await oauthAuthenticator.constructPayload(apiPayload, actorInfo);
|
|
41
|
+
expect(result).toEqual({
|
|
42
|
+
account: {}
|
|
43
|
+
});
|
|
44
|
+
expect(result.account.oauth2).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _OrgOAuthAuthenticator = _interopRequireDefault(require("../../../../../../src/core/dataGenerator/authenticator/OrgOAuthAuthenticator"));
|
|
5
|
+
describe('OrgOAuthAuthenticator', () => {
|
|
6
|
+
it('should merge org_oauth from actor info into payload account', async () => {
|
|
7
|
+
const orgOAuthAuthenticator = new _OrgOAuthAuthenticator.default();
|
|
8
|
+
const apiPayload = {
|
|
9
|
+
account: {
|
|
10
|
+
org_oauth: {
|
|
11
|
+
existing_key: 'existing-value'
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const actorInfo = {
|
|
16
|
+
'data-generator': {
|
|
17
|
+
account: {
|
|
18
|
+
org_oauth: {
|
|
19
|
+
org_id: 'org-1001',
|
|
20
|
+
region: 'us'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const result = await orgOAuthAuthenticator.constructPayload(apiPayload, actorInfo);
|
|
26
|
+
expect(result.account.org_oauth).toEqual({
|
|
27
|
+
existing_key: 'existing-value',
|
|
28
|
+
org_id: 'org-1001',
|
|
29
|
+
region: 'us'
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
it('should initialize account when missing and keep payload unchanged if org_oauth is absent', async () => {
|
|
33
|
+
const orgOAuthAuthenticator = new _OrgOAuthAuthenticator.default();
|
|
34
|
+
const apiPayload = {};
|
|
35
|
+
const actorInfo = {
|
|
36
|
+
'data-generator': {
|
|
37
|
+
account: {}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const result = await orgOAuthAuthenticator.constructPayload(apiPayload, actorInfo);
|
|
41
|
+
expect(result).toEqual({
|
|
42
|
+
account: {}
|
|
43
|
+
});
|
|
44
|
+
expect(result.account.org_oauth).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _JWTauthenticator = _interopRequireDefault(require("../../../../../core/dataGenerator/authenticator/JWTauthenticator.js"));
|
|
5
|
+
const MOCK_ACCESS_TOKEN = '1026812030.abc123.def456';
|
|
6
|
+
const makeActorInfo = (overrides = {}) => ({
|
|
7
|
+
email: 'anitha.m+uatagent@zohotest.com',
|
|
8
|
+
'data-generator': {
|
|
9
|
+
account: {
|
|
10
|
+
authentications: ['jwt-auth'],
|
|
11
|
+
'jwt-oauth': {
|
|
12
|
+
jwt_secret: 'PZkhUzx0ruJQNU4QRagh0u13uuKk9s0m5EU1pUbD',
|
|
13
|
+
response_type: 'remote_token',
|
|
14
|
+
client_id: '1026812030.WKK443JMM12S4ZVR23C3HUK66PFUSG',
|
|
15
|
+
token_url: 'https://accounts-portal.csez.zohocorpin.com/clientoauth/v2/1026812030/remote/auth',
|
|
16
|
+
domain_url: 'https://zdesk-devops08.csez.zohocorpin.com:31000'
|
|
17
|
+
},
|
|
18
|
+
...overrides
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const makeApiPayload = (overrides = {}) => ({
|
|
23
|
+
scenario_name: 'verify the Department page is loaded',
|
|
24
|
+
account: {
|
|
25
|
+
storeVariables: {
|
|
26
|
+
orgId: '20408511'
|
|
27
|
+
},
|
|
28
|
+
authentications: ['jwt-auth']
|
|
29
|
+
},
|
|
30
|
+
...overrides
|
|
31
|
+
});
|
|
32
|
+
const mockFetchSuccess = () => {
|
|
33
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
34
|
+
ok: true,
|
|
35
|
+
json: jest.fn().mockResolvedValue({
|
|
36
|
+
access_token: MOCK_ACCESS_TOKEN
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
describe('JWTauthenticator.constructPayload', () => {
|
|
41
|
+
let authenticator;
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
authenticator = new _JWTauthenticator.default();
|
|
44
|
+
process.env.DG_JWT_AUTHENTICATOR_API = 'https://authenticator.zdesk.csez.zohocorpin.com/jwtToken';
|
|
45
|
+
process.env.DG_JWT_AUTH_URL = 'https://jwt.zdesk.csez.zohocorpin.com/JWTAuth';
|
|
46
|
+
delete process.env.DG_JWT_TOKEN_URL;
|
|
47
|
+
delete process.env.DG_DOMAIN_URL;
|
|
48
|
+
jest.clearAllMocks();
|
|
49
|
+
});
|
|
50
|
+
describe('no-op cases', () => {
|
|
51
|
+
it('returns apiPayload unchanged when jwt-oauth config is absent in actorInfo', async () => {
|
|
52
|
+
const actorInfo = {
|
|
53
|
+
email: 'anitha.m+uatagent@zohotest.com',
|
|
54
|
+
'data-generator': {
|
|
55
|
+
account: {
|
|
56
|
+
authentications: ['jwt-auth']
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const apiPayload = makeApiPayload();
|
|
61
|
+
const result = await authenticator.constructPayload(apiPayload, actorInfo);
|
|
62
|
+
expect(result).toBe(apiPayload);
|
|
63
|
+
expect(result.account.authHeaders).toBeUndefined();
|
|
64
|
+
});
|
|
65
|
+
it('returns apiPayload unchanged when actorInfo has no data-generator', async () => {
|
|
66
|
+
const apiPayload = makeApiPayload();
|
|
67
|
+
const result = await authenticator.constructPayload(apiPayload, {});
|
|
68
|
+
expect(result).toBe(apiPayload);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('successful token fetch', () => {
|
|
72
|
+
it('sets authHeaders.Authorization with Zoho-oauthtoken prefix', async () => {
|
|
73
|
+
mockFetchSuccess();
|
|
74
|
+
const result = await authenticator.constructPayload(makeApiPayload(), makeActorInfo());
|
|
75
|
+
expect(result.account.authHeaders.Authorization).toBe(`Zoho-oauthtoken ${MOCK_ACCESS_TOKEN}`);
|
|
76
|
+
});
|
|
77
|
+
it('URL-encodes email with + and @ characters as user_token', async () => {
|
|
78
|
+
mockFetchSuccess();
|
|
79
|
+
await authenticator.constructPayload(makeApiPayload(), makeActorInfo());
|
|
80
|
+
const body = JSON.parse(global.fetch.mock.calls[0][1].body);
|
|
81
|
+
expect(body.user_token).toBe('anitha.m%2Buatagent%40zohotest.com');
|
|
82
|
+
});
|
|
83
|
+
it('posts to DG_JWT_AUTHENTICATOR_API with correct payload fields', async () => {
|
|
84
|
+
mockFetchSuccess();
|
|
85
|
+
await authenticator.constructPayload(makeApiPayload(), makeActorInfo());
|
|
86
|
+
const [url, options] = global.fetch.mock.calls[0];
|
|
87
|
+
const body = JSON.parse(options.body);
|
|
88
|
+
expect(url).toBe(process.env.DG_JWT_AUTHENTICATOR_API);
|
|
89
|
+
expect(options.method).toBe('POST');
|
|
90
|
+
expect(options.headers['Content-Type']).toBe('application/json');
|
|
91
|
+
expect(body.jwt_secret).toBe('PZkhUzx0ruJQNU4QRagh0u13uuKk9s0m5EU1pUbD');
|
|
92
|
+
expect(body.response_type).toBe('remote_token');
|
|
93
|
+
expect(body.client_id).toBe('1026812030.WKK443JMM12S4ZVR23C3HUK66PFUSG');
|
|
94
|
+
expect(body.jwt_auth_url).toBe(process.env.DG_JWT_AUTH_URL);
|
|
95
|
+
expect(body.token_url).toBe('https://accounts-portal.csez.zohocorpin.com/clientoauth/v2/1026812030/remote/auth');
|
|
96
|
+
expect(body.domain_url).toBe('https://zdesk-devops08.csez.zohocorpin.com:31000');
|
|
97
|
+
});
|
|
98
|
+
it('does not overwrite existing authHeaders fields other than Authorization', async () => {
|
|
99
|
+
mockFetchSuccess();
|
|
100
|
+
const apiPayload = makeApiPayload();
|
|
101
|
+
apiPayload.account.authHeaders = {
|
|
102
|
+
'X-Custom-Header': 'custom-value'
|
|
103
|
+
};
|
|
104
|
+
const result = await authenticator.constructPayload(apiPayload, makeActorInfo());
|
|
105
|
+
expect(result.account.authHeaders['X-Custom-Header']).toBe('custom-value');
|
|
106
|
+
expect(result.account.authHeaders.Authorization).toBe(`Zoho-oauthtoken ${MOCK_ACCESS_TOKEN}`);
|
|
107
|
+
});
|
|
108
|
+
it('resolves token_url from DG_JWT_TOKEN_URL env when not in config', async () => {
|
|
109
|
+
mockFetchSuccess();
|
|
110
|
+
process.env.DG_JWT_TOKEN_URL = 'https://accounts-portal.csez.zohocorpin.com/clientoauth/v2/{ZSOID}/remote/auth';
|
|
111
|
+
const actorInfo = makeActorInfo({
|
|
112
|
+
'jwt-oauth': {
|
|
113
|
+
...makeActorInfo()['data-generator'].account['jwt-oauth'],
|
|
114
|
+
token_url: undefined
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
await authenticator.constructPayload(makeApiPayload(), actorInfo);
|
|
118
|
+
const body = JSON.parse(global.fetch.mock.calls[0][1].body);
|
|
119
|
+
expect(body.token_url).toBe('https://accounts-portal.csez.zohocorpin.com/clientoauth/v2/1026812030/remote/auth');
|
|
120
|
+
});
|
|
121
|
+
it('resolves domain_url from DG_DOMAIN_URL env when not in config', async () => {
|
|
122
|
+
mockFetchSuccess();
|
|
123
|
+
process.env.DG_DOMAIN_URL = 'https://zdesk-env-domain.csez.zohocorpin.com:31000';
|
|
124
|
+
const jwtOauth = {
|
|
125
|
+
...makeActorInfo()['data-generator'].account['jwt-oauth'],
|
|
126
|
+
domain_url: undefined
|
|
127
|
+
};
|
|
128
|
+
const actorInfo = {
|
|
129
|
+
...makeActorInfo(),
|
|
130
|
+
'data-generator': {
|
|
131
|
+
account: {
|
|
132
|
+
authentications: ['jwt-auth'],
|
|
133
|
+
'jwt-oauth': jwtOauth
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
await authenticator.constructPayload(makeApiPayload(), actorInfo);
|
|
138
|
+
const body = JSON.parse(global.fetch.mock.calls[0][1].body);
|
|
139
|
+
expect(body.domain_url).toBe('https://zdesk-env-domain.csez.zohocorpin.com:31000');
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe('authenticator service errors', () => {
|
|
143
|
+
it('throws when authenticator responds with non-ok status', async () => {
|
|
144
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
145
|
+
ok: false,
|
|
146
|
+
status: 401,
|
|
147
|
+
text: jest.fn().mockResolvedValue('Unauthorized')
|
|
148
|
+
});
|
|
149
|
+
await expect(authenticator.constructPayload(makeApiPayload(), makeActorInfo())).rejects.toThrow('status: 401');
|
|
150
|
+
});
|
|
151
|
+
it('throws when authenticator response has no access_token', async () => {
|
|
152
|
+
global.fetch = jest.fn().mockResolvedValue({
|
|
153
|
+
ok: true,
|
|
154
|
+
json: jest.fn().mockResolvedValue({
|
|
155
|
+
error: 'invalid_grant'
|
|
156
|
+
})
|
|
157
|
+
});
|
|
158
|
+
await expect(authenticator.constructPayload(makeApiPayload(), makeActorInfo())).rejects.toThrow('access_token');
|
|
159
|
+
});
|
|
160
|
+
it('throws when fetch fails due to network error', async () => {
|
|
161
|
+
global.fetch = jest.fn().mockRejectedValue(new Error('ECONNREFUSED'));
|
|
162
|
+
await expect(authenticator.constructPayload(makeApiPayload(), makeActorInfo())).rejects.toThrow('ECONNREFUSED');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|