@anmiles/google-api-wrapper 7.0.6 → 8.0.0
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/.eslintrc.js +1 -86
- package/.gitlab-ci.yml +0 -1
- package/.vscode/settings.json +0 -4
- package/CHANGELOG.md +11 -0
- package/README.md +5 -2
- package/dist/index.d.ts +5 -5
- package/dist/index.js +15 -15
- package/dist/lib/api/calendar.d.ts +3 -3
- package/dist/lib/api/calendar.js +13 -13
- package/dist/lib/api/shared.d.ts +23 -23
- package/dist/lib/api/shared.js +26 -23
- package/dist/lib/api/shared.js.map +1 -1
- package/dist/lib/api/youtube.d.ts +3 -3
- package/dist/lib/api/youtube.js +13 -13
- package/dist/lib/auth.d.ts +10 -10
- package/dist/lib/auth.js +34 -34
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/paths.d.ts +12 -16
- package/dist/lib/paths.js +28 -45
- package/dist/lib/paths.js.map +1 -1
- package/dist/lib/profiles.d.ts +11 -10
- package/dist/lib/profiles.js +33 -33
- package/dist/lib/profiles.js.map +1 -1
- package/dist/lib/secrets.d.ts +26 -22
- package/dist/lib/secrets.js +152 -146
- package/dist/lib/secrets.js.map +1 -1
- package/dist/types/common.d.ts +3 -3
- package/dist/types/common.js +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +18 -18
- package/dist/types/secrets.d.ts +15 -15
- package/dist/types/secrets.js +2 -2
- package/package.json +18 -15
- package/src/lib/__tests__/auth.test.ts +23 -23
- package/src/lib/__tests__/paths.test.ts +1 -63
- package/src/lib/__tests__/profiles.test.ts +25 -21
- package/src/lib/__tests__/secrets.test.ts +100 -94
- package/src/lib/api/__tests__/calendar.test.ts +3 -3
- package/src/lib/api/__tests__/shared.test.ts +12 -14
- package/src/lib/api/__tests__/youtube.test.ts +3 -3
- package/src/lib/api/shared.ts +2 -2
- package/src/lib/auth.ts +1 -1
- package/src/lib/paths.ts +2 -20
- package/src/lib/profiles.ts +5 -5
- package/src/lib/secrets.ts +24 -17
- package/dist/lib/jsonLib.d.ts +0 -14
- package/dist/lib/jsonLib.js +0 -56
- package/dist/lib/jsonLib.js.map +0 -1
- package/dist/lib/logger.d.ts +0 -12
- package/dist/lib/logger.js +0 -46
- package/dist/lib/logger.js.map +0 -1
- package/dist/lib/sleep.d.ts +0 -6
- package/dist/lib/sleep.js +0 -11
- package/dist/lib/sleep.js.map +0 -1
- package/src/lib/__tests__/jsonLib.test.ts +0 -253
- package/src/lib/__tests__/logger.test.ts +0 -57
- package/src/lib/__tests__/sleep.test.ts +0 -17
- package/src/lib/jsonLib.ts +0 -57
- package/src/lib/logger.ts +0 -21
- package/src/lib/sleep.ts +0 -8
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
1
2
|
import http from 'http';
|
|
2
3
|
import path from 'path';
|
|
3
|
-
import * as colorette from 'colorette';
|
|
4
4
|
import open from 'open';
|
|
5
5
|
import type GoogleApis from 'googleapis';
|
|
6
|
-
import
|
|
7
|
-
import logger from '../logger';
|
|
6
|
+
import logger from '@anmiles/logger';
|
|
8
7
|
import paths from '../paths';
|
|
9
8
|
import type { Secrets } from '../../types';
|
|
9
|
+
import '@anmiles/prototypes';
|
|
10
10
|
|
|
11
11
|
import secrets from '../secrets';
|
|
12
12
|
const original = jest.requireActual('../secrets').default as typeof secrets;
|
|
@@ -34,36 +34,26 @@ jest.mock<Partial<typeof http>>('http', () => ({
|
|
|
34
34
|
}),
|
|
35
35
|
}));
|
|
36
36
|
|
|
37
|
-
jest.mock<Partial<typeof
|
|
38
|
-
|
|
37
|
+
jest.mock<Partial<typeof fs>>('fs', () => ({
|
|
38
|
+
existsSync : jest.fn().mockImplementation(() => exists),
|
|
39
39
|
}));
|
|
40
40
|
|
|
41
|
-
jest.mock<Partial<typeof
|
|
42
|
-
|
|
41
|
+
jest.mock<Partial<typeof path>>('path', () => ({
|
|
42
|
+
join : jest.fn().mockImplementation((...args) => args.join('/')),
|
|
43
43
|
}));
|
|
44
44
|
|
|
45
45
|
jest.mock('open', () => jest.fn().mockImplementation((url: string) => {
|
|
46
46
|
willOpen(url.replace('http://localhost:6006', ''));
|
|
47
47
|
}));
|
|
48
48
|
|
|
49
|
-
jest.mock<Partial<typeof
|
|
50
|
-
|
|
51
|
-
getJSONAsync : jest.fn().mockImplementation(async () => json),
|
|
52
|
-
readJSON : jest.fn().mockImplementation(async () => json),
|
|
53
|
-
}));
|
|
54
|
-
|
|
55
|
-
jest.mock<Partial<typeof logger>>('../logger', () => ({
|
|
56
|
-
warn : jest.fn(),
|
|
57
|
-
error : jest.fn().mockImplementation((error) => {
|
|
58
|
-
throw error;
|
|
59
|
-
}) as jest.Mock<never, any>,
|
|
49
|
+
jest.mock<Partial<typeof logger>>('@anmiles/logger', () => ({
|
|
50
|
+
warn : jest.fn(),
|
|
60
51
|
}));
|
|
61
52
|
|
|
62
53
|
jest.mock<Partial<typeof paths>>('../paths', () => ({
|
|
63
54
|
getScopesFile : jest.fn().mockImplementation(() => scopesFile),
|
|
64
55
|
getSecretsFile : jest.fn().mockImplementation(() => secretsFile),
|
|
65
56
|
getCredentialsFile : jest.fn().mockImplementation(() => credentialsFile),
|
|
66
|
-
ensureFile : jest.fn().mockImplementation(() => fileExists),
|
|
67
57
|
}));
|
|
68
58
|
|
|
69
59
|
const profile = 'username1';
|
|
@@ -148,164 +138,180 @@ const connections = [
|
|
|
148
138
|
{ remoteAddress : 'server', remotePort : '1003', on : jest.fn(), destroy : jest.fn() },
|
|
149
139
|
];
|
|
150
140
|
|
|
151
|
-
let
|
|
141
|
+
let exists: boolean;
|
|
142
|
+
|
|
143
|
+
let getJSONSpy: jest.SpyInstance;
|
|
144
|
+
let getJSONAsyncSpy: jest.SpyInstance;
|
|
145
|
+
let readJSONSpy: jest.SpyInstance;
|
|
146
|
+
|
|
147
|
+
beforeAll(() => {
|
|
148
|
+
getJSONSpy = jest.spyOn(fs, 'getJSON');
|
|
149
|
+
getJSONAsyncSpy = jest.spyOn(fs, 'getJSONAsync');
|
|
150
|
+
readJSONSpy = jest.spyOn(fs, 'readJSON');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
beforeEach(() => {
|
|
154
|
+
getJSONSpy.mockImplementation(() => json);
|
|
155
|
+
getJSONAsyncSpy.mockImplementation(() => json);
|
|
156
|
+
readJSONSpy.mockImplementation(() => json);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
afterAll(() => {
|
|
160
|
+
getJSONSpy.mockRestore();
|
|
161
|
+
getJSONAsyncSpy.mockRestore();
|
|
162
|
+
readJSONSpy.mockRestore();
|
|
163
|
+
});
|
|
152
164
|
|
|
153
165
|
describe('src/lib/secrets', () => {
|
|
154
166
|
describe('getScopes', () => {
|
|
155
|
-
const getJSONSpy = jest.spyOn(jsonLib, 'getJSON');
|
|
156
|
-
|
|
157
167
|
beforeEach(() => {
|
|
158
168
|
json = scopesJSON;
|
|
159
169
|
});
|
|
160
170
|
|
|
161
|
-
it('should get json from scopes file',
|
|
162
|
-
|
|
171
|
+
it('should get json from scopes file', () => {
|
|
172
|
+
original.getScopes();
|
|
163
173
|
|
|
164
|
-
expect(getJSONSpy).
|
|
174
|
+
expect(getJSONSpy).toHaveBeenCalled();
|
|
165
175
|
expect(getJSONSpy.mock.calls[0][0]).toEqual(scopesFile);
|
|
166
176
|
});
|
|
167
177
|
|
|
168
|
-
it('should fallback to error',
|
|
169
|
-
|
|
178
|
+
it('should fallback to error', () => {
|
|
179
|
+
original.getScopes();
|
|
170
180
|
|
|
171
|
-
expect(getJSONSpy.mock.calls[0][1]).
|
|
181
|
+
expect(getJSONSpy.mock.calls[0][1]).toThrow(scopesError);
|
|
172
182
|
});
|
|
173
183
|
|
|
174
|
-
it('should return scopes',
|
|
175
|
-
const result =
|
|
184
|
+
it('should return scopes', () => {
|
|
185
|
+
const result = original.getScopes();
|
|
176
186
|
|
|
177
187
|
expect(result).toEqual(scopesJSON);
|
|
178
188
|
});
|
|
179
189
|
});
|
|
180
190
|
|
|
181
191
|
describe('getSecrets', () => {
|
|
182
|
-
const getJSONSpy = jest.spyOn(jsonLib, 'getJSON');
|
|
183
|
-
|
|
184
192
|
beforeEach(() => {
|
|
185
193
|
json = secretsJSON;
|
|
186
194
|
});
|
|
187
195
|
|
|
188
|
-
it('should get json from secrets file',
|
|
189
|
-
|
|
196
|
+
it('should get json from secrets file', () => {
|
|
197
|
+
original.getSecrets(profile);
|
|
190
198
|
|
|
191
|
-
expect(getJSONSpy).
|
|
199
|
+
expect(getJSONSpy).toHaveBeenCalled();
|
|
192
200
|
expect(getJSONSpy.mock.calls[0][0]).toEqual(secretsFile);
|
|
193
201
|
});
|
|
194
202
|
|
|
195
|
-
it('should fallback to error',
|
|
196
|
-
|
|
203
|
+
it('should fallback to error', () => {
|
|
204
|
+
original.getSecrets(profile);
|
|
197
205
|
|
|
198
|
-
expect(getJSONSpy.mock.calls[0][1]).
|
|
206
|
+
expect(getJSONSpy.mock.calls[0][1]).toThrow(secretsError);
|
|
199
207
|
});
|
|
200
208
|
|
|
201
|
-
it('should check secrets',
|
|
202
|
-
|
|
209
|
+
it('should check secrets', () => {
|
|
210
|
+
original.getSecrets(profile);
|
|
203
211
|
|
|
204
|
-
expect(secrets.checkSecrets).
|
|
212
|
+
expect(secrets.checkSecrets).toHaveBeenCalledWith(profile, json, secretsFile);
|
|
205
213
|
});
|
|
206
214
|
|
|
207
|
-
it('should return secrets',
|
|
208
|
-
const result =
|
|
215
|
+
it('should return secrets', () => {
|
|
216
|
+
const result = original.getSecrets(profile);
|
|
209
217
|
|
|
210
218
|
expect(result).toEqual(secretsJSON);
|
|
211
219
|
});
|
|
212
220
|
});
|
|
213
221
|
|
|
214
222
|
describe('getCredentials', () => {
|
|
215
|
-
const getJSONAsyncSpy = jest.spyOn(jsonLib, 'getJSONAsync');
|
|
216
|
-
|
|
217
223
|
beforeEach(() => {
|
|
218
|
-
json
|
|
219
|
-
|
|
224
|
+
json = credentialsJSON;
|
|
225
|
+
exists = false;
|
|
220
226
|
});
|
|
221
227
|
|
|
222
228
|
it('should get json from credentials file by default', async () => {
|
|
223
229
|
await original.getCredentials(profile, auth);
|
|
224
230
|
|
|
225
|
-
expect(getJSONAsyncSpy).
|
|
231
|
+
expect(getJSONAsyncSpy).toHaveBeenCalled();
|
|
226
232
|
expect(getJSONAsyncSpy.mock.calls[0][0]).toEqual(credentialsFile);
|
|
227
233
|
});
|
|
228
234
|
|
|
229
235
|
it('should get json from credentials file if temporariness not set', async () => {
|
|
230
236
|
await original.getCredentials(profile, auth, { temporary : false });
|
|
231
237
|
|
|
232
|
-
expect(getJSONAsyncSpy).
|
|
238
|
+
expect(getJSONAsyncSpy).toHaveBeenCalled();
|
|
233
239
|
expect(getJSONAsyncSpy.mock.calls[0][0]).toEqual(credentialsFile);
|
|
234
240
|
});
|
|
235
241
|
|
|
236
242
|
it('should not get json from credentials file if temporariness set', async () => {
|
|
237
243
|
await original.getCredentials(profile, auth, { temporary : true });
|
|
238
244
|
|
|
239
|
-
expect(getJSONAsyncSpy).not.
|
|
245
|
+
expect(getJSONAsyncSpy).not.toHaveBeenCalled();
|
|
240
246
|
});
|
|
241
247
|
|
|
242
248
|
it('should call createCredentials with consent in fallback if no existing credentials', async () => {
|
|
243
|
-
|
|
249
|
+
exists = false;
|
|
244
250
|
|
|
245
251
|
await original.getCredentials(profile, auth);
|
|
246
252
|
|
|
247
|
-
expect(secrets.createCredentials).not.
|
|
253
|
+
expect(secrets.createCredentials).not.toHaveBeenCalled();
|
|
248
254
|
|
|
249
255
|
const fallback = getJSONAsyncSpy.mock.calls[0][1];
|
|
250
256
|
const result = await fallback();
|
|
251
257
|
|
|
252
|
-
expect(
|
|
253
|
-
expect(secrets.createCredentials).
|
|
258
|
+
expect(readJSONSpy).not.toHaveBeenCalled();
|
|
259
|
+
expect(secrets.createCredentials).toHaveBeenCalledWith(profile, auth, undefined, 'consent');
|
|
254
260
|
expect(result).toEqual(credentialsJSON);
|
|
255
261
|
});
|
|
256
262
|
|
|
257
263
|
it('should call createCredentials with consent in fallback if no existing credentials and pass temporariness', async () => {
|
|
258
|
-
|
|
264
|
+
exists = false;
|
|
259
265
|
|
|
260
266
|
await original.getCredentials(profile, auth, { temporary : false });
|
|
261
267
|
|
|
262
|
-
expect(secrets.createCredentials).not.
|
|
268
|
+
expect(secrets.createCredentials).not.toHaveBeenCalled();
|
|
263
269
|
|
|
264
270
|
const fallback = getJSONAsyncSpy.mock.calls[0][1];
|
|
265
271
|
const result = await fallback();
|
|
266
272
|
|
|
267
|
-
expect(
|
|
268
|
-
expect(secrets.createCredentials).
|
|
273
|
+
expect(readJSONSpy).not.toHaveBeenCalled();
|
|
274
|
+
expect(secrets.createCredentials).toHaveBeenCalledWith(profile, auth, { temporary : false }, 'consent');
|
|
269
275
|
expect(result).toEqual(credentialsJSON);
|
|
270
276
|
});
|
|
271
277
|
|
|
272
278
|
it('should call createCredentials with consent in fallback if existing credentials do not have refresh token', async () => {
|
|
273
|
-
|
|
279
|
+
exists = true;
|
|
274
280
|
|
|
275
281
|
await original.getCredentials(profile, auth);
|
|
276
282
|
|
|
277
|
-
expect(secrets.createCredentials).not.
|
|
283
|
+
expect(secrets.createCredentials).not.toHaveBeenCalled();
|
|
278
284
|
|
|
279
285
|
const fallback = getJSONAsyncSpy.mock.calls[0][1];
|
|
280
286
|
const result = await fallback();
|
|
281
287
|
|
|
282
|
-
expect(
|
|
283
|
-
expect(secrets.createCredentials).
|
|
288
|
+
expect(readJSONSpy).toHaveBeenCalledWith(credentialsFile);
|
|
289
|
+
expect(secrets.createCredentials).toHaveBeenCalledWith(profile, auth, undefined, 'consent');
|
|
284
290
|
expect(result).toEqual(credentialsJSON);
|
|
285
291
|
});
|
|
286
292
|
|
|
287
293
|
it('should call createCredentials without consent in fallback and replace refresh_token if existing credentials have refresh token', async () => {
|
|
288
|
-
|
|
294
|
+
exists = true;
|
|
289
295
|
// eslint-disable-next-line camelcase
|
|
290
|
-
|
|
296
|
+
readJSONSpy.mockReturnValueOnce({ ...credentialsJSON, refresh_token : 'refresh_token' });
|
|
291
297
|
|
|
292
298
|
await original.getCredentials(profile, auth);
|
|
293
299
|
|
|
294
|
-
expect(secrets.createCredentials).not.
|
|
300
|
+
expect(secrets.createCredentials).not.toHaveBeenCalled();
|
|
295
301
|
|
|
296
302
|
const fallback = getJSONAsyncSpy.mock.calls[0][1];
|
|
297
303
|
const result = await fallback();
|
|
298
304
|
|
|
299
|
-
expect(
|
|
300
|
-
expect(secrets.createCredentials).
|
|
305
|
+
expect(readJSONSpy).toHaveBeenCalledWith(credentialsFile);
|
|
306
|
+
expect(secrets.createCredentials).toHaveBeenCalledWith(profile, auth, undefined, undefined);
|
|
301
307
|
// eslint-disable-next-line camelcase
|
|
302
308
|
expect(result).toEqual({ ... credentialsJSON, refresh_token : 'refresh_token' });
|
|
303
309
|
});
|
|
304
310
|
|
|
305
311
|
it('should call createCredentials without consent in fallback and leave refresh token if existing credentials have refresh token', async () => {
|
|
306
|
-
|
|
312
|
+
exists = true;
|
|
307
313
|
// eslint-disable-next-line camelcase
|
|
308
|
-
|
|
314
|
+
readJSONSpy.mockReturnValueOnce({ ...credentialsJSON, refresh_token : 'refresh_token' });
|
|
309
315
|
// eslint-disable-next-line camelcase
|
|
310
316
|
jest.spyOn(secrets, 'createCredentials').mockResolvedValueOnce({ ...credentialsJSON, refresh_token : 'refresh_token_exists' });
|
|
311
317
|
|
|
@@ -314,8 +320,8 @@ describe('src/lib/secrets', () => {
|
|
|
314
320
|
const fallback = getJSONAsyncSpy.mock.calls[0][1];
|
|
315
321
|
const result = await fallback();
|
|
316
322
|
|
|
317
|
-
expect(
|
|
318
|
-
expect(secrets.createCredentials).
|
|
323
|
+
expect(readJSONSpy).toHaveBeenCalledWith(credentialsFile);
|
|
324
|
+
expect(secrets.createCredentials).toHaveBeenCalledWith(profile, auth, undefined, undefined);
|
|
319
325
|
// eslint-disable-next-line camelcase
|
|
320
326
|
expect(result).toEqual({ ...credentialsJSON, refresh_token : 'refresh_token_exists' });
|
|
321
327
|
});
|
|
@@ -323,31 +329,31 @@ describe('src/lib/secrets', () => {
|
|
|
323
329
|
|
|
324
330
|
describe('validateCredentials', () => {
|
|
325
331
|
it('should return false if no access token', async () => {
|
|
326
|
-
expect(await original.validateCredentials({})).toEqual(false);
|
|
332
|
+
expect(await original.validateCredentials({})).toEqual({ isValid : false, validationError : 'Credentials does not have access_token' });
|
|
327
333
|
});
|
|
328
334
|
|
|
329
|
-
it('should return
|
|
335
|
+
it('should return false if no refresh token', async () => {
|
|
330
336
|
// eslint-disable-next-line camelcase
|
|
331
|
-
expect(await original.validateCredentials({ access_token : 'token' })).toEqual(false);
|
|
337
|
+
expect(await original.validateCredentials({ access_token : 'token' })).toEqual({ isValid : false, validationError : 'Credentials does not have refresh_token' });
|
|
332
338
|
});
|
|
333
339
|
|
|
334
|
-
it('should return
|
|
340
|
+
it('should return false if no expiration date', async () => {
|
|
335
341
|
// eslint-disable-next-line camelcase
|
|
336
|
-
expect(await original.validateCredentials({ access_token : 'token', refresh_token : 'token' })).toEqual(
|
|
342
|
+
expect(await original.validateCredentials({ access_token : 'token', refresh_token : 'token' })).toEqual({ isValid : false, validationError : 'Credentials does not have expiry_date' });
|
|
337
343
|
});
|
|
338
344
|
|
|
339
345
|
it('should return true if credentials are not more than 1 week ago', async () => {
|
|
340
346
|
const expiryDate = new Date();
|
|
341
347
|
expiryDate.setDate(expiryDate.getDate() - 6);
|
|
342
348
|
// eslint-disable-next-line camelcase
|
|
343
|
-
expect(await original.validateCredentials({ access_token : 'token', refresh_token : 'token', expiry_date : expiryDate.getTime() })).toEqual(true);
|
|
349
|
+
expect(await original.validateCredentials({ access_token : 'token', refresh_token : 'token', expiry_date : expiryDate.getTime() })).toEqual({ isValid : true });
|
|
344
350
|
});
|
|
345
351
|
|
|
346
|
-
it('should return
|
|
352
|
+
it('should return false if credentials are more than 1 week ago', async () => {
|
|
347
353
|
const expiryDate = new Date();
|
|
348
354
|
expiryDate.setDate(expiryDate.getDate() - 8);
|
|
349
355
|
// eslint-disable-next-line camelcase
|
|
350
|
-
expect(await original.validateCredentials({ access_token : 'token', refresh_token : 'token', expiry_date : expiryDate.getTime() })).toEqual(false);
|
|
356
|
+
expect(await original.validateCredentials({ access_token : 'token', refresh_token : 'token', expiry_date : expiryDate.getTime() })).toEqual({ isValid : false, validationError : 'Credentials expired' });
|
|
351
357
|
});
|
|
352
358
|
});
|
|
353
359
|
|
|
@@ -359,7 +365,7 @@ describe('src/lib/secrets', () => {
|
|
|
359
365
|
|
|
360
366
|
await original.createCredentials(profile, auth);
|
|
361
367
|
|
|
362
|
-
expect(auth.generateAuthUrl).
|
|
368
|
+
expect(auth.generateAuthUrl).toHaveBeenCalledWith({
|
|
363
369
|
// eslint-disable-next-line camelcase
|
|
364
370
|
access_type : 'offline',
|
|
365
371
|
prompt : undefined,
|
|
@@ -375,7 +381,7 @@ describe('src/lib/secrets', () => {
|
|
|
375
381
|
|
|
376
382
|
await original.createCredentials(profile, auth, { temporary : true }, 'consent');
|
|
377
383
|
|
|
378
|
-
expect(auth.generateAuthUrl).
|
|
384
|
+
expect(auth.generateAuthUrl).toHaveBeenCalledWith({
|
|
379
385
|
// eslint-disable-next-line camelcase
|
|
380
386
|
access_type : 'offline',
|
|
381
387
|
prompt : 'consent',
|
|
@@ -391,7 +397,7 @@ describe('src/lib/secrets', () => {
|
|
|
391
397
|
|
|
392
398
|
await original.createCredentials(profile, auth, { scopes : [ 'scope1', 'scope2' ] });
|
|
393
399
|
|
|
394
|
-
expect(auth.generateAuthUrl).
|
|
400
|
+
expect(auth.generateAuthUrl).toHaveBeenCalledWith({
|
|
395
401
|
// eslint-disable-next-line camelcase
|
|
396
402
|
access_type : 'offline',
|
|
397
403
|
prompt : undefined,
|
|
@@ -404,8 +410,8 @@ describe('src/lib/secrets', () => {
|
|
|
404
410
|
|
|
405
411
|
await original.createCredentials(profile, auth);
|
|
406
412
|
|
|
407
|
-
expect(http.createServer).
|
|
408
|
-
expect(listen).
|
|
413
|
+
expect(http.createServer).toHaveBeenCalled();
|
|
414
|
+
expect(listen).toHaveBeenCalledWith(6006);
|
|
409
415
|
});
|
|
410
416
|
|
|
411
417
|
it('should open browser page and warn about it', async () => {
|
|
@@ -413,8 +419,8 @@ describe('src/lib/secrets', () => {
|
|
|
413
419
|
|
|
414
420
|
await original.createCredentials(profile, auth);
|
|
415
421
|
|
|
416
|
-
expect(open).
|
|
417
|
-
expect(logger.warn).
|
|
422
|
+
expect(open).toHaveBeenCalledWith('http://localhost:6006/');
|
|
423
|
+
expect(logger.warn).toHaveBeenCalledWith('Please check your browser for further actions');
|
|
418
424
|
});
|
|
419
425
|
|
|
420
426
|
it('should show nothing on the browser page if request.url is empty', async () => {
|
|
@@ -423,7 +429,7 @@ describe('src/lib/secrets', () => {
|
|
|
423
429
|
|
|
424
430
|
await original.createCredentials(profile, auth);
|
|
425
431
|
|
|
426
|
-
expect(response.end).
|
|
432
|
+
expect(response.end).toHaveBeenCalledWith('');
|
|
427
433
|
});
|
|
428
434
|
|
|
429
435
|
it('should show opening instructions if opened the home page', async () => {
|
|
@@ -432,7 +438,7 @@ describe('src/lib/secrets', () => {
|
|
|
432
438
|
|
|
433
439
|
await original.createCredentials(profile, auth);
|
|
434
440
|
|
|
435
|
-
expect(response.end).
|
|
441
|
+
expect(response.end).toHaveBeenCalledWith(`\
|
|
436
442
|
<div style="width: 100%;height: 100%;display: flex;align-items: start;justify-content: center">\n\
|
|
437
443
|
<div style="padding: 0 1em;border: 1px solid black;font-family: Arial, sans-serif;margin: 1em;">\n\
|
|
438
444
|
<p>Please open <a href="${authUrl}">auth page</a> using <strong>${profile}</strong> google profile</p>\n\
|
|
@@ -447,7 +453,7 @@ describe('src/lib/secrets', () => {
|
|
|
447
453
|
|
|
448
454
|
await original.createCredentials(profile, auth);
|
|
449
455
|
|
|
450
|
-
expect(response.end).
|
|
456
|
+
expect(response.end).toHaveBeenCalledWith('\
|
|
451
457
|
<div style="width: 100%;height: 100%;display: flex;align-items: start;justify-content: center">\n\
|
|
452
458
|
<div style="padding: 0 1em;border: 1px solid black;font-family: Arial, sans-serif;margin: 1em;">\n\
|
|
453
459
|
<p>Please close this page and return to application</p>\n\
|
|
@@ -460,9 +466,9 @@ describe('src/lib/secrets', () => {
|
|
|
460
466
|
|
|
461
467
|
await original.createCredentials(profile, auth);
|
|
462
468
|
|
|
463
|
-
expect(close).
|
|
469
|
+
expect(close).toHaveBeenCalled();
|
|
464
470
|
|
|
465
|
-
connections.forEach((connection) => expect(connection.destroy).
|
|
471
|
+
connections.forEach((connection) => expect(connection.destroy).toHaveBeenCalled());
|
|
466
472
|
});
|
|
467
473
|
|
|
468
474
|
it('should only resolve when request.url is truthy', async () => {
|
|
@@ -476,7 +482,7 @@ describe('src/lib/secrets', () => {
|
|
|
476
482
|
const result = await original.createCredentials(profile, auth);
|
|
477
483
|
const after = new Date().getTime();
|
|
478
484
|
|
|
479
|
-
expect(close).
|
|
485
|
+
expect(close).toHaveBeenCalledTimes(1);
|
|
480
486
|
expect(closedTime - before).toBeGreaterThanOrEqual(requestTime - 1);
|
|
481
487
|
expect(after - before).toBeGreaterThanOrEqual(requestTime - 1);
|
|
482
488
|
expect(result).toEqual(credentialsJSON);
|
|
@@ -493,7 +499,7 @@ describe('src/lib/secrets', () => {
|
|
|
493
499
|
const result = await original.createCredentials(profile, auth);
|
|
494
500
|
const after = new Date().getTime();
|
|
495
501
|
|
|
496
|
-
expect(close).
|
|
502
|
+
expect(close).toHaveBeenCalledTimes(1);
|
|
497
503
|
expect(closedTime - before).toBeGreaterThanOrEqual(requestTime - 1);
|
|
498
504
|
expect(after - before).toBeGreaterThanOrEqual(requestTime - 1);
|
|
499
505
|
expect(result).toEqual(credentialsJSON);
|
|
@@ -520,7 +526,7 @@ describe('src/lib/secrets', () => {
|
|
|
520
526
|
wrongSecretsJSON.web.redirect_uris[0] = wrongRedirectURI;
|
|
521
527
|
const func = () => original.checkSecrets(profile, wrongSecretsJSON, secretsFile);
|
|
522
528
|
|
|
523
|
-
expect(func).
|
|
529
|
+
expect(func).toThrow('Error in credentials file: redirect URI should be http://localhost:6006/oauthcallback.\nsecretsError');
|
|
524
530
|
});
|
|
525
531
|
});
|
|
526
532
|
|
|
@@ -21,19 +21,19 @@ describe('src/lib/api/calendar', () => {
|
|
|
21
21
|
it('should call getAuth', async () => {
|
|
22
22
|
await getAPI(profile);
|
|
23
23
|
|
|
24
|
-
expect(auth.getAuth).
|
|
24
|
+
expect(auth.getAuth).toHaveBeenCalledWith(profile, undefined);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it('should pass temporariness', async () => {
|
|
28
28
|
await getAPI(profile, { temporary : true });
|
|
29
29
|
|
|
30
|
-
expect(auth.getAuth).
|
|
30
|
+
expect(auth.getAuth).toHaveBeenCalledWith(profile, { temporary : true });
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('should get calendar api', async () => {
|
|
34
34
|
await getAPI(profile);
|
|
35
35
|
|
|
36
|
-
expect(google.calendar).
|
|
36
|
+
expect(google.calendar).toHaveBeenCalledWith({ version : 'v3', auth : googleAuth });
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
it('should return calendar api', async () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import logger from '
|
|
2
|
-
import sleep from '
|
|
1
|
+
import logger from '@anmiles/logger';
|
|
2
|
+
import sleep from '@anmiles/sleep';
|
|
3
3
|
import shared from '../shared';
|
|
4
4
|
|
|
5
5
|
const original = jest.requireActual('../shared').default as typeof shared;
|
|
@@ -7,13 +7,11 @@ jest.mock<Partial<typeof shared>>('../shared', () => ({
|
|
|
7
7
|
getItems : jest.fn().mockImplementation(async () => items),
|
|
8
8
|
}));
|
|
9
9
|
|
|
10
|
-
jest.mock<Partial<typeof logger>>('
|
|
10
|
+
jest.mock<Partial<typeof logger>>('@anmiles/logger', () => ({
|
|
11
11
|
log : jest.fn(),
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
|
-
jest.mock<Partial<typeof sleep>>('
|
|
15
|
-
sleep : jest.fn(),
|
|
16
|
-
}));
|
|
14
|
+
jest.mock<Partial<typeof sleep>>('@anmiles/sleep', () => jest.fn());
|
|
17
15
|
|
|
18
16
|
const items: Array<{ data: string}> = [
|
|
19
17
|
{ data : 'first' },
|
|
@@ -60,30 +58,30 @@ describe('src/lib/api/shared', () => {
|
|
|
60
58
|
await original.getItems(api, args);
|
|
61
59
|
|
|
62
60
|
pageTokens.forEach((pageToken) => {
|
|
63
|
-
expect(api.list).
|
|
61
|
+
expect(api.list).toHaveBeenCalledWith({ ...args, pageToken });
|
|
64
62
|
});
|
|
65
63
|
});
|
|
66
64
|
|
|
67
65
|
it('should output progress by default', async () => {
|
|
68
66
|
await original.getItems(api, args);
|
|
69
67
|
|
|
70
|
-
expect(logger.log).
|
|
71
|
-
expect(logger.log).
|
|
72
|
-
expect(logger.log).
|
|
73
|
-
expect(logger.log).
|
|
68
|
+
expect(logger.log).toHaveBeenCalledTimes(response.length);
|
|
69
|
+
expect(logger.log).toHaveBeenCalledWith('Getting items (2 of 4)...');
|
|
70
|
+
expect(logger.log).toHaveBeenCalledWith('Getting items (2 of many)...');
|
|
71
|
+
expect(logger.log).toHaveBeenCalledWith('Getting items (4 of 4)...');
|
|
74
72
|
});
|
|
75
73
|
|
|
76
74
|
it('should not output progress if hidden', async () => {
|
|
77
75
|
await original.getItems(api, args, { hideProgress : true });
|
|
78
76
|
|
|
79
|
-
expect(logger.log).not.
|
|
77
|
+
expect(logger.log).not.toHaveBeenCalled();
|
|
80
78
|
});
|
|
81
79
|
|
|
82
80
|
it('should sleep after reach request', async () => {
|
|
83
81
|
await original.getItems(api, args);
|
|
84
82
|
|
|
85
|
-
expect(sleep
|
|
86
|
-
expect(sleep
|
|
83
|
+
expect(sleep).toHaveBeenCalledTimes(response.length);
|
|
84
|
+
expect(sleep).toHaveBeenCalledWith(300);
|
|
87
85
|
});
|
|
88
86
|
|
|
89
87
|
it('should return items data', async () => {
|
|
@@ -21,19 +21,19 @@ describe('src/lib/api/youtube', () => {
|
|
|
21
21
|
it('should call getAuth', async () => {
|
|
22
22
|
await getAPI(profile);
|
|
23
23
|
|
|
24
|
-
expect(auth.getAuth).
|
|
24
|
+
expect(auth.getAuth).toHaveBeenCalledWith(profile, undefined);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it('should pass temporariness', async () => {
|
|
28
28
|
await getAPI(profile, { temporary : true });
|
|
29
29
|
|
|
30
|
-
expect(auth.getAuth).
|
|
30
|
+
expect(auth.getAuth).toHaveBeenCalledWith(profile, { temporary : true });
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('should get youtube api', async () => {
|
|
34
34
|
await getAPI(profile);
|
|
35
35
|
|
|
36
|
-
expect(google.youtube).
|
|
36
|
+
expect(google.youtube).toHaveBeenCalledWith({ version : 'v3', auth : googleAuth });
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
it('should return youtube api', async () => {
|
package/src/lib/api/shared.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type GoogleApis from 'googleapis';
|
|
2
|
+
import { log } from '@anmiles/logger';
|
|
3
|
+
import sleep from '@anmiles/sleep';
|
|
2
4
|
import type { CommonOptions } from '../../types';
|
|
3
|
-
import { log } from '../logger';
|
|
4
|
-
import { sleep } from '../sleep';
|
|
5
5
|
|
|
6
6
|
export { getItems };
|
|
7
7
|
export default { getItems };
|
package/src/lib/auth.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { google } from 'googleapis';
|
|
2
2
|
import type GoogleApis from 'googleapis';
|
|
3
|
+
import { info, warn } from '@anmiles/logger';
|
|
3
4
|
import type { CommonOptions, AuthOptions } from '../types';
|
|
4
|
-
import { info, warn } from './logger';
|
|
5
5
|
import { getProfiles } from './profiles';
|
|
6
6
|
import { getCredentials, getSecrets } from './secrets';
|
|
7
7
|
|
package/src/lib/paths.ts
CHANGED
|
@@ -1,31 +1,13 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
1
|
import path from 'path';
|
|
3
|
-
import paths from './paths';
|
|
4
2
|
|
|
5
|
-
export {
|
|
6
|
-
export default {
|
|
3
|
+
export { getProfilesFile, getScopesFile, getSecretsFile, getCredentialsFile };
|
|
4
|
+
export default { getProfilesFile, getScopesFile, getSecretsFile, getCredentialsFile };
|
|
7
5
|
|
|
8
6
|
const dirPaths = {
|
|
9
7
|
input : 'input',
|
|
10
8
|
secrets : 'secrets',
|
|
11
9
|
};
|
|
12
10
|
|
|
13
|
-
function ensureDir(dirPath: string) {
|
|
14
|
-
if (!fs.existsSync(dirPath)) {
|
|
15
|
-
fs.mkdirSync(dirPath, { recursive : true });
|
|
16
|
-
}
|
|
17
|
-
return dirPath;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function ensureFile(filePath: string) {
|
|
21
|
-
paths.ensureDir(path.dirname(filePath));
|
|
22
|
-
|
|
23
|
-
if (!fs.existsSync(filePath)) {
|
|
24
|
-
fs.writeFileSync(filePath, '');
|
|
25
|
-
}
|
|
26
|
-
return filePath;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
11
|
function getProfilesFile() {
|
|
30
12
|
return path.join(dirPaths.input, 'profiles.json');
|
|
31
13
|
}
|
package/src/lib/profiles.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import '@anmiles/prototypes';
|
|
3
3
|
import { getProfilesFile } from './paths';
|
|
4
4
|
|
|
5
5
|
import profiles from './profiles';
|
|
@@ -9,17 +9,17 @@ export default { getProfiles, setProfiles, createProfile };
|
|
|
9
9
|
|
|
10
10
|
function getProfiles(): string[] {
|
|
11
11
|
const profilesFile = getProfilesFile();
|
|
12
|
-
return getJSON(profilesFile, () => []);
|
|
12
|
+
return fs.getJSON(profilesFile, () => []);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function setProfiles(profiles: string[]): void {
|
|
16
16
|
const profilesFile = getProfilesFile();
|
|
17
|
-
writeJSON(profilesFile, profiles);
|
|
17
|
+
fs.writeJSON(profilesFile, profiles);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function createProfile(profile: string): void {
|
|
21
21
|
if (!profile) {
|
|
22
|
-
|
|
22
|
+
throw 'Usage: `npm run create <profile>` where `profile` - is any profile name you want';
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const existingProfiles = profiles.getProfiles();
|