@superblocksteam/sdk 1.14.2 → 2.0.3-next.100
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/.mocharc.json +7 -0
- package/.prettierrc +18 -0
- package/dist/cli-replacement/dev.d.mts +19 -0
- package/dist/cli-replacement/dev.d.mts.map +1 -0
- package/dist/cli-replacement/dev.mjs +129 -0
- package/dist/cli-replacement/dev.mjs.map +1 -0
- package/dist/cli-replacement/init.d.ts +14 -0
- package/dist/cli-replacement/init.d.ts.map +1 -0
- package/dist/cli-replacement/init.js +26 -0
- package/dist/cli-replacement/init.js.map +1 -0
- package/dist/client.d.ts +31 -17
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +137 -155
- package/dist/client.js.map +1 -0
- package/dist/dbfs/client.d.ts +6 -0
- package/dist/dbfs/client.d.ts.map +1 -0
- package/dist/dbfs/client.js +117 -0
- package/dist/dbfs/client.js.map +1 -0
- package/dist/dbfs/local.d.ts +15 -0
- package/dist/dbfs/local.d.ts.map +1 -0
- package/dist/dbfs/local.js +126 -0
- package/dist/dbfs/local.js.map +1 -0
- package/dist/dev-utils/custom-build.d.mts +4 -0
- package/dist/dev-utils/custom-build.d.mts.map +1 -0
- package/dist/dev-utils/custom-build.mjs +99 -0
- package/dist/dev-utils/custom-build.mjs.map +1 -0
- package/dist/dev-utils/custom-config.d.mts +2 -0
- package/dist/dev-utils/custom-config.d.mts.map +1 -0
- package/dist/dev-utils/custom-config.mjs +57 -0
- package/dist/dev-utils/custom-config.mjs.map +1 -0
- package/dist/dev-utils/dev-logger.d.mts +8 -0
- package/dist/dev-utils/dev-logger.d.mts.map +1 -0
- package/dist/dev-utils/dev-logger.mjs +25 -0
- package/dist/dev-utils/dev-logger.mjs.map +1 -0
- package/dist/dev-utils/dev-server.d.mts +18 -0
- package/dist/dev-utils/dev-server.d.mts.map +1 -0
- package/dist/dev-utils/dev-server.mjs +265 -0
- package/dist/dev-utils/dev-server.mjs.map +1 -0
- package/dist/dev-utils/dev-tracer.d.ts +3 -0
- package/dist/dev-utils/dev-tracer.d.ts.map +1 -0
- package/dist/dev-utils/dev-tracer.js +28 -0
- package/dist/dev-utils/dev-tracer.js.map +1 -0
- package/dist/dev-utils/vite-plugin-dd-rum.d.mts +10 -0
- package/dist/dev-utils/vite-plugin-dd-rum.d.mts.map +1 -0
- package/dist/dev-utils/vite-plugin-dd-rum.mjs +34 -0
- package/dist/dev-utils/vite-plugin-dd-rum.mjs.map +1 -0
- package/dist/dev-utils/vite-plugin-react-transform.d.mts +7 -0
- package/dist/dev-utils/vite-plugin-react-transform.d.mts.map +1 -0
- package/dist/dev-utils/vite-plugin-react-transform.mjs +110 -0
- package/dist/dev-utils/vite-plugin-react-transform.mjs.map +1 -0
- package/dist/dev-utils/vite-plugin-sb-cdn.d.mts +34 -0
- package/dist/dev-utils/vite-plugin-sb-cdn.d.mts.map +1 -0
- package/dist/dev-utils/vite-plugin-sb-cdn.mjs +720 -0
- package/dist/dev-utils/vite-plugin-sb-cdn.mjs.map +1 -0
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +4 -9
- package/dist/errors.js.map +1 -0
- package/dist/flag.d.ts +2 -2
- package/dist/flag.d.ts.map +1 -0
- package/dist/flag.js +5 -9
- package/dist/flag.js.map +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -20
- package/dist/index.js.map +1 -0
- package/dist/sdk.d.ts +42 -18
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +47 -43
- package/dist/sdk.js.map +1 -0
- package/dist/socket/handlers.d.ts +3 -128
- package/dist/socket/handlers.d.ts.map +1 -0
- package/dist/socket/handlers.js +7 -9
- package/dist/socket/handlers.js.map +1 -0
- package/dist/socket/index.d.ts +4 -3
- package/dist/socket/index.d.ts.map +1 -0
- package/dist/socket/index.js +12 -21
- package/dist/socket/index.js.map +1 -0
- package/dist/socket/signing.d.ts +3 -1
- package/dist/socket/signing.d.ts.map +1 -0
- package/dist/socket/signing.js +8 -17
- package/dist/socket/signing.js.map +1 -0
- package/dist/socket/socket.d.ts +3 -2
- package/dist/socket/socket.d.ts.map +1 -0
- package/dist/socket/socket.js +9 -19
- package/dist/socket/socket.js.map +1 -0
- package/dist/types/common.d.ts +2 -103
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +8 -24
- package/dist/types/common.js.map +1 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -20
- package/dist/types/index.js.map +1 -0
- package/dist/types/plugin.d.ts +1 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +3 -5
- package/dist/types/plugin.js.map +1 -0
- package/dist/types/signing.d.ts +2 -1
- package/dist/types/signing.d.ts.map +1 -0
- package/dist/types/signing.js +2 -2
- package/dist/types/signing.js.map +1 -0
- package/dist/types/socket.d.ts +1 -0
- package/dist/types/socket.d.ts.map +1 -0
- package/dist/types/socket.js +2 -5
- package/dist/types/socket.js.map +1 -0
- package/dist/utils.d.ts +3 -1
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +14 -23
- package/dist/utils.js.map +1 -0
- package/dist/version-control.d.mts +59 -0
- package/dist/version-control.d.mts.map +1 -0
- package/dist/version-control.mjs +899 -0
- package/dist/version-control.mjs.map +1 -0
- package/eslint.config.js +85 -0
- package/package.json +76 -30
- package/src/cli-replacement/dev.mts +194 -0
- package/src/cli-replacement/init.ts +47 -0
- package/src/client.ts +114 -38
- package/src/dbfs/client.ts +162 -0
- package/src/dbfs/local.ts +163 -0
- package/src/dev-utils/custom-build.mts +113 -0
- package/src/dev-utils/custom-config.mts +66 -0
- package/src/dev-utils/dev-logger.mts +39 -0
- package/src/dev-utils/dev-server.mts +342 -0
- package/src/dev-utils/dev-tracer.ts +31 -0
- package/src/dev-utils/vite-plugin-dd-rum.mts +47 -0
- package/src/dev-utils/vite-plugin-react-transform.mts +130 -0
- package/src/dev-utils/vite-plugin-sb-cdn.mts +988 -0
- package/src/flag.ts +2 -3
- package/src/index.ts +119 -4
- package/src/sdk.ts +91 -17
- package/src/socket/handlers.ts +9 -147
- package/src/socket/index.ts +6 -9
- package/src/socket/signing.ts +7 -8
- package/src/socket/socket.ts +8 -9
- package/src/types/common.ts +2 -119
- package/src/types/index.ts +4 -4
- package/src/types/signing.ts +1 -1
- package/src/types/socket.ts +1 -1
- package/src/utils.ts +5 -6
- package/src/version-control.mts +1351 -0
- package/test/dev-utils/fixture/index.html +12 -0
- package/test/dev-utils/fixture/main.jsx +22 -0
- package/test/dev-utils/fixture/package-lock.json +25 -0
- package/test/dev-utils/fixture/package.json +9 -0
- package/test/dev-utils/vite-plugin-sb-cdn.test.mts +74 -0
- package/test/tsconfig.json +9 -0
- package/test/version-control.test.mts +1412 -0
- package/tsconfig.json +15 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/.eslintrc.json +0 -55
|
@@ -0,0 +1,1412 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readAppApiYamlFile, LoopType } from "@superblocksteam/util";
|
|
4
|
+
import { expect } from "chai";
|
|
5
|
+
import fs from "fs-extra";
|
|
6
|
+
import { describe, it } from "mocha";
|
|
7
|
+
import { stringify as ymlstringify } from "yaml";
|
|
8
|
+
import { FeatureFlags } from "../src/flag.js";
|
|
9
|
+
import {
|
|
10
|
+
addExistingFilePathsForApi,
|
|
11
|
+
validateLocalResource,
|
|
12
|
+
writeAppApi,
|
|
13
|
+
writeApplicationToDisk,
|
|
14
|
+
writeResourceToDisk,
|
|
15
|
+
} from "../src/version-control.mjs";
|
|
16
|
+
import type {
|
|
17
|
+
ApplicationWrapper,
|
|
18
|
+
MultiPageApplicationWrapperWithComponents,
|
|
19
|
+
} from "../src/client.js";
|
|
20
|
+
import type { ApiWithPb } from "../src/types/common.js";
|
|
21
|
+
import type { ApiRepresentation } from "../src/version-control.mjs";
|
|
22
|
+
import type {
|
|
23
|
+
SuperblocksApplicationConfig,
|
|
24
|
+
SuperblocksBackendConfig,
|
|
25
|
+
SuperblocksConfig,
|
|
26
|
+
} from "@superblocksteam/util";
|
|
27
|
+
import type { ApiWrapper } from "@superblocksteam/util";
|
|
28
|
+
|
|
29
|
+
// set to false to use the `test-output` workspace directory for debugging
|
|
30
|
+
const USE_TEMP_TEST_DIR = true;
|
|
31
|
+
|
|
32
|
+
const JS_LINE = "const x = 1;\n";
|
|
33
|
+
const SMALL_JS_CONTENT = JS_LINE.repeat(2);
|
|
34
|
+
const LARGE_JS_CONTENT = JS_LINE.repeat(20);
|
|
35
|
+
const LARGER_JS_CONTENT = JS_LINE.repeat(30);
|
|
36
|
+
|
|
37
|
+
const EXTRACT_SOURCE_CODE: ApiRepresentation = {
|
|
38
|
+
extractLargeSourceFiles: true,
|
|
39
|
+
minLinesForExtraction: 0,
|
|
40
|
+
};
|
|
41
|
+
const NO_EXTRACT_SOURCE_CODE: ApiRepresentation = {
|
|
42
|
+
extractLargeSourceFiles: false,
|
|
43
|
+
minLinesForExtraction: 0,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
describe("version-control", function () {
|
|
47
|
+
const testDir = USE_TEMP_TEST_DIR
|
|
48
|
+
? // eslint-disable-next-line mocha/no-setup-in-describe
|
|
49
|
+
fs.mkdtempSync(path.join(os.tmpdir(), "test-output"))
|
|
50
|
+
: // eslint-disable-next-line mocha/no-setup-in-describe
|
|
51
|
+
new URL("../../test-output", import.meta.url).pathname;
|
|
52
|
+
|
|
53
|
+
beforeEach(async function () {
|
|
54
|
+
// Clean up the temporary directory before each test, then create it
|
|
55
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
56
|
+
await fs.ensureDir(testDir);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
afterEach(async function () {
|
|
60
|
+
// Clean up the temporary directory after each test
|
|
61
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("writeAppApi", function () {
|
|
65
|
+
it("should write app api to separate directory with correct name", async function () {
|
|
66
|
+
// Setup
|
|
67
|
+
const api: ApiWrapper = {
|
|
68
|
+
apiPb: {
|
|
69
|
+
metadata: {
|
|
70
|
+
id: "test-id",
|
|
71
|
+
name: "Test API",
|
|
72
|
+
organization: "test-org-id",
|
|
73
|
+
},
|
|
74
|
+
blocks: [],
|
|
75
|
+
trigger: {},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const apiPromises: Promise<void>[] = [];
|
|
79
|
+
|
|
80
|
+
// Execute
|
|
81
|
+
const existingFilePaths = new Set<string>(); // empty since not overwriting existing files
|
|
82
|
+
const apiInfo = await writeAppApi(
|
|
83
|
+
api,
|
|
84
|
+
testDir,
|
|
85
|
+
existingFilePaths,
|
|
86
|
+
apiPromises,
|
|
87
|
+
EXTRACT_SOURCE_CODE,
|
|
88
|
+
);
|
|
89
|
+
await Promise.all(apiPromises);
|
|
90
|
+
|
|
91
|
+
// Verify the ApiInfo object is correct
|
|
92
|
+
expect(apiInfo.name).to.equal("Test API");
|
|
93
|
+
expect(apiInfo.sourceFiles).to.deep.equal([]);
|
|
94
|
+
|
|
95
|
+
// Verify the files exist and match expectations: one YAML file in directory nested under `apis`
|
|
96
|
+
const apiDir = path.join(testDir, "apis");
|
|
97
|
+
await expectFileExists(apiDir, "test_api/api.yaml");
|
|
98
|
+
|
|
99
|
+
// And does not have a YAML file in the `apis` directory
|
|
100
|
+
await expectNoFileExists(apiDir, "test_api.yaml");
|
|
101
|
+
|
|
102
|
+
// and can be read back in
|
|
103
|
+
(await readApiFile(apiDir, "Test API")).to.deep.equal({
|
|
104
|
+
api: api.apiPb,
|
|
105
|
+
stepPathMap: {},
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should write app api to separate directory and extract large code blocks to separate files", async function () {
|
|
110
|
+
// Setup
|
|
111
|
+
const api: ApiWrapper = {
|
|
112
|
+
apiPb: {
|
|
113
|
+
metadata: {
|
|
114
|
+
id: "test-id",
|
|
115
|
+
name: "Test API",
|
|
116
|
+
organization: "test-org-id",
|
|
117
|
+
},
|
|
118
|
+
blocks: [
|
|
119
|
+
{
|
|
120
|
+
name: "Large Block",
|
|
121
|
+
step: {
|
|
122
|
+
integration: "javascript",
|
|
123
|
+
javascript: {
|
|
124
|
+
body: LARGE_JS_CONTENT,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
trigger: {},
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
const apiPromises: Promise<void>[] = [];
|
|
133
|
+
|
|
134
|
+
// Execute
|
|
135
|
+
const existingFilePaths = new Set<string>(); // empty since not overwriting existing files
|
|
136
|
+
const apiInfo = await writeAppApi(
|
|
137
|
+
api,
|
|
138
|
+
testDir,
|
|
139
|
+
existingFilePaths,
|
|
140
|
+
apiPromises,
|
|
141
|
+
EXTRACT_SOURCE_CODE,
|
|
142
|
+
);
|
|
143
|
+
await Promise.all(apiPromises);
|
|
144
|
+
|
|
145
|
+
// Verify the ApiInfo object is correct
|
|
146
|
+
expect(apiInfo.name).to.equal("Test API");
|
|
147
|
+
expect(apiInfo.sourceFiles).to.deep.equal(["large_block.js"]);
|
|
148
|
+
|
|
149
|
+
// Verify the files exist and match expectations
|
|
150
|
+
const apiDir = path.join(testDir, "apis");
|
|
151
|
+
(await expectFileExists(apiDir, "test_api/api.yaml")).and.contains(
|
|
152
|
+
"path: ./large_block.js",
|
|
153
|
+
);
|
|
154
|
+
(await expectFileExists(apiDir, "test_api/large_block.js")).and.includes(
|
|
155
|
+
LARGE_JS_CONTENT,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// And does not have a YAML file in the `apis` directory
|
|
159
|
+
await expectNoFileExists(apiDir, "test_api.yaml");
|
|
160
|
+
|
|
161
|
+
// and can be read back in
|
|
162
|
+
(await readApiFile(apiDir, api.apiPb.metadata.name)).to.deep.equal({
|
|
163
|
+
api: api.apiPb,
|
|
164
|
+
stepPathMap: {
|
|
165
|
+
"Large Block": "./large_block.js",
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should write app api with similarly-named steps to separate directory and extract large code blocks to separate files", async function () {
|
|
171
|
+
const stepName1 = "Large Block";
|
|
172
|
+
const stepName2 = stepName1.toLocaleLowerCase();
|
|
173
|
+
|
|
174
|
+
// Setup
|
|
175
|
+
const api: ApiWrapper = {
|
|
176
|
+
apiPb: {
|
|
177
|
+
metadata: {
|
|
178
|
+
id: "test-id",
|
|
179
|
+
name: "Test API",
|
|
180
|
+
organization: "test-org-id",
|
|
181
|
+
},
|
|
182
|
+
blocks: [
|
|
183
|
+
{
|
|
184
|
+
name: stepName1,
|
|
185
|
+
step: {
|
|
186
|
+
integration: "javascript",
|
|
187
|
+
javascript: {
|
|
188
|
+
body: LARGE_JS_CONTENT,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: stepName2,
|
|
194
|
+
step: {
|
|
195
|
+
integration: "javascript",
|
|
196
|
+
javascript: {
|
|
197
|
+
body: LARGER_JS_CONTENT,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
trigger: {},
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
const apiPromises: Promise<void>[] = [];
|
|
206
|
+
|
|
207
|
+
// Execute
|
|
208
|
+
const existingFilePaths = new Set<string>(); // empty since not overwriting existing files
|
|
209
|
+
const apiInfo = await writeAppApi(
|
|
210
|
+
api,
|
|
211
|
+
testDir,
|
|
212
|
+
existingFilePaths,
|
|
213
|
+
apiPromises,
|
|
214
|
+
EXTRACT_SOURCE_CODE,
|
|
215
|
+
);
|
|
216
|
+
await Promise.all(apiPromises);
|
|
217
|
+
|
|
218
|
+
// Verify the ApiInfo object is correct
|
|
219
|
+
expect(apiInfo.name).to.equal("Test API");
|
|
220
|
+
expect(apiInfo.sourceFiles).to.deep.equal([
|
|
221
|
+
"large_block.js",
|
|
222
|
+
"large_block_1.js",
|
|
223
|
+
]);
|
|
224
|
+
|
|
225
|
+
// Verify the files exist and match expectations
|
|
226
|
+
const apiDir = path.join(testDir, "apis");
|
|
227
|
+
(await expectFileExists(apiDir, "test_api/api.yaml")).and.contains(
|
|
228
|
+
"path: ./large_block.js",
|
|
229
|
+
);
|
|
230
|
+
(await expectFileExists(apiDir, "test_api/large_block.js")).and.includes(
|
|
231
|
+
LARGE_JS_CONTENT,
|
|
232
|
+
);
|
|
233
|
+
(
|
|
234
|
+
await expectFileExists(apiDir, "test_api/large_block_1.js")
|
|
235
|
+
).and.includes(LARGER_JS_CONTENT);
|
|
236
|
+
|
|
237
|
+
// And does not have a YAML file in the `apis` directory
|
|
238
|
+
await expectNoFileExists(apiDir, "test_api.yaml");
|
|
239
|
+
|
|
240
|
+
// and can be read back in
|
|
241
|
+
(await readApiFile(apiDir, api.apiPb.metadata.name)).to.deep.equal({
|
|
242
|
+
api: api.apiPb,
|
|
243
|
+
stepPathMap: {
|
|
244
|
+
"Large Block": "./large_block.js",
|
|
245
|
+
"large block": "./large_block_1.js",
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("should write app api to separate directory and extract small code blocks to separate files", async function () {
|
|
251
|
+
// Setup
|
|
252
|
+
const api: ApiWrapper = {
|
|
253
|
+
apiPb: {
|
|
254
|
+
metadata: {
|
|
255
|
+
id: "test-id",
|
|
256
|
+
name: "Test API",
|
|
257
|
+
organization: "test-org-id",
|
|
258
|
+
},
|
|
259
|
+
blocks: [
|
|
260
|
+
{
|
|
261
|
+
name: "Small Block",
|
|
262
|
+
step: {
|
|
263
|
+
integration: "javascript",
|
|
264
|
+
javascript: {
|
|
265
|
+
body: SMALL_JS_CONTENT,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
trigger: {},
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
const apiPromises: Promise<void>[] = [];
|
|
274
|
+
|
|
275
|
+
// Execute
|
|
276
|
+
const existingFilePaths = new Set<string>(); // empty since not overwriting existing files
|
|
277
|
+
const apiInfo = await writeAppApi(
|
|
278
|
+
api,
|
|
279
|
+
testDir,
|
|
280
|
+
existingFilePaths,
|
|
281
|
+
apiPromises,
|
|
282
|
+
EXTRACT_SOURCE_CODE,
|
|
283
|
+
);
|
|
284
|
+
await Promise.all(apiPromises);
|
|
285
|
+
|
|
286
|
+
// Verify the ApiInfo object is correct
|
|
287
|
+
expect(apiInfo.name).to.equal("Test API");
|
|
288
|
+
expect(apiInfo.sourceFiles).to.deep.equal(["small_block.js"]);
|
|
289
|
+
|
|
290
|
+
// Verify the files exist and match expectations: one YAML file in directory nested under `apis`
|
|
291
|
+
const apisDir = path.join(testDir, "apis");
|
|
292
|
+
(await expectFileExists(apisDir, "test_api/api.yaml")).and.contains(
|
|
293
|
+
"path: ./small_block.js",
|
|
294
|
+
);
|
|
295
|
+
(await expectFileExists(apisDir, "test_api/small_block.js")).and.contains(
|
|
296
|
+
SMALL_JS_CONTENT,
|
|
297
|
+
);
|
|
298
|
+
// And no separate code file and no nested directory with the files
|
|
299
|
+
await expectNoFileExists(apisDir, "small_block.js");
|
|
300
|
+
await expectNoFileExists(apisDir, "test_api.yaml");
|
|
301
|
+
await expectNoFileExists(apisDir, "test_api/test_api.yaml");
|
|
302
|
+
|
|
303
|
+
// and can be read back in
|
|
304
|
+
(await readApiFile(apisDir, api.apiPb.metadata.name)).to.deep.equal({
|
|
305
|
+
api: api.apiPb,
|
|
306
|
+
stepPathMap: {
|
|
307
|
+
"Small Block": "./small_block.js",
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it("should write app api to apis directory and not extract code blocks to separate files", async function () {
|
|
313
|
+
// Setup
|
|
314
|
+
const api: ApiWrapper = {
|
|
315
|
+
apiPb: {
|
|
316
|
+
metadata: {
|
|
317
|
+
id: "test-id",
|
|
318
|
+
name: "Test API",
|
|
319
|
+
organization: "test-org-id",
|
|
320
|
+
},
|
|
321
|
+
blocks: [
|
|
322
|
+
{
|
|
323
|
+
name: "Large Block",
|
|
324
|
+
step: {
|
|
325
|
+
integration: "javascript",
|
|
326
|
+
javascript: {
|
|
327
|
+
body: LARGE_JS_CONTENT,
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
trigger: {},
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
const apiPromises: Promise<void>[] = [];
|
|
336
|
+
|
|
337
|
+
// Execute
|
|
338
|
+
const existingFilePaths = new Set<string>(); // empty since not overwriting existing files
|
|
339
|
+
const apiInfo = await writeAppApi(
|
|
340
|
+
api,
|
|
341
|
+
testDir,
|
|
342
|
+
existingFilePaths,
|
|
343
|
+
apiPromises,
|
|
344
|
+
NO_EXTRACT_SOURCE_CODE,
|
|
345
|
+
);
|
|
346
|
+
await Promise.all(apiPromises);
|
|
347
|
+
|
|
348
|
+
// Verify the ApiInfo object is correct
|
|
349
|
+
expect(apiInfo.name).to.equal("Test API");
|
|
350
|
+
expect(apiInfo.sourceFiles).to.deep.equal([]);
|
|
351
|
+
|
|
352
|
+
// Compute the expected YAML file content
|
|
353
|
+
const expectedYamlContent = ymlstringify(api.apiPb, {
|
|
354
|
+
sortMapEntries: true,
|
|
355
|
+
blockQuote: "literal",
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Verify the files exist and match expectations
|
|
359
|
+
const apisDir = path.join(testDir, "apis");
|
|
360
|
+
(await expectFileExists(apisDir, "test_api.yaml")).and.equals(
|
|
361
|
+
expectedYamlContent,
|
|
362
|
+
);
|
|
363
|
+
await expectNoFileExists(apisDir, "large_block.js");
|
|
364
|
+
await expectNoFileExists(apisDir, "test_api/test_api.yaml");
|
|
365
|
+
await expectNoFileExists(apisDir, "test_api/large_block.js");
|
|
366
|
+
|
|
367
|
+
// and can be read back in
|
|
368
|
+
(await readApiFile(apisDir, api.apiPb.metadata.name)).to.deep.equal({
|
|
369
|
+
api: api.apiPb,
|
|
370
|
+
stepPathMap: {},
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("should write api with try-catch, conditional, loop, and parallel JavaScript steps", async function () {
|
|
375
|
+
const api: ApiWrapper = {
|
|
376
|
+
apiPb: {
|
|
377
|
+
metadata: {
|
|
378
|
+
id: "test-id",
|
|
379
|
+
name: "Try Catch API",
|
|
380
|
+
organization: "test-org-id",
|
|
381
|
+
},
|
|
382
|
+
blocks: [
|
|
383
|
+
{
|
|
384
|
+
name: "Try Catch Block",
|
|
385
|
+
tryCatch: {
|
|
386
|
+
catch: {
|
|
387
|
+
blocks: [
|
|
388
|
+
{
|
|
389
|
+
name: "Catch Block",
|
|
390
|
+
loop: {
|
|
391
|
+
range: "{{[1,2,3]}}",
|
|
392
|
+
type: LoopType.FOR_EACH,
|
|
393
|
+
variables: {
|
|
394
|
+
index: "indexVar",
|
|
395
|
+
item: "itemVar",
|
|
396
|
+
},
|
|
397
|
+
blocks: [
|
|
398
|
+
{
|
|
399
|
+
name: "Loop Step",
|
|
400
|
+
step: {
|
|
401
|
+
integration: "javascript",
|
|
402
|
+
javascript: {
|
|
403
|
+
body: LARGER_JS_CONTENT,
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
],
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
],
|
|
411
|
+
},
|
|
412
|
+
try: {
|
|
413
|
+
blocks: [
|
|
414
|
+
{
|
|
415
|
+
name: "Conditional Block",
|
|
416
|
+
conditional: {
|
|
417
|
+
if: {
|
|
418
|
+
condition: "{{2 > 1}}",
|
|
419
|
+
blocks: [
|
|
420
|
+
{
|
|
421
|
+
name: "If Step",
|
|
422
|
+
step: {
|
|
423
|
+
integration: "javascript",
|
|
424
|
+
javascript: {
|
|
425
|
+
body: LARGER_JS_CONTENT,
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
],
|
|
430
|
+
},
|
|
431
|
+
elseIf: [
|
|
432
|
+
{
|
|
433
|
+
condition: "{{}}",
|
|
434
|
+
blocks: [
|
|
435
|
+
{
|
|
436
|
+
name: "Else If Step",
|
|
437
|
+
step: {
|
|
438
|
+
integration: "javascript",
|
|
439
|
+
javascript: {
|
|
440
|
+
body: LARGE_JS_CONTENT,
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
],
|
|
445
|
+
},
|
|
446
|
+
],
|
|
447
|
+
else: {
|
|
448
|
+
blocks: [
|
|
449
|
+
{
|
|
450
|
+
name: "Else Step",
|
|
451
|
+
step: {
|
|
452
|
+
integration: "javascript",
|
|
453
|
+
javascript: {
|
|
454
|
+
body: LARGE_JS_CONTENT,
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
},
|
|
464
|
+
variables: {
|
|
465
|
+
indexVar: "indexVar",
|
|
466
|
+
itemVar: "itemVar",
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: "Second Block",
|
|
472
|
+
step: {
|
|
473
|
+
integration: "javascript",
|
|
474
|
+
javascript: {
|
|
475
|
+
body: LARGE_JS_CONTENT,
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
name: "Parallel Block",
|
|
481
|
+
parallel: {
|
|
482
|
+
static: {
|
|
483
|
+
paths: {
|
|
484
|
+
Path1: {
|
|
485
|
+
blocks: [
|
|
486
|
+
{
|
|
487
|
+
name: "Path1 step",
|
|
488
|
+
step: {
|
|
489
|
+
integration: "javascript",
|
|
490
|
+
javascript: {
|
|
491
|
+
body: LARGE_JS_CONTENT,
|
|
492
|
+
},
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
],
|
|
496
|
+
},
|
|
497
|
+
Path2: {
|
|
498
|
+
blocks: [
|
|
499
|
+
{
|
|
500
|
+
name: "Path2 step",
|
|
501
|
+
step: {
|
|
502
|
+
integration: "javascript",
|
|
503
|
+
javascript: {
|
|
504
|
+
body: SMALL_JS_CONTENT,
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
],
|
|
515
|
+
trigger: {},
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
// Compute the expected YAML file content
|
|
519
|
+
const expectedYamlContent = ymlstringify(api.apiPb, {
|
|
520
|
+
sortMapEntries: true,
|
|
521
|
+
blockQuote: "literal",
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// This test writes the API several times, so we need to keep track of the existing files
|
|
525
|
+
const existingFilePaths = new Set<string>();
|
|
526
|
+
|
|
527
|
+
{
|
|
528
|
+
// Write the API and extract code blocks
|
|
529
|
+
const apiPromises: Promise<void>[] = [];
|
|
530
|
+
const apiInfo = await writeAppApi(
|
|
531
|
+
api,
|
|
532
|
+
testDir,
|
|
533
|
+
existingFilePaths,
|
|
534
|
+
apiPromises,
|
|
535
|
+
EXTRACT_SOURCE_CODE,
|
|
536
|
+
);
|
|
537
|
+
await Promise.all(apiPromises);
|
|
538
|
+
|
|
539
|
+
// Verify the ApiInfo object is correct
|
|
540
|
+
expect(apiInfo.name).to.equal("Try Catch API");
|
|
541
|
+
expect(apiInfo.sourceFiles).to.deep.equal([
|
|
542
|
+
"else_if_step.js",
|
|
543
|
+
"else_step.js",
|
|
544
|
+
"if_step.js",
|
|
545
|
+
"loop_step.js",
|
|
546
|
+
"path1_step.js",
|
|
547
|
+
"path2_step.js",
|
|
548
|
+
"second_block.js",
|
|
549
|
+
]);
|
|
550
|
+
|
|
551
|
+
// Verify the files exist and match expectations
|
|
552
|
+
const apiDir = path.join(testDir, "apis");
|
|
553
|
+
(await expectFileExists(apiDir, "try_catch_api/api.yaml")).and.contains(
|
|
554
|
+
"path: ./loop_step.js",
|
|
555
|
+
);
|
|
556
|
+
(
|
|
557
|
+
await expectFileExists(apiDir, "try_catch_api/loop_step.js")
|
|
558
|
+
).and.includes(LARGER_JS_CONTENT);
|
|
559
|
+
(
|
|
560
|
+
await expectFileExists(apiDir, "try_catch_api/second_block.js")
|
|
561
|
+
).and.includes(LARGE_JS_CONTENT);
|
|
562
|
+
(
|
|
563
|
+
await expectFileExists(apiDir, "try_catch_api/if_step.js")
|
|
564
|
+
).and.includes(LARGER_JS_CONTENT);
|
|
565
|
+
(
|
|
566
|
+
await expectFileExists(apiDir, "try_catch_api/else_if_step.js")
|
|
567
|
+
).and.includes(LARGE_JS_CONTENT);
|
|
568
|
+
(
|
|
569
|
+
await expectFileExists(apiDir, "try_catch_api/else_step.js")
|
|
570
|
+
).and.includes(LARGE_JS_CONTENT);
|
|
571
|
+
(
|
|
572
|
+
await expectFileExists(apiDir, "try_catch_api/path1_step.js")
|
|
573
|
+
).and.includes(LARGE_JS_CONTENT);
|
|
574
|
+
(
|
|
575
|
+
await expectFileExists(apiDir, "try_catch_api/path2_step.js")
|
|
576
|
+
).and.includes(SMALL_JS_CONTENT);
|
|
577
|
+
|
|
578
|
+
// and can be read back in
|
|
579
|
+
(await readApiFile(apiDir, "Try Catch API")).to.deep.equal({
|
|
580
|
+
api: api.apiPb,
|
|
581
|
+
stepPathMap: {
|
|
582
|
+
"Else If Step": "./else_if_step.js",
|
|
583
|
+
"Else Step": "./else_step.js",
|
|
584
|
+
"If Step": "./if_step.js",
|
|
585
|
+
"Loop Step": "./loop_step.js",
|
|
586
|
+
"Path1 step": "./path1_step.js",
|
|
587
|
+
"Path2 step": "./path2_step.js",
|
|
588
|
+
"Second Block": "./second_block.js",
|
|
589
|
+
},
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
// Finally add the existing files to the set to be removed later
|
|
593
|
+
addExistingFilePathsForApi(apiInfo, apiDir, existingFilePaths, true);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
{
|
|
597
|
+
// Write the API and do NOT extract code blocks
|
|
598
|
+
const apiPromises: Promise<void>[] = [];
|
|
599
|
+
const apiInfo = await writeAppApi(
|
|
600
|
+
api,
|
|
601
|
+
testDir,
|
|
602
|
+
existingFilePaths,
|
|
603
|
+
apiPromises,
|
|
604
|
+
NO_EXTRACT_SOURCE_CODE,
|
|
605
|
+
);
|
|
606
|
+
await Promise.all(apiPromises);
|
|
607
|
+
await removeExistingFiles(existingFilePaths);
|
|
608
|
+
|
|
609
|
+
// Verify the ApiInfo object is correct
|
|
610
|
+
expect(apiInfo.name).to.equal("Try Catch API");
|
|
611
|
+
expect(apiInfo.sourceFiles).to.deep.equal([]);
|
|
612
|
+
|
|
613
|
+
// Verify the files exist and match expectations
|
|
614
|
+
const apiDir = path.join(testDir, "apis");
|
|
615
|
+
(await expectFileExists(apiDir, "try_catch_api.yaml")).and.equals(
|
|
616
|
+
expectedYamlContent,
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
// And no code files are created in a nested directory
|
|
620
|
+
await expectNoFileExists(apiDir, "try_catch_api/api.yaml");
|
|
621
|
+
await expectNoFileExists(apiDir, "try_catch_api/try_catch_api.yaml");
|
|
622
|
+
await expectNoFileExists(apiDir, "try_catch_api/loop_step.js");
|
|
623
|
+
await expectNoFileExists(apiDir, "try_catch_api/second_block.js");
|
|
624
|
+
await expectNoFileExists(apiDir, "try_catch_api/if_step.js");
|
|
625
|
+
await expectNoFileExists(apiDir, "try_catch_api/else_if_step.js");
|
|
626
|
+
await expectNoFileExists(apiDir, "try_catch_api/else_step.js");
|
|
627
|
+
await expectNoFileExists(apiDir, "try_catch_api/path1_step.js");
|
|
628
|
+
await expectNoFileExists(apiDir, "try_catch_api/path2_step.js");
|
|
629
|
+
await expectNoFileExists(apiDir, "try_catch_api");
|
|
630
|
+
|
|
631
|
+
// and can be read back in
|
|
632
|
+
(await readApiFile(apiDir, "Try Catch API")).to.deep.equal({
|
|
633
|
+
api: api.apiPb,
|
|
634
|
+
stepPathMap: {},
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
describe("writeResourcesToDisk", function () {
|
|
641
|
+
const mockFeatureFlags = new FeatureFlags({
|
|
642
|
+
"superblocks.git.split.large.steps.enabled": true,
|
|
643
|
+
"superblocks.git.split.large.steps.new.enabled": true,
|
|
644
|
+
"superblocks.git.split.large.step.lines": 10,
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it("should write single page app to separate directory and extract code blocks to separate files", async function () {
|
|
648
|
+
// Setup
|
|
649
|
+
const resourceId = "9736f700-88d6-49fc-a519-245a20af248b";
|
|
650
|
+
const testApi: ApiWithPb = {
|
|
651
|
+
id: "test-id",
|
|
652
|
+
apiPb: {
|
|
653
|
+
metadata: {
|
|
654
|
+
id: "test-id",
|
|
655
|
+
name: "Test API",
|
|
656
|
+
organization: "test-org-id",
|
|
657
|
+
},
|
|
658
|
+
blocks: [
|
|
659
|
+
{
|
|
660
|
+
name: "Large Block",
|
|
661
|
+
step: {
|
|
662
|
+
integration: "javascript",
|
|
663
|
+
javascript: {
|
|
664
|
+
body: LARGE_JS_CONTENT,
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
],
|
|
669
|
+
trigger: {},
|
|
670
|
+
},
|
|
671
|
+
};
|
|
672
|
+
const singlePageApp: ApplicationWrapper = {
|
|
673
|
+
application: {
|
|
674
|
+
id: resourceId,
|
|
675
|
+
name: "Test App",
|
|
676
|
+
metadata: {
|
|
677
|
+
fileVersion: "0.2.0", // this and the feature flag drive whether we split files or not
|
|
678
|
+
},
|
|
679
|
+
},
|
|
680
|
+
page: {
|
|
681
|
+
id: "test-page-id",
|
|
682
|
+
name: "Test Page",
|
|
683
|
+
apis: [],
|
|
684
|
+
applicationId: resourceId,
|
|
685
|
+
isHidden: false,
|
|
686
|
+
layouts: [],
|
|
687
|
+
},
|
|
688
|
+
apis: [testApi],
|
|
689
|
+
};
|
|
690
|
+
const apiPromises: Promise<void>[] = [];
|
|
691
|
+
|
|
692
|
+
// Execute
|
|
693
|
+
const resourceConfig = await writeResourceToDisk(
|
|
694
|
+
"APPLICATION",
|
|
695
|
+
resourceId,
|
|
696
|
+
singlePageApp,
|
|
697
|
+
testDir,
|
|
698
|
+
mockFeatureFlags,
|
|
699
|
+
undefined,
|
|
700
|
+
EXTRACT_SOURCE_CODE,
|
|
701
|
+
);
|
|
702
|
+
await Promise.all(apiPromises);
|
|
703
|
+
|
|
704
|
+
// Verify the superblocks.json file is correct for a SINGLE PAGE APP (no source files)
|
|
705
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
706
|
+
`${testDir}/apps/test_app`,
|
|
707
|
+
)) as SuperblocksApplicationConfig;
|
|
708
|
+
// Verify the apis is undefined for the new format
|
|
709
|
+
expect(config.apis).to.be.undefined;
|
|
710
|
+
// and the appApis is defined
|
|
711
|
+
expect(config.appApis?.[testApi.id].name).to.equal(
|
|
712
|
+
testApi.apiPb.metadata.name,
|
|
713
|
+
);
|
|
714
|
+
|
|
715
|
+
// Verify the files exist and match expectations
|
|
716
|
+
expect(resourceConfig.location).to.equal("apps/test_app");
|
|
717
|
+
await expectFileExists(testDir, "apps/test_app/application.yaml");
|
|
718
|
+
await expectFileExists(testDir, "apps/test_app/page.yaml");
|
|
719
|
+
(
|
|
720
|
+
await expectFileExists(testDir, "apps/test_app/apis/test_api/api.yaml")
|
|
721
|
+
).and.contains("path: ./large_block.js");
|
|
722
|
+
(
|
|
723
|
+
await expectFileExists(
|
|
724
|
+
testDir,
|
|
725
|
+
"apps/test_app/apis/test_api/large_block.js",
|
|
726
|
+
)
|
|
727
|
+
).and.includes(LARGE_JS_CONTENT);
|
|
728
|
+
// and can be read back in
|
|
729
|
+
(
|
|
730
|
+
await readApiFile(`${testDir}/apps/test_app/apis`, "Test API")
|
|
731
|
+
).to.deep.equal({
|
|
732
|
+
api: testApi.apiPb,
|
|
733
|
+
stepPathMap: {
|
|
734
|
+
"Large Block": "./large_block.js",
|
|
735
|
+
},
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
it("should write backend to separate directory and extract code blocks to separate files", async function () {
|
|
740
|
+
// Setup
|
|
741
|
+
const resourceId = "9736f700-88d6-49fc-a519-245a20af248b";
|
|
742
|
+
const testApi: ApiWrapper = {
|
|
743
|
+
apiPb: {
|
|
744
|
+
metadata: {
|
|
745
|
+
id: "test-id",
|
|
746
|
+
name: "Test Backend",
|
|
747
|
+
organization: "test-org-id",
|
|
748
|
+
},
|
|
749
|
+
blocks: [
|
|
750
|
+
{
|
|
751
|
+
name: "Large Block",
|
|
752
|
+
step: {
|
|
753
|
+
integration: "javascript",
|
|
754
|
+
javascript: {
|
|
755
|
+
body: LARGE_JS_CONTENT,
|
|
756
|
+
},
|
|
757
|
+
},
|
|
758
|
+
},
|
|
759
|
+
],
|
|
760
|
+
trigger: {},
|
|
761
|
+
},
|
|
762
|
+
};
|
|
763
|
+
// Compute the expected YAML file content
|
|
764
|
+
const expectedYamlContent = ymlstringify(testApi.apiPb, {
|
|
765
|
+
sortMapEntries: true,
|
|
766
|
+
blockQuote: "literal",
|
|
767
|
+
});
|
|
768
|
+
// Write out the backend without extracting any code blocks
|
|
769
|
+
{
|
|
770
|
+
// Execute
|
|
771
|
+
const apiPromises: Promise<void>[] = [];
|
|
772
|
+
const resourceConfig = await writeResourceToDisk(
|
|
773
|
+
"BACKEND",
|
|
774
|
+
resourceId,
|
|
775
|
+
testApi,
|
|
776
|
+
testDir,
|
|
777
|
+
mockFeatureFlags,
|
|
778
|
+
undefined,
|
|
779
|
+
NO_EXTRACT_SOURCE_CODE,
|
|
780
|
+
);
|
|
781
|
+
await Promise.all(apiPromises);
|
|
782
|
+
|
|
783
|
+
// Verify the superblocks.json file is correct for a BACKEND that does not extract source files
|
|
784
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
785
|
+
`${testDir}/backends/test_backend`,
|
|
786
|
+
)) as SuperblocksBackendConfig;
|
|
787
|
+
expect(config.sourceFiles).to.be.undefined;
|
|
788
|
+
|
|
789
|
+
// Verify the files exist and match expectations
|
|
790
|
+
expect(resourceConfig.location).to.equal("backends/test_backend");
|
|
791
|
+
await expectFileExists(testDir, "backends/test_backend/api.yaml");
|
|
792
|
+
(
|
|
793
|
+
await expectFileExists(testDir, "backends/test_backend/api.yaml")
|
|
794
|
+
).and.contains(expectedYamlContent);
|
|
795
|
+
await expectNoFileExists(
|
|
796
|
+
testDir,
|
|
797
|
+
"backends/test_backend/large_block.js",
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
// and can be read back in
|
|
801
|
+
(await readApiFile(`${testDir}/backends/test_backend`)).to.deep.equal({
|
|
802
|
+
api: testApi.apiPb,
|
|
803
|
+
stepPathMap: {},
|
|
804
|
+
});
|
|
805
|
+
// and a push operation would consider it valid
|
|
806
|
+
expect(await validateLocalResource(testDir, resourceConfig)).to.be
|
|
807
|
+
.undefined;
|
|
808
|
+
}
|
|
809
|
+
// Write out the backend AND extract any code blocks
|
|
810
|
+
{
|
|
811
|
+
// Execute
|
|
812
|
+
const apiPromises: Promise<void>[] = [];
|
|
813
|
+
const resourceConfig = await writeResourceToDisk(
|
|
814
|
+
"BACKEND",
|
|
815
|
+
resourceId,
|
|
816
|
+
testApi,
|
|
817
|
+
testDir,
|
|
818
|
+
mockFeatureFlags,
|
|
819
|
+
undefined,
|
|
820
|
+
EXTRACT_SOURCE_CODE,
|
|
821
|
+
);
|
|
822
|
+
await Promise.all(apiPromises);
|
|
823
|
+
|
|
824
|
+
// Verify the superblocks.json file is correct for a BACKEND that does extract source files
|
|
825
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
826
|
+
`${testDir}/backends/test_backend`,
|
|
827
|
+
)) as SuperblocksBackendConfig;
|
|
828
|
+
expect(config.sourceFiles).to.deep.equal(["large_block.js"]);
|
|
829
|
+
|
|
830
|
+
// Verify the files exist and match expectations
|
|
831
|
+
expect(resourceConfig.location).to.equal("backends/test_backend");
|
|
832
|
+
(
|
|
833
|
+
await expectFileExists(testDir, "backends/test_backend/api.yaml")
|
|
834
|
+
).and.contains("path: ./large_block.js");
|
|
835
|
+
(
|
|
836
|
+
await expectFileExists(
|
|
837
|
+
testDir,
|
|
838
|
+
"backends/test_backend/large_block.js",
|
|
839
|
+
)
|
|
840
|
+
).and.contains(LARGE_JS_CONTENT);
|
|
841
|
+
// and can be read back in
|
|
842
|
+
(await readApiFile(`${testDir}/backends/test_backend`)).to.deep.equal({
|
|
843
|
+
api: testApi.apiPb,
|
|
844
|
+
stepPathMap: {
|
|
845
|
+
"Large Block": "./large_block.js",
|
|
846
|
+
},
|
|
847
|
+
});
|
|
848
|
+
// and a push operation would consider it valid
|
|
849
|
+
expect(await validateLocalResource(testDir, resourceConfig)).to.be
|
|
850
|
+
.undefined;
|
|
851
|
+
}
|
|
852
|
+
// Write out the backend AGAIN without extracting any code blocks
|
|
853
|
+
{
|
|
854
|
+
// Execute
|
|
855
|
+
const apiPromises: Promise<void>[] = [];
|
|
856
|
+
const resourceConfig = await writeResourceToDisk(
|
|
857
|
+
"BACKEND",
|
|
858
|
+
resourceId,
|
|
859
|
+
testApi,
|
|
860
|
+
testDir,
|
|
861
|
+
mockFeatureFlags,
|
|
862
|
+
undefined,
|
|
863
|
+
NO_EXTRACT_SOURCE_CODE,
|
|
864
|
+
);
|
|
865
|
+
await Promise.all(apiPromises);
|
|
866
|
+
|
|
867
|
+
// Verify the superblocks.json file is correct for a BACKEND that does not extract source files
|
|
868
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
869
|
+
`${testDir}/backends/test_backend`,
|
|
870
|
+
)) as SuperblocksBackendConfig;
|
|
871
|
+
expect(config.sourceFiles).to.be.undefined;
|
|
872
|
+
|
|
873
|
+
// Verify the files exist and match expectations
|
|
874
|
+
expect(resourceConfig.location).to.equal("backends/test_backend");
|
|
875
|
+
await expectFileExists(testDir, "backends/test_backend/api.yaml");
|
|
876
|
+
(
|
|
877
|
+
await expectFileExists(testDir, "backends/test_backend/api.yaml")
|
|
878
|
+
).and.contains(expectedYamlContent);
|
|
879
|
+
await expectNoFileExists(
|
|
880
|
+
testDir,
|
|
881
|
+
"backends/test_backend/large_block.js",
|
|
882
|
+
);
|
|
883
|
+
// and can be read back in
|
|
884
|
+
(await readApiFile(`${testDir}/backends/test_backend`)).to.deep.equal({
|
|
885
|
+
api: testApi.apiPb,
|
|
886
|
+
stepPathMap: {},
|
|
887
|
+
});
|
|
888
|
+
// and a push operation would consider it valid
|
|
889
|
+
expect(await validateLocalResource(testDir, resourceConfig)).to.be
|
|
890
|
+
.undefined;
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
describe("writeApplicationToDIsk", function () {
|
|
896
|
+
const mockFeatureFlags = new FeatureFlags({
|
|
897
|
+
"superblocks.git.split.large.steps.enabled": true,
|
|
898
|
+
"superblocks.git.split.large.steps.new.enabled": false,
|
|
899
|
+
"superblocks.git.split.large.step.lines": 10,
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
it("should write multi-pageapp to disk", async function () {
|
|
903
|
+
// Setup
|
|
904
|
+
const resourceId = "9736f700-88d6-49fc-a519-245a20af248b";
|
|
905
|
+
const testApi: ApiWithPb = {
|
|
906
|
+
id: "test-id",
|
|
907
|
+
apiPb: {
|
|
908
|
+
metadata: {
|
|
909
|
+
id: "test-id",
|
|
910
|
+
name: "Test API",
|
|
911
|
+
organization: "test-org-id",
|
|
912
|
+
},
|
|
913
|
+
blocks: [
|
|
914
|
+
{
|
|
915
|
+
name: "Large Block",
|
|
916
|
+
step: {
|
|
917
|
+
integration: "javascript",
|
|
918
|
+
javascript: {
|
|
919
|
+
body: LARGE_JS_CONTENT,
|
|
920
|
+
},
|
|
921
|
+
},
|
|
922
|
+
},
|
|
923
|
+
],
|
|
924
|
+
trigger: {},
|
|
925
|
+
},
|
|
926
|
+
};
|
|
927
|
+
const multiPageApp: MultiPageApplicationWrapperWithComponents = {
|
|
928
|
+
type: "multi-page",
|
|
929
|
+
application: {
|
|
930
|
+
id: resourceId,
|
|
931
|
+
name: "Test App",
|
|
932
|
+
},
|
|
933
|
+
pages: [
|
|
934
|
+
{
|
|
935
|
+
id: "test-page-id",
|
|
936
|
+
name: "Test Page",
|
|
937
|
+
apis: [testApi],
|
|
938
|
+
applicationId: resourceId,
|
|
939
|
+
isHidden: false,
|
|
940
|
+
layouts: [],
|
|
941
|
+
},
|
|
942
|
+
],
|
|
943
|
+
apis: [],
|
|
944
|
+
componentFiles: [],
|
|
945
|
+
};
|
|
946
|
+
const apiPromises: Promise<void>[] = [];
|
|
947
|
+
|
|
948
|
+
// Execute
|
|
949
|
+
const resourceConfig = await writeApplicationToDisk({
|
|
950
|
+
sdk: {} as any,
|
|
951
|
+
resource: multiPageApp,
|
|
952
|
+
projectRootFolder: testDir,
|
|
953
|
+
featureFlags: mockFeatureFlags,
|
|
954
|
+
migrateFromSinglePage: false,
|
|
955
|
+
preferredApiRepresentation: EXTRACT_SOURCE_CODE,
|
|
956
|
+
});
|
|
957
|
+
await Promise.all(apiPromises);
|
|
958
|
+
|
|
959
|
+
// Verify the superblocks.json file is correct for a multipage app that does extract source files
|
|
960
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
961
|
+
`${testDir}/apps/test_app/`,
|
|
962
|
+
)) as SuperblocksApplicationConfig;
|
|
963
|
+
const page = config.pages?.[multiPageApp.pages[0].id];
|
|
964
|
+
expect(page?.apis).to.be.undefined;
|
|
965
|
+
expect(page?.pageApis?.[testApi.id]?.sourceFiles).to.deep.equal([
|
|
966
|
+
"large_block.js",
|
|
967
|
+
]);
|
|
968
|
+
|
|
969
|
+
// Verify the files exist and match expectations
|
|
970
|
+
expect(resourceConfig.location).to.equal("apps/test_app");
|
|
971
|
+
await expectFileExists(testDir, "apps/test_app/application.yaml");
|
|
972
|
+
await expectFileExists(
|
|
973
|
+
testDir,
|
|
974
|
+
"apps/test_app/pages/test_page/page.yaml",
|
|
975
|
+
);
|
|
976
|
+
(
|
|
977
|
+
await expectFileExists(
|
|
978
|
+
testDir,
|
|
979
|
+
"apps/test_app/pages/test_page/apis/test_api/api.yaml",
|
|
980
|
+
)
|
|
981
|
+
).and.includes("path: ./large_block.js");
|
|
982
|
+
(
|
|
983
|
+
await expectFileExists(
|
|
984
|
+
testDir,
|
|
985
|
+
"apps/test_app/pages/test_page/apis/test_api/large_block.js",
|
|
986
|
+
)
|
|
987
|
+
).and.includes(LARGE_JS_CONTENT);
|
|
988
|
+
|
|
989
|
+
// and does not have the files in the old format
|
|
990
|
+
await expectNoFileExists(
|
|
991
|
+
testDir,
|
|
992
|
+
"apps/test_app/pages/test_page/apis/test_api.yaml",
|
|
993
|
+
);
|
|
994
|
+
await expectNoFileExists(
|
|
995
|
+
testDir,
|
|
996
|
+
"apps/test_app/pages/test_page/apis/test_api/test_api.yaml",
|
|
997
|
+
);
|
|
998
|
+
|
|
999
|
+
// and can be read back in
|
|
1000
|
+
(
|
|
1001
|
+
await readApiFile(
|
|
1002
|
+
`${testDir}/apps/test_app/pages/test_page/apis`,
|
|
1003
|
+
"Test API",
|
|
1004
|
+
)
|
|
1005
|
+
).to.deep.equal({
|
|
1006
|
+
api: testApi.apiPb,
|
|
1007
|
+
stepPathMap: {
|
|
1008
|
+
"Large Block": "./large_block.js",
|
|
1009
|
+
},
|
|
1010
|
+
});
|
|
1011
|
+
// and a push operation would consider it valid
|
|
1012
|
+
expect(await validateLocalResource(testDir, resourceConfig)).to.be
|
|
1013
|
+
.undefined;
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
it("should write multi-pageapp to disk and overwrite existing files", async function () {
|
|
1017
|
+
// Setup
|
|
1018
|
+
const resourceId = "9736f700-88d6-49fc-a519-245a20af248b";
|
|
1019
|
+
const testApi: ApiWithPb = {
|
|
1020
|
+
id: "test-id",
|
|
1021
|
+
apiPb: {
|
|
1022
|
+
metadata: {
|
|
1023
|
+
id: "test-id",
|
|
1024
|
+
name: "Test API",
|
|
1025
|
+
organization: "test-org-id",
|
|
1026
|
+
},
|
|
1027
|
+
blocks: [
|
|
1028
|
+
{
|
|
1029
|
+
name: "Large Block",
|
|
1030
|
+
step: {
|
|
1031
|
+
integration: "javascript",
|
|
1032
|
+
javascript: {
|
|
1033
|
+
body: LARGE_JS_CONTENT,
|
|
1034
|
+
},
|
|
1035
|
+
},
|
|
1036
|
+
},
|
|
1037
|
+
],
|
|
1038
|
+
trigger: {},
|
|
1039
|
+
},
|
|
1040
|
+
};
|
|
1041
|
+
const multiPageApp: MultiPageApplicationWrapperWithComponents = {
|
|
1042
|
+
type: "multi-page",
|
|
1043
|
+
application: {
|
|
1044
|
+
id: resourceId,
|
|
1045
|
+
name: "Test App",
|
|
1046
|
+
},
|
|
1047
|
+
pages: [
|
|
1048
|
+
{
|
|
1049
|
+
id: "test-page-id",
|
|
1050
|
+
name: "Test Page",
|
|
1051
|
+
apis: [testApi],
|
|
1052
|
+
applicationId: resourceId,
|
|
1053
|
+
isHidden: false,
|
|
1054
|
+
layouts: [],
|
|
1055
|
+
},
|
|
1056
|
+
],
|
|
1057
|
+
apis: [],
|
|
1058
|
+
componentFiles: [],
|
|
1059
|
+
};
|
|
1060
|
+
const apiPromises: Promise<void>[] = [];
|
|
1061
|
+
|
|
1062
|
+
// Write out the multi-page app without extracting any code blocks
|
|
1063
|
+
{
|
|
1064
|
+
const resourceConfig = await writeApplicationToDisk({
|
|
1065
|
+
sdk: {} as any,
|
|
1066
|
+
resource: multiPageApp,
|
|
1067
|
+
projectRootFolder: testDir,
|
|
1068
|
+
featureFlags: mockFeatureFlags,
|
|
1069
|
+
migrateFromSinglePage: false,
|
|
1070
|
+
preferredApiRepresentation: NO_EXTRACT_SOURCE_CODE,
|
|
1071
|
+
});
|
|
1072
|
+
await Promise.all(apiPromises);
|
|
1073
|
+
|
|
1074
|
+
// Compute the expected YAML file content with embedded source code
|
|
1075
|
+
const expectedYamlContent = ymlstringify(testApi.apiPb, {
|
|
1076
|
+
sortMapEntries: true,
|
|
1077
|
+
blockQuote: "literal",
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
// Verify the superblocks.json file is correct for a multipage app that does NOT extract source files
|
|
1081
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
1082
|
+
`${testDir}/apps/test_app/`,
|
|
1083
|
+
)) as SuperblocksApplicationConfig;
|
|
1084
|
+
const page = config.pages?.[multiPageApp.pages[0].id];
|
|
1085
|
+
expect(page?.pageApis).to.be.undefined;
|
|
1086
|
+
expect(page?.apis).to.be.deep.equal({ "test-id": "Test API" });
|
|
1087
|
+
|
|
1088
|
+
// Verify the files exist and match expectations
|
|
1089
|
+
expect(resourceConfig.location).to.equal("apps/test_app");
|
|
1090
|
+
await expectFileExists(testDir, "apps/test_app/application.yaml");
|
|
1091
|
+
await expectFileExists(
|
|
1092
|
+
testDir,
|
|
1093
|
+
"apps/test_app/pages/test_page/page.yaml",
|
|
1094
|
+
);
|
|
1095
|
+
(
|
|
1096
|
+
await expectFileExists(
|
|
1097
|
+
testDir,
|
|
1098
|
+
"apps/test_app/pages/test_page/apis/test_api.yaml",
|
|
1099
|
+
)
|
|
1100
|
+
).and.contains(expectedYamlContent);
|
|
1101
|
+
// And does not have the source code extracted
|
|
1102
|
+
await expectNoFileExists(
|
|
1103
|
+
testDir,
|
|
1104
|
+
"apps/test_app/pages/test_page/apis/test_api/large_block.js",
|
|
1105
|
+
);
|
|
1106
|
+
// and can be read back in
|
|
1107
|
+
(
|
|
1108
|
+
await readApiFile(
|
|
1109
|
+
`${testDir}/apps/test_app/pages/test_page/apis`,
|
|
1110
|
+
"Test API",
|
|
1111
|
+
)
|
|
1112
|
+
).to.deep.equal({ api: testApi.apiPb, stepPathMap: {} });
|
|
1113
|
+
// and a push operation would consider it valid
|
|
1114
|
+
expect(await validateLocalResource(testDir, resourceConfig)).to.be
|
|
1115
|
+
.undefined;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// Write out the same multi-page app again, but this time extract any code blocks
|
|
1119
|
+
{
|
|
1120
|
+
const resourceConfig = await writeApplicationToDisk({
|
|
1121
|
+
sdk: {} as any,
|
|
1122
|
+
resource: multiPageApp,
|
|
1123
|
+
projectRootFolder: testDir,
|
|
1124
|
+
featureFlags: mockFeatureFlags,
|
|
1125
|
+
migrateFromSinglePage: false,
|
|
1126
|
+
preferredApiRepresentation: EXTRACT_SOURCE_CODE,
|
|
1127
|
+
});
|
|
1128
|
+
await Promise.all(apiPromises);
|
|
1129
|
+
|
|
1130
|
+
// Verify the superblocks.json file is correct for a multipage app that does extract source files
|
|
1131
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
1132
|
+
`${testDir}/apps/test_app/`,
|
|
1133
|
+
)) as SuperblocksApplicationConfig;
|
|
1134
|
+
const page = config.pages?.[multiPageApp.pages[0].id];
|
|
1135
|
+
expect(page?.apis).to.be.undefined;
|
|
1136
|
+
expect(page?.pageApis?.[testApi.id]?.sourceFiles).to.deep.equal([
|
|
1137
|
+
"large_block.js",
|
|
1138
|
+
]);
|
|
1139
|
+
|
|
1140
|
+
// Verify the files exist and match expectations
|
|
1141
|
+
expect(resourceConfig.location).to.equal("apps/test_app");
|
|
1142
|
+
await expectFileExists(testDir, "apps/test_app/application.yaml");
|
|
1143
|
+
await expectFileExists(
|
|
1144
|
+
testDir,
|
|
1145
|
+
"apps/test_app/pages/test_page/page.yaml",
|
|
1146
|
+
);
|
|
1147
|
+
(
|
|
1148
|
+
await expectFileExists(
|
|
1149
|
+
testDir,
|
|
1150
|
+
"apps/test_app/pages/test_page/apis/test_api/api.yaml",
|
|
1151
|
+
)
|
|
1152
|
+
).and.contains("path: ./large_block.js");
|
|
1153
|
+
(
|
|
1154
|
+
await expectFileExists(
|
|
1155
|
+
testDir,
|
|
1156
|
+
"apps/test_app/pages/test_page/apis/test_api/large_block.js",
|
|
1157
|
+
)
|
|
1158
|
+
).and.includes(LARGE_JS_CONTENT);
|
|
1159
|
+
// And the old file no longer exists
|
|
1160
|
+
await expectNoFileExists(
|
|
1161
|
+
testDir,
|
|
1162
|
+
"apps/test_app/pages/test_page/apis/test_api.yaml",
|
|
1163
|
+
);
|
|
1164
|
+
await expectNoFileExists(
|
|
1165
|
+
testDir,
|
|
1166
|
+
"apps/test_app/pages/test_page/apis/test_api/test_api.yaml",
|
|
1167
|
+
);
|
|
1168
|
+
// and can be read back in
|
|
1169
|
+
(
|
|
1170
|
+
await readApiFile(
|
|
1171
|
+
`${testDir}/apps/test_app/pages/test_page/apis`,
|
|
1172
|
+
"Test API",
|
|
1173
|
+
)
|
|
1174
|
+
).to.deep.equal({
|
|
1175
|
+
api: testApi.apiPb,
|
|
1176
|
+
stepPathMap: {
|
|
1177
|
+
"Large Block": "./large_block.js",
|
|
1178
|
+
},
|
|
1179
|
+
});
|
|
1180
|
+
// and a push operation would consider it valid
|
|
1181
|
+
expect(await validateLocalResource(testDir, resourceConfig)).to.be
|
|
1182
|
+
.undefined;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// Write out the same multi-page app again, but this time with shorter code that should be extracted
|
|
1186
|
+
{
|
|
1187
|
+
// Change the JS code to be shorter
|
|
1188
|
+
if (testApi.apiPb?.blocks?.[0]?.step?.javascript) {
|
|
1189
|
+
testApi.apiPb.blocks[0].step.javascript.body = SMALL_JS_CONTENT;
|
|
1190
|
+
}
|
|
1191
|
+
const resourceConfig = await writeApplicationToDisk({
|
|
1192
|
+
sdk: {} as any,
|
|
1193
|
+
resource: multiPageApp,
|
|
1194
|
+
projectRootFolder: testDir,
|
|
1195
|
+
featureFlags: mockFeatureFlags,
|
|
1196
|
+
migrateFromSinglePage: false,
|
|
1197
|
+
preferredApiRepresentation: EXTRACT_SOURCE_CODE,
|
|
1198
|
+
});
|
|
1199
|
+
await Promise.all(apiPromises);
|
|
1200
|
+
|
|
1201
|
+
// Verify the superblocks.json file is correct for a multipage app that does extract source files
|
|
1202
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
1203
|
+
`${testDir}/apps/test_app/`,
|
|
1204
|
+
)) as SuperblocksApplicationConfig;
|
|
1205
|
+
const page = config.pages?.[multiPageApp.pages[0].id];
|
|
1206
|
+
expect(page?.apis).to.be.undefined;
|
|
1207
|
+
expect(page?.pageApis?.[testApi.id]?.sourceFiles).to.deep.equal([
|
|
1208
|
+
"large_block.js",
|
|
1209
|
+
]);
|
|
1210
|
+
|
|
1211
|
+
// Verify the files exist and match expectations
|
|
1212
|
+
expect(resourceConfig.location).to.equal("apps/test_app");
|
|
1213
|
+
await expectFileExists(testDir, "apps/test_app/application.yaml");
|
|
1214
|
+
await expectFileExists(
|
|
1215
|
+
testDir,
|
|
1216
|
+
"apps/test_app/pages/test_page/page.yaml",
|
|
1217
|
+
);
|
|
1218
|
+
(
|
|
1219
|
+
await expectFileExists(
|
|
1220
|
+
testDir,
|
|
1221
|
+
"apps/test_app/pages/test_page/apis/test_api/api.yaml",
|
|
1222
|
+
)
|
|
1223
|
+
).and.contains("path: ./large_block.js");
|
|
1224
|
+
// And does have the source code extracted
|
|
1225
|
+
(
|
|
1226
|
+
await expectFileExists(
|
|
1227
|
+
testDir,
|
|
1228
|
+
"apps/test_app/pages/test_page/apis/test_api/large_block.js",
|
|
1229
|
+
)
|
|
1230
|
+
).and.includes(SMALL_JS_CONTENT);
|
|
1231
|
+
// And does not have the old file
|
|
1232
|
+
await expectNoFileExists(
|
|
1233
|
+
testDir,
|
|
1234
|
+
"apps/test_app/pages/test_page/apis/test_api.yaml",
|
|
1235
|
+
);
|
|
1236
|
+
// and can be read back in
|
|
1237
|
+
(
|
|
1238
|
+
await readApiFile(
|
|
1239
|
+
`${testDir}/apps/test_app/pages/test_page/apis`,
|
|
1240
|
+
"Test API",
|
|
1241
|
+
)
|
|
1242
|
+
).to.deep.equal({
|
|
1243
|
+
api: testApi.apiPb,
|
|
1244
|
+
stepPathMap: {
|
|
1245
|
+
"Large Block": "./large_block.js",
|
|
1246
|
+
},
|
|
1247
|
+
});
|
|
1248
|
+
// and a push operation would consider it valid
|
|
1249
|
+
expect(await validateLocalResource(testDir, resourceConfig)).to.be
|
|
1250
|
+
.undefined;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// Write out the same multi-page app again, again with large code so files are extracted
|
|
1254
|
+
{
|
|
1255
|
+
// Change the JS code to be shorter so no files are extracted
|
|
1256
|
+
if (testApi.apiPb?.blocks?.[0]?.step?.javascript) {
|
|
1257
|
+
testApi.apiPb.blocks[0].step.javascript.body = LARGE_JS_CONTENT;
|
|
1258
|
+
}
|
|
1259
|
+
const resourceConfig = await writeApplicationToDisk({
|
|
1260
|
+
sdk: {} as any,
|
|
1261
|
+
resource: multiPageApp,
|
|
1262
|
+
projectRootFolder: testDir,
|
|
1263
|
+
featureFlags: mockFeatureFlags,
|
|
1264
|
+
migrateFromSinglePage: false,
|
|
1265
|
+
preferredApiRepresentation: EXTRACT_SOURCE_CODE,
|
|
1266
|
+
});
|
|
1267
|
+
await Promise.all(apiPromises);
|
|
1268
|
+
|
|
1269
|
+
// Verify the superblocks.json file is correct for a multipage app that does extract source files
|
|
1270
|
+
const config = (await expectSuperblocksJsonFileExists(
|
|
1271
|
+
`${testDir}/apps/test_app/`,
|
|
1272
|
+
)) as SuperblocksApplicationConfig;
|
|
1273
|
+
const page = config.pages?.[multiPageApp.pages[0].id];
|
|
1274
|
+
expect(page?.apis).to.be.undefined;
|
|
1275
|
+
expect(page?.pageApis?.[testApi.id]?.sourceFiles).to.deep.equal([
|
|
1276
|
+
"large_block.js",
|
|
1277
|
+
]);
|
|
1278
|
+
|
|
1279
|
+
// Verify the files exist and match expectations
|
|
1280
|
+
expect(resourceConfig.location).to.equal("apps/test_app");
|
|
1281
|
+
await expectFileExists(testDir, "apps/test_app/application.yaml");
|
|
1282
|
+
await expectFileExists(
|
|
1283
|
+
testDir,
|
|
1284
|
+
"apps/test_app/pages/test_page/page.yaml",
|
|
1285
|
+
);
|
|
1286
|
+
(
|
|
1287
|
+
await expectFileExists(
|
|
1288
|
+
testDir,
|
|
1289
|
+
"apps/test_app/pages/test_page/apis/test_api/api.yaml",
|
|
1290
|
+
)
|
|
1291
|
+
).and.contains("path: ./large_block.js");
|
|
1292
|
+
(
|
|
1293
|
+
await expectFileExists(
|
|
1294
|
+
testDir,
|
|
1295
|
+
"apps/test_app/pages/test_page/apis/test_api/large_block.js",
|
|
1296
|
+
)
|
|
1297
|
+
).and.includes(LARGE_JS_CONTENT);
|
|
1298
|
+
// And the old file no longer exists
|
|
1299
|
+
await expectNoFileExists(
|
|
1300
|
+
testDir,
|
|
1301
|
+
"apps/test_app/pages/test_page/apis/test_api.yaml",
|
|
1302
|
+
);
|
|
1303
|
+
// and the file with the wrong name does not exist
|
|
1304
|
+
await expectNoFileExists(
|
|
1305
|
+
testDir,
|
|
1306
|
+
"apps/test_app/pages/test_page/apis/test_api/test_api.yaml",
|
|
1307
|
+
);
|
|
1308
|
+
// and can be read back in
|
|
1309
|
+
(
|
|
1310
|
+
await readApiFile(
|
|
1311
|
+
`${testDir}/apps/test_app/pages/test_page/apis`,
|
|
1312
|
+
"Test API",
|
|
1313
|
+
)
|
|
1314
|
+
).to.deep.equal({
|
|
1315
|
+
api: testApi.apiPb,
|
|
1316
|
+
stepPathMap: {
|
|
1317
|
+
"Large Block": "./large_block.js",
|
|
1318
|
+
},
|
|
1319
|
+
});
|
|
1320
|
+
// and a push operation would consider it valid
|
|
1321
|
+
expect(await validateLocalResource(testDir, resourceConfig)).to.be
|
|
1322
|
+
.undefined;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
// Write out the multi-page app again without extracting any code blocks
|
|
1326
|
+
{
|
|
1327
|
+
const resourceConfig = await writeApplicationToDisk({
|
|
1328
|
+
sdk: {} as any,
|
|
1329
|
+
resource: multiPageApp,
|
|
1330
|
+
projectRootFolder: testDir,
|
|
1331
|
+
featureFlags: mockFeatureFlags,
|
|
1332
|
+
migrateFromSinglePage: false,
|
|
1333
|
+
preferredApiRepresentation: NO_EXTRACT_SOURCE_CODE,
|
|
1334
|
+
});
|
|
1335
|
+
await Promise.all(apiPromises);
|
|
1336
|
+
|
|
1337
|
+
// Compute the expected YAML file content with embedded source code
|
|
1338
|
+
const expectedYamlContent = ymlstringify(testApi.apiPb, {
|
|
1339
|
+
sortMapEntries: true,
|
|
1340
|
+
blockQuote: "literal",
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1343
|
+
// Verify the files exist and match expectations
|
|
1344
|
+
expect(resourceConfig.location).to.equal("apps/test_app");
|
|
1345
|
+
await expectFileExists(testDir, "apps/test_app/application.yaml");
|
|
1346
|
+
await expectFileExists(
|
|
1347
|
+
testDir,
|
|
1348
|
+
"apps/test_app/pages/test_page/page.yaml",
|
|
1349
|
+
);
|
|
1350
|
+
(
|
|
1351
|
+
await expectFileExists(
|
|
1352
|
+
testDir,
|
|
1353
|
+
"apps/test_app/pages/test_page/apis/test_api.yaml",
|
|
1354
|
+
)
|
|
1355
|
+
).and.contains(expectedYamlContent);
|
|
1356
|
+
// And does not have the source code extracted
|
|
1357
|
+
await expectNoFileExists(
|
|
1358
|
+
testDir,
|
|
1359
|
+
"apps/test_app/pages/test_page/apis/test_api/large_block.js",
|
|
1360
|
+
);
|
|
1361
|
+
// and can be read back in
|
|
1362
|
+
(
|
|
1363
|
+
await readApiFile(
|
|
1364
|
+
`${testDir}/apps/test_app/pages/test_page/apis`,
|
|
1365
|
+
"Test API",
|
|
1366
|
+
)
|
|
1367
|
+
).to.deep.equal({
|
|
1368
|
+
api: testApi.apiPb,
|
|
1369
|
+
stepPathMap: {},
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
});
|
|
1374
|
+
});
|
|
1375
|
+
|
|
1376
|
+
async function expectFileExists(
|
|
1377
|
+
testDir: string,
|
|
1378
|
+
relativePath: string,
|
|
1379
|
+
): Promise<Chai.Assertion> {
|
|
1380
|
+
const filePath = path.join(testDir, relativePath);
|
|
1381
|
+
await expect(await fs.pathExists(filePath)).to.be.true;
|
|
1382
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
1383
|
+
return expect(content);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
async function expectNoFileExists(testDir: string, relativePath: string) {
|
|
1387
|
+
const filePath = path.join(testDir, relativePath);
|
|
1388
|
+
expect(await fs.pathExists(filePath)).to.be.false;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
async function readApiFile(
|
|
1392
|
+
testDir: string,
|
|
1393
|
+
apiName?: string,
|
|
1394
|
+
): Promise<Chai.Assertion> {
|
|
1395
|
+
const api = await readAppApiYamlFile(testDir, apiName);
|
|
1396
|
+
return expect(api);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
async function expectSuperblocksJsonFileExists(
|
|
1400
|
+
testDir: string,
|
|
1401
|
+
): Promise<SuperblocksConfig> {
|
|
1402
|
+
const filePath = path.join(testDir, ".superblocks/superblocks.json");
|
|
1403
|
+
await expect(await fs.pathExists(filePath)).to.be.true;
|
|
1404
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
1405
|
+
return JSON.parse(content) as SuperblocksConfig;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
async function removeExistingFiles(existingFilePaths: Set<string>) {
|
|
1409
|
+
for (const filePath of existingFilePaths) {
|
|
1410
|
+
await fs.remove(filePath);
|
|
1411
|
+
}
|
|
1412
|
+
}
|