@ondc/automation-mock-runner 0.0.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.
Files changed (43) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +372 -0
  3. package/dist/index.d.ts +18 -0
  4. package/dist/index.js +43 -0
  5. package/dist/lib/MockRunner.d.ts +18 -0
  6. package/dist/lib/MockRunner.js +335 -0
  7. package/dist/lib/configHelper.d.ts +2 -0
  8. package/dist/lib/configHelper.js +101 -0
  9. package/dist/lib/constants/function-registry.d.ts +26 -0
  10. package/dist/lib/constants/function-registry.js +132 -0
  11. package/dist/lib/runners/base-runner.d.ts +6 -0
  12. package/dist/lib/runners/base-runner.js +6 -0
  13. package/dist/lib/runners/browser-runner.d.ts +12 -0
  14. package/dist/lib/runners/browser-runner.js +91 -0
  15. package/dist/lib/runners/node-runner.d.ts +16 -0
  16. package/dist/lib/runners/node-runner.js +189 -0
  17. package/dist/lib/runners/runner-factory.d.ts +25 -0
  18. package/dist/lib/runners/runner-factory.js +113 -0
  19. package/dist/lib/types/execution-results.d.ts +30 -0
  20. package/dist/lib/types/execution-results.js +2 -0
  21. package/dist/lib/types/mock-config.d.ts +107 -0
  22. package/dist/lib/types/mock-config.js +52 -0
  23. package/dist/lib/utils/errors.d.ts +47 -0
  24. package/dist/lib/utils/errors.js +84 -0
  25. package/dist/lib/utils/input-validator.d.ts +18 -0
  26. package/dist/lib/utils/input-validator.js +146 -0
  27. package/dist/lib/utils/logger.d.ts +36 -0
  28. package/dist/lib/utils/logger.js +86 -0
  29. package/dist/lib/utils/performance-monitor.d.ts +34 -0
  30. package/dist/lib/utils/performance-monitor.js +98 -0
  31. package/dist/lib/utils/validateConfig.d.ts +6 -0
  32. package/dist/lib/utils/validateConfig.js +16 -0
  33. package/dist/lib/validators/code-validator.d.ts +30 -0
  34. package/dist/lib/validators/code-validator.js +327 -0
  35. package/dist/lib/worker/worker-factory.d.ts +3 -0
  36. package/dist/lib/worker/worker-factory.js +81 -0
  37. package/dist/test/MockRunner.test.d.ts +4 -0
  38. package/dist/test/MockRunner.test.js +144 -0
  39. package/dist/test/__mocks__/uuid.d.ts +5 -0
  40. package/dist/test/__mocks__/uuid.js +8 -0
  41. package/dist/test/setup.d.ts +3 -0
  42. package/dist/test/setup.js +43 -0
  43. package/package.json +84 -0
@@ -0,0 +1,327 @@
1
+ "use strict";
2
+ // lib/code-runner/code-validator.ts
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.CodeValidator = void 0;
38
+ const acorn = __importStar(require("acorn"));
39
+ const walk = __importStar(require("acorn-walk"));
40
+ class CodeValidator {
41
+ /**
42
+ * Get code statistics
43
+ */
44
+ static getCodeStatistics(code) {
45
+ const stats = {
46
+ lines: code.split("\n").length,
47
+ functions: 0,
48
+ complexity: 1,
49
+ loops: 0,
50
+ conditionals: 0,
51
+ };
52
+ try {
53
+ const ast = acorn.parse(code, {
54
+ ecmaVersion: 2020,
55
+ sourceType: "script",
56
+ });
57
+ walk.simple(ast, {
58
+ FunctionDeclaration() {
59
+ stats.functions++;
60
+ },
61
+ FunctionExpression() {
62
+ stats.functions++;
63
+ },
64
+ ArrowFunctionExpression() {
65
+ stats.functions++;
66
+ },
67
+ WhileStatement() {
68
+ stats.loops++;
69
+ stats.complexity++;
70
+ },
71
+ DoWhileStatement() {
72
+ stats.loops++;
73
+ stats.complexity++;
74
+ },
75
+ ForStatement() {
76
+ stats.loops++;
77
+ stats.complexity++;
78
+ },
79
+ ForInStatement() {
80
+ stats.loops++;
81
+ stats.complexity++;
82
+ },
83
+ ForOfStatement() {
84
+ stats.loops++;
85
+ stats.complexity++;
86
+ },
87
+ IfStatement() {
88
+ stats.conditionals++;
89
+ stats.complexity++;
90
+ },
91
+ ConditionalExpression() {
92
+ stats.conditionals++;
93
+ stats.complexity++;
94
+ },
95
+ SwitchCase(node) {
96
+ if (node.test) {
97
+ stats.conditionals++;
98
+ stats.complexity++;
99
+ }
100
+ },
101
+ LogicalExpression(node) {
102
+ if (node.operator === "||" || node.operator === "&&") {
103
+ stats.complexity++;
104
+ }
105
+ },
106
+ });
107
+ }
108
+ catch (e) {
109
+ // Ignore parse errors, return partial stats
110
+ console.error("Error parsing code for statistics:", e);
111
+ }
112
+ return stats;
113
+ }
114
+ /**
115
+ * Main validation method - now handles function bodies
116
+ */
117
+ static validate(functionBody, schema) {
118
+ const errors = [];
119
+ const warnings = [];
120
+ // 1. Wrap the body with function declaration
121
+ const wrappedCode = functionBody;
122
+ // const wrappedCode = schema.template(functionBody);
123
+ try {
124
+ // 2. Parse complete code into AST
125
+ const ast = acorn.parse(wrappedCode, {
126
+ ecmaVersion: 2020,
127
+ sourceType: "script",
128
+ locations: true,
129
+ });
130
+ // 3. Security analysis on the complete code
131
+ const securityIssues = this.analyzeSecurityIssues(ast);
132
+ securityIssues.forEach((issue) => {
133
+ errors.push(`[Line ${issue.line}] ${issue.message}`);
134
+ });
135
+ // 4. Check for dangerous patterns
136
+ const dangerousPatterns = this.detectDangerousPatterns(ast);
137
+ dangerousPatterns.forEach((pattern) => {
138
+ errors.push(`[Line ${pattern.line}] ${pattern.message}`);
139
+ });
140
+ // 5. Validate return type structure (for validate and meetsRequirements)
141
+ if (schema.returnType.properties) {
142
+ const returnValidation = this.validateReturnStructure(ast, schema.returnType.properties);
143
+ errors.push(...returnValidation);
144
+ }
145
+ // 6. Check for best practices
146
+ const practiceWarnings = this.checkBestPractices(ast, schema);
147
+ warnings.push(...practiceWarnings);
148
+ }
149
+ catch (e) {
150
+ // Syntax error during parsing
151
+ let errorMessage = `Syntax Error: ${e.message}`;
152
+ // Try to extract line number and adjust for function body
153
+ const lineMatch = e.message.match(/\((\d+):(\d+)\)/);
154
+ if (lineMatch) {
155
+ const line = parseInt(lineMatch[1]);
156
+ const col = lineMatch[2];
157
+ // Subtract the number of lines in the template before the body
158
+ const templateLines = schema.template("").split("\n").length - 1;
159
+ const actualLine = Math.max(1, line - templateLines);
160
+ errorMessage = `Syntax Error at line ${actualLine}, column ${col}: ${e.message.split("(")[0]}`;
161
+ }
162
+ errors.push(errorMessage);
163
+ }
164
+ return {
165
+ isValid: errors.length === 0,
166
+ errors,
167
+ warnings,
168
+ wrappedCode: errors.length === 0 ? wrappedCode : undefined,
169
+ };
170
+ }
171
+ /**
172
+ * Validate that return statements match expected structure
173
+ */
174
+ static validateReturnStructure(ast, expectedProperties) {
175
+ const warnings = [];
176
+ const foundReturns = [];
177
+ walk.simple(ast, {
178
+ ReturnStatement(node) {
179
+ if (node.argument) {
180
+ foundReturns.push(node.argument);
181
+ }
182
+ },
183
+ });
184
+ // Check if we have return statements
185
+ if (foundReturns.length === 0) {
186
+ warnings.push(`Function should return an object with properties: ${Object.keys(expectedProperties).join(", ")}`);
187
+ return warnings;
188
+ }
189
+ // Check the structure of returned objects
190
+ foundReturns.forEach((returnArg) => {
191
+ if (returnArg.type === "ObjectExpression") {
192
+ const returnedProps = new Set(returnArg.properties.map((p) => p.key.name));
193
+ const expectedProps = Object.keys(expectedProperties);
194
+ // Check for missing properties
195
+ expectedProps.forEach((prop) => {
196
+ if (!returnedProps.has(prop)) {
197
+ warnings.push(`Return object is missing property '${prop}' (expected: ${expectedProperties[prop].type})`);
198
+ }
199
+ });
200
+ // Check for extra properties
201
+ returnedProps.forEach((prop) => {
202
+ if (!expectedProps.includes(prop)) {
203
+ warnings.push(`Return object has unexpected property '${prop}'`);
204
+ }
205
+ });
206
+ }
207
+ else {
208
+ warnings.push(`Function should return an object literal with properties: ${Object.keys(expectedProperties).join(", ")}`);
209
+ }
210
+ });
211
+ return warnings;
212
+ }
213
+ /**
214
+ * Security analysis - checks for forbidden functions and properties
215
+ */
216
+ static analyzeSecurityIssues(ast) {
217
+ const issues = [];
218
+ walk.simple(ast, {
219
+ CallExpression(node) {
220
+ if (node.callee.type === "Identifier") {
221
+ const name = node.callee.name;
222
+ if (CodeValidator.FORBIDDEN_GLOBALS.includes(name)) {
223
+ issues.push({
224
+ type: "forbidden_function",
225
+ message: `Forbidden function call: ${name}()`,
226
+ line: node.loc?.start.line || 0,
227
+ column: node.loc?.start.column || 0,
228
+ });
229
+ }
230
+ }
231
+ },
232
+ NewExpression(node) {
233
+ if (node.callee.type === "Identifier" &&
234
+ node.callee.name === "Function") {
235
+ issues.push({
236
+ type: "function_constructor",
237
+ message: "Using Function constructor is forbidden",
238
+ line: node.loc?.start.line || 0,
239
+ column: node.loc?.start.column || 0,
240
+ });
241
+ }
242
+ },
243
+ MemberExpression(node) {
244
+ if (node.property.type === "Identifier") {
245
+ const propName = node.property.name;
246
+ if (CodeValidator.FORBIDDEN_PROPERTIES.includes(propName)) {
247
+ issues.push({
248
+ type: "forbidden_property",
249
+ message: `Access to '${propName}' is forbidden`,
250
+ line: node.loc?.start.line || 0,
251
+ column: node.loc?.start.column || 0,
252
+ });
253
+ }
254
+ }
255
+ },
256
+ });
257
+ return issues;
258
+ }
259
+ /**
260
+ * Detect dangerous patterns like infinite loops
261
+ */
262
+ static detectDangerousPatterns(ast) {
263
+ const issues = [];
264
+ walk.simple(ast, {
265
+ WhileStatement(node) {
266
+ if (node.test.type === "Literal" && node.test.value === true) {
267
+ issues.push({
268
+ type: "infinite_loop",
269
+ message: "Potential infinite loop: while(true)",
270
+ line: node.loc?.start.line || 0,
271
+ });
272
+ }
273
+ },
274
+ ForStatement(node) {
275
+ if (!node.test) {
276
+ issues.push({
277
+ type: "infinite_loop",
278
+ message: "Potential infinite loop: for(;;)",
279
+ line: node.loc?.start.line || 0,
280
+ });
281
+ }
282
+ },
283
+ WithStatement(node) {
284
+ issues.push({
285
+ type: "with_statement",
286
+ message: "'with' statement is forbidden",
287
+ line: node.loc?.start.line || 0,
288
+ });
289
+ },
290
+ });
291
+ return issues;
292
+ }
293
+ /**
294
+ * Check for best practices
295
+ */
296
+ static checkBestPractices(ast, schema) {
297
+ const warnings = [];
298
+ let hasReturn = false;
299
+ walk.simple(ast, {
300
+ ReturnStatement() {
301
+ hasReturn = true;
302
+ },
303
+ });
304
+ if (!hasReturn) {
305
+ warnings.push(`Function should return a value (expected: ${schema.returnType.description})`);
306
+ }
307
+ return warnings;
308
+ }
309
+ }
310
+ exports.CodeValidator = CodeValidator;
311
+ CodeValidator.FORBIDDEN_GLOBALS = [
312
+ "eval",
313
+ "Function",
314
+ "importScripts",
315
+ "Worker",
316
+ "SharedWorker",
317
+ "WebSocket",
318
+ "XMLHttpRequest",
319
+ "fetch",
320
+ ];
321
+ CodeValidator.FORBIDDEN_PROPERTIES = [
322
+ "localStorage",
323
+ "sessionStorage",
324
+ "indexedDB",
325
+ "webkitStorageInfo",
326
+ "__proto__",
327
+ ];
@@ -0,0 +1,3 @@
1
+ export declare class WorkerFactory {
2
+ static createCodeRunnerWorker(): Worker;
3
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkerFactory = void 0;
4
+ // lib/src/workers/worker-factory.ts
5
+ class WorkerFactory {
6
+ static createCodeRunnerWorker() {
7
+ const workerCode = `
8
+ // Complete worker implementation
9
+ self.addEventListener('message', (event) => {
10
+ const { id, code, functionName, args } = event.data;
11
+
12
+ try {
13
+ const startTime = Date.now();
14
+ const logs = [];
15
+
16
+ // Capture console outputs
17
+ const originalConsole = {
18
+ log: console.log,
19
+ error: console.error,
20
+ warn: console.warn
21
+ };
22
+
23
+ console.log = (...args) => {
24
+ logs.push({
25
+ type: 'log',
26
+ message: args.join(' '),
27
+ timestamp: Date.now()
28
+ });
29
+ };
30
+
31
+ console.error = (...args) => {
32
+ logs.push({
33
+ type: 'error',
34
+ message: args.join(' '),
35
+ timestamp: Date.now()
36
+ });
37
+ };
38
+
39
+ console.warn = (...args) => {
40
+ logs.push({
41
+ type: 'warn',
42
+ message: args.join(' '),
43
+ timestamp: Date.now()
44
+ });
45
+ };
46
+
47
+ // Execute the code
48
+ const func = new Function('args', code);
49
+ const result = func(args);
50
+
51
+ // Restore console
52
+ Object.assign(console, originalConsole);
53
+
54
+ self.postMessage({
55
+ id,
56
+ success: true,
57
+ result,
58
+ logs,
59
+ executionTime: Date.now() - startTime
60
+ });
61
+
62
+ } catch (error) {
63
+ self.postMessage({
64
+ id,
65
+ success: false,
66
+ error: {
67
+ message: error.message,
68
+ name: error.name,
69
+ stack: error.stack
70
+ },
71
+ logs,
72
+ executionTime: Date.now() - startTime
73
+ });
74
+ }
75
+ });
76
+ `;
77
+ const blob = new Blob([workerCode], { type: "application/javascript" });
78
+ return new Worker(URL.createObjectURL(blob));
79
+ }
80
+ }
81
+ exports.WorkerFactory = WorkerFactory;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tests for MockRunner class - ONDC Automation Mock Runner
3
+ */
4
+ export {};
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for MockRunner class - ONDC Automation Mock Runner
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const MockRunner_1 = require("../lib/MockRunner");
7
+ describe("MockRunner", () => {
8
+ let mockRunner;
9
+ let mockConfig;
10
+ beforeEach(() => {
11
+ mockConfig = {
12
+ meta: {
13
+ domain: "ONDC:TRV14",
14
+ version: "2.0.0",
15
+ flowId: "testing",
16
+ },
17
+ transaction_data: {
18
+ transaction_id: "e9e0b5cb-3f15-48a1-9d86-d4d643f0909d",
19
+ latest_timestamp: "1970-01-01T00:00:00.000Z",
20
+ },
21
+ steps: [],
22
+ transaction_history: [],
23
+ validationLib: "",
24
+ helperLib: "",
25
+ };
26
+ try {
27
+ mockRunner = new MockRunner_1.MockRunner(mockConfig);
28
+ mockConfig.steps.push(mockRunner.getDefaultStep("search", "search_0"));
29
+ }
30
+ catch (error) {
31
+ throw error;
32
+ }
33
+ });
34
+ afterEach(() => {
35
+ jest.clearAllMocks();
36
+ });
37
+ describe("Constructor", () => {
38
+ it("should create MockRunner with valid config", () => {
39
+ expect(mockRunner).toBeDefined();
40
+ expect(mockRunner).toBeInstanceOf(MockRunner_1.MockRunner);
41
+ });
42
+ });
43
+ describe("Config Validation", () => {
44
+ it("should validate correct config successfully", () => {
45
+ const validation = mockRunner.validateConfig();
46
+ expect(validation.success).toBe(true);
47
+ expect(validation.errors).toBeUndefined();
48
+ });
49
+ it("should detect validation errors in invalid config", () => {
50
+ expect(() => {
51
+ new MockRunner_1.MockRunner({
52
+ meta: { domain: "", version: "", flowId: "" },
53
+ transaction_data: {
54
+ transaction_id: "",
55
+ latest_timestamp: "",
56
+ bap_id: "",
57
+ bap_uri: "invalid-url",
58
+ bpp_id: "",
59
+ bpp_uri: "invalid-url",
60
+ },
61
+ steps: [],
62
+ transaction_history: [],
63
+ validationLib: "",
64
+ helperLib: "",
65
+ });
66
+ }).toThrow();
67
+ });
68
+ });
69
+ describe("Generate Payload", () => {
70
+ it("should generate payload successfully", async () => {
71
+ const result = await mockRunner.runGeneratePayload("search_0", {
72
+ category: "Electronics",
73
+ });
74
+ expect(result).toBeDefined();
75
+ expect(result.success).toBe(true);
76
+ expect(result.result).toBeDefined();
77
+ expect(result.timestamp).toBeDefined();
78
+ expect(typeof result.executionTime).toBe("number");
79
+ });
80
+ it("should fail with non-existent action ID", async () => {
81
+ const result = await mockRunner.runGeneratePayload("non-existent", {});
82
+ expect(result.success).toBe(false);
83
+ expect(result.error).toBeDefined();
84
+ expect(result.error.message).toContain("not found");
85
+ });
86
+ });
87
+ describe("Validate Payload", () => {
88
+ it("should validate payload successfully", async () => {
89
+ const targetPayload = {
90
+ context: { domain: "retail", action: "search" },
91
+ message: {
92
+ intent: { category: { descriptor: { name: "Electronics" } } },
93
+ },
94
+ };
95
+ const result = await mockRunner.runValidatePayload("search_0", targetPayload);
96
+ expect(result).toBeDefined();
97
+ expect(result.success).toBe(true);
98
+ });
99
+ it("should fail validation with invalid action ID", async () => {
100
+ const result = await mockRunner.runValidatePayload("invalid-id", {});
101
+ expect(result.success).toBe(false);
102
+ expect(result.error).toBeDefined();
103
+ expect(result.error.name).toBe("PayloadValidationError");
104
+ });
105
+ });
106
+ describe("Context Generation", () => {
107
+ it("should generate context for search action (v2.0)", () => {
108
+ const context = mockRunner.generateContext("search_0", "search");
109
+ expect(context).toBeDefined();
110
+ expect(context.domain).toBe("ONDC:TRV14");
111
+ expect(context.action).toBe("search");
112
+ expect(context.transaction_id).toBe("e9e0b5cb-3f15-48a1-9d86-d4d643f0909d");
113
+ expect(context.message_id).toBeDefined();
114
+ expect(context.timestamp).toBeDefined();
115
+ expect(context.bap_id).toBe("");
116
+ expect(context.bap_uri).toBe("");
117
+ // v2.0 specific fields
118
+ expect(context.version).toBe("2.0.0");
119
+ expect(context.location).toBeDefined();
120
+ expect(context.location.country.code).toBe("IND");
121
+ // Search action should not have BPP details
122
+ expect(context.bpp_id).toBeUndefined();
123
+ expect(context.bpp_uri).toBeUndefined();
124
+ });
125
+ it("should generate context for non-search action", () => {
126
+ // Add a select step first
127
+ mockConfig.steps.push(mockRunner.getDefaultStep("select", "select_0"));
128
+ const context = mockRunner.generateContext("select_0", "select");
129
+ expect(context.bpp_id).toBe("");
130
+ expect(context.bpp_uri).toBe("");
131
+ expect(context.action).toBe("select");
132
+ });
133
+ });
134
+ describe("Session Data Management", () => {
135
+ it("should extract session data correctly", () => {
136
+ const sessionData = mockRunner.getSessionDataUpToStep(0, mockConfig);
137
+ expect(sessionData).toEqual({});
138
+ });
139
+ it("should handle invalid step indices", () => {
140
+ const sessionData = mockRunner.getSessionDataUpToStep(-1, mockConfig);
141
+ expect(sessionData).toEqual({});
142
+ });
143
+ });
144
+ });
@@ -0,0 +1,5 @@
1
+ export declare const v4: jest.Mock<string, [], any>;
2
+ declare const _default: {
3
+ v4: jest.Mock<string, [], any>;
4
+ };
5
+ export default _default;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.v4 = void 0;
4
+ // Mock implementation of uuid for Jest tests
5
+ exports.v4 = jest.fn(() => "mocked-uuid-v4-12345678-1234-1234-1234-123456789012");
6
+ exports.default = {
7
+ v4: exports.v4,
8
+ };
@@ -0,0 +1,3 @@
1
+ /**
2
+ * Jest setup file for ONDC Mock Runner tests
3
+ */
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /**
3
+ * Jest setup file for ONDC Mock Runner tests
4
+ */
5
+ // Global test configuration
6
+ beforeAll(() => {
7
+ // Set up any global test configuration
8
+ process.env.NODE_ENV = "test";
9
+ });
10
+ afterAll(() => {
11
+ // Clean up after all tests
12
+ });
13
+ beforeEach(() => {
14
+ // Reset any mocks or state before each test
15
+ jest.clearAllMocks();
16
+ });
17
+ afterEach(() => {
18
+ // Clean up after each test
19
+ });
20
+ // Extend Jest matchers
21
+ expect.extend({
22
+ toBeValidExecutionResult(received) {
23
+ const pass = received &&
24
+ typeof received === "object" &&
25
+ typeof received.success === "boolean" &&
26
+ typeof received.timestamp === "string" &&
27
+ Array.isArray(received.logs) &&
28
+ received.validation &&
29
+ typeof received.validation.isValid === "boolean";
30
+ if (pass) {
31
+ return {
32
+ message: () => `Expected ${received} not to be a valid ExecutionResult`,
33
+ pass: true,
34
+ };
35
+ }
36
+ else {
37
+ return {
38
+ message: () => `Expected ${received} to be a valid ExecutionResult`,
39
+ pass: false,
40
+ };
41
+ }
42
+ },
43
+ });