mirror of
https://github.com/ChainSafe/lodestar.git
synced 2026-01-09 15:48:08 -05:00
test(prover): move tests for prover to vitest (#6074)
* Automatic assertion migration * Fix some left over assertions * Remove sinon * Add config files * Move browser tests to vitest * Fix browser tests * Add a skip lib check for now * Fix the spellings * Fix deprecated flags * Fix types * Update the script tasks * Fix the e2e tests * Fix e2e tests * Update webdriverio to fix browser installtion issue * Fix the vitest config * Add a peer dependency * Add vite resolution * Add a manual install for browsers * Update packages to support additional browser options * Update the resolutions * Add resolutions to fix dependencies * Update the yarn linter script * Add sigfault handler * Rebuild native modules with debug flag * Update depedencies * Update e2e tests * Update dependencies * Add browser capabilities * Revert a whitespace change * Remove segfault handler * Remove native dep for lightclient * Add debug flag to introspect error * Rename a file * Upgrade the vitest package * Fix the regressions introduced in vitest 1 > * Revert the regression of vitest 1.0.1 * Clean dependencies * Update multiple fork fix * Add dependency fix * Fix broken singleThread option for e2e
This commit is contained in:
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@@ -270,7 +270,10 @@ jobs:
|
||||
packages/*/.git-data.json
|
||||
key: ${{ runner.os }}-node-${{ matrix.node }}-${{ github.sha }}
|
||||
fail-on-cache-miss: true
|
||||
|
||||
- name: Install Chrome browser
|
||||
run: npx @puppeteer/browsers install chrome
|
||||
- name: Install Firefox browser
|
||||
run: npx @puppeteer/browsers install firefox
|
||||
- name: Browser tests
|
||||
run: |
|
||||
export DISPLAY=':99.0'
|
||||
|
||||
25
package.json
25
package.json
@@ -52,6 +52,8 @@
|
||||
"@types/sinon-chai": "^3.2.9",
|
||||
"@typescript-eslint/eslint-plugin": "6.7.2",
|
||||
"@typescript-eslint/parser": "6.7.2",
|
||||
"@vitest/coverage-v8": "^1.0.1",
|
||||
"@vitest/browser": "^1.0.1",
|
||||
"c8": "^8.0.1",
|
||||
"chai": "^4.3.8",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
@@ -59,12 +61,13 @@
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"electron": "^26.2.2",
|
||||
"eslint": "^8.50.0",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-plugin-chai-expect": "^3.0.0",
|
||||
"eslint-plugin-mocha": "^10.2.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-chai-expect": "^3.0.0",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"eslint-plugin-mocha": "^10.2.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"https-browserify": "^1.0.0",
|
||||
"jsdom": "^23.0.1",
|
||||
"karma": "^6.4.2",
|
||||
"karma-chai": "^0.1.0",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
@@ -93,13 +96,17 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-docs-verifier": "^2.5.0",
|
||||
"webpack": "^5.88.2",
|
||||
"vite-plugin-node-polyfills": "^0.17.0",
|
||||
"vite-plugin-top-level-await": "^1.3.1",
|
||||
"vitest": "^1.0.2",
|
||||
"vitest-when": "^0.3.0",
|
||||
"wait-port": "^1.1.0",
|
||||
"vitest": "^0.34.6",
|
||||
"vitest-when": "^0.2.0",
|
||||
"@vitest/coverage-v8": "^0.34.6"
|
||||
"webdriverio": "^8.24.12",
|
||||
"webpack": "^5.88.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"dns-over-http-resolver": "^2.1.1"
|
||||
"dns-over-http-resolver": "^2.1.1",
|
||||
"chai": "^4.3.10",
|
||||
"loupe": "^2.3.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
"test:unit:minimal": "vitest --run --segfaultRetry 3 --dir test/unit/ --coverage",
|
||||
"test:unit:mainnet": "LODESTAR_PRESET=mainnet nyc --cache-dir .nyc_output/.cache -e .ts mocha 'test/unit-mainnet/**/*.test.ts'",
|
||||
"test:unit": "yarn test:unit:minimal && yarn test:unit:mainnet",
|
||||
"test:e2e": "LODESTAR_PRESET=minimal vitest --run --segfaultRetry 3 --single-thread --dir test/e2e",
|
||||
"test:e2e": "LODESTAR_PRESET=minimal vitest --run --segfaultRetry 3 --poolOptions.threads.singleThread --dir test/e2e",
|
||||
"test:sim": "mocha 'test/sim/**/*.test.ts'",
|
||||
"test:sim:merge-interop": "mocha 'test/sim/merge-interop.test.ts'",
|
||||
"test:sim:mergemock": "mocha 'test/sim/mergemock.test.ts'",
|
||||
|
||||
@@ -38,7 +38,7 @@ describe("chain / opPools / SyncCommitteeMessagePool", function () {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("should preaggregate SyncCommitteeContribution", () => {
|
||||
it("should propagate SyncCommitteeContribution", () => {
|
||||
clockStub.secFromSlot.mockReturnValue(0);
|
||||
let contribution = cache.getContribution(subcommitteeIndex, syncCommittee.slot, syncCommittee.beaconBlockRoot);
|
||||
expect(contribution).not.toBeNull();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, it, expect, beforeEach, afterEach, vi, SpyInstance, Mock} from "vitest";
|
||||
import {describe, it, expect, beforeEach, afterEach, vi, Mock, MockInstance} from "vitest";
|
||||
import {config} from "@lodestar/config/default";
|
||||
import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params";
|
||||
import {routes} from "@lodestar/api";
|
||||
@@ -20,7 +20,7 @@ describe("PrepareNextSlot scheduler", () => {
|
||||
let regenStub: MockedBeaconChain["regen"];
|
||||
let loggerStub: MockedLogger;
|
||||
let beaconProposerCacheStub: MockedBeaconChain["beaconProposerCache"];
|
||||
let getForkStub: SpyInstance<[number], ForkName>;
|
||||
let getForkStub: MockInstance<[number], ForkName>;
|
||||
let updateBuilderStatus: MockedBeaconChain["updateBuilderStatus"];
|
||||
let executionEngineStub: MockedBeaconChain["executionEngine"];
|
||||
const emitPayloadAttributes = true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, it, expect, beforeEach, afterEach, vi, SpyInstance} from "vitest";
|
||||
import {describe, it, expect, beforeEach, afterEach, vi, MockInstance} from "vitest";
|
||||
import {config} from "@lodestar/config/default";
|
||||
import {TimeoutError} from "@lodestar/utils";
|
||||
import {Eth1DepositDataTracker} from "../../../src/eth1/eth1DepositDataTracker.js";
|
||||
@@ -17,8 +17,8 @@ describe("Eth1DepositDataTracker", function () {
|
||||
const eth1Provider = new Eth1Provider(config, opts, signal, null);
|
||||
let db: BeaconDb;
|
||||
let eth1DepositDataTracker: Eth1DepositDataTracker;
|
||||
let getBlocksByNumberStub: SpyInstance;
|
||||
let getDepositEventsStub: SpyInstance;
|
||||
let getBlocksByNumberStub: MockInstance;
|
||||
let getDepositEventsStub: MockInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
db = getMockedBeaconDb();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, it, expect, beforeEach, beforeAll, afterAll, vi, afterEach, SpyInstance} from "vitest";
|
||||
import {describe, it, expect, beforeEach, beforeAll, afterAll, vi, afterEach, MockInstance} from "vitest";
|
||||
import {ErrorAborted, TimeoutError} from "@lodestar/utils";
|
||||
import {RegistryMetricCreator} from "../../../src/index.js";
|
||||
import {HistogramExtra} from "../../../src/metrics/utils/histogram.js";
|
||||
@@ -115,7 +115,7 @@ describe("monitoring / service", () => {
|
||||
});
|
||||
|
||||
describe("MonitoringService - close", () => {
|
||||
let clearTimeout: SpyInstance;
|
||||
let clearTimeout: MockInstance;
|
||||
|
||||
beforeAll(() => {
|
||||
clearTimeout = vi.spyOn(global, "clearTimeout");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import path from "node:path";
|
||||
import {sleep, toHex, toHexString} from "@lodestar/utils";
|
||||
import {ApiError} from "@lodestar/api";
|
||||
import {SLOTS_PER_EPOCH} from "@lodestar/params";
|
||||
import {CLIQUE_SEALING_PERIOD, SIM_TESTS_SECONDS_PER_SLOT} from "../utils/simulation/constants.js";
|
||||
import {AssertionMatch, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js";
|
||||
import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js";
|
||||
@@ -213,7 +214,8 @@ const unknownBlockSync = await env.createNodePair({
|
||||
// unknown block sync can work only if the gap is maximum `slotImportTolerance * 2`
|
||||
// default value for slotImportTolerance is one epoch, so if gap is more than 2 epoch
|
||||
// unknown block sync will not work. So why we have to increase it for tests.
|
||||
"sync.slotImportTolerance": headForUnknownBlockSync.response.data.message.slot / 2 + 2,
|
||||
// Adding SLOTS_PER_EPOCH will cover the case if the node starts on the last slot of epoch
|
||||
"sync.slotImportTolerance": headForUnknownBlockSync.response.data.message.slot / 2 + SLOTS_PER_EPOCH,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
colors: true
|
||||
timeout: 2000
|
||||
exit: true
|
||||
extension: ["ts"]
|
||||
require:
|
||||
- ./test/setup.ts
|
||||
node-option:
|
||||
- "loader=ts-node/esm"
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../../.nycrc.json"
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
const karmaConfig = require("../../karma.base.config.js");
|
||||
const webpackConfig = require("./webpack.test.config.cjs");
|
||||
|
||||
module.exports = function karmaConfigurator(config) {
|
||||
config.set({
|
||||
...karmaConfig,
|
||||
webpack: webpackConfig,
|
||||
});
|
||||
};
|
||||
@@ -53,9 +53,12 @@
|
||||
"lint:fix": "yarn run lint --fix",
|
||||
"pretest": "yarn run check-types",
|
||||
"test": "yarn test:unit && yarn test:e2e",
|
||||
"test:unit": "nyc --cache-dir .nyc_output/.cache -e .ts mocha 'test/unit/**/*.test.ts'",
|
||||
"test:browsers": "yarn karma start karma.config.cjs",
|
||||
"test:e2e": "LODESTAR_PRESET=minimal mocha 'test/e2e/**/*.test.ts'",
|
||||
"test:unit": "vitest --run --dir test/unit/ --coverage",
|
||||
"test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron",
|
||||
"test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit",
|
||||
"test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit",
|
||||
"test:browsers:electron": "echo 'Electron tests will be introduced back in the future as soon vitest supports electron.'",
|
||||
"test:e2e": "LODESTAR_PRESET=minimal vitest --run --poolOptions.threads.singleThread --dir test/e2e",
|
||||
"check-readme": "typescript-docs-verifier",
|
||||
"generate-fixtures": "node --loader ts-node/esm scripts/generate_fixtures.ts"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import childProcess from "node:child_process";
|
||||
import {writeFile, mkdir} from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect, beforeAll, afterAll} from "vitest";
|
||||
import Web3 from "web3";
|
||||
import {runCliCommand, spawnCliCommand, stopChildProcess} from "@lodestar/test-utils";
|
||||
import {sleep} from "@lodestar/utils";
|
||||
@@ -15,11 +15,11 @@ describe("prover/start", () => {
|
||||
it("should show help", async () => {
|
||||
const output = await runCliCommand(cli, ["start", "--help"]);
|
||||
|
||||
expect(output).contains("Show help");
|
||||
expect(output).toEqual(expect.stringContaining("Show help"));
|
||||
});
|
||||
|
||||
it("should fail when --executionRpcUrl is missing", async () => {
|
||||
await expect(runCliCommand(cli, ["start", "--port", "8088"])).eventually.rejectedWith(
|
||||
await expect(runCliCommand(cli, ["start", "--port", "8088"])).rejects.toThrow(
|
||||
"Missing required argument: executionRpcUrl"
|
||||
);
|
||||
});
|
||||
@@ -33,13 +33,13 @@ describe("prover/start", () => {
|
||||
"--beaconBootnodes",
|
||||
"http://localhost:0000",
|
||||
])
|
||||
).eventually.rejectedWith("Arguments beaconBootnodes and beaconUrls are mutually exclusive");
|
||||
).rejects.toThrow("Arguments beaconBootnodes and beaconUrls are mutually exclusive");
|
||||
});
|
||||
|
||||
it("should fail when both of --beaconUrls and --beaconBootnodes are not provided", async () => {
|
||||
await expect(
|
||||
runCliCommand(cli, ["start", "--port", "8088", "--executionRpcUrl", "http://localhost:3000"])
|
||||
).eventually.rejectedWith("Either --beaconUrls or --beaconBootnodes must be provided");
|
||||
).rejects.toThrow("Either --beaconUrls or --beaconBootnodes must be provided");
|
||||
});
|
||||
|
||||
describe("when started", () => {
|
||||
@@ -47,8 +47,7 @@ describe("prover/start", () => {
|
||||
const paramsFilePath = path.join("/tmp", "e2e-test-env", "params.json");
|
||||
const web3: Web3 = new Web3(proxyUrl);
|
||||
|
||||
before(async function () {
|
||||
this.timeout(50000);
|
||||
beforeAll(async function () {
|
||||
await waitForCapellaFork();
|
||||
await mkdir(path.dirname(paramsFilePath), {recursive: true});
|
||||
await writeFile(paramsFilePath, JSON.stringify(chainConfigToJson(config as ChainConfig)));
|
||||
@@ -72,22 +71,22 @@ describe("prover/start", () => {
|
||||
);
|
||||
// Give sometime to the prover to start proxy server
|
||||
await sleep(3000);
|
||||
});
|
||||
}, 50000);
|
||||
|
||||
after(async () => {
|
||||
afterAll(async () => {
|
||||
await stopChildProcess(proc);
|
||||
});
|
||||
|
||||
it("should respond to verified calls", async () => {
|
||||
const accounts = await web3.eth.getAccounts();
|
||||
|
||||
expect(accounts.length).to.be.gt(0);
|
||||
await expect(web3.eth.getBalance(accounts[0])).eventually.not.null;
|
||||
expect(accounts.length).toBeGreaterThan(0);
|
||||
await expect(web3.eth.getBalance(accounts[0])).resolves.not.toBeNull();
|
||||
});
|
||||
|
||||
it("should respond to unverified calls", async () => {
|
||||
// Because web3 latest version return numbers as bigint by default
|
||||
await expect(web3.eth.getChainId()).eventually.eql(BigInt(chainId));
|
||||
await expect(web3.eth.getChainId()).resolves.toEqual(BigInt(chainId));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect, beforeAll} from "vitest";
|
||||
import Web3 from "web3";
|
||||
import {LCTransport} from "../../src/interfaces.js";
|
||||
import {createVerifiedExecutionProvider} from "../../src/web3_provider.js";
|
||||
import {rpcUrl, beaconUrl, config} from "../utils/e2e_env.js";
|
||||
import {getVerificationFailedMessage} from "../../src/utils/json_rpc.js";
|
||||
|
||||
/* prettier-ignore */
|
||||
describe("web3_batch_requests", function () {
|
||||
// Give some margin to sync light client
|
||||
this.timeout("10s");
|
||||
|
||||
let web3: Web3;
|
||||
|
||||
before(() => {
|
||||
beforeAll(() => {
|
||||
const {provider} = createVerifiedExecutionProvider(new Web3.providers.HttpProvider(rpcUrl), {
|
||||
transport: LCTransport.Rest,
|
||||
urls: [beaconUrl],
|
||||
@@ -45,8 +43,8 @@ describe("web3_batch_requests", function () {
|
||||
|
||||
await batch.execute();
|
||||
|
||||
expect(results.length).to.be.gt(1);
|
||||
await expect(Promise.all(results)).to.be.fulfilled;
|
||||
expect(results.length).toBeGreaterThan(1);
|
||||
await expect(Promise.all(results)).resolves.toBeDefined();
|
||||
});
|
||||
|
||||
it("should be able to process batch request containing error", async () => {
|
||||
@@ -66,8 +64,8 @@ describe("web3_batch_requests", function () {
|
||||
|
||||
await batch.execute();
|
||||
|
||||
await expect(successRequest).to.be.fulfilled;
|
||||
await expect(errorRequest).to.be.rejectedWith(getVerificationFailedMessage("eth_getBlockByHash"));
|
||||
await expect(successRequest).resolves.toBeDefined();
|
||||
await expect(errorRequest).rejects.toThrow(getVerificationFailedMessage("eth_getBlockByHash"));
|
||||
});
|
||||
});
|
||||
});
|
||||
}, {timeout: 10_000});
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect, beforeAll} from "vitest";
|
||||
import Web3 from "web3";
|
||||
import {ethers} from "ethers";
|
||||
import {LCTransport} from "../../src/interfaces.js";
|
||||
import {createVerifiedExecutionProvider} from "../../src/web3_provider.js";
|
||||
import {waitForCapellaFork, testTimeout, rpcUrl, beaconUrl, config} from "../utils/e2e_env.js";
|
||||
|
||||
/* prettier-ignore */
|
||||
describe("web3_provider", function () {
|
||||
this.timeout(testTimeout);
|
||||
|
||||
before("wait for the capella fork", async () => {
|
||||
beforeAll(async () => {
|
||||
await waitForCapellaFork();
|
||||
});
|
||||
|
||||
@@ -26,8 +25,8 @@ describe("web3_provider", function () {
|
||||
const accounts = await web3.eth.getAccounts();
|
||||
// `getProof` will always remain the non-verified method
|
||||
// as we use it to create proof and verify
|
||||
expect(accounts).not.to.be.empty;
|
||||
await expect(web3.eth.getProof(accounts[0], [], "latest")).fulfilled;
|
||||
expect(Object.keys(accounts)).not.toHaveLength(0);
|
||||
await expect(web3.eth.getProof(accounts[0], [], "latest")).resolves.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,9 +39,9 @@ describe("web3_provider", function () {
|
||||
});
|
||||
const accounts = await provider.listAccounts();
|
||||
|
||||
expect(accounts).not.to.be.empty;
|
||||
await expect(provider.send("eth_getProof", [accounts[0].address, [], "latest"])).fulfilled;
|
||||
expect(Object.keys(accounts)).not.toHaveLength(0);
|
||||
await expect(provider.send("eth_getProof", [accounts[0].address, [], "latest"])).resolves.toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, {timeout: testTimeout});
|
||||
|
||||
2
packages/prover/test/globalSetup.ts
Normal file
2
packages/prover/test/globalSetup.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export async function setup(): Promise<void> {}
|
||||
export async function teardown(): Promise<void> {}
|
||||
@@ -1,4 +1,5 @@
|
||||
import sinon from "sinon";
|
||||
import {vi, expect} from "vitest";
|
||||
import {when} from "vitest-when";
|
||||
import deepmerge from "deepmerge";
|
||||
import {NetworkName} from "@lodestar/config/networks";
|
||||
import {ForkConfig} from "@lodestar/config";
|
||||
@@ -51,28 +52,29 @@ export interface TestFixture<R = unknown, P = unknown[]> {
|
||||
dependentRequests: {payload: JsonRpcRequestOrBatch; response: Writeable<JsonRpcResponseOrBatch>}[];
|
||||
}
|
||||
|
||||
function matchTransaction(value: ELTransaction, expected: ELTransaction): boolean {
|
||||
if (
|
||||
value.to?.toLowerCase() !== expected.to?.toLowerCase() ||
|
||||
value.from.toLocaleLowerCase() !== expected.from.toLowerCase()
|
||||
) {
|
||||
function matchTransaction(received: ELTransaction, expected: ELTransaction): boolean {
|
||||
if (received.to?.toLowerCase() !== expected.to?.toLowerCase()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("value" in value && value.value.toLowerCase() !== expected.value.toLowerCase()) {
|
||||
if ("from" in expected && "from" in received && received.from.toLowerCase() !== expected.from.toLowerCase()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("data" in value && value.data?.toLowerCase() !== expected.data?.toLowerCase()) {
|
||||
if ("value" in received && received.value.toLowerCase() !== expected.value.toLowerCase()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("data" in received && received.data?.toLowerCase() !== expected.data?.toLowerCase()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function matchParams(params: unknown[], expected: unknown[]): boolean {
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const item = params[i];
|
||||
function matchParams(received: unknown[], expected: unknown[]): boolean {
|
||||
for (let i = 0; i < received.length; i++) {
|
||||
const item = received[i];
|
||||
const expectedItem = expected[i];
|
||||
|
||||
if (typeof item === "string" && typeof expectedItem === "string") {
|
||||
@@ -92,20 +94,12 @@ function matchParams(params: unknown[], expected: unknown[]): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getPayloadParamsMatcher(expected: unknown[]): sinon.SinonMatcher {
|
||||
return sinon.match(function (params: unknown[]): boolean {
|
||||
return matchParams(params, expected);
|
||||
}, "payload match params");
|
||||
}
|
||||
|
||||
function getBatchPayloadMatcher(expected: JsonRpcBatchRequest): sinon.SinonMatcher {
|
||||
return sinon.match(function (value: JsonRpcBatchRequest): boolean {
|
||||
for (const [index, item] of value.entries()) {
|
||||
if (item.method !== expected[index].method) return false;
|
||||
if (!matchParams(item.params, expected[index].params)) return false;
|
||||
}
|
||||
return true;
|
||||
}, "batch payload match");
|
||||
function matchBatchPayload(received: JsonRpcBatchRequest, expected: JsonRpcBatchRequest): boolean {
|
||||
for (const [index, item] of received.entries()) {
|
||||
if (item.method !== expected[index].method) return false;
|
||||
if (!matchParams(item.params, expected[index].params)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function generateReqHandlerOptionsMock(
|
||||
@@ -119,7 +113,7 @@ export function generateReqHandlerOptionsMock(
|
||||
const options = {
|
||||
logger: getEmptyLogger(),
|
||||
proofProvider: {
|
||||
getExecutionPayload: sinon.stub().resolves(executionPayload),
|
||||
getExecutionPayload: vi.fn().mockResolvedValue(executionPayload),
|
||||
config: {
|
||||
...config,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
@@ -129,35 +123,46 @@ export function generateReqHandlerOptionsMock(
|
||||
} as unknown as ProofProvider,
|
||||
network: data.network as NetworkName,
|
||||
rpc: {
|
||||
request: sinon.stub(),
|
||||
batchRequest: sinon.stub(),
|
||||
request: vi.fn(),
|
||||
batchRequest: vi.fn(),
|
||||
getRequestId: () => (Math.random() * 10000).toFixed(0),
|
||||
},
|
||||
};
|
||||
|
||||
options.rpc.request
|
||||
.withArgs(data.request.method, getPayloadParamsMatcher(data.request.params), sinon.match.any)
|
||||
.resolves(data.response);
|
||||
when(options.rpc.request)
|
||||
.calledWith(
|
||||
data.request.method,
|
||||
expect.toSatisfy((received) => matchParams(received as unknown[], data.request.params)),
|
||||
expect.anything()
|
||||
)
|
||||
.thenResolve(data.response);
|
||||
|
||||
for (const {payload, response} of data.dependentRequests) {
|
||||
if (isBatchRequest(payload)) {
|
||||
options.rpc.batchRequest
|
||||
.withArgs(getBatchPayloadMatcher(payload), sinon.match.any)
|
||||
.resolves(mergeBatchReqResp(payload, response as JsonRpcBatchResponse));
|
||||
when(options.rpc.batchRequest)
|
||||
.calledWith(
|
||||
expect.toSatisfy((received) => matchBatchPayload(received as JsonRpcBatchRequest, payload)),
|
||||
expect.anything()
|
||||
)
|
||||
.thenResolve(mergeBatchReqResp(payload, response as JsonRpcBatchResponse));
|
||||
} else {
|
||||
options.rpc.request
|
||||
.withArgs(payload.method, getPayloadParamsMatcher(payload.params), sinon.match.any)
|
||||
.resolves(response);
|
||||
when(options.rpc.request)
|
||||
.calledWith(
|
||||
payload.method,
|
||||
expect.toSatisfy((received) => matchParams(received as unknown[], data.request.params)),
|
||||
expect.anything()
|
||||
)
|
||||
.thenResolve(response);
|
||||
}
|
||||
}
|
||||
|
||||
options.rpc.request
|
||||
.withArgs("eth_getBlockByNumber", [data.execution.block.number, true], sinon.match.any)
|
||||
.resolves({id: 1233, jsonrpc: "2.0", result: data.execution.block});
|
||||
when(options.rpc.request)
|
||||
.calledWith("eth_getBlockByNumber", [data.execution.block.number, true], expect.anything())
|
||||
.thenResolve({id: 1233, jsonrpc: "2.0", result: data.execution.block});
|
||||
|
||||
options.rpc.request
|
||||
.withArgs("eth_getBlockByHash", [data.execution.block.hash, true], sinon.match.any)
|
||||
.resolves({id: 1233, jsonrpc: "2.0", result: data.execution.block});
|
||||
when(options.rpc.request)
|
||||
.calledWith("eth_getBlockByHash", [data.execution.block.hash, true], expect.anything())
|
||||
.thenResolve({id: 1233, jsonrpc: "2.0", result: data.execution.block});
|
||||
|
||||
return options as unknown as Omit<ELVerifiedRequestHandlerOpts<any>, "payload">;
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import chai from "chai";
|
||||
import chaiAsPromised from "chai-as-promised";
|
||||
import sinonChai from "sinon-chai";
|
||||
|
||||
chai.use(chaiAsPromised);
|
||||
chai.use(sinonChai);
|
||||
6
packages/prover/test/tsconfig.json
Normal file
6
packages/prover/test/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../tsconfig",
|
||||
"compilerOptions": {
|
||||
"noEmit": false
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,25 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {OrderedMap} from "../../../src/proof_provider/ordered_map.js";
|
||||
|
||||
describe("proof_provider/ordered_map", () => {
|
||||
it("should initialize the min with undefined", () => {
|
||||
const omap = new OrderedMap<string>();
|
||||
|
||||
expect(omap.min).to.undefined;
|
||||
expect(omap.min).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should initialize the max with undefined", () => {
|
||||
const omap = new OrderedMap<string>();
|
||||
|
||||
expect(omap.max).to.undefined;
|
||||
expect(omap.max).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should set the min and max to the first value ", () => {
|
||||
const omap = new OrderedMap<string>();
|
||||
omap.set(11, "value");
|
||||
|
||||
expect(omap.min).eql(11);
|
||||
expect(omap.max).eql(11);
|
||||
expect(omap.min).toEqual(11);
|
||||
expect(omap.max).toEqual(11);
|
||||
});
|
||||
|
||||
it("should set the max value", () => {
|
||||
@@ -27,7 +27,7 @@ describe("proof_provider/ordered_map", () => {
|
||||
omap.set(10, "value");
|
||||
omap.set(11, "value");
|
||||
|
||||
expect(omap.max).eql(11);
|
||||
expect(omap.max).toEqual(11);
|
||||
});
|
||||
|
||||
it("should set the min value", () => {
|
||||
@@ -35,6 +35,6 @@ describe("proof_provider/ordered_map", () => {
|
||||
omap.set(10, "value");
|
||||
omap.set(11, "value");
|
||||
|
||||
expect(omap.min).eql(10);
|
||||
expect(omap.min).toEqual(10);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import {expect} from "chai";
|
||||
import chai from "chai";
|
||||
import sinon from "sinon";
|
||||
import sinonChai from "sinon-chai";
|
||||
import {Api} from "@lodestar/api";
|
||||
import {describe, it, expect, beforeEach, vi, MockedObject} from "vitest";
|
||||
import {when} from "vitest-when";
|
||||
import {Api, HttpStatusCode, routes} from "@lodestar/api";
|
||||
import {hash} from "@lodestar/utils";
|
||||
import {Logger} from "@lodestar/logger";
|
||||
import {allForks, capella} from "@lodestar/types";
|
||||
import {toHexString} from "@lodestar/utils";
|
||||
import {ForkName} from "@lodestar/params";
|
||||
import {PayloadStore} from "../../../src/proof_provider/payload_store.js";
|
||||
import {MAX_PAYLOAD_HISTORY} from "../../../src/constants.js";
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
const createHash = (input: string): Uint8Array => hash(Buffer.from(input, "utf8"));
|
||||
|
||||
const buildPayload = ({blockNumber}: {blockNumber: number}): allForks.ExecutionPayload =>
|
||||
@@ -47,22 +44,23 @@ const buildBlockResponse = ({
|
||||
}: {
|
||||
slot: number;
|
||||
blockNumber: number;
|
||||
}): {ok: boolean; response: {version: number; executionOptimistic: boolean; data: allForks.SignedBeaconBlock}} => ({
|
||||
}): routes.beacon.block.BlockV2Response<"json"> => ({
|
||||
ok: true,
|
||||
status: HttpStatusCode.OK,
|
||||
response: {
|
||||
version: 12,
|
||||
version: ForkName.altair,
|
||||
executionOptimistic: true,
|
||||
data: buildBlock({slot, blockNumber}),
|
||||
},
|
||||
});
|
||||
|
||||
describe("proof_provider/payload_store", function () {
|
||||
let api: Api;
|
||||
let api: Api & {beacon: MockedObject<Api["beacon"]>};
|
||||
let logger: Logger;
|
||||
let store: PayloadStore;
|
||||
|
||||
beforeEach(() => {
|
||||
api = {beacon: {getBlockV2: sinon.stub()}} as unknown as Api;
|
||||
api = {beacon: {getBlockV2: vi.fn()}} as unknown as Api & {beacon: MockedObject<Api["beacon"]>};
|
||||
logger = console as unknown as Logger;
|
||||
store = new PayloadStore({api, logger});
|
||||
});
|
||||
@@ -82,7 +80,7 @@ describe("proof_provider/payload_store", function () {
|
||||
const payload = buildPayload({blockNumber: 10});
|
||||
store.set(payload, true);
|
||||
|
||||
expect(store.finalized).to.eql(payload);
|
||||
expect(store.finalized).toEqual(payload);
|
||||
});
|
||||
|
||||
it("should return highest finalized payload", () => {
|
||||
@@ -91,7 +89,7 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(payload1, true);
|
||||
store.set(payload2, true);
|
||||
|
||||
expect(store.finalized).to.eql(payload2);
|
||||
expect(store.finalized).toEqual(payload2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -106,7 +104,7 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(payload1, true);
|
||||
store.set(payload2, true);
|
||||
|
||||
expect(store.latest).to.eql(payload2);
|
||||
expect(store.latest).toEqual(payload2);
|
||||
});
|
||||
|
||||
it("should return latest payload if not finalized", () => {
|
||||
@@ -115,20 +113,20 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(payload1, false);
|
||||
store.set(payload2, false);
|
||||
|
||||
expect(store.latest).to.eql(payload2);
|
||||
expect(store.latest).toEqual(payload2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("get", () => {
|
||||
it("should return undefined for an empty store", async () => {
|
||||
await expect(store.get(10)).to.eventually.undefined;
|
||||
await expect(store.get(10)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return undefined for non existing block id", async () => {
|
||||
const payload1 = buildPayload({blockNumber: 10});
|
||||
store.set(payload1, false);
|
||||
|
||||
await expect(store.get(11)).to.eventually.undefined;
|
||||
await expect(store.get(11)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return undefined for non existing block hash", async () => {
|
||||
@@ -136,7 +134,7 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(payload1, false);
|
||||
const nonExistingBlockHash = createHash("non-existing-block-hash");
|
||||
|
||||
await expect(store.get(toHexString(nonExistingBlockHash))).to.eventually.undefined;
|
||||
await expect(store.get(toHexString(nonExistingBlockHash))).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
describe("block hash as blockId", () => {
|
||||
@@ -144,7 +142,7 @@ describe("proof_provider/payload_store", function () {
|
||||
const payload1 = buildPayload({blockNumber: 10});
|
||||
store.set(payload1, false);
|
||||
|
||||
await expect(store.get(toHexString(payload1.blockHash))).to.eventually.eql(payload1);
|
||||
await expect(store.get(toHexString(payload1.blockHash))).resolves.toEqual(payload1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -153,7 +151,7 @@ describe("proof_provider/payload_store", function () {
|
||||
const finalizedPayload = buildPayload({blockNumber: 10});
|
||||
store.set(finalizedPayload, true);
|
||||
|
||||
await expect(store.get(11)).to.rejectedWith(
|
||||
await expect(store.get(11)).rejects.toThrow(
|
||||
"Block number 11 is higher than the latest finalized block number. We recommend to use block hash for unfinalized blocks."
|
||||
);
|
||||
});
|
||||
@@ -162,28 +160,28 @@ describe("proof_provider/payload_store", function () {
|
||||
const payload1 = buildPayload({blockNumber: 10});
|
||||
store.set(payload1, false);
|
||||
|
||||
await expect(store.get(10)).to.eventually.undefined;
|
||||
await expect(store.get(10)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return payload for a block number in hex", async () => {
|
||||
const payload1 = buildPayload({blockNumber: 10});
|
||||
store.set(payload1, true);
|
||||
|
||||
await expect(store.get(`0x${payload1.blockNumber.toString(16)}`)).to.eventually.eql(payload1);
|
||||
await expect(store.get(`0x${payload1.blockNumber.toString(16)}`)).resolves.toEqual(payload1);
|
||||
});
|
||||
|
||||
it("should return payload for a block number as string", async () => {
|
||||
const payload1 = buildPayload({blockNumber: 10});
|
||||
store.set(payload1, true);
|
||||
|
||||
await expect(store.get(payload1.blockNumber.toString())).to.eventually.eql(payload1);
|
||||
await expect(store.get(payload1.blockNumber.toString())).resolves.toEqual(payload1);
|
||||
});
|
||||
|
||||
it("should return payload for a block number as integer", async () => {
|
||||
const payload1 = buildPayload({blockNumber: 10});
|
||||
store.set(payload1, true);
|
||||
|
||||
await expect(store.get(10)).to.eventually.eql(payload1);
|
||||
await expect(store.get(10)).resolves.toEqual(payload1);
|
||||
});
|
||||
|
||||
it("should fetch the finalized payload from API if payload root not exists", async () => {
|
||||
@@ -193,22 +191,22 @@ describe("proof_provider/payload_store", function () {
|
||||
const availablePayload = buildPayload({blockNumber});
|
||||
const unavailablePayload = buildPayload({blockNumber: unavailableBlockNumber});
|
||||
|
||||
(api.beacon.getBlockV2 as sinon.SinonStub)
|
||||
.withArgs(blockNumber)
|
||||
.resolves(buildBlockResponse({blockNumber, slot: blockNumber}));
|
||||
when(api.beacon.getBlockV2)
|
||||
.calledWith(blockNumber)
|
||||
.thenResolve(buildBlockResponse({blockNumber, slot: blockNumber}));
|
||||
|
||||
(api.beacon.getBlockV2 as sinon.SinonStub)
|
||||
.withArgs(unavailableBlockNumber)
|
||||
.resolves(buildBlockResponse({blockNumber: unavailableBlockNumber, slot: unavailableBlockNumber}));
|
||||
when(api.beacon.getBlockV2)
|
||||
.calledWith(unavailableBlockNumber)
|
||||
.thenResolve(buildBlockResponse({blockNumber: unavailableBlockNumber, slot: unavailableBlockNumber}));
|
||||
|
||||
store.set(availablePayload, true);
|
||||
|
||||
const result = await store.get(unavailablePayload.blockNumber);
|
||||
|
||||
expect(api.beacon.getBlockV2 as sinon.SinonStub).calledTwice;
|
||||
expect(api.beacon.getBlockV2 as sinon.SinonStub).calledWith(blockNumber);
|
||||
expect(api.beacon.getBlockV2 as sinon.SinonStub).calledWith(unavailableBlockNumber);
|
||||
expect(result).to.eql(unavailablePayload);
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledTimes(2);
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledWith(blockNumber);
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledWith(unavailableBlockNumber);
|
||||
expect(result).toEqual(unavailablePayload);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -219,16 +217,16 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(payload1, false);
|
||||
|
||||
// Unfinalized blocks are not indexed by block hash
|
||||
await expect(store.get(toHexString(payload1.blockHash))).to.eventually.eql(payload1);
|
||||
expect(store.finalized).to.eql(undefined);
|
||||
await expect(store.get(toHexString(payload1.blockHash))).resolves.toEqual(payload1);
|
||||
expect(store.finalized).toEqual(undefined);
|
||||
});
|
||||
|
||||
it("should set the payload for finalized blocks", async () => {
|
||||
const payload1 = buildPayload({blockNumber: 10});
|
||||
store.set(payload1, true);
|
||||
|
||||
await expect(store.get(payload1.blockNumber.toString())).to.eventually.eql(payload1);
|
||||
expect(store.finalized).to.eql(payload1);
|
||||
await expect(store.get(payload1.blockNumber.toString())).resolves.toEqual(payload1);
|
||||
expect(store.finalized).toEqual(payload1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -243,15 +241,15 @@ describe("proof_provider/payload_store", function () {
|
||||
const slot = 20;
|
||||
const header = buildLCHeader({slot, blockNumber});
|
||||
const blockResponse = buildBlockResponse({blockNumber, slot});
|
||||
const executionPayload = (blockResponse.response.data as capella.SignedBeaconBlock).message.body
|
||||
const executionPayload = (blockResponse.response?.data as capella.SignedBeaconBlock).message.body
|
||||
.executionPayload;
|
||||
(api.beacon.getBlockV2 as sinon.SinonStub).resolves(blockResponse);
|
||||
api.beacon.getBlockV2.mockResolvedValue(blockResponse);
|
||||
|
||||
await store.processLCHeader(header, true);
|
||||
|
||||
expect(api.beacon.getBlockV2).calledOnce;
|
||||
expect(api.beacon.getBlockV2).calledWith(20);
|
||||
expect(store.finalized).to.eql(executionPayload);
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledOnce();
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledWith(20);
|
||||
expect(store.finalized).toEqual(executionPayload);
|
||||
});
|
||||
|
||||
it("should process lightclient header for finalized block which exists as un-finalized in store", async () => {
|
||||
@@ -259,9 +257,9 @@ describe("proof_provider/payload_store", function () {
|
||||
const slot = 20;
|
||||
const header = buildLCHeader({slot, blockNumber});
|
||||
const blockResponse = buildBlockResponse({blockNumber, slot});
|
||||
const executionPayload = (blockResponse.response.data as capella.SignedBeaconBlock).message.body
|
||||
const executionPayload = (blockResponse.response?.data as capella.SignedBeaconBlock).message.body
|
||||
.executionPayload;
|
||||
(api.beacon.getBlockV2 as sinon.SinonStub).resolves(blockResponse);
|
||||
api.beacon.getBlockV2.mockResolvedValue(blockResponse);
|
||||
|
||||
expect(store.finalized).to.undefined;
|
||||
// First process as unfinalized
|
||||
@@ -271,8 +269,8 @@ describe("proof_provider/payload_store", function () {
|
||||
await store.processLCHeader(header, true);
|
||||
|
||||
// Called only once when we process unfinalized
|
||||
expect(api.beacon.getBlockV2).to.be.calledOnce;
|
||||
expect(store.finalized).to.eql(executionPayload);
|
||||
expect(api.beacon.getBlockV2).to.be.toHaveBeenCalledOnce();
|
||||
expect(store.finalized).toEqual(executionPayload);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -280,19 +278,19 @@ describe("proof_provider/payload_store", function () {
|
||||
const blockNumber = 10;
|
||||
const slot = 20;
|
||||
const header = buildLCHeader({slot, blockNumber});
|
||||
(api.beacon.getBlockV2 as sinon.SinonStub).resolves(buildBlockResponse({blockNumber, slot}));
|
||||
api.beacon.getBlockV2.mockResolvedValue(buildBlockResponse({blockNumber, slot}));
|
||||
|
||||
await store.processLCHeader(header);
|
||||
|
||||
expect(api.beacon.getBlockV2).calledOnce;
|
||||
expect(api.beacon.getBlockV2).calledWith(20);
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledOnce();
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledWith(20);
|
||||
});
|
||||
|
||||
it("should not fetch existing payload for lightclient header", async () => {
|
||||
const blockNumber = 10;
|
||||
const slot = 20;
|
||||
const header = buildLCHeader({slot, blockNumber});
|
||||
(api.beacon.getBlockV2 as sinon.SinonStub).resolves(buildBlockResponse({blockNumber, slot}));
|
||||
api.beacon.getBlockV2.mockResolvedValue(buildBlockResponse({blockNumber, slot}));
|
||||
|
||||
await store.processLCHeader(header);
|
||||
|
||||
@@ -300,21 +298,21 @@ describe("proof_provider/payload_store", function () {
|
||||
await store.processLCHeader(header);
|
||||
|
||||
// The network fetch should be done once
|
||||
expect(api.beacon.getBlockV2).calledOnce;
|
||||
expect(api.beacon.getBlockV2).calledWith(20);
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledOnce();
|
||||
expect(api.beacon.getBlockV2).toHaveBeenCalledWith(20);
|
||||
});
|
||||
|
||||
it("should prune the existing payloads", async () => {
|
||||
const blockNumber = 10;
|
||||
const slot = 20;
|
||||
const header = buildLCHeader({slot, blockNumber});
|
||||
(api.beacon.getBlockV2 as sinon.SinonStub).resolves(buildBlockResponse({blockNumber, slot}));
|
||||
api.beacon.getBlockV2.mockResolvedValue(buildBlockResponse({blockNumber, slot}));
|
||||
|
||||
sinon.spy(store, "prune");
|
||||
vi.spyOn(store, "prune");
|
||||
|
||||
await store.processLCHeader(header);
|
||||
|
||||
expect(store.prune).to.be.calledOnce;
|
||||
expect(store.prune).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -330,11 +328,11 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(buildPayload({blockNumber: i}), true);
|
||||
}
|
||||
|
||||
expect(store["payloads"].size).to.equal(numberOfPayloads);
|
||||
expect(store["payloads"].size).toEqual(numberOfPayloads);
|
||||
|
||||
store.prune();
|
||||
|
||||
expect(store["payloads"].size).to.equal(MAX_PAYLOAD_HISTORY);
|
||||
expect(store["payloads"].size).toEqual(MAX_PAYLOAD_HISTORY);
|
||||
});
|
||||
|
||||
it("should not prune the existing payloads if equal to MAX_PAYLOAD_HISTORY", () => {
|
||||
@@ -344,11 +342,11 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(buildPayload({blockNumber: i}), true);
|
||||
}
|
||||
|
||||
expect(store["payloads"].size).to.equal(MAX_PAYLOAD_HISTORY);
|
||||
expect(store["payloads"].size).toEqual(MAX_PAYLOAD_HISTORY);
|
||||
|
||||
store.prune();
|
||||
|
||||
expect(store["payloads"].size).to.equal(MAX_PAYLOAD_HISTORY);
|
||||
expect(store["payloads"].size).toEqual(MAX_PAYLOAD_HISTORY);
|
||||
});
|
||||
|
||||
it("should not prune the existing payloads if less than MAX_PAYLOAD_HISTORY", () => {
|
||||
@@ -358,11 +356,11 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(buildPayload({blockNumber: i}), true);
|
||||
}
|
||||
|
||||
expect(store["payloads"].size).to.equal(numberOfPayloads);
|
||||
expect(store["payloads"].size).toEqual(numberOfPayloads);
|
||||
|
||||
store.prune();
|
||||
|
||||
expect(store["payloads"].size).to.equal(numberOfPayloads);
|
||||
expect(store["payloads"].size).toEqual(numberOfPayloads);
|
||||
});
|
||||
|
||||
it("should prune finalized roots", () => {
|
||||
@@ -372,33 +370,33 @@ describe("proof_provider/payload_store", function () {
|
||||
store.set(buildPayload({blockNumber: i}), true);
|
||||
}
|
||||
|
||||
expect(store["finalizedRoots"].size).to.equal(numberOfPayloads);
|
||||
expect(store["finalizedRoots"].size).toEqual(numberOfPayloads);
|
||||
|
||||
store.prune();
|
||||
|
||||
expect(store["finalizedRoots"].size).to.equal(MAX_PAYLOAD_HISTORY);
|
||||
expect(store["finalizedRoots"].size).toEqual(MAX_PAYLOAD_HISTORY);
|
||||
});
|
||||
|
||||
it("should prune unfinalized roots", async () => {
|
||||
const numberOfPayloads = MAX_PAYLOAD_HISTORY + 2;
|
||||
|
||||
for (let i = 1; i <= numberOfPayloads; i++) {
|
||||
(api.beacon.getBlockV2 as sinon.SinonStub)
|
||||
.withArgs(i)
|
||||
.resolves(buildBlockResponse({blockNumber: 500 + i, slot: i}));
|
||||
when(api.beacon.getBlockV2)
|
||||
.calledWith(i)
|
||||
.thenResolve(buildBlockResponse({blockNumber: 500 + i, slot: i}));
|
||||
|
||||
await store.processLCHeader(buildLCHeader({blockNumber: 500 + i, slot: i}), false);
|
||||
}
|
||||
|
||||
// Because all payloads are unfinalized, they are not pruned
|
||||
expect(store["unfinalizedRoots"].size).to.equal(numberOfPayloads);
|
||||
expect(store["unfinalizedRoots"].size).toEqual(numberOfPayloads);
|
||||
|
||||
// Let make some payloads finalized
|
||||
await store.processLCHeader(buildLCHeader({blockNumber: 500 + 1, slot: 1}), true);
|
||||
await store.processLCHeader(buildLCHeader({blockNumber: 500 + 2, slot: 2}), true);
|
||||
|
||||
// store.processLCHeader will call the prune method internally and clean the unfinalized roots
|
||||
expect(store["unfinalizedRoots"].size).to.equal(numberOfPayloads - 2);
|
||||
expect(store["unfinalizedRoots"].size).toEqual(numberOfPayloads - 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {ethers} from "ethers";
|
||||
import Web3 from "web3";
|
||||
import {isSendProvider, isWeb3jsProvider, isEthersProvider} from "../../../src/utils/assertion.js";
|
||||
@@ -11,41 +11,41 @@ describe("utils/assertion", () => {
|
||||
// Do nothing;
|
||||
},
|
||||
};
|
||||
expect(isSendProvider(provider)).to.be.true;
|
||||
expect(isSendProvider(provider)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for ethers provider", () => {
|
||||
const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io");
|
||||
expect(isSendProvider(provider)).to.be.false;
|
||||
expect(isSendProvider(provider)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for web3 provider", () => {
|
||||
const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io");
|
||||
expect(isSendProvider(provider)).to.be.false;
|
||||
expect(isSendProvider(provider)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isWeb3jsProvider", () => {
|
||||
it("should return true if provider is web3.js provider", () => {
|
||||
const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io");
|
||||
expect(isWeb3jsProvider(provider)).to.be.true;
|
||||
expect(isWeb3jsProvider(provider)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false if provider is not web3.js provider", () => {
|
||||
const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io");
|
||||
expect(isWeb3jsProvider(provider)).to.be.false;
|
||||
expect(isWeb3jsProvider(provider)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isEthersProvider", () => {
|
||||
it("should return false if provider is not ethers provider", () => {
|
||||
const provider = new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io");
|
||||
expect(isEthersProvider(provider)).to.be.false;
|
||||
expect(isEthersProvider(provider)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true if provider is ethers provider", () => {
|
||||
const provider = new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io");
|
||||
expect(isEthersProvider(provider)).to.be.true;
|
||||
expect(isEthersProvider(provider)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {chunkIntoN} from "../../../src/utils/conversion.js";
|
||||
|
||||
describe("utils/conversion", () => {
|
||||
@@ -71,12 +71,12 @@ describe("utils/conversion", () => {
|
||||
|
||||
for (const {title, input, output} of testCases) {
|
||||
it(`should chunkify data when ${title}`, async () => {
|
||||
expect(chunkIntoN(input.data, input.n)).to.be.deep.eq(output);
|
||||
expect(chunkIntoN(input.data, input.n)).toEqual(output);
|
||||
});
|
||||
}
|
||||
|
||||
it("should not change the order of elements", () => {
|
||||
expect(chunkIntoN([6, 5, 4, 3, 2, 1], 2)).to.be.deep.eq([
|
||||
expect(chunkIntoN([6, 5, 4, 3, 2, 1], 2)).toEqual([
|
||||
[6, 5],
|
||||
[4, 3],
|
||||
[2, 1],
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import chai from "chai";
|
||||
import chaiAsPromised from "chai-as-promised";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import deepmerge from "deepmerge";
|
||||
import {getEnvLogger} from "@lodestar/logger/env";
|
||||
import {ELProof, ELStorageProof} from "../../../src/types.js";
|
||||
@@ -16,8 +14,6 @@ const validStateRoot = hexToBuffer(eoaProof.beacon.executionPayload.state_root);
|
||||
const invalidAccountProof = deepmerge(validAccountProof, {});
|
||||
delete invalidAccountProof.accountProof[0];
|
||||
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
describe("uitls/execution", () => {
|
||||
const logger = getEnvLogger();
|
||||
|
||||
@@ -30,7 +26,7 @@ describe("uitls/execution", () => {
|
||||
stateRoot: validStateRoot,
|
||||
logger,
|
||||
})
|
||||
).eventually.to.be.true;
|
||||
).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it("should fail with error if proof is valid but address is wrong", async () => {
|
||||
@@ -48,7 +44,7 @@ describe("uitls/execution", () => {
|
||||
stateRoot,
|
||||
logger,
|
||||
})
|
||||
).eventually.to.be.false;
|
||||
).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it("should fail with error if account is not valid", async () => {
|
||||
@@ -62,7 +58,7 @@ describe("uitls/execution", () => {
|
||||
stateRoot,
|
||||
logger,
|
||||
})
|
||||
).eventually.to.be.false;
|
||||
).resolves.toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,7 +72,7 @@ describe("uitls/execution", () => {
|
||||
storageKeys,
|
||||
logger,
|
||||
})
|
||||
).eventually.to.be.true;
|
||||
).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it("should fail with error for a wrong proof", async () => {
|
||||
@@ -88,7 +84,7 @@ describe("uitls/execution", () => {
|
||||
proof: invalidStorageProof,
|
||||
storageKeys,
|
||||
})
|
||||
).eventually.to.be.false;
|
||||
).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it("should fail with error for a non existance key", async () => {
|
||||
@@ -110,7 +106,7 @@ describe("uitls/execution", () => {
|
||||
storageKeys,
|
||||
logger,
|
||||
})
|
||||
).eventually.to.be.false;
|
||||
).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it("should return true empty keys", async () => {
|
||||
@@ -126,7 +122,7 @@ describe("uitls/execution", () => {
|
||||
storageKeys,
|
||||
logger,
|
||||
})
|
||||
).eventually.to.be.true;
|
||||
).resolves.toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {createForkConfig} from "@lodestar/config";
|
||||
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
|
||||
import {ELTransaction} from "../../../lib/types.js";
|
||||
@@ -28,7 +28,7 @@ describe("verified_requests / eth_call", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql(testCase.response);
|
||||
expect(response).toEqual(testCase.response);
|
||||
});
|
||||
|
||||
it("should return the json-rpc response with error for an invalid call", async () => {
|
||||
@@ -57,7 +57,7 @@ describe("verified_requests / eth_call", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_call")},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {createForkConfig} from "@lodestar/config";
|
||||
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
|
||||
import {ELTransaction} from "../../../lib/types.js";
|
||||
@@ -29,7 +29,7 @@ describe("verified_requests / eth_estimateGas", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql(testCase.response);
|
||||
expect(response).toEqual(testCase.response);
|
||||
});
|
||||
|
||||
it("should return the json-rpc response with error for an invalid call", async () => {
|
||||
@@ -59,7 +59,7 @@ describe("verified_requests / eth_estimateGas", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_estimateGas")},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {createForkConfig} from "@lodestar/config";
|
||||
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
|
||||
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js";
|
||||
@@ -25,7 +25,7 @@ describe("verified_requests / eth_getBalance", () => {
|
||||
params: [data.request.params[0], data.request.params[1]],
|
||||
},
|
||||
});
|
||||
expect(response).to.eql(data.response);
|
||||
expect(response).toEqual(data.response);
|
||||
});
|
||||
|
||||
it("should return the json-rpc response with error for an invalid account", async () => {
|
||||
@@ -43,7 +43,7 @@ describe("verified_requests / eth_getBalance", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: data.request.id,
|
||||
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_getBalance")},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {createForkConfig} from "@lodestar/config";
|
||||
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
|
||||
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js";
|
||||
@@ -29,7 +29,7 @@ describe("verified_requests / eth_getBlockByHash", () => {
|
||||
params: testCase.request.params as [string, boolean],
|
||||
},
|
||||
});
|
||||
expect(response).to.eql(testCase.response);
|
||||
expect(response).toEqual(testCase.response);
|
||||
});
|
||||
|
||||
it("should return the json-rpc response with error for an invalid block header with valid execution payload", async () => {
|
||||
@@ -48,7 +48,7 @@ describe("verified_requests / eth_getBlockByHash", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_getBlockByHash")},
|
||||
@@ -71,7 +71,7 @@ describe("verified_requests / eth_getBlockByHash", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_getBlockByHash")},
|
||||
@@ -94,7 +94,7 @@ describe("verified_requests / eth_getBlockByHash", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_getBlockByHash")},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {createForkConfig} from "@lodestar/config";
|
||||
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
|
||||
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js";
|
||||
@@ -29,7 +29,7 @@ describe("verified_requests / eth_getBlockByNumber", () => {
|
||||
params: testCase.request.params as [string | number, boolean],
|
||||
},
|
||||
});
|
||||
expect(response).to.eql(testCase.response);
|
||||
expect(response).toEqual(testCase.response);
|
||||
});
|
||||
|
||||
it("should return the json-rpc response with error for an invalid block header with valid execution payload", async () => {
|
||||
@@ -48,7 +48,7 @@ describe("verified_requests / eth_getBlockByNumber", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {
|
||||
@@ -74,7 +74,7 @@ describe("verified_requests / eth_getBlockByNumber", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {
|
||||
@@ -103,7 +103,7 @@ describe("verified_requests / eth_getBlockByNumber", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {createForkConfig} from "@lodestar/config";
|
||||
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
|
||||
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js";
|
||||
@@ -25,7 +25,7 @@ describe("verified_requests / eth_getCode", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql(testCase.response);
|
||||
expect(response).toEqual(testCase.response);
|
||||
});
|
||||
|
||||
it("should return the json-rpc response with error for an invalid account", async () => {
|
||||
@@ -41,7 +41,7 @@ describe("verified_requests / eth_getCode", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {code: VERIFICATION_FAILED_RESPONSE_CODE, message: getVerificationFailedMessage("eth_getCode")},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect} from "vitest";
|
||||
import {createForkConfig} from "@lodestar/config";
|
||||
import {NetworkName, networksChainConfig} from "@lodestar/config/networks";
|
||||
import {VERIFICATION_FAILED_RESPONSE_CODE} from "../../../src/constants.js";
|
||||
@@ -25,7 +25,7 @@ describe("verified_requests / eth_getTransactionCount", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql(testCase.response);
|
||||
expect(response).toEqual(testCase.response);
|
||||
});
|
||||
|
||||
it("should return the json-rpc response with error for an invalid account", async () => {
|
||||
@@ -43,7 +43,7 @@ describe("verified_requests / eth_getTransactionCount", () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(response).to.eql({
|
||||
expect(response).toEqual({
|
||||
jsonrpc: "2.0",
|
||||
id: testCase.request.id,
|
||||
error: {
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import {expect} from "chai";
|
||||
import {describe, it, expect, afterEach, vi} from "vitest";
|
||||
import Web3 from "web3";
|
||||
import {ethers} from "ethers";
|
||||
import sinon from "sinon";
|
||||
import {createVerifiedExecutionProvider, ProofProvider, LCTransport} from "@lodestar/prover/browser";
|
||||
import {ELRpc} from "../../src/utils/rpc.js";
|
||||
|
||||
describe("web3_provider", () => {
|
||||
const sandbox = sinon.createSandbox();
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("createVerifiedExecutionProvider", () => {
|
||||
describe("web3", () => {
|
||||
it("should create a verified execution provider for the web3 provider", () => {
|
||||
// Don't invoke network in unit tests
|
||||
sandbox.stub(ELRpc.prototype, "verifyCompatibility").resolves();
|
||||
vi.spyOn(ELRpc.prototype, "verifyCompatibility").mockResolvedValue();
|
||||
|
||||
const {provider, proofProvider} = createVerifiedExecutionProvider(
|
||||
new Web3.providers.HttpProvider("https://lodestar-sepoliarpc.chainsafe.io"),
|
||||
@@ -27,15 +24,15 @@ describe("web3_provider", () => {
|
||||
}
|
||||
);
|
||||
|
||||
expect(provider).be.instanceof(Web3.providers.HttpProvider);
|
||||
expect(proofProvider).be.instanceOf(ProofProvider);
|
||||
expect(provider).toBeInstanceOf(Web3.providers.HttpProvider);
|
||||
expect(proofProvider).toBeInstanceOf(ProofProvider);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ethers", () => {
|
||||
it("should create a verified execution provider for the ethers provider", () => {
|
||||
// Don't invoke network in unit tests
|
||||
sandbox.stub(ELRpc.prototype, "verifyCompatibility").resolves();
|
||||
vi.spyOn(ELRpc.prototype, "verifyCompatibility").mockResolvedValue();
|
||||
|
||||
const {provider, proofProvider} = createVerifiedExecutionProvider(
|
||||
new ethers.JsonRpcProvider("https://lodestar-sepoliarpc.chainsafe.io"),
|
||||
@@ -46,8 +43,8 @@ describe("web3_provider", () => {
|
||||
}
|
||||
);
|
||||
|
||||
expect(provider).be.instanceof(ethers.JsonRpcProvider);
|
||||
expect(proofProvider).be.instanceOf(ProofProvider);
|
||||
expect(provider).toBeInstanceOf(ethers.JsonRpcProvider);
|
||||
expect(proofProvider).toBeInstanceOf(ProofProvider);
|
||||
});
|
||||
});
|
||||
});
|
||||
14
packages/prover/vitest.browser.config.ts
Normal file
14
packages/prover/vitest.browser.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {defineConfig, mergeConfig} from "vitest/config";
|
||||
import vitestConfig from "../../vitest.base.browser.config";
|
||||
|
||||
export default mergeConfig(
|
||||
vitestConfig,
|
||||
defineConfig({
|
||||
test: {
|
||||
globalSetup: ["./test/globalSetup.ts"],
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ["@chainsafe/blst"],
|
||||
},
|
||||
})
|
||||
);
|
||||
11
packages/prover/vitest.config.ts
Normal file
11
packages/prover/vitest.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import {defineConfig, mergeConfig} from "vitest/config";
|
||||
import vitestConfig from "../../vitest.base.config";
|
||||
|
||||
export default mergeConfig(
|
||||
vitestConfig,
|
||||
defineConfig({
|
||||
test: {
|
||||
globalSetup: ["./test/globalSetup.ts"],
|
||||
},
|
||||
})
|
||||
);
|
||||
@@ -1,5 +0,0 @@
|
||||
const webpackConfig = require("../../webpack.test.config.js");
|
||||
|
||||
module.exports = {
|
||||
...webpackConfig,
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import bls from "@chainsafe/bls";
|
||||
import {CoordType} from "@chainsafe/blst";
|
||||
import {CoordType} from "@chainsafe/bls/types";
|
||||
import {BeaconConfig} from "@lodestar/config";
|
||||
import {loadState} from "../util/loadState/loadState.js";
|
||||
import {EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import bls from "@chainsafe/bls";
|
||||
import {CoordType} from "@chainsafe/blst";
|
||||
import {CoordType} from "@chainsafe/bls/types";
|
||||
import {itBench, setBenchOpts} from "@dapplion/benchmark";
|
||||
import {loadState} from "../../../../src/util/loadState/loadState.js";
|
||||
import {createCachedBeaconState} from "../../../../src/cache/stateCache.js";
|
||||
|
||||
@@ -30,11 +30,19 @@ export async function runCliCommand<T>(
|
||||
return wrapTimeout(
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
new Promise(async (resolve, reject) => {
|
||||
await cli.parseAsync(parseArgs(args), {}, (err, _argv, output) => {
|
||||
if (err) return reject(err);
|
||||
try {
|
||||
await cli
|
||||
.parseAsync(parseArgs(args), {}, (err, _argv, output) => {
|
||||
if (err) return reject(err);
|
||||
|
||||
resolve(output);
|
||||
});
|
||||
resolve(output);
|
||||
})
|
||||
.catch(() => {
|
||||
// We are suppressing error here as we are throwing from inside the callback
|
||||
});
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
}),
|
||||
opts.timeoutMs
|
||||
);
|
||||
|
||||
@@ -5,8 +5,21 @@ OUTPUT=$(yarn install --check-files 2>&1)
|
||||
|
||||
echo $OUTPUT
|
||||
|
||||
MATCH=("warning")
|
||||
|
||||
# There are few yarn warnings we can't find a fix for. Excluding those.
|
||||
# TODO: Keep checking occasionally if the warnings are fixed upstream.
|
||||
EXCLUDE=("Pattern \[\".*\"\] is trying to unpack in the same destination")
|
||||
ARGS=()
|
||||
|
||||
for m in "${MATCH[@]}"; do ARGS+=(-e "$m"); done
|
||||
for e in "${EXCLUDE[@]}"; do ARGS+=(--exclude "$e"); done
|
||||
COMMAND="grep -qi ${ARGS[@]}"
|
||||
|
||||
echo "Running $COMMAND"
|
||||
|
||||
# grep the output for 'warning'
|
||||
if echo "$OUTPUT" | grep -qi 'warning'; then
|
||||
if echo "$OUTPUT" | ${COMMAND}; then
|
||||
echo "There were warnings in yarn install --check-files"
|
||||
exit 1
|
||||
else
|
||||
|
||||
@@ -52,4 +52,17 @@ expect.extend({
|
||||
message: () => message,
|
||||
};
|
||||
},
|
||||
toSatisfy: (received: unknown, func: (received: unknown) => boolean) => {
|
||||
if (func(received)) {
|
||||
return {
|
||||
message: () => "Expected value satisfied the condition",
|
||||
pass: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
pass: false,
|
||||
message: () => "Expected value did not satisfy the condition",
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
2
scripts/vitest/polyfills/perf_hooks.js
Normal file
2
scripts/vitest/polyfills/perf_hooks.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export default null;
|
||||
export const performance = {};
|
||||
@@ -23,6 +23,12 @@
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"incremental": true,
|
||||
"preserveWatchOutput": true
|
||||
"preserveWatchOutput": true,
|
||||
|
||||
|
||||
// There are two duplicate type definitions included from `chai` and `vitest` packages.
|
||||
// There is one invalid type declaration introduced from `webdriverio -> got` package.
|
||||
// TODO: Once we completely remove `chai` and upgrade `webdriverio` we can enable this check again.
|
||||
"skipLibCheck": true,
|
||||
}
|
||||
}
|
||||
|
||||
9
types/vitest/index.d.ts
vendored
9
types/vitest/index.d.ts
vendored
@@ -28,8 +28,15 @@ interface CustomMatchers<R = unknown> {
|
||||
toBeWithMessage(expected: unknown, message: string): R;
|
||||
}
|
||||
|
||||
interface CustomAsymmetricMatchers<R = unknown> extends CustomMatchers<R> {
|
||||
/**
|
||||
* Non-asymmetric matcher already exists, we just need to add asymmetric version
|
||||
*/
|
||||
toSatisfy(func: (received: unknown) => boolean): R;
|
||||
}
|
||||
|
||||
declare module "vitest" {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
interface Assertion<T = any> extends CustomMatchers<T> {}
|
||||
interface AsymmetricMatchersContaining extends CustomMatchers {}
|
||||
interface AsymmetricMatchersContaining extends CustomAsymmetricMatchers {}
|
||||
}
|
||||
|
||||
49
vitest.base.browser.config.ts
Normal file
49
vitest.base.browser.config.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import path from "node:path";
|
||||
import {defineConfig} from "vitest/config";
|
||||
const __dirname = new URL(".", import.meta.url).pathname;
|
||||
import {nodePolyfills} from "vite-plugin-node-polyfills";
|
||||
import topLevelAwait from "vite-plugin-top-level-await";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
topLevelAwait(),
|
||||
nodePolyfills({
|
||||
include: ["buffer", "process", "util", "string_decoder", "url", "querystring", "events"],
|
||||
globals: {Buffer: true, process: true},
|
||||
protocolImports: true,
|
||||
}),
|
||||
],
|
||||
test: {
|
||||
include: ["**/*.test.ts"],
|
||||
exclude: [
|
||||
"**/*.node.test.ts",
|
||||
"**/node_modules/**",
|
||||
"**/dist/**",
|
||||
"**/lib/**",
|
||||
"**/cypress/**",
|
||||
"**/.{idea,git,cache,output,temp}/**",
|
||||
"**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*",
|
||||
],
|
||||
setupFiles: [path.join(__dirname, "./scripts/vitest/customMatchers.ts")],
|
||||
reporters: ["default", "hanging-process"],
|
||||
coverage: {
|
||||
enabled: false,
|
||||
},
|
||||
browser: {
|
||||
name: "chrome",
|
||||
headless: true,
|
||||
provider: "webdriverio",
|
||||
slowHijackESM: false,
|
||||
providerOptions: {
|
||||
capabilities: {
|
||||
browserVersion: "latest",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"node:perf_hooks": path.join(__dirname, "scripts/vitest/polyfills/perf_hooks.js"),
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -4,6 +4,16 @@ const __dirname = new URL(".", import.meta.url).pathname;
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
pool: "threads",
|
||||
include: ["**/*.test.ts"],
|
||||
exclude: [
|
||||
"**/*.browser.test.ts",
|
||||
"**/node_modules/**",
|
||||
"**/dist/**",
|
||||
"**/cypress/**",
|
||||
"**/.{idea,git,cache,output,temp}/**",
|
||||
"**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*",
|
||||
],
|
||||
setupFiles: [path.join(__dirname, "./scripts/vitest/customMatchers.ts")],
|
||||
reporters: ["default", "hanging-process"],
|
||||
coverage: {
|
||||
|
||||
Reference in New Issue
Block a user