Skip to content

Commit 65694d3

Browse files
test: bringing back ws tests and applying codacy suggestion (#3823)
Signed-off-by: Mariusz Jasuwienas <mariusz.jasuwienas@arianelabs.com>
1 parent 13e8db2 commit 65694d3

File tree

2 files changed

+87
-22
lines changed

2 files changed

+87
-22
lines changed

packages/server/tests/acceptance/conformityTests.spec.ts

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { parseOpenRPCDocument } from '@open-rpc/schema-utils-js';
44
import { expect } from 'chai';
55
import fs from 'fs';
66
import path from 'path';
7+
import WebSocket from 'ws';
78

8-
// import WebSocket from 'ws';
99
import openRpcData from '../../../../docs/openrpc.json';
1010
import CallerContract from '../contracts/Caller.json';
1111
import LogsContract from '../contracts/Logs.json';
@@ -21,8 +21,9 @@ import {
2121
setTransaction1559_2930AndBlockHash,
2222
setTransaction1559AndBlockHash,
2323
setTransaction2930AndBlockHash,
24+
WS_RELAY_URL,
2425
} from './data/conformity/utils/constants';
25-
import { TestCases, UpdateParamFunction } from './data/conformity/utils/interfaces';
26+
import { TestCase, TestCases, UpdateParamFunction } from './data/conformity/utils/interfaces';
2627
import { processFileContent, splitReqAndRes } from './data/conformity/utils/processors';
2728
import {
2829
createContractLegacyTransaction,
@@ -32,7 +33,7 @@ import {
3233
transaction2930,
3334
} from './data/conformity/utils/transactions';
3435
import { getLatestBlockHash, sendRequestToRelay, signAndSendRawTransaction } from './data/conformity/utils/utils';
35-
import { isResponseValid } from './data/conformity/utils/validations';
36+
import { getMissingKeys, isResponseValid } from './data/conformity/utils/validations';
3637

3738
const directoryPath = path.resolve(__dirname, '../../../../node_modules/execution-apis/tests');
3839
const overwritesDirectoryPath = path.resolve(__dirname, 'data/conformity/overwrites');
@@ -42,19 +43,48 @@ let relayOpenRpcData: OpenrpcDocument;
4243
relayOpenRpcData = await parseOpenRPCDocument(JSON.stringify(openRpcData));
4344
})().catch((error) => console.error('Error parsing OpenRPC document:', error));
4445

46+
/**
47+
* Determines whether a given test case is expected to return an error response.
48+
*
49+
* @param testCase - The test case to evaluate.
50+
* @returns {boolean} `true` if an error response is expected, otherwise `false`.
51+
*
52+
* @example
53+
* ```typescript
54+
* const tc = { status: 404, response: '{"error": "Not found"}' };
55+
* console.log(isErrorResponseExpected(tc)); // true
56+
* ```
57+
*/
58+
const isErrorResponseExpected = function (testCase: TestCase): boolean {
59+
return (testCase?.status && testCase.status != 200) || !!JSON.parse(testCase.response).error;
60+
};
61+
62+
/**
63+
* Retrieves the JSON schema object for the result of a given method name from the OpenRPC data.
64+
*
65+
* @param name - The name of the method to look up.
66+
* @returns {JSONSchemaObject | undefined} The method's result schema, or `undefined` if not found or invalid.
67+
*
68+
* @example
69+
* ```typescript
70+
* const schema = getMethodSchema("eth_getBalance");
71+
* console.log(schema); // JSON schema object or undefined
72+
* ```
73+
*/
74+
const getMethodSchema = function (name: string): JSONSchemaObject | undefined {
75+
const method = relayOpenRpcData.methods.find(
76+
(m: MethodOrReference): m is MethodObject => 'name' in m && m.name === name,
77+
);
78+
return method?.result && 'schema' in method.result && typeof method.result.schema === 'object'
79+
? method.result.schema
80+
: undefined;
81+
};
82+
4583
const synthesizeTestCases = function (testCases: TestCases, updateParamIfNeeded: UpdateParamFunction) {
4684
for (const testName in testCases) {
4785
it(`${testName}`, async function () {
48-
const isErrorStatusExpected: boolean =
49-
(testCases[testName]?.status && testCases[testName].status != 200) ||
50-
!!JSON.parse(testCases[testName].response).error;
51-
const method = relayOpenRpcData.methods.find(
52-
(m: MethodOrReference): m is MethodObject => 'name' in m && m.name === testName.split(' ')[0],
53-
);
54-
const schema: JSONSchemaObject | undefined =
55-
method?.result && 'schema' in method.result && typeof method.result.schema === 'object'
56-
? method.result.schema
57-
: undefined;
86+
const isErrorStatusExpected = isErrorResponseExpected(testCases[testName]);
87+
const schema = getMethodSchema(testName.split(' ')[0]);
5888
try {
5989
const req = updateParamIfNeeded(testName, JSON.parse(testCases[testName].request));
6090
const res = await sendRequestToRelay(RELAY_URL, req, false);
@@ -240,7 +270,7 @@ describe('@api-conformity', async function () {
240270

241271
synthesizeTestCases(TEST_CASES_BATCH_3['server'], updateParamIfNeeded);
242272

243-
/* describe('ws related rpc methods', async function () {
273+
describe('ws related rpc methods', async function () {
244274
let webSocket: WebSocket;
245275
let contractAddress: string | null;
246276
let existingFilter: string;
@@ -319,14 +349,14 @@ describe('@api-conformity', async function () {
319349
});
320350
await new Promise((r) => setTimeout(r, 500));
321351

322-
const hasMissingKeys: boolean = hasResponseFormatIssues(response, JSON.parse(testCases[testName].response));
352+
const hasMissingKeys = getMissingKeys(response, JSON.parse(testCases[testName].response)).length > 0;
323353
expect(hasMissingKeys).to.be.false;
324354
});
325355
}
326356
};
327357

328358
synthesizeWsTestCases(TEST_CASES_BATCH_3['ws-server'], updateParamIfNeeded);
329-
});*/
359+
});
330360
});
331361

332362
describe('@conformity-batch-4 Ethereum execution apis tests', async function () {

packages/server/tests/acceptance/data/conformity/utils/validations.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,7 @@ export function hasResponseFormatIssues(
8484
}
8585
return true;
8686
}
87-
88-
const actualResponseKeys = extractKeys(actualResponse as Record<string, unknown>);
89-
const expectedResponseKeys = extractKeys(parsedExpectedResponse as Record<string, unknown>);
90-
const filteredExpectedKeys = expectedResponseKeys.filter((key) => !wildcards.includes(key));
91-
const missingKeys = filteredExpectedKeys.filter((key) => !actualResponseKeys.includes(key));
92-
87+
const missingKeys = getMissingKeys(actualResponse as Record<string, unknown>, parsedExpectedResponse, wildcards);
9388
if (missingKeys.length > 0) {
9489
console.log(`Missing keys in response: ${JSON.stringify(missingKeys)}`);
9590
return true;
@@ -98,6 +93,46 @@ export function hasResponseFormatIssues(
9893
return hasValuesMismatch(actualResponse, parsedExpectedResponse, wildcards);
9994
}
10095

96+
/**
97+
* Returns the list of keys that exist in `expectedResponse` but are missing in `actualResponse`,
98+
* excluding any keys listed in `wildcards`.
99+
*
100+
* This function compares only key presence (as produced by `extractKeys`)—it does not parse,
101+
* validate error states, or compare values. Any keys in `expectedResponse` that match entries
102+
* in `wildcards` are ignored.
103+
*
104+
* @param actualResponse - The actual response object whose keys will be checked.
105+
* @param expectedResponse - The reference object whose keys are considered required.
106+
* @param wildcards - Array of key paths to ignore during the check (default: []).
107+
* @returns {string[]} Array of key names/paths that are required by `expectedResponse`
108+
* but absent from `actualResponse`.
109+
*
110+
* @example
111+
* ```typescript
112+
* const actual = { result: "0x123" };
113+
* const expected = { result: "0x123", id: 1 };
114+
* const missing = getMissingKeys(actual, expected);
115+
* console.log(missing); // ["id"]
116+
* ```
117+
*
118+
* @example
119+
* ```typescript
120+
* const actual = { result: "0x123", timestamp: "2023-01-01" };
121+
* const expected = { result: "0x123", timestamp: "2023-01-02", id: 1 };
122+
* const missing = getMissingKeys(actual, expected, ["timestamp"]);
123+
* console.log(missing); // ["id"] // "timestamp" is ignored by wildcard
124+
* ```
125+
*/
126+
export function getMissingKeys(
127+
actualResponse: Record<string, unknown>,
128+
expectedResponse: Record<string, unknown>,
129+
wildcards: string[] = [],
130+
): string[] {
131+
const actualResponseKeys = extractKeys(actualResponse);
132+
const expectedResponseKeys = extractKeys(expectedResponse);
133+
return expectedResponseKeys.filter((key) => !actualResponseKeys.includes(key) && !wildcards.includes(key));
134+
}
135+
101136
/**
102137
* Checks if the actual response is missing required error properties
103138
*

0 commit comments

Comments
 (0)