@gcoredev/fastedge-test 0.1.0-beta.3 → 0.1.2
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/dist/lib/index.cjs +33 -8
- package/dist/lib/index.js +33 -8
- package/dist/lib/runner/HttpWasmRunner.d.ts +2 -0
- package/dist/lib/test-framework/assertions.d.ts +39 -0
- package/dist/lib/test-framework/index.cjs +145 -10
- package/dist/lib/test-framework/index.d.ts +3 -3
- package/dist/lib/test-framework/index.js +135 -10
- package/dist/lib/test-framework/suite-runner.d.ts +11 -2
- package/dist/lib/test-framework/types.d.ts +10 -0
- package/dist/lib/utils/legacy-wasm-detect.d.ts +25 -0
- package/dist/server.js +25 -25
- package/docs/API.md +13 -16
- package/docs/DEBUGGER.md +17 -16
- package/docs/INDEX.md +47 -47
- package/docs/RUNNER.md +40 -40
- package/docs/TEST_CONFIG.md +32 -32
- package/docs/TEST_FRAMEWORK.md +141 -18
- package/docs/WEBSOCKET.md +19 -19
- package/llms.txt +12 -225
- package/package.json +9 -3
package/dist/lib/index.cjs
CHANGED
|
@@ -1808,8 +1808,8 @@ var ProxyWasmRunner = class {
|
|
|
1808
1808
|
this.resetState();
|
|
1809
1809
|
let buffer;
|
|
1810
1810
|
if (typeof bufferOrPath === "string") {
|
|
1811
|
-
const { readFile:
|
|
1812
|
-
buffer = await
|
|
1811
|
+
const { readFile: readFile3 } = await import("fs/promises");
|
|
1812
|
+
buffer = await readFile3(bufferOrPath);
|
|
1813
1813
|
} else {
|
|
1814
1814
|
buffer = bufferOrPath;
|
|
1815
1815
|
}
|
|
@@ -2665,6 +2665,26 @@ async function removeTempWasmFile(filePath) {
|
|
|
2665
2665
|
}
|
|
2666
2666
|
}
|
|
2667
2667
|
|
|
2668
|
+
// server/utils/legacy-wasm-detect.ts
|
|
2669
|
+
var import_promises3 = require("fs/promises");
|
|
2670
|
+
async function isLegacySyncWasm(bufferOrPath) {
|
|
2671
|
+
let buffer;
|
|
2672
|
+
if (typeof bufferOrPath === "string") {
|
|
2673
|
+
buffer = await (0, import_promises3.readFile)(bufferOrPath);
|
|
2674
|
+
} else {
|
|
2675
|
+
buffer = bufferOrPath;
|
|
2676
|
+
}
|
|
2677
|
+
try {
|
|
2678
|
+
const module2 = await WebAssembly.compile(new Uint8Array(buffer));
|
|
2679
|
+
const exports2 = WebAssembly.Module.exports(module2);
|
|
2680
|
+
return exports2.some(
|
|
2681
|
+
(exp) => exp.name === "process" || exp.name.endsWith("#process")
|
|
2682
|
+
);
|
|
2683
|
+
} catch {
|
|
2684
|
+
return false;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2668
2688
|
// server/runner/HttpWasmRunner.ts
|
|
2669
2689
|
var HttpWasmRunner = class {
|
|
2670
2690
|
constructor(portManager, dotenvEnabled = true) {
|
|
@@ -2678,6 +2698,8 @@ var HttpWasmRunner = class {
|
|
|
2678
2698
|
this.stateManager = null;
|
|
2679
2699
|
this.dotenvEnabled = true;
|
|
2680
2700
|
this.dotenvPath = null;
|
|
2701
|
+
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
2702
|
+
this.isLegacySync = false;
|
|
2681
2703
|
this.portManager = portManager;
|
|
2682
2704
|
this.dotenvEnabled = dotenvEnabled;
|
|
2683
2705
|
}
|
|
@@ -2701,7 +2723,9 @@ var HttpWasmRunner = class {
|
|
|
2701
2723
|
wasmPath = await writeTempWasmFile(bufferOrPath);
|
|
2702
2724
|
this.tempWasmPath = wasmPath;
|
|
2703
2725
|
}
|
|
2726
|
+
this.isLegacySync = await isLegacySyncWasm(bufferOrPath);
|
|
2704
2727
|
this.port = await this.portManager.allocate();
|
|
2728
|
+
const wasi_http = !this.isLegacySync;
|
|
2705
2729
|
const args = [
|
|
2706
2730
|
"http",
|
|
2707
2731
|
"-p",
|
|
@@ -2709,7 +2733,7 @@ var HttpWasmRunner = class {
|
|
|
2709
2733
|
"-w",
|
|
2710
2734
|
wasmPath,
|
|
2711
2735
|
"--wasi-http",
|
|
2712
|
-
|
|
2736
|
+
String(wasi_http)
|
|
2713
2737
|
];
|
|
2714
2738
|
if (this.dotenvEnabled) {
|
|
2715
2739
|
if (this.dotenvPath) {
|
|
@@ -2799,6 +2823,7 @@ var HttpWasmRunner = class {
|
|
|
2799
2823
|
}
|
|
2800
2824
|
await this.killProcess();
|
|
2801
2825
|
this.process = null;
|
|
2826
|
+
const wasi_http = !this.isLegacySync;
|
|
2802
2827
|
const args = [
|
|
2803
2828
|
"http",
|
|
2804
2829
|
"-p",
|
|
@@ -2806,7 +2831,7 @@ var HttpWasmRunner = class {
|
|
|
2806
2831
|
"-w",
|
|
2807
2832
|
this.currentWasmPath,
|
|
2808
2833
|
"--wasi-http",
|
|
2809
|
-
|
|
2834
|
+
String(wasi_http)
|
|
2810
2835
|
];
|
|
2811
2836
|
if (this.dotenvEnabled) {
|
|
2812
2837
|
if (this.dotenvPath) {
|
|
@@ -3154,14 +3179,14 @@ var NullStateManager = class {
|
|
|
3154
3179
|
};
|
|
3155
3180
|
|
|
3156
3181
|
// server/runner/standalone.ts
|
|
3157
|
-
var
|
|
3182
|
+
var import_promises4 = require("fs/promises");
|
|
3158
3183
|
|
|
3159
3184
|
// server/utils/wasmTypeDetector.ts
|
|
3160
3185
|
async function detectWasmType(bufferOrPath) {
|
|
3161
3186
|
let buffer;
|
|
3162
3187
|
if (typeof bufferOrPath === "string") {
|
|
3163
|
-
const { readFile:
|
|
3164
|
-
buffer = await
|
|
3188
|
+
const { readFile: readFile3 } = await import("fs/promises");
|
|
3189
|
+
buffer = await readFile3(bufferOrPath);
|
|
3165
3190
|
} else {
|
|
3166
3191
|
buffer = bufferOrPath;
|
|
3167
3192
|
}
|
|
@@ -3188,7 +3213,7 @@ async function detectWasmType(bufferOrPath) {
|
|
|
3188
3213
|
|
|
3189
3214
|
// server/runner/standalone.ts
|
|
3190
3215
|
async function createRunner(wasmPath, config) {
|
|
3191
|
-
const buffer = await (0,
|
|
3216
|
+
const buffer = await (0, import_promises4.readFile)(wasmPath);
|
|
3192
3217
|
return createRunnerFromBuffer(buffer, config);
|
|
3193
3218
|
}
|
|
3194
3219
|
async function createRunnerFromBuffer(buffer, config) {
|
package/dist/lib/index.js
CHANGED
|
@@ -1766,8 +1766,8 @@ var ProxyWasmRunner = class {
|
|
|
1766
1766
|
this.resetState();
|
|
1767
1767
|
let buffer;
|
|
1768
1768
|
if (typeof bufferOrPath === "string") {
|
|
1769
|
-
const { readFile:
|
|
1770
|
-
buffer = await
|
|
1769
|
+
const { readFile: readFile3 } = await import("fs/promises");
|
|
1770
|
+
buffer = await readFile3(bufferOrPath);
|
|
1771
1771
|
} else {
|
|
1772
1772
|
buffer = bufferOrPath;
|
|
1773
1773
|
}
|
|
@@ -2623,6 +2623,26 @@ async function removeTempWasmFile(filePath) {
|
|
|
2623
2623
|
}
|
|
2624
2624
|
}
|
|
2625
2625
|
|
|
2626
|
+
// server/utils/legacy-wasm-detect.ts
|
|
2627
|
+
import { readFile } from "fs/promises";
|
|
2628
|
+
async function isLegacySyncWasm(bufferOrPath) {
|
|
2629
|
+
let buffer;
|
|
2630
|
+
if (typeof bufferOrPath === "string") {
|
|
2631
|
+
buffer = await readFile(bufferOrPath);
|
|
2632
|
+
} else {
|
|
2633
|
+
buffer = bufferOrPath;
|
|
2634
|
+
}
|
|
2635
|
+
try {
|
|
2636
|
+
const module = await WebAssembly.compile(new Uint8Array(buffer));
|
|
2637
|
+
const exports = WebAssembly.Module.exports(module);
|
|
2638
|
+
return exports.some(
|
|
2639
|
+
(exp) => exp.name === "process" || exp.name.endsWith("#process")
|
|
2640
|
+
);
|
|
2641
|
+
} catch {
|
|
2642
|
+
return false;
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2626
2646
|
// server/runner/HttpWasmRunner.ts
|
|
2627
2647
|
var HttpWasmRunner = class {
|
|
2628
2648
|
constructor(portManager, dotenvEnabled = true) {
|
|
@@ -2636,6 +2656,8 @@ var HttpWasmRunner = class {
|
|
|
2636
2656
|
this.stateManager = null;
|
|
2637
2657
|
this.dotenvEnabled = true;
|
|
2638
2658
|
this.dotenvPath = null;
|
|
2659
|
+
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
2660
|
+
this.isLegacySync = false;
|
|
2639
2661
|
this.portManager = portManager;
|
|
2640
2662
|
this.dotenvEnabled = dotenvEnabled;
|
|
2641
2663
|
}
|
|
@@ -2659,7 +2681,9 @@ var HttpWasmRunner = class {
|
|
|
2659
2681
|
wasmPath = await writeTempWasmFile(bufferOrPath);
|
|
2660
2682
|
this.tempWasmPath = wasmPath;
|
|
2661
2683
|
}
|
|
2684
|
+
this.isLegacySync = await isLegacySyncWasm(bufferOrPath);
|
|
2662
2685
|
this.port = await this.portManager.allocate();
|
|
2686
|
+
const wasi_http = !this.isLegacySync;
|
|
2663
2687
|
const args = [
|
|
2664
2688
|
"http",
|
|
2665
2689
|
"-p",
|
|
@@ -2667,7 +2691,7 @@ var HttpWasmRunner = class {
|
|
|
2667
2691
|
"-w",
|
|
2668
2692
|
wasmPath,
|
|
2669
2693
|
"--wasi-http",
|
|
2670
|
-
|
|
2694
|
+
String(wasi_http)
|
|
2671
2695
|
];
|
|
2672
2696
|
if (this.dotenvEnabled) {
|
|
2673
2697
|
if (this.dotenvPath) {
|
|
@@ -2757,6 +2781,7 @@ var HttpWasmRunner = class {
|
|
|
2757
2781
|
}
|
|
2758
2782
|
await this.killProcess();
|
|
2759
2783
|
this.process = null;
|
|
2784
|
+
const wasi_http = !this.isLegacySync;
|
|
2760
2785
|
const args = [
|
|
2761
2786
|
"http",
|
|
2762
2787
|
"-p",
|
|
@@ -2764,7 +2789,7 @@ var HttpWasmRunner = class {
|
|
|
2764
2789
|
"-w",
|
|
2765
2790
|
this.currentWasmPath,
|
|
2766
2791
|
"--wasi-http",
|
|
2767
|
-
|
|
2792
|
+
String(wasi_http)
|
|
2768
2793
|
];
|
|
2769
2794
|
if (this.dotenvEnabled) {
|
|
2770
2795
|
if (this.dotenvPath) {
|
|
@@ -3112,14 +3137,14 @@ var NullStateManager = class {
|
|
|
3112
3137
|
};
|
|
3113
3138
|
|
|
3114
3139
|
// server/runner/standalone.ts
|
|
3115
|
-
import { readFile } from "fs/promises";
|
|
3140
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
3116
3141
|
|
|
3117
3142
|
// server/utils/wasmTypeDetector.ts
|
|
3118
3143
|
async function detectWasmType(bufferOrPath) {
|
|
3119
3144
|
let buffer;
|
|
3120
3145
|
if (typeof bufferOrPath === "string") {
|
|
3121
|
-
const { readFile:
|
|
3122
|
-
buffer = await
|
|
3146
|
+
const { readFile: readFile3 } = await import("fs/promises");
|
|
3147
|
+
buffer = await readFile3(bufferOrPath);
|
|
3123
3148
|
} else {
|
|
3124
3149
|
buffer = bufferOrPath;
|
|
3125
3150
|
}
|
|
@@ -3146,7 +3171,7 @@ async function detectWasmType(bufferOrPath) {
|
|
|
3146
3171
|
|
|
3147
3172
|
// server/runner/standalone.ts
|
|
3148
3173
|
async function createRunner(wasmPath, config) {
|
|
3149
|
-
const buffer = await
|
|
3174
|
+
const buffer = await readFile2(wasmPath);
|
|
3150
3175
|
return createRunnerFromBuffer(buffer, config);
|
|
3151
3176
|
}
|
|
3152
3177
|
async function createRunnerFromBuffer(buffer, config) {
|
|
@@ -24,6 +24,8 @@ export declare class HttpWasmRunner implements IWasmRunner {
|
|
|
24
24
|
private portManager;
|
|
25
25
|
private dotenvEnabled;
|
|
26
26
|
private dotenvPath;
|
|
27
|
+
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
28
|
+
private isLegacySync;
|
|
27
29
|
constructor(portManager: PortManager, dotenvEnabled?: boolean);
|
|
28
30
|
/**
|
|
29
31
|
* Load WASM binary and spawn fastedge-run process
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* (vitest, jest, node:assert) or plain try/catch in agent scripts.
|
|
6
6
|
*/
|
|
7
7
|
import type { HookResult, FullFlowResult } from "../runner/types.js";
|
|
8
|
+
import type { HttpResponse } from "../runner/IWasmRunner.js";
|
|
8
9
|
/**
|
|
9
10
|
* Assert that a named header exists (and optionally matches a value)
|
|
10
11
|
* in the hook's output request headers.
|
|
@@ -60,3 +61,41 @@ export declare function assertPropertyAllowed(result: HookResult, propertyPath:
|
|
|
60
61
|
* Assert that a property access WAS denied.
|
|
61
62
|
*/
|
|
62
63
|
export declare function assertPropertyDenied(result: HookResult, propertyPath: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Assert the HTTP response status code.
|
|
66
|
+
*/
|
|
67
|
+
export declare function assertHttpStatus(response: HttpResponse, expected: number): void;
|
|
68
|
+
/**
|
|
69
|
+
* Assert that a named header exists (and optionally matches a value)
|
|
70
|
+
* in the HTTP response.
|
|
71
|
+
*/
|
|
72
|
+
export declare function assertHttpHeader(response: HttpResponse, name: string, expected?: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Assert that a named header is absent in the HTTP response.
|
|
75
|
+
*/
|
|
76
|
+
export declare function assertHttpNoHeader(response: HttpResponse, name: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* Assert the HTTP response body matches exactly.
|
|
79
|
+
*/
|
|
80
|
+
export declare function assertHttpBody(response: HttpResponse, expected: string): void;
|
|
81
|
+
/**
|
|
82
|
+
* Assert the HTTP response body contains a substring.
|
|
83
|
+
*/
|
|
84
|
+
export declare function assertHttpBodyContains(response: HttpResponse, substring: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* Parse the HTTP response body as JSON and return it.
|
|
87
|
+
* Throws with a descriptive error if the body is not valid JSON.
|
|
88
|
+
*/
|
|
89
|
+
export declare function assertHttpJson<T = unknown>(response: HttpResponse): T;
|
|
90
|
+
/**
|
|
91
|
+
* Assert the HTTP response content-type contains the expected type string.
|
|
92
|
+
*/
|
|
93
|
+
export declare function assertHttpContentType(response: HttpResponse, expected: string): void;
|
|
94
|
+
/**
|
|
95
|
+
* Assert that at least one log entry contains the given substring (HTTP variant).
|
|
96
|
+
*/
|
|
97
|
+
export declare function assertHttpLog(response: HttpResponse, messageSubstring: string): void;
|
|
98
|
+
/**
|
|
99
|
+
* Assert that no log entry contains the given substring (HTTP variant).
|
|
100
|
+
*/
|
|
101
|
+
export declare function assertHttpNoLog(response: HttpResponse, messageSubstring: string): void;
|
|
@@ -33,6 +33,15 @@ var index_exports = {};
|
|
|
33
33
|
__export(index_exports, {
|
|
34
34
|
assertFinalHeader: () => assertFinalHeader,
|
|
35
35
|
assertFinalStatus: () => assertFinalStatus,
|
|
36
|
+
assertHttpBody: () => assertHttpBody,
|
|
37
|
+
assertHttpBodyContains: () => assertHttpBodyContains,
|
|
38
|
+
assertHttpContentType: () => assertHttpContentType,
|
|
39
|
+
assertHttpHeader: () => assertHttpHeader,
|
|
40
|
+
assertHttpJson: () => assertHttpJson,
|
|
41
|
+
assertHttpLog: () => assertHttpLog,
|
|
42
|
+
assertHttpNoHeader: () => assertHttpNoHeader,
|
|
43
|
+
assertHttpNoLog: () => assertHttpNoLog,
|
|
44
|
+
assertHttpStatus: () => assertHttpStatus,
|
|
36
45
|
assertLog: () => assertLog,
|
|
37
46
|
assertNoLog: () => assertNoLog,
|
|
38
47
|
assertNoRequestHeader: () => assertNoRequestHeader,
|
|
@@ -48,15 +57,16 @@ __export(index_exports, {
|
|
|
48
57
|
logsContain: () => logsContain,
|
|
49
58
|
runAndExit: () => runAndExit,
|
|
50
59
|
runFlow: () => runFlow,
|
|
60
|
+
runHttpRequest: () => runHttpRequest,
|
|
51
61
|
runTestSuite: () => runTestSuite
|
|
52
62
|
});
|
|
53
63
|
module.exports = __toCommonJS(index_exports);
|
|
54
64
|
|
|
55
65
|
// server/test-framework/suite-runner.ts
|
|
56
|
-
var
|
|
66
|
+
var import_promises5 = require("fs/promises");
|
|
57
67
|
|
|
58
68
|
// server/runner/standalone.ts
|
|
59
|
-
var
|
|
69
|
+
var import_promises4 = require("fs/promises");
|
|
60
70
|
|
|
61
71
|
// server/runner/ProxyWasmRunner.ts
|
|
62
72
|
var import_node_wasi = require("node:wasi");
|
|
@@ -1826,8 +1836,8 @@ var ProxyWasmRunner = class {
|
|
|
1826
1836
|
this.resetState();
|
|
1827
1837
|
let buffer;
|
|
1828
1838
|
if (typeof bufferOrPath === "string") {
|
|
1829
|
-
const { readFile:
|
|
1830
|
-
buffer = await
|
|
1839
|
+
const { readFile: readFile4 } = await import("fs/promises");
|
|
1840
|
+
buffer = await readFile4(bufferOrPath);
|
|
1831
1841
|
} else {
|
|
1832
1842
|
buffer = bufferOrPath;
|
|
1833
1843
|
}
|
|
@@ -2683,6 +2693,26 @@ async function removeTempWasmFile(filePath) {
|
|
|
2683
2693
|
}
|
|
2684
2694
|
}
|
|
2685
2695
|
|
|
2696
|
+
// server/utils/legacy-wasm-detect.ts
|
|
2697
|
+
var import_promises3 = require("fs/promises");
|
|
2698
|
+
async function isLegacySyncWasm(bufferOrPath) {
|
|
2699
|
+
let buffer;
|
|
2700
|
+
if (typeof bufferOrPath === "string") {
|
|
2701
|
+
buffer = await (0, import_promises3.readFile)(bufferOrPath);
|
|
2702
|
+
} else {
|
|
2703
|
+
buffer = bufferOrPath;
|
|
2704
|
+
}
|
|
2705
|
+
try {
|
|
2706
|
+
const module2 = await WebAssembly.compile(new Uint8Array(buffer));
|
|
2707
|
+
const exports2 = WebAssembly.Module.exports(module2);
|
|
2708
|
+
return exports2.some(
|
|
2709
|
+
(exp) => exp.name === "process" || exp.name.endsWith("#process")
|
|
2710
|
+
);
|
|
2711
|
+
} catch {
|
|
2712
|
+
return false;
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2686
2716
|
// server/runner/HttpWasmRunner.ts
|
|
2687
2717
|
var HttpWasmRunner = class {
|
|
2688
2718
|
constructor(portManager, dotenvEnabled = true) {
|
|
@@ -2696,6 +2726,8 @@ var HttpWasmRunner = class {
|
|
|
2696
2726
|
this.stateManager = null;
|
|
2697
2727
|
this.dotenvEnabled = true;
|
|
2698
2728
|
this.dotenvPath = null;
|
|
2729
|
+
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
2730
|
+
this.isLegacySync = false;
|
|
2699
2731
|
this.portManager = portManager;
|
|
2700
2732
|
this.dotenvEnabled = dotenvEnabled;
|
|
2701
2733
|
}
|
|
@@ -2719,7 +2751,9 @@ var HttpWasmRunner = class {
|
|
|
2719
2751
|
wasmPath = await writeTempWasmFile(bufferOrPath);
|
|
2720
2752
|
this.tempWasmPath = wasmPath;
|
|
2721
2753
|
}
|
|
2754
|
+
this.isLegacySync = await isLegacySyncWasm(bufferOrPath);
|
|
2722
2755
|
this.port = await this.portManager.allocate();
|
|
2756
|
+
const wasi_http = !this.isLegacySync;
|
|
2723
2757
|
const args = [
|
|
2724
2758
|
"http",
|
|
2725
2759
|
"-p",
|
|
@@ -2727,7 +2761,7 @@ var HttpWasmRunner = class {
|
|
|
2727
2761
|
"-w",
|
|
2728
2762
|
wasmPath,
|
|
2729
2763
|
"--wasi-http",
|
|
2730
|
-
|
|
2764
|
+
String(wasi_http)
|
|
2731
2765
|
];
|
|
2732
2766
|
if (this.dotenvEnabled) {
|
|
2733
2767
|
if (this.dotenvPath) {
|
|
@@ -2817,6 +2851,7 @@ var HttpWasmRunner = class {
|
|
|
2817
2851
|
}
|
|
2818
2852
|
await this.killProcess();
|
|
2819
2853
|
this.process = null;
|
|
2854
|
+
const wasi_http = !this.isLegacySync;
|
|
2820
2855
|
const args = [
|
|
2821
2856
|
"http",
|
|
2822
2857
|
"-p",
|
|
@@ -2824,7 +2859,7 @@ var HttpWasmRunner = class {
|
|
|
2824
2859
|
"-w",
|
|
2825
2860
|
this.currentWasmPath,
|
|
2826
2861
|
"--wasi-http",
|
|
2827
|
-
|
|
2862
|
+
String(wasi_http)
|
|
2828
2863
|
];
|
|
2829
2864
|
if (this.dotenvEnabled) {
|
|
2830
2865
|
if (this.dotenvPath) {
|
|
@@ -3125,8 +3160,8 @@ var PortManager = class {
|
|
|
3125
3160
|
async function detectWasmType(bufferOrPath) {
|
|
3126
3161
|
let buffer;
|
|
3127
3162
|
if (typeof bufferOrPath === "string") {
|
|
3128
|
-
const { readFile:
|
|
3129
|
-
buffer = await
|
|
3163
|
+
const { readFile: readFile4 } = await import("fs/promises");
|
|
3164
|
+
buffer = await readFile4(bufferOrPath);
|
|
3130
3165
|
} else {
|
|
3131
3166
|
buffer = bufferOrPath;
|
|
3132
3167
|
}
|
|
@@ -3153,7 +3188,7 @@ async function detectWasmType(bufferOrPath) {
|
|
|
3153
3188
|
|
|
3154
3189
|
// server/runner/standalone.ts
|
|
3155
3190
|
async function createRunner(wasmPath, config) {
|
|
3156
|
-
const buffer = await (0,
|
|
3191
|
+
const buffer = await (0, import_promises4.readFile)(wasmPath);
|
|
3157
3192
|
return createRunnerFromBuffer(buffer, config);
|
|
3158
3193
|
}
|
|
3159
3194
|
async function createRunnerFromBuffer(buffer, config) {
|
|
@@ -3208,7 +3243,7 @@ function defineTestSuite(config) {
|
|
|
3208
3243
|
return config;
|
|
3209
3244
|
}
|
|
3210
3245
|
async function loadConfigFile(configPath) {
|
|
3211
|
-
const raw = await (0,
|
|
3246
|
+
const raw = await (0, import_promises5.readFile)(configPath, "utf-8");
|
|
3212
3247
|
let json;
|
|
3213
3248
|
try {
|
|
3214
3249
|
json = JSON.parse(raw);
|
|
@@ -3294,6 +3329,15 @@ async function runFlow(runner, options) {
|
|
|
3294
3329
|
enforceProductionPropertyRules
|
|
3295
3330
|
);
|
|
3296
3331
|
}
|
|
3332
|
+
async function runHttpRequest(runner, options) {
|
|
3333
|
+
const {
|
|
3334
|
+
path: path2,
|
|
3335
|
+
method = "GET",
|
|
3336
|
+
headers = {},
|
|
3337
|
+
body = ""
|
|
3338
|
+
} = options;
|
|
3339
|
+
return runner.execute({ path: path2, method, headers, body });
|
|
3340
|
+
}
|
|
3297
3341
|
async function runAndExit(suite) {
|
|
3298
3342
|
const results = await runTestSuite(suite);
|
|
3299
3343
|
console.log("");
|
|
@@ -3431,10 +3475,100 @@ function assertPropertyDenied(result, propertyPath) {
|
|
|
3431
3475
|
);
|
|
3432
3476
|
}
|
|
3433
3477
|
}
|
|
3478
|
+
function assertHttpStatus(response, expected) {
|
|
3479
|
+
if (response.status !== expected) {
|
|
3480
|
+
throw new Error(
|
|
3481
|
+
`Expected HTTP status ${expected}, got ${response.status}`
|
|
3482
|
+
);
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
function assertHttpHeader(response, name, expected) {
|
|
3486
|
+
const lower = name.toLowerCase();
|
|
3487
|
+
const value = Object.entries(response.headers).find(
|
|
3488
|
+
([k]) => k.toLowerCase() === lower
|
|
3489
|
+
)?.[1];
|
|
3490
|
+
if (value === void 0) {
|
|
3491
|
+
throw new Error(
|
|
3492
|
+
`Expected HTTP response header '${name}' to be set, but it was missing`
|
|
3493
|
+
);
|
|
3494
|
+
}
|
|
3495
|
+
if (expected !== void 0 && value !== expected) {
|
|
3496
|
+
throw new Error(
|
|
3497
|
+
`Expected HTTP response header '${name}' to be '${expected}', got '${value}'`
|
|
3498
|
+
);
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
function assertHttpNoHeader(response, name) {
|
|
3502
|
+
const lower = name.toLowerCase();
|
|
3503
|
+
const value = Object.entries(response.headers).find(
|
|
3504
|
+
([k]) => k.toLowerCase() === lower
|
|
3505
|
+
)?.[1];
|
|
3506
|
+
if (value !== void 0) {
|
|
3507
|
+
throw new Error(
|
|
3508
|
+
`Expected HTTP response header '${name}' to be absent, but found '${value}'`
|
|
3509
|
+
);
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
function assertHttpBody(response, expected) {
|
|
3513
|
+
if (response.body !== expected) {
|
|
3514
|
+
throw new Error(
|
|
3515
|
+
`Expected HTTP body to be '${expected}', got '${response.body}'`
|
|
3516
|
+
);
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
function assertHttpBodyContains(response, substring) {
|
|
3520
|
+
if (!response.body.includes(substring)) {
|
|
3521
|
+
throw new Error(
|
|
3522
|
+
`Expected HTTP body to contain '${substring}', but it was not found`
|
|
3523
|
+
);
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
function assertHttpJson(response) {
|
|
3527
|
+
try {
|
|
3528
|
+
return JSON.parse(response.body);
|
|
3529
|
+
} catch {
|
|
3530
|
+
throw new Error(
|
|
3531
|
+
`Expected HTTP body to be valid JSON, but parsing failed. Body: '${response.body.slice(0, 200)}'`
|
|
3532
|
+
);
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
function assertHttpContentType(response, expected) {
|
|
3536
|
+
const ct = response.contentType ?? "";
|
|
3537
|
+
if (!ct.toLowerCase().includes(expected.toLowerCase())) {
|
|
3538
|
+
throw new Error(
|
|
3539
|
+
`Expected HTTP content-type to contain '${expected}', got '${ct}'`
|
|
3540
|
+
);
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
function assertHttpLog(response, messageSubstring) {
|
|
3544
|
+
const found = response.logs.some((log) => log.message.includes(messageSubstring));
|
|
3545
|
+
if (!found) {
|
|
3546
|
+
throw new Error(
|
|
3547
|
+
`Expected an HTTP log message containing '${messageSubstring}' but none found`
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
function assertHttpNoLog(response, messageSubstring) {
|
|
3552
|
+
const match = response.logs.find((log) => log.message.includes(messageSubstring));
|
|
3553
|
+
if (match) {
|
|
3554
|
+
throw new Error(
|
|
3555
|
+
`Expected no HTTP log containing '${messageSubstring}', but found: '${match.message}'`
|
|
3556
|
+
);
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3434
3559
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3435
3560
|
0 && (module.exports = {
|
|
3436
3561
|
assertFinalHeader,
|
|
3437
3562
|
assertFinalStatus,
|
|
3563
|
+
assertHttpBody,
|
|
3564
|
+
assertHttpBodyContains,
|
|
3565
|
+
assertHttpContentType,
|
|
3566
|
+
assertHttpHeader,
|
|
3567
|
+
assertHttpJson,
|
|
3568
|
+
assertHttpLog,
|
|
3569
|
+
assertHttpNoHeader,
|
|
3570
|
+
assertHttpNoLog,
|
|
3571
|
+
assertHttpStatus,
|
|
3438
3572
|
assertLog,
|
|
3439
3573
|
assertNoLog,
|
|
3440
3574
|
assertNoRequestHeader,
|
|
@@ -3450,5 +3584,6 @@ function assertPropertyDenied(result, propertyPath) {
|
|
|
3450
3584
|
logsContain,
|
|
3451
3585
|
runAndExit,
|
|
3452
3586
|
runFlow,
|
|
3587
|
+
runHttpRequest,
|
|
3453
3588
|
runTestSuite
|
|
3454
3589
|
});
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* Entry point for the `./test` sub-path export.
|
|
5
5
|
* Import via: import { defineTestSuite, runTestSuite } from '@gcoredev/fastedge-test/test'
|
|
6
6
|
*/
|
|
7
|
-
export { defineTestSuite, runTestSuite, runAndExit, runFlow, loadConfigFile } from "./suite-runner.js";
|
|
8
|
-
export { assertRequestHeader, assertNoRequestHeader, assertResponseHeader, assertNoResponseHeader, assertFinalStatus, assertFinalHeader, assertReturnCode, assertLog, assertNoLog, logsContain, hasPropertyAccessViolation, assertPropertyAllowed, assertPropertyDenied, } from "./assertions.js";
|
|
9
|
-
export type { TestSuite, TestCase, TestResult, SuiteResult, FlowOptions, RunnerConfig, } from "./types.js";
|
|
7
|
+
export { defineTestSuite, runTestSuite, runAndExit, runFlow, runHttpRequest, loadConfigFile } from "./suite-runner.js";
|
|
8
|
+
export { assertRequestHeader, assertNoRequestHeader, assertResponseHeader, assertNoResponseHeader, assertFinalStatus, assertFinalHeader, assertReturnCode, assertLog, assertNoLog, logsContain, hasPropertyAccessViolation, assertPropertyAllowed, assertPropertyDenied, assertHttpStatus, assertHttpHeader, assertHttpNoHeader, assertHttpBody, assertHttpBodyContains, assertHttpJson, assertHttpContentType, assertHttpLog, assertHttpNoLog, } from "./assertions.js";
|
|
9
|
+
export type { TestSuite, TestCase, TestResult, SuiteResult, FlowOptions, HttpRequestOptions, RunnerConfig, } from "./types.js";
|