@embeddable.com/sdk-core 3.3.1 → 3.4.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/embeddable +5 -1
- package/lib/cleanup.d.ts +8 -0
- package/lib/index.esm.js +188 -78
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +188 -78
- package/lib/index.js.map +1 -1
- package/lib/login.d.ts +1 -0
- package/lib/utils.d.ts +2 -1
- package/lib/validate.d.ts +1 -0
- package/package.json +5 -3
- package/src/build.test.ts +96 -0
- package/src/buildTypes.test.ts +98 -0
- package/src/buildTypes.ts +20 -12
- package/src/cleanup.test.ts +85 -0
- package/src/cleanup.ts +13 -5
- package/src/login.test.ts +121 -0
- package/src/login.ts +1 -1
- package/src/provideConfig.test.ts +32 -0
- package/src/push.test.ts +184 -0
- package/src/push.ts +5 -2
- package/src/utils.test.ts +118 -0
- package/src/utils.ts +11 -6
- package/src/validate.test.ts +124 -0
- package/src/validate.ts +21 -31
package/lib/login.d.ts
CHANGED
package/lib/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const checkNodeVersion: () => Promise<
|
|
1
|
+
export declare const checkNodeVersion: () => Promise<boolean>;
|
|
2
2
|
/**
|
|
3
3
|
* Get the value of a process argument by key
|
|
4
4
|
* Example: getArgumentByKey("--email") or getArgumentByKey(["--email", "-e"])
|
|
@@ -6,6 +6,7 @@ export declare const checkNodeVersion: () => Promise<void>;
|
|
|
6
6
|
* @returns
|
|
7
7
|
*/
|
|
8
8
|
export declare const getArgumentByKey: (key: string | string[]) => string | undefined;
|
|
9
|
+
export declare const SUCCESS_FLAG_FILE: string;
|
|
9
10
|
/**
|
|
10
11
|
* Store a flag in the credentials directory to indicate a successful build
|
|
11
12
|
* This is used to determine if the build was successful or not
|
package/lib/validate.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
declare const _default: (ctx: any, exitIfInvalid?: boolean) => Promise<boolean>;
|
|
2
2
|
export default _default;
|
|
3
3
|
export declare function dataModelsValidation(filesList: [string, string][]): Promise<string[]>;
|
|
4
|
+
export declare function securityContextValidation(filesList: [string, string][]): Promise<string[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@embeddable.com/sdk-core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.1",
|
|
4
4
|
"description": "Core Embeddable SDK module responsible for web-components bundling and publishing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"embeddable",
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
"directory": "packages/core-sdk"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "rollup -c"
|
|
19
|
+
"build": "rollup -c",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest"
|
|
20
22
|
},
|
|
21
23
|
"author": "Embeddable.com <engineering@embeddable.com>",
|
|
22
24
|
"files": [
|
|
@@ -49,7 +51,7 @@
|
|
|
49
51
|
"ora": "^8.0.1",
|
|
50
52
|
"serve-static": "^1.15.0",
|
|
51
53
|
"sorcery": "^0.11.0",
|
|
52
|
-
"vite": "^
|
|
54
|
+
"vite": "^5.3.2",
|
|
53
55
|
"ws": "^8.17.0",
|
|
54
56
|
"yaml": "^2.3.3"
|
|
55
57
|
},
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import build from "./build";
|
|
2
|
+
import prepare from "./prepare";
|
|
3
|
+
import validate from "./validate";
|
|
4
|
+
import buildTypes from "./buildTypes";
|
|
5
|
+
import provideConfig from "./provideConfig";
|
|
6
|
+
import generate from "./generate";
|
|
7
|
+
import cleanup from "./cleanup";
|
|
8
|
+
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
import reportErrorToRollbar from "./rollbar.mjs";
|
|
11
|
+
import { storeBuildSuccessFlag } from "./utils";
|
|
12
|
+
|
|
13
|
+
const mockPlugin = {
|
|
14
|
+
validate: vi.fn(),
|
|
15
|
+
build: vi.fn(),
|
|
16
|
+
cleanup: vi.fn(),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
vi.mock("./provideConfig", () => ({
|
|
20
|
+
default: vi.fn(),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
vi.mock("./buildTypes", () => ({
|
|
24
|
+
default: vi.fn(),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
vi.mock("./rollbar.mjs", () => ({
|
|
28
|
+
default: vi.fn(),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
vi.mock("./validate", () => ({
|
|
32
|
+
default: vi.fn(),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
vi.mock("./prepare", () => ({
|
|
36
|
+
default: vi.fn(),
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
vi.mock("./generate", () => ({
|
|
40
|
+
default: vi.fn(),
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
vi.mock("./cleanup", () => ({
|
|
44
|
+
default: vi.fn(),
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
vi.mock("./utils", async () => {
|
|
48
|
+
const actual = await vi.importActual("./utils");
|
|
49
|
+
return {
|
|
50
|
+
...actual,
|
|
51
|
+
storeBuildSuccessFlag: vi.fn(),
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const config = {
|
|
56
|
+
plugins: [() => mockPlugin],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
describe("build", () => {
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
vi.mocked(provideConfig).mockResolvedValue(config);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should call all the necessary functions", async () => {
|
|
65
|
+
await build();
|
|
66
|
+
|
|
67
|
+
expect(validate).toHaveBeenCalledWith(config);
|
|
68
|
+
expect(prepare).toHaveBeenCalledWith(config);
|
|
69
|
+
expect(buildTypes).toHaveBeenCalledWith(config);
|
|
70
|
+
|
|
71
|
+
// Plugin
|
|
72
|
+
expect(mockPlugin.validate).toHaveBeenCalledWith(config);
|
|
73
|
+
expect(mockPlugin.build).toHaveBeenCalledWith(config);
|
|
74
|
+
expect(mockPlugin.cleanup).toHaveBeenCalledWith(config);
|
|
75
|
+
|
|
76
|
+
expect(generate).toHaveBeenCalledWith(config, "sdk-react");
|
|
77
|
+
|
|
78
|
+
expect(cleanup).toHaveBeenCalledWith(config);
|
|
79
|
+
expect(storeBuildSuccessFlag).toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should call reportErrorToRollbar and exit if an error occurs", async () => {
|
|
83
|
+
vi.spyOn(process, "exit").mockImplementation(() => null as never);
|
|
84
|
+
vi.spyOn(console, "log").mockImplementation(() => undefined);
|
|
85
|
+
const error = new Error("test error");
|
|
86
|
+
|
|
87
|
+
vi.mocked(validate).mockRejectedValue(error);
|
|
88
|
+
vi.mocked(reportErrorToRollbar).mockResolvedValue(undefined);
|
|
89
|
+
|
|
90
|
+
await build();
|
|
91
|
+
|
|
92
|
+
expect(reportErrorToRollbar).toHaveBeenCalledWith(error);
|
|
93
|
+
expect(console.log).toHaveBeenCalledWith(error);
|
|
94
|
+
expect(process.exit).toHaveBeenCalledWith(1);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import buildTypes, { EMB_TYPE_FILE_REGEX } from "./buildTypes";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { build } from "vite";
|
|
5
|
+
import { findFiles, getContentHash } from "@embeddable.com/sdk-utils";
|
|
6
|
+
|
|
7
|
+
const config = {
|
|
8
|
+
client: {
|
|
9
|
+
srcDir: "src",
|
|
10
|
+
rootDir: "root",
|
|
11
|
+
buildDir: "build",
|
|
12
|
+
},
|
|
13
|
+
outputOptions: {
|
|
14
|
+
typesEntryPointFilename: "typesEntryPointFilename",
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const startMock = {
|
|
19
|
+
succeed: vi.fn(),
|
|
20
|
+
fail: vi.fn(),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
vi.mock("ora", () => ({
|
|
24
|
+
default: () => ({
|
|
25
|
+
start: vi.fn().mockImplementation(() => startMock),
|
|
26
|
+
info: vi.fn(),
|
|
27
|
+
fail: vi.fn(),
|
|
28
|
+
}),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
vi.mock("@embeddable.com/sdk-utils", () => ({
|
|
32
|
+
findFiles: vi.fn(),
|
|
33
|
+
getContentHash: vi.fn(),
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
vi.mock("node:path", () => ({
|
|
37
|
+
resolve: vi.fn(),
|
|
38
|
+
relative: vi.fn(),
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
vi.mock("node:fs/promises", () => ({
|
|
42
|
+
writeFile: vi.fn(),
|
|
43
|
+
rm: vi.fn(),
|
|
44
|
+
readFile: vi.fn(),
|
|
45
|
+
rename: vi.fn(),
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
vi.mock("vite", () => ({
|
|
49
|
+
build: vi.fn(),
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
describe("buildTypes", () => {
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
vi.mocked(findFiles).mockResolvedValue([["fileName", "filePath"]]);
|
|
55
|
+
vi.mocked(path.relative).mockReturnValue("relativePath");
|
|
56
|
+
vi.mocked(path.resolve).mockReturnValue("resolvedPath");
|
|
57
|
+
vi.mocked(fs.readFile).mockResolvedValue("fileContent");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should build types", async () => {
|
|
61
|
+
await buildTypes(config);
|
|
62
|
+
|
|
63
|
+
expect(findFiles).toHaveBeenCalledWith("src", EMB_TYPE_FILE_REGEX);
|
|
64
|
+
|
|
65
|
+
expect(build).toHaveBeenCalledWith({
|
|
66
|
+
build: {
|
|
67
|
+
emptyOutDir: false,
|
|
68
|
+
lib: {
|
|
69
|
+
entry: "resolvedPath",
|
|
70
|
+
fileName: "embeddable-types",
|
|
71
|
+
formats: ["es"],
|
|
72
|
+
},
|
|
73
|
+
outDir: "build",
|
|
74
|
+
},
|
|
75
|
+
logLevel: "error",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(fs.readFile).toHaveBeenCalledWith("resolvedPath", "utf8");
|
|
79
|
+
expect(getContentHash).toHaveBeenCalledWith("fileContent");
|
|
80
|
+
|
|
81
|
+
expect(startMock.succeed).toHaveBeenCalledWith("Types built completed");
|
|
82
|
+
|
|
83
|
+
expect(fs.writeFile).toHaveBeenCalledWith(
|
|
84
|
+
"resolvedPath",
|
|
85
|
+
`import '../relativePath';
|
|
86
|
+
import '../relativePath';`,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
expect(fs.rm).toHaveBeenCalledWith("resolvedPath");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should not add hash to the file name when watch is enabled", async () => {
|
|
93
|
+
await buildTypes({ ...config, dev: { watch: true } });
|
|
94
|
+
|
|
95
|
+
expect(getContentHash).not.toHaveBeenCalled();
|
|
96
|
+
expect(fs.rename).not.toHaveBeenCalled();
|
|
97
|
+
});
|
|
98
|
+
});
|
package/src/buildTypes.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import * as vite from "vite";
|
|
4
4
|
const oraP = import("ora");
|
|
5
|
-
import { findFiles } from "@embeddable.com/sdk-utils";
|
|
5
|
+
import { findFiles, getContentHash } from "@embeddable.com/sdk-utils";
|
|
6
6
|
|
|
7
7
|
export const EMB_TYPE_FILE_REGEX = /^(.*)\.type\.emb\.[jt]s$/;
|
|
8
8
|
export const EMB_OPTIONS_FILE_REGEX = /^(.*)\.options\.emb\.[jt]s$/;
|
|
@@ -48,28 +48,36 @@ async function generate(ctx: any) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
async function build(ctx: any) {
|
|
51
|
+
const typesFilePath = path.resolve(
|
|
52
|
+
ctx.client.buildDir,
|
|
53
|
+
ctx.outputOptions.typesEntryPointFilename,
|
|
54
|
+
);
|
|
55
|
+
|
|
51
56
|
await vite.build({
|
|
52
57
|
logLevel: "error",
|
|
53
58
|
build: {
|
|
54
59
|
emptyOutDir: false,
|
|
55
60
|
lib: {
|
|
56
|
-
entry:
|
|
57
|
-
ctx.client.buildDir,
|
|
58
|
-
ctx.outputOptions.typesEntryPointFilename,
|
|
59
|
-
),
|
|
61
|
+
entry: typesFilePath,
|
|
60
62
|
formats: ["es"],
|
|
61
63
|
fileName: "embeddable-types",
|
|
62
64
|
},
|
|
63
|
-
rollupOptions: ctx.dev?.watch
|
|
64
|
-
? undefined
|
|
65
|
-
: {
|
|
66
|
-
output: {
|
|
67
|
-
entryFileNames: "embeddable-types-[hash].js",
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
65
|
outDir: ctx.client.buildDir,
|
|
71
66
|
},
|
|
72
67
|
});
|
|
68
|
+
|
|
69
|
+
if (!ctx.dev?.watch) {
|
|
70
|
+
const fileContent = await fs.readFile(typesFilePath, "utf8");
|
|
71
|
+
|
|
72
|
+
const fileHash = getContentHash(fileContent);
|
|
73
|
+
|
|
74
|
+
const fileName = `embeddable-types-${fileHash}.js`;
|
|
75
|
+
|
|
76
|
+
await fs.rename(
|
|
77
|
+
path.resolve(ctx.client.buildDir, "embeddable-types.js"),
|
|
78
|
+
path.resolve(ctx.client.buildDir, fileName),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
async function cleanup(ctx: any) {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { createManifest } from "./cleanup";
|
|
4
|
+
import { findFiles } from "@embeddable.com/sdk-utils";
|
|
5
|
+
|
|
6
|
+
const ctx = {
|
|
7
|
+
client: {
|
|
8
|
+
tmpDir: "tmpDir",
|
|
9
|
+
stencilBuild: "stencilBuild",
|
|
10
|
+
buildDir: "buildDir",
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
vi.mock("node:fs/promises", () => ({
|
|
15
|
+
writeFile: vi.fn(),
|
|
16
|
+
rename: vi.fn(),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock("@embeddable.com/sdk-utils", () => ({
|
|
20
|
+
findFiles: vi.fn(),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
vi.mock("node:path", async () => {
|
|
24
|
+
const actual = await vi.importActual("node:path");
|
|
25
|
+
return {
|
|
26
|
+
...actual,
|
|
27
|
+
resolve: vi.fn(),
|
|
28
|
+
basename: vi.fn(),
|
|
29
|
+
join: vi.fn(),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("cleanup", () => {
|
|
34
|
+
describe("createManifest", () => {
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
vi.mocked(fs.writeFile).mockImplementation(async () => undefined);
|
|
37
|
+
vi.mocked(fs.rename).mockImplementation(async () => undefined);
|
|
38
|
+
vi.mocked(findFiles).mockResolvedValue([["", ""]]);
|
|
39
|
+
vi.mocked(path.basename).mockReturnValue("basename");
|
|
40
|
+
vi.mocked(path.join).mockImplementation((...args) => args.join("/"));
|
|
41
|
+
|
|
42
|
+
Object.defineProperties(process, {
|
|
43
|
+
platform: {
|
|
44
|
+
value: "darwin",
|
|
45
|
+
},
|
|
46
|
+
version: {
|
|
47
|
+
value: "v18.20.2",
|
|
48
|
+
},
|
|
49
|
+
env: {
|
|
50
|
+
value: {
|
|
51
|
+
npm_config_user_agent: "npm/10.7.0",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
it("should create manifest", async () => {
|
|
57
|
+
await createManifest({
|
|
58
|
+
ctx,
|
|
59
|
+
typesFileName: "typesFileName",
|
|
60
|
+
metaFileName: "metaFileName",
|
|
61
|
+
editorsMetaFileName: "editorsMetaFileName",
|
|
62
|
+
stencilWrapperFileName: "stencilWrapperFileName",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
expect(fs.writeFile).toHaveBeenCalledWith(
|
|
66
|
+
"tmpDir/embeddable-manifest.json",
|
|
67
|
+
JSON.stringify({
|
|
68
|
+
entryFiles: {
|
|
69
|
+
"embeddable-types.js": "typesFileName",
|
|
70
|
+
"embeddable-components-meta.js": "metaFileName",
|
|
71
|
+
"embeddable-editors-meta.js": "editorsMetaFileName",
|
|
72
|
+
"embeddable-wrapper.esm.js": "stencilWrapperFileName",
|
|
73
|
+
},
|
|
74
|
+
metadata: {
|
|
75
|
+
nodeVersion: "v18.20.2",
|
|
76
|
+
platform: "darwin",
|
|
77
|
+
sdkVersions: {},
|
|
78
|
+
packageManager: "npm",
|
|
79
|
+
packageManagerVersion: "10.7.0",
|
|
80
|
+
},
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
package/src/cleanup.ts
CHANGED
|
@@ -19,7 +19,7 @@ type ManifestArgs = {
|
|
|
19
19
|
stencilWrapperFileName: string;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
async function createManifest({
|
|
22
|
+
export async function createManifest({
|
|
23
23
|
ctx,
|
|
24
24
|
typesFileName,
|
|
25
25
|
metaFileName,
|
|
@@ -81,36 +81,44 @@ async function createManifest({
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
async function extractBuild(ctx: any) {
|
|
84
|
-
const
|
|
84
|
+
const stencilBuildFiles = await findFiles(
|
|
85
85
|
ctx.client.stencilBuild,
|
|
86
86
|
/embeddable-wrapper.esm-[a-z0-9]+\.js/,
|
|
87
87
|
);
|
|
88
88
|
|
|
89
|
+
const [[, stencilWrapperFilePath]] = stencilBuildFiles || [];
|
|
90
|
+
|
|
89
91
|
const stencilWrapperFileName = path.basename(stencilWrapperFilePath);
|
|
90
92
|
await fs.rename(
|
|
91
93
|
path.resolve(ctx.client.buildDir, ctx.client.stencilBuild),
|
|
92
94
|
ctx.client.tmpDir,
|
|
93
95
|
);
|
|
94
96
|
|
|
95
|
-
const
|
|
97
|
+
const typesBuildFiles = await findFiles(
|
|
96
98
|
ctx.client.buildDir,
|
|
97
99
|
/embeddable-types-[a-z0-9]+\.js/,
|
|
98
100
|
);
|
|
99
101
|
|
|
102
|
+
const [[, typesFilePath]] = typesBuildFiles || [];
|
|
103
|
+
|
|
100
104
|
const typesFileName = path.basename(typesFilePath);
|
|
101
105
|
await fs.rename(typesFilePath, path.join(ctx.client.tmpDir, typesFileName));
|
|
102
106
|
|
|
103
|
-
const
|
|
107
|
+
const metaBuildFiles = await findFiles(
|
|
104
108
|
ctx.client.buildDir,
|
|
105
109
|
/embeddable-components-meta-[a-z0-9]+\.js/,
|
|
106
110
|
);
|
|
111
|
+
|
|
112
|
+
const [[, metaFilePath]] = metaBuildFiles || [];
|
|
107
113
|
const metaFileName = path.basename(metaFilePath);
|
|
108
114
|
await fs.rename(metaFilePath, path.join(ctx.client.tmpDir, metaFileName));
|
|
109
115
|
|
|
110
|
-
const
|
|
116
|
+
const editorsMetaBuildFiles = await findFiles(
|
|
111
117
|
ctx.client.buildDir,
|
|
112
118
|
/embeddable-editors-meta-[a-z0-9]+\.js/,
|
|
113
119
|
);
|
|
120
|
+
|
|
121
|
+
const [[, editorsMetaFilePath]] = editorsMetaBuildFiles || [];
|
|
114
122
|
const editorsMetaFileName = path.basename(editorsMetaFilePath);
|
|
115
123
|
await fs.rename(
|
|
116
124
|
editorsMetaFilePath,
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { server } from "./../../../mocks/server";
|
|
2
|
+
import login, { resolveFiles, getToken } from "./login";
|
|
3
|
+
import { vi } from "vitest";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { mkdir, access, writeFile, readFile } from "fs/promises";
|
|
7
|
+
import { CREDENTIALS_DIR, CREDENTIALS_FILE } from "./credentials";
|
|
8
|
+
import { http, HttpResponse } from "msw";
|
|
9
|
+
import { AxiosError } from "axios";
|
|
10
|
+
|
|
11
|
+
vi.mock("fs/promises", () => ({
|
|
12
|
+
readFile: vi.fn(),
|
|
13
|
+
writeFile: vi.fn(),
|
|
14
|
+
access: vi.fn(),
|
|
15
|
+
mkdir: vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
const startMock = {
|
|
19
|
+
succeed: vi.fn(),
|
|
20
|
+
fail: vi.fn(),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
vi.mock("ora", () => ({
|
|
24
|
+
default: () => ({
|
|
25
|
+
start: vi.fn().mockImplementation(() => startMock),
|
|
26
|
+
info: vi.fn(),
|
|
27
|
+
}),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
vi.mock("./rollbar.mjs", () => ({
|
|
31
|
+
default: vi.fn(),
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
vi.mock("open", () => ({
|
|
35
|
+
default: vi.fn(),
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
vi.mock("node:fs", () => ({
|
|
39
|
+
existsSync: vi.fn(),
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
vi.mock("node:url", () => ({
|
|
43
|
+
pathToFileURL: vi.fn(),
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
vi.mock(`${process.cwd()}/embeddable.config.ts`, () => ({
|
|
47
|
+
default: {
|
|
48
|
+
authDomain: "test-domain.com",
|
|
49
|
+
},
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
describe("login", () => {
|
|
53
|
+
beforeEach(async () => {
|
|
54
|
+
vi.mocked(readFile).mockImplementation(async () =>
|
|
55
|
+
Buffer.from(`{"access_token":"mocked-token"}`),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
vi.mocked(access).mockImplementation(async () => {
|
|
59
|
+
throw new Error();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
vi.mocked(mkdir).mockImplementation(async () => "mocked");
|
|
63
|
+
|
|
64
|
+
vi.mocked(writeFile).mockImplementation(async () => undefined);
|
|
65
|
+
|
|
66
|
+
vi.mocked(existsSync).mockImplementation(() => true);
|
|
67
|
+
vi.mocked(pathToFileURL).mockImplementation(
|
|
68
|
+
() => new URL("mocked-config-path"),
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
vi.mock("./reportErrorToRollbar", () => vi.fn());
|
|
73
|
+
vi.mock("./sleep", () => vi.fn());
|
|
74
|
+
|
|
75
|
+
it("should resolve files", async () => {
|
|
76
|
+
await resolveFiles();
|
|
77
|
+
|
|
78
|
+
expect(access).toHaveBeenCalledWith(CREDENTIALS_DIR);
|
|
79
|
+
expect(mkdir).toHaveBeenCalledWith(CREDENTIALS_DIR);
|
|
80
|
+
expect(writeFile).toHaveBeenCalledWith(CREDENTIALS_FILE, "");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should get token", async () => {
|
|
84
|
+
const token = await getToken();
|
|
85
|
+
|
|
86
|
+
expect(token).toBe("mocked-token");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should login by saving token in the credentials file", async () => {
|
|
90
|
+
await login();
|
|
91
|
+
expect(startMock.succeed).toHaveBeenCalledWith(
|
|
92
|
+
"You are successfully authenticated now!",
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
expect(writeFile).toHaveBeenCalledWith(
|
|
96
|
+
CREDENTIALS_FILE,
|
|
97
|
+
JSON.stringify({ access_token: "mocked-token " }),
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should fail to login when the response returns 500 error", async () => {
|
|
102
|
+
vi.spyOn(console, "log").mockImplementation(() => undefined);
|
|
103
|
+
vi.spyOn(process, "exit").mockImplementation(() => undefined as never);
|
|
104
|
+
|
|
105
|
+
server.use(
|
|
106
|
+
http.post("**/oauth/device/code", () => {
|
|
107
|
+
return new HttpResponse(null, { status: 500 });
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
await login();
|
|
112
|
+
|
|
113
|
+
expect(startMock.fail).toHaveBeenCalledWith(
|
|
114
|
+
"Authentication failed. Please try again.",
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
118
|
+
new AxiosError("Request failed with status code 500"),
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
});
|
package/src/login.ts
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import provideConfig from "./provideConfig";
|
|
4
|
+
import { vi } from "vitest";
|
|
5
|
+
|
|
6
|
+
vi.mock("node:fs", () => ({
|
|
7
|
+
existsSync: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
vi.mock("node:url", () => ({
|
|
11
|
+
pathToFileURL: vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock(`${process.cwd()}/embeddable.config.ts`, () => ({
|
|
15
|
+
default: "mocked-config",
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
describe("provideConfig", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.mocked(existsSync).mockImplementation(() => true);
|
|
21
|
+
vi.mocked(pathToFileURL).mockImplementation(
|
|
22
|
+
() => new URL("mocked-config-path"),
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should return the default config when the config file exists", async () => {
|
|
27
|
+
const result = await provideConfig();
|
|
28
|
+
|
|
29
|
+
// Assert the result
|
|
30
|
+
expect(result).toEqual("mocked-config");
|
|
31
|
+
});
|
|
32
|
+
});
|