@botonic/cli 0.43.0 → 0.45.0-alpha.1
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/bin/dev.js +2 -2
- package/bin/run.js +2 -2
- package/lib/src/botonic-api-service.d.ts +3 -3
- package/lib/src/botonic-api-service.js +11 -8
- package/lib/src/botonic-api-service.js.map +1 -1
- package/lib/src/botonic-examples.d.ts +1 -1
- package/lib/src/botonic-examples.js +3 -4
- package/lib/src/botonic-examples.js.map +1 -1
- package/lib/src/commands/deploy.d.ts +3 -3
- package/lib/src/commands/deploy.js +35 -20
- package/lib/src/commands/deploy.js.map +1 -1
- package/lib/src/commands/login.js +2 -2
- package/lib/src/commands/login.js.map +1 -1
- package/lib/src/commands/logout.js +1 -1
- package/lib/src/commands/logout.js.map +1 -1
- package/lib/src/commands/new.d.ts +1 -1
- package/lib/src/commands/new.js +6 -5
- package/lib/src/commands/new.js.map +1 -1
- package/lib/src/util/bot-config.js +12 -12
- package/lib/src/util/bot-config.js.map +1 -1
- package/lib/src/util/credentials-handler.d.ts +1 -1
- package/lib/src/util/credentials-handler.js +13 -9
- package/lib/src/util/credentials-handler.js.map +1 -1
- package/lib/src/util/download-gzip.js +2 -2
- package/lib/src/util/download-gzip.js.map +1 -1
- package/lib/src/util/environment-info.d.ts +1 -1
- package/lib/src/util/environment-info.js +4 -3
- package/lib/src/util/environment-info.js.map +1 -1
- package/lib/src/util/file-system.d.ts +1 -1
- package/lib/src/util/file-system.js +7 -5
- package/lib/src/util/file-system.js.map +1 -1
- package/lib/src/util/system.js +2 -2
- package/lib/src/util/system.js.map +1 -1
- package/lib/tests/botonic-api-service.test.d.ts +1 -0
- package/lib/tests/botonic-api-service.test.js +423 -0
- package/lib/tests/botonic-api-service.test.js.map +1 -0
- package/lib/tests/commands/deploy.test.d.ts +1 -0
- package/lib/tests/commands/deploy.test.js +83 -0
- package/lib/tests/commands/deploy.test.js.map +1 -0
- package/lib/tests/commands/new.test.d.ts +1 -0
- package/lib/tests/commands/new.test.js +62 -0
- package/lib/tests/commands/new.test.js.map +1 -0
- package/lib/tests/util/credentials-handler.test.d.ts +1 -0
- package/lib/tests/util/credentials-handler.test.js +65 -0
- package/lib/tests/util/credentials-handler.test.js.map +1 -0
- package/lib/tests/util/file-system.test.d.ts +1 -0
- package/lib/tests/util/file-system.test.js +78 -0
- package/lib/tests/util/file-system.test.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +5 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join, resolve } from 'path';
|
|
1
|
+
import { join, resolve } from 'node:path';
|
|
2
2
|
import { BOT_CREDENTIALS_FILENAME, BOTONIC_HOME_DIRNAME, BOTONIC_PROJECT_PATH, GLOBAL_CREDENTIALS_FILENAME, } from '../constants.js';
|
|
3
3
|
import { createDir, getHomeDirectory, pathExists, readJSON, writeJSON, } from '../util/file-system.js';
|
|
4
4
|
export class CredentialsHandler {
|
|
@@ -13,16 +13,18 @@ export class CredentialsHandler {
|
|
|
13
13
|
this.createDirIfNotExists();
|
|
14
14
|
}
|
|
15
15
|
createDirIfNotExists() {
|
|
16
|
-
if (!pathExists(this.homeDir))
|
|
16
|
+
if (!pathExists(this.homeDir)) {
|
|
17
17
|
createDir(this.homeDir);
|
|
18
|
+
}
|
|
18
19
|
}
|
|
19
20
|
loadJSON() {
|
|
20
21
|
try {
|
|
21
|
-
if (!pathExists(this.pathToCredentials))
|
|
22
|
+
if (!pathExists(this.pathToCredentials)) {
|
|
22
23
|
return undefined;
|
|
24
|
+
}
|
|
23
25
|
return readJSON(this.pathToCredentials);
|
|
24
26
|
}
|
|
25
|
-
catch (
|
|
27
|
+
catch (_e) {
|
|
26
28
|
console.warn('Credentials could not be loaded');
|
|
27
29
|
return undefined;
|
|
28
30
|
}
|
|
@@ -31,7 +33,7 @@ export class CredentialsHandler {
|
|
|
31
33
|
try {
|
|
32
34
|
writeJSON(this.pathToCredentials, obj);
|
|
33
35
|
}
|
|
34
|
-
catch (
|
|
36
|
+
catch (_e) {
|
|
35
37
|
console.warn('Credentials could not be overwritten');
|
|
36
38
|
}
|
|
37
39
|
}
|
|
@@ -48,12 +50,13 @@ export class GlobalCredentialsHandler extends CredentialsHandler {
|
|
|
48
50
|
}
|
|
49
51
|
load() {
|
|
50
52
|
const json = this.loadJSON();
|
|
51
|
-
if (!json)
|
|
53
|
+
if (!json) {
|
|
52
54
|
return undefined;
|
|
55
|
+
}
|
|
53
56
|
return json;
|
|
54
57
|
}
|
|
55
58
|
dump(obj) {
|
|
56
|
-
|
|
59
|
+
this.dumpJSON(obj);
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
export class BotCredentialsHandler extends CredentialsHandler {
|
|
@@ -62,12 +65,13 @@ export class BotCredentialsHandler extends CredentialsHandler {
|
|
|
62
65
|
}
|
|
63
66
|
load() {
|
|
64
67
|
const json = this.loadJSON();
|
|
65
|
-
if (!json)
|
|
68
|
+
if (!json) {
|
|
66
69
|
return undefined;
|
|
70
|
+
}
|
|
67
71
|
return json;
|
|
68
72
|
}
|
|
69
73
|
dump(obj) {
|
|
70
|
-
|
|
74
|
+
this.dumpJSON(obj);
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
//# sourceMappingURL=credentials-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials-handler.js","sourceRoot":"","sources":["../../../src/util/credentials-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"credentials-handler.js","sourceRoot":"","sources":["../../../src/util/credentials-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEzC,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,iBAAiB,CAAA;AAOxB,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,SAAS,GACV,MAAM,wBAAwB,CAAA;AAE/B,MAAM,OAAO,kBAAkB;IAC7B,OAAO,CAAQ;IACf,iBAAiB,CAAQ;IAEzB,YAAY,IAA4B;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACpC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC1D,IAAI,CAAC,UAAU,EAAE,CAAA;IACnB,CAAC;IAED,UAAU;QACR,IAAI,CAAC,oBAAoB,EAAE,CAAA;IAC7B,CAAC;IAED,oBAAoB;QAClB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACzB,CAAC;IACH,CAAC;IAED,QAAQ;QACN,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBACxC,OAAO,SAAS,CAAA;YAClB,CAAC;YACD,OAAO,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;QACzC,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAA;YAC/C,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,GAAe;QACtB,IAAI,CAAC;YACH,SAAS,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAA;QACxC,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,kBAAkB;IAC9D;QACE,KAAK,CAAC;YACJ,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,EAAE,oBAAoB,CAAC;YACvD,QAAQ,EAAE,2BAA2B;SACtC,CAAC,CAAA;IACJ,CAAC;IAED,UAAU;QACR,IAAI,CAAC,oBAAoB,EAAE,CAAA;IAC7B,CAAC;IAED,IAAI;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,IAAoC,CAAA;IAC7C,CAAC;IAED,IAAI,CAAC,GAAsB;QACzB,IAAI,CAAC,QAAQ,CAAC,GAA4B,CAAC,CAAA;IAC7C,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,kBAAkB;IAC3D;QACE,KAAK,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,wBAAwB,EAAE,CAAC,CAAA;IAC9E,CAAC;IAED,IAAI;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,IAAiC,CAAA;IAC1C,CAAC;IAED,IAAI,CAAC,GAAmB;QACtB,IAAI,CAAC,QAAQ,CAAC,GAA4B,CAAC,CAAA;IAC7C,CAAC;CACF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { exec } from 'node:child_process';
|
|
1
2
|
import { createReadStream } from 'node:fs';
|
|
2
3
|
import { readFile, rename, writeFile } from 'node:fs/promises';
|
|
3
4
|
import { platform } from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
4
6
|
import { createGunzip } from 'node:zlib';
|
|
5
|
-
import { exec } from 'child_process';
|
|
6
|
-
import path from 'path';
|
|
7
7
|
import { extract } from 'tar';
|
|
8
8
|
import { removeRecursively } from './file-system.js';
|
|
9
9
|
function pathByOS(...paths) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download-gzip.js","sourceRoot":"","sources":["../../../src/util/download-gzip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"download-gzip.js","sourceRoot":"","sources":["../../../src/util/download-gzip.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SystemInformation } from '../interfaces.js';
|
|
1
|
+
import type { SystemInformation } from '../interfaces.js';
|
|
2
2
|
export declare function isWindows(): boolean;
|
|
3
3
|
export declare function getBotonicCLIVersion(): string;
|
|
4
4
|
export declare function getBotonicDependencies(): any[] | string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { arch, platform } from 'os';
|
|
2
|
-
import { join } from 'path';
|
|
1
|
+
import { arch, platform } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
3
|
import { BOTONIC_NPM_NAMESPACE } from '../constants.js';
|
|
4
4
|
import { readJSON } from './file-system.js';
|
|
5
5
|
import { execCommandSafe } from './system.js';
|
|
@@ -18,8 +18,9 @@ export function getBotonicCLIVersion() {
|
|
|
18
18
|
export function getBotonicDependencies() {
|
|
19
19
|
try {
|
|
20
20
|
const packageJSON = readJSON('package.json');
|
|
21
|
-
if (!packageJSON)
|
|
21
|
+
if (!packageJSON) {
|
|
22
22
|
return 'No package.json found.';
|
|
23
|
+
}
|
|
23
24
|
const botonicDependencies = Object.entries(packageJSON.dependencies).filter(([k, _]) => k.includes(BOTONIC_NPM_NAMESPACE));
|
|
24
25
|
return botonicDependencies;
|
|
25
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment-info.js","sourceRoot":"","sources":["../../../src/util/environment-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"environment-info.js","sourceRoot":"","sources":["../../../src/util/environment-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,UAAU,SAAS;IACvB,OAAO,QAAQ,EAAE,KAAK,OAAO,CAAA;AAC/B,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,IAAI,CAAC;QACH,OAAQ,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAS;aAClE,OAAO,CAAA;IACZ,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,MAAM,CAAC,CAAC,CAAC,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAA;QAC5C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,wBAAwB,CAAA;QACjC,CAAC;QACD,MAAM,mBAAmB,GAAG,MAAM,CAAC,OAAO,CACxC,WAAW,CAAC,YAAmB,CAChC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAA;QACvD,OAAO,mBAAmB,CAAA;IAC5B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,MAAM,CAAC,CAAC,CAAC,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,QAAQ,EAAE,QAAQ,EAAE;QACpB,IAAI,EAAE,IAAI,EAAE;QACZ,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,QAAQ;QAC1D,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QACrC,cAAc,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;QACrC,WAAW,EAAE,SAAS,EAAE;YACtB,CAAC,CAAC,eAAe,CAAC,aAAa,CAAC;YAChC,CAAC,CAAC,eAAe,CAAC,YAAY,CAAC;QACjC,YAAY,EAAE,eAAe,CAAC,gBAAgB,CAAC;QAC/C,mBAAmB,EAAE,oBAAoB,EAAE;QAC3C,oBAAoB,EAAE,sBAAsB,EAAE;KAC/C,CAAA;AACH,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JSONObject } from '../interfaces.js';
|
|
1
|
+
import type { JSONObject } from '../interfaces.js';
|
|
2
2
|
export declare function pathExists(path: string): boolean;
|
|
3
3
|
export declare function readDir(path: string): string[];
|
|
4
4
|
export declare function readJSON(path: string): JSONObject | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync, } from 'fs';
|
|
2
|
-
import { homedir } from 'os';
|
|
3
|
-
import { basename } from 'path';
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { basename } from 'node:path';
|
|
4
4
|
import { isWindows } from './environment-info.js';
|
|
5
5
|
import { execCommand } from './system.js';
|
|
6
6
|
export function pathExists(path) {
|
|
@@ -11,8 +11,9 @@ export function readDir(path) {
|
|
|
11
11
|
}
|
|
12
12
|
export function readJSON(path) {
|
|
13
13
|
const fileContent = readFileSync(path, 'utf8');
|
|
14
|
-
if (!fileContent)
|
|
14
|
+
if (!fileContent) {
|
|
15
15
|
return undefined;
|
|
16
|
+
}
|
|
16
17
|
return JSON.parse(fileContent);
|
|
17
18
|
}
|
|
18
19
|
export function writeJSON(path, object) {
|
|
@@ -20,7 +21,7 @@ export function writeJSON(path, object) {
|
|
|
20
21
|
}
|
|
21
22
|
export function createDir(path) {
|
|
22
23
|
// If directory already exists, it will throw an error.
|
|
23
|
-
|
|
24
|
+
mkdirSync(path);
|
|
24
25
|
}
|
|
25
26
|
export function createTempDir(name) {
|
|
26
27
|
return mkdtempSync(name);
|
|
@@ -37,6 +38,7 @@ export function removeRecursively(path) {
|
|
|
37
38
|
rmSync(path, { recursive: true, force: true });
|
|
38
39
|
}
|
|
39
40
|
export function getHomeDirectory() {
|
|
41
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: intentional shell variable interpolation
|
|
40
42
|
return isWindows() ? homedir() : execCommand('eval echo ~${SUDO_USER}');
|
|
41
43
|
}
|
|
42
44
|
export function getCurrentDirectory() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-system.js","sourceRoot":"","sources":["../../../src/util/file-system.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,UAAU,EACV,SAAS,EACT,WAAW,EACX,WAAW,EACX,YAAY,EACZ,MAAM,EACN,aAAa,GACd,MAAM,
|
|
1
|
+
{"version":3,"file":"file-system.js","sourceRoot":"","sources":["../../../src/util/file-system.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,UAAU,EACV,SAAS,EACT,WAAW,EACX,WAAW,EACX,YAAY,EACZ,MAAM,EACN,aAAa,GACd,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGpC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC9C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;AAChC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAW;IACjD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,uDAAuD;IACvD,SAAS,CAAC,IAAI,CAAC,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,EAAU;IACtD;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,iGAAiG;IACjG,OAAO,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAA;AACzE,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;AAChC,CAAC"}
|
package/lib/src/util/system.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execSync, spawn } from 'child_process';
|
|
1
|
+
import { execSync, spawn } from 'node:child_process';
|
|
2
2
|
export async function sleep(ms) {
|
|
3
3
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
4
4
|
}
|
|
@@ -22,7 +22,7 @@ export function spawnProcess(command, args, onClose) {
|
|
|
22
22
|
process.stderr.write(stderr);
|
|
23
23
|
});
|
|
24
24
|
childProcess.on('close', code => {
|
|
25
|
-
onClose
|
|
25
|
+
onClose?.();
|
|
26
26
|
process.stdout.write(`child process exited with code ${String(code)}`);
|
|
27
27
|
});
|
|
28
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../../src/util/system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../../src/util/system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAEpD,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,EAAU;IACpC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,MAAM,CAAC,CAAC,CAAC,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,OAAe,EACf,IAAc,EACd,OAAsB;IAEtB,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA,CAAC,gGAAgG;IAC3J,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;QACnC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC,CAAC,CAAA;IACF,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;QACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAC9B,CAAC,CAAC,CAAA;IACF,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;QAC9B,OAAO,EAAE,EAAE,CAAA;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAAsB;IACnE,YAAY,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAA;AAC/C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { jest } from '@jest/globals';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import { BotonicAPIService } from '../src/botonic-api-service.js';
|
|
5
|
+
import { BotCredentialsHandler, GlobalCredentialsHandler, } from '../src/util/credentials-handler.js';
|
|
6
|
+
describe('TEST: BotonicApiService', () => {
|
|
7
|
+
let service;
|
|
8
|
+
const mockOAuth = {
|
|
9
|
+
access_token: 'test-access-token',
|
|
10
|
+
expires_in: 3600,
|
|
11
|
+
token_type: 'Bearer',
|
|
12
|
+
scope: 'read write',
|
|
13
|
+
refresh_token: 'test-refresh-token',
|
|
14
|
+
};
|
|
15
|
+
const mockMe = {
|
|
16
|
+
id: 'user-123',
|
|
17
|
+
email: 'test@example.com',
|
|
18
|
+
first_name: 'John',
|
|
19
|
+
last_name: 'Doe',
|
|
20
|
+
organization_id: 'org-123',
|
|
21
|
+
campaign: 'test-campaign',
|
|
22
|
+
};
|
|
23
|
+
const mockBot = {
|
|
24
|
+
id: 'bot-123',
|
|
25
|
+
name: 'test-bot',
|
|
26
|
+
organization: 'org-123',
|
|
27
|
+
last_update: {
|
|
28
|
+
version: '1.0.0',
|
|
29
|
+
created_at: '2024-01-01T00:00:00Z',
|
|
30
|
+
modified_at: '2024-01-02T00:00:00Z',
|
|
31
|
+
published_at: '2024-01-03T00:00:00Z',
|
|
32
|
+
comment: 'Test update',
|
|
33
|
+
},
|
|
34
|
+
created_at: '2024-01-01T00:00:00Z',
|
|
35
|
+
provider_accounts: [],
|
|
36
|
+
is_debug: false,
|
|
37
|
+
is_published: true,
|
|
38
|
+
active_users: 10,
|
|
39
|
+
};
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
// Mock the credential handlers
|
|
42
|
+
jest
|
|
43
|
+
.spyOn(GlobalCredentialsHandler.prototype, 'load')
|
|
44
|
+
.mockReturnValue(undefined);
|
|
45
|
+
jest
|
|
46
|
+
.spyOn(BotCredentialsHandler.prototype, 'load')
|
|
47
|
+
.mockReturnValue(undefined);
|
|
48
|
+
jest
|
|
49
|
+
.spyOn(GlobalCredentialsHandler.prototype, 'dump')
|
|
50
|
+
.mockImplementation(() => { });
|
|
51
|
+
jest
|
|
52
|
+
.spyOn(BotCredentialsHandler.prototype, 'dump')
|
|
53
|
+
.mockImplementation(() => { });
|
|
54
|
+
jest
|
|
55
|
+
.spyOn(GlobalCredentialsHandler.prototype, 'createDirIfNotExists')
|
|
56
|
+
.mockImplementation(() => { });
|
|
57
|
+
jest
|
|
58
|
+
.spyOn(BotCredentialsHandler.prototype, 'createDirIfNotExists')
|
|
59
|
+
.mockImplementation(() => { });
|
|
60
|
+
});
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
jest.restoreAllMocks();
|
|
63
|
+
});
|
|
64
|
+
describe('Constructor', () => {
|
|
65
|
+
it('should initialize with no credentials', () => {
|
|
66
|
+
service = new BotonicAPIService();
|
|
67
|
+
expect(service.oauth).toBeUndefined();
|
|
68
|
+
expect(service.me).toBeUndefined();
|
|
69
|
+
expect(service.bot).toBeNull();
|
|
70
|
+
expect(service.apiClient).toBeDefined();
|
|
71
|
+
});
|
|
72
|
+
it('should load existing global credentials', () => {
|
|
73
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
74
|
+
oauth: mockOAuth,
|
|
75
|
+
me: mockMe,
|
|
76
|
+
});
|
|
77
|
+
service = new BotonicAPIService();
|
|
78
|
+
expect(service.oauth).toEqual(mockOAuth);
|
|
79
|
+
expect(service.me).toEqual(mockMe);
|
|
80
|
+
});
|
|
81
|
+
it('should load existing bot credentials', () => {
|
|
82
|
+
jest
|
|
83
|
+
.spyOn(BotCredentialsHandler.prototype, 'load')
|
|
84
|
+
.mockReturnValue({ bot: mockBot });
|
|
85
|
+
service = new BotonicAPIService();
|
|
86
|
+
expect(service.bot).toEqual(mockBot);
|
|
87
|
+
});
|
|
88
|
+
it('should set headers with access token', () => {
|
|
89
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
90
|
+
oauth: mockOAuth,
|
|
91
|
+
me: mockMe,
|
|
92
|
+
});
|
|
93
|
+
service = new BotonicAPIService();
|
|
94
|
+
expect(service.headers.get('Authorization')).toContain('Bearer test-access-token');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('botInfo', () => {
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
jest
|
|
100
|
+
.spyOn(BotCredentialsHandler.prototype, 'load')
|
|
101
|
+
.mockReturnValue({ bot: mockBot });
|
|
102
|
+
service = new BotonicAPIService();
|
|
103
|
+
});
|
|
104
|
+
it('should return bot info when bot exists', () => {
|
|
105
|
+
const result = service.botInfo();
|
|
106
|
+
expect(result).toEqual(mockBot);
|
|
107
|
+
});
|
|
108
|
+
it('should throw error when bot info is not available', () => {
|
|
109
|
+
service.bot = null;
|
|
110
|
+
expect(() => service.botInfo()).toThrow('Not bot info available');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe('getOauth', () => {
|
|
114
|
+
beforeEach(() => {
|
|
115
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
116
|
+
oauth: mockOAuth,
|
|
117
|
+
me: mockMe,
|
|
118
|
+
});
|
|
119
|
+
service = new BotonicAPIService();
|
|
120
|
+
});
|
|
121
|
+
it('should return oauth when available', () => {
|
|
122
|
+
const result = service.getOauth();
|
|
123
|
+
expect(result).toEqual(mockOAuth);
|
|
124
|
+
});
|
|
125
|
+
it('should throw error when oauth is not available', () => {
|
|
126
|
+
service.oauth = undefined;
|
|
127
|
+
expect(() => service.getOauth()).toThrow('Not OAuth available');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
describe('beforeExit', () => {
|
|
131
|
+
beforeEach(() => {
|
|
132
|
+
service = new BotonicAPIService();
|
|
133
|
+
});
|
|
134
|
+
it('should save global and bot credentials', () => {
|
|
135
|
+
const globalDumpSpy = jest.spyOn(service.globalCredentialsHandler, 'dump');
|
|
136
|
+
const botDumpSpy = jest.spyOn(service.botCredentialsHandler, 'dump');
|
|
137
|
+
const createDirSpy = jest.spyOn(service.globalCredentialsHandler, 'createDirIfNotExists');
|
|
138
|
+
service.oauth = mockOAuth;
|
|
139
|
+
service.me = mockMe;
|
|
140
|
+
service.bot = mockBot;
|
|
141
|
+
service.beforeExit();
|
|
142
|
+
expect(createDirSpy).toHaveBeenCalled();
|
|
143
|
+
expect(globalDumpSpy).toHaveBeenCalledWith({
|
|
144
|
+
oauth: mockOAuth,
|
|
145
|
+
me: mockMe,
|
|
146
|
+
});
|
|
147
|
+
expect(botDumpSpy).toHaveBeenCalledWith({
|
|
148
|
+
bot: mockBot,
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('login', () => {
|
|
153
|
+
beforeEach(() => {
|
|
154
|
+
service = new BotonicAPIService();
|
|
155
|
+
});
|
|
156
|
+
it('should login successfully and set credentials', async () => {
|
|
157
|
+
const postSpy = jest.spyOn(axios, 'post').mockResolvedValueOnce({
|
|
158
|
+
data: mockOAuth,
|
|
159
|
+
status: 200,
|
|
160
|
+
statusText: 'OK',
|
|
161
|
+
headers: {},
|
|
162
|
+
config: {},
|
|
163
|
+
});
|
|
164
|
+
const _getSpy = jest
|
|
165
|
+
.spyOn(service.apiClient, 'get')
|
|
166
|
+
.mockResolvedValueOnce({
|
|
167
|
+
data: mockMe,
|
|
168
|
+
status: 200,
|
|
169
|
+
statusText: 'OK',
|
|
170
|
+
headers: {},
|
|
171
|
+
config: {},
|
|
172
|
+
});
|
|
173
|
+
await service.login('test@example.com', 'password123');
|
|
174
|
+
expect(postSpy).toHaveBeenCalledWith(expect.stringContaining('/o/token/'), expect.any(String), expect.objectContaining({
|
|
175
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
176
|
+
}));
|
|
177
|
+
expect(service.oauth).toEqual(mockOAuth);
|
|
178
|
+
expect(service.me).toEqual(mockMe);
|
|
179
|
+
expect(service.headers.get('Authorization')).toContain('Bearer test-access-token');
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
describe('signup', () => {
|
|
183
|
+
beforeEach(() => {
|
|
184
|
+
service = new BotonicAPIService();
|
|
185
|
+
});
|
|
186
|
+
it('should call signup endpoint with correct data', async () => {
|
|
187
|
+
const postSpy = jest
|
|
188
|
+
.spyOn(service.apiClient, 'post')
|
|
189
|
+
.mockResolvedValueOnce({
|
|
190
|
+
data: { success: true },
|
|
191
|
+
status: 200,
|
|
192
|
+
statusText: 'OK',
|
|
193
|
+
headers: {},
|
|
194
|
+
config: {},
|
|
195
|
+
});
|
|
196
|
+
await service.signup('test@example.com', 'password123', 'Test Org', {
|
|
197
|
+
source: 'web',
|
|
198
|
+
});
|
|
199
|
+
expect(postSpy).toHaveBeenCalledWith(expect.stringContaining('sign-up/'), {
|
|
200
|
+
email: 'test@example.com',
|
|
201
|
+
password: 'password123',
|
|
202
|
+
org_name: 'Test Org',
|
|
203
|
+
campaign: { source: 'web' },
|
|
204
|
+
}, expect.any(Object));
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe('createBot', () => {
|
|
208
|
+
beforeEach(() => {
|
|
209
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
210
|
+
oauth: mockOAuth,
|
|
211
|
+
me: mockMe,
|
|
212
|
+
});
|
|
213
|
+
service = new BotonicAPIService();
|
|
214
|
+
});
|
|
215
|
+
it('should create a new bot and set it as current', async () => {
|
|
216
|
+
const postSpy = jest
|
|
217
|
+
.spyOn(service.apiClient, 'post')
|
|
218
|
+
.mockResolvedValueOnce({
|
|
219
|
+
data: mockBot,
|
|
220
|
+
status: 201,
|
|
221
|
+
statusText: 'Created',
|
|
222
|
+
headers: {},
|
|
223
|
+
config: {},
|
|
224
|
+
});
|
|
225
|
+
const result = await service.createBot('new-bot');
|
|
226
|
+
expect(postSpy).toHaveBeenCalledWith(expect.stringContaining('v2/bots/'), { name: 'new-bot' }, expect.any(Object));
|
|
227
|
+
expect(service.bot).toEqual(mockBot);
|
|
228
|
+
expect(result.data).toEqual(mockBot);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
describe('getBots', () => {
|
|
232
|
+
beforeEach(() => {
|
|
233
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
234
|
+
oauth: mockOAuth,
|
|
235
|
+
me: mockMe,
|
|
236
|
+
});
|
|
237
|
+
service = new BotonicAPIService();
|
|
238
|
+
});
|
|
239
|
+
it('should get bots without pagination', async () => {
|
|
240
|
+
const mockResponse = {
|
|
241
|
+
data: {
|
|
242
|
+
count: 2,
|
|
243
|
+
next: null,
|
|
244
|
+
previous: null,
|
|
245
|
+
results: [
|
|
246
|
+
{ id: 'bot-1', name: 'Bot 1' },
|
|
247
|
+
{ id: 'bot-2', name: 'Bot 2' },
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
status: 200,
|
|
251
|
+
statusText: 'OK',
|
|
252
|
+
headers: {},
|
|
253
|
+
config: {},
|
|
254
|
+
};
|
|
255
|
+
const getSpy = jest
|
|
256
|
+
.spyOn(service.apiClient, 'get')
|
|
257
|
+
.mockResolvedValueOnce(mockResponse);
|
|
258
|
+
const result = await service.getBots();
|
|
259
|
+
expect(result.data.results).toHaveLength(2);
|
|
260
|
+
expect(getSpy).toHaveBeenCalledTimes(1);
|
|
261
|
+
});
|
|
262
|
+
it('should handle paginated bot results', async () => {
|
|
263
|
+
const firstPageResponse = {
|
|
264
|
+
data: {
|
|
265
|
+
count: 150,
|
|
266
|
+
next: 'https://api.hubtype.com/v2/bots/?page=2',
|
|
267
|
+
previous: null,
|
|
268
|
+
results: Array.from({ length: 100 }, (_, i) => ({
|
|
269
|
+
id: `bot-${i}`,
|
|
270
|
+
name: `Bot ${i}`,
|
|
271
|
+
})),
|
|
272
|
+
},
|
|
273
|
+
status: 200,
|
|
274
|
+
statusText: 'OK',
|
|
275
|
+
headers: {},
|
|
276
|
+
config: {},
|
|
277
|
+
};
|
|
278
|
+
const secondPageResponse = {
|
|
279
|
+
data: {
|
|
280
|
+
count: 150,
|
|
281
|
+
next: null,
|
|
282
|
+
previous: 'https://api.hubtype.com/v2/bots/?page=1',
|
|
283
|
+
results: Array.from({ length: 50 }, (_, i) => ({
|
|
284
|
+
id: `bot-${i + 100}`,
|
|
285
|
+
name: `Bot ${i + 100}`,
|
|
286
|
+
})),
|
|
287
|
+
},
|
|
288
|
+
status: 200,
|
|
289
|
+
statusText: 'OK',
|
|
290
|
+
headers: {},
|
|
291
|
+
config: {},
|
|
292
|
+
};
|
|
293
|
+
const getSpy = jest
|
|
294
|
+
.spyOn(service.apiClient, 'get')
|
|
295
|
+
.mockResolvedValueOnce(firstPageResponse)
|
|
296
|
+
.mockResolvedValueOnce(secondPageResponse);
|
|
297
|
+
const result = await service.getBots();
|
|
298
|
+
expect(result.data.results).toHaveLength(150);
|
|
299
|
+
expect(getSpy).toHaveBeenCalledTimes(2);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
describe('setCurrentBot', () => {
|
|
303
|
+
beforeEach(() => {
|
|
304
|
+
service = new BotonicAPIService();
|
|
305
|
+
});
|
|
306
|
+
it('should set current bot', () => {
|
|
307
|
+
service.setCurrentBot(mockBot);
|
|
308
|
+
expect(service.bot).toEqual(mockBot);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
describe('logout', () => {
|
|
312
|
+
beforeEach(() => {
|
|
313
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
314
|
+
oauth: mockOAuth,
|
|
315
|
+
me: mockMe,
|
|
316
|
+
});
|
|
317
|
+
service = new BotonicAPIService();
|
|
318
|
+
});
|
|
319
|
+
it('should call logout and attempt to delete credentials', () => {
|
|
320
|
+
// Just verify the logout method runs without errors
|
|
321
|
+
// File system operations are mocked at the module level
|
|
322
|
+
expect(() => service.logout()).not.toThrow();
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
describe('getProviders', () => {
|
|
326
|
+
beforeEach(() => {
|
|
327
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
328
|
+
oauth: mockOAuth,
|
|
329
|
+
me: mockMe,
|
|
330
|
+
});
|
|
331
|
+
jest
|
|
332
|
+
.spyOn(BotCredentialsHandler.prototype, 'load')
|
|
333
|
+
.mockReturnValue({ bot: mockBot });
|
|
334
|
+
service = new BotonicAPIService();
|
|
335
|
+
});
|
|
336
|
+
it('should get providers for current bot', async () => {
|
|
337
|
+
const mockProviders = [
|
|
338
|
+
{ id: 'provider-1', name: 'Provider 1' },
|
|
339
|
+
{ id: 'provider-2', name: 'Provider 2' },
|
|
340
|
+
];
|
|
341
|
+
const getSpy = jest
|
|
342
|
+
.spyOn(service.apiClient, 'get')
|
|
343
|
+
.mockResolvedValueOnce({
|
|
344
|
+
data: mockProviders,
|
|
345
|
+
status: 200,
|
|
346
|
+
statusText: 'OK',
|
|
347
|
+
headers: {},
|
|
348
|
+
config: {},
|
|
349
|
+
});
|
|
350
|
+
await service.getProviders();
|
|
351
|
+
expect(getSpy).toHaveBeenCalledWith(expect.stringContaining('provider_accounts/'), expect.objectContaining({
|
|
352
|
+
params: { bot_id: 'bot-123' },
|
|
353
|
+
}));
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
describe('deployStatus', () => {
|
|
357
|
+
beforeEach(() => {
|
|
358
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
359
|
+
oauth: mockOAuth,
|
|
360
|
+
me: mockMe,
|
|
361
|
+
});
|
|
362
|
+
jest
|
|
363
|
+
.spyOn(BotCredentialsHandler.prototype, 'load')
|
|
364
|
+
.mockReturnValue({ bot: mockBot });
|
|
365
|
+
service = new BotonicAPIService();
|
|
366
|
+
});
|
|
367
|
+
it('should get deploy status', async () => {
|
|
368
|
+
const mockDeployStatus = { status: 'completed', deploy_id: 'deploy-123' };
|
|
369
|
+
const getSpy = jest
|
|
370
|
+
.spyOn(service.apiClient, 'get')
|
|
371
|
+
.mockResolvedValueOnce({
|
|
372
|
+
data: mockDeployStatus,
|
|
373
|
+
status: 200,
|
|
374
|
+
statusText: 'OK',
|
|
375
|
+
headers: {},
|
|
376
|
+
config: {},
|
|
377
|
+
});
|
|
378
|
+
await service.deployStatus('deploy-123');
|
|
379
|
+
expect(getSpy).toHaveBeenCalledWith(expect.stringContaining(`v2/bots/${mockBot.id}/deploy_status/`), expect.objectContaining({
|
|
380
|
+
params: { deploy_id: 'deploy-123' },
|
|
381
|
+
}));
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
describe('refreshToken', () => {
|
|
385
|
+
beforeEach(() => {
|
|
386
|
+
jest.spyOn(GlobalCredentialsHandler.prototype, 'load').mockReturnValue({
|
|
387
|
+
oauth: mockOAuth,
|
|
388
|
+
me: mockMe,
|
|
389
|
+
});
|
|
390
|
+
service = new BotonicAPIService();
|
|
391
|
+
});
|
|
392
|
+
it('should refresh token successfully', async () => {
|
|
393
|
+
const newOAuth = { ...mockOAuth, access_token: 'new-access-token' };
|
|
394
|
+
const postSpy = jest.spyOn(axios, 'post').mockResolvedValueOnce({
|
|
395
|
+
status: 200,
|
|
396
|
+
data: newOAuth,
|
|
397
|
+
statusText: 'OK',
|
|
398
|
+
headers: {},
|
|
399
|
+
config: {},
|
|
400
|
+
});
|
|
401
|
+
const dumpSpy = jest.spyOn(service.globalCredentialsHandler, 'dump');
|
|
402
|
+
// Access private method through any
|
|
403
|
+
await service.refreshToken();
|
|
404
|
+
expect(postSpy).toHaveBeenCalledWith(expect.stringContaining('/o/token/'), expect.any(String), expect.objectContaining({
|
|
405
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
406
|
+
}));
|
|
407
|
+
expect(service.oauth).toEqual(newOAuth);
|
|
408
|
+
expect(service.headers.get('Authorization')).toContain('Bearer new-access-token');
|
|
409
|
+
expect(dumpSpy).toHaveBeenCalled();
|
|
410
|
+
});
|
|
411
|
+
it('should throw error when refresh fails', async () => {
|
|
412
|
+
jest.spyOn(axios, 'post').mockResolvedValueOnce({
|
|
413
|
+
status: 401,
|
|
414
|
+
data: {},
|
|
415
|
+
statusText: 'Unauthorized',
|
|
416
|
+
headers: {},
|
|
417
|
+
config: {},
|
|
418
|
+
});
|
|
419
|
+
await expect(service.refreshToken()).rejects.toThrow('Error refreshing token');
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
//# sourceMappingURL=botonic-api-service.test.js.map
|