Skip to content

Commit 5f1f4b0

Browse files
Migrate mocha to vitest for parachain ts-test (#3833)
* feat: migrate from Mocha to Vitest for better TS/ESM support - Replace Mocha + Chai + mocha-steps with Vitest - Update package.json: remove mocha/chai deps, add vitest - Add vitest.config.ts with test configuration - Convert test syntax: * step() → test() * expect().to.equal() → expect().toBe() * describeLitentry now uses Vitest hooks (beforeAll/afterAll) - Update all imports to use .js extensions for ESM compatibility - Update package.json to use 'type: module' - Test scripts remain same (test-filter, test-evm-contract, etc.) - No changes to CI or bash scripts needed (they call pnpm scripts) Benefits: - Native ESM support (no more ts-node/register hacks) - Better TypeScript integration - Faster test execution - Modern test framework with better DX * chore: update Vitest to v3.2.4 and refresh pnpm-lock.yaml - Update @vitest/ui: 3.0.0 → 3.2.4 - Update vitest: 3.0.0 → 3.2.4 - Refresh pnpm-lock.yaml with latest resolved versions * upgrade to vitest 4 * try to fix ci * try to fix ci * try to fix more ci --------- Co-authored-by: BillyWooo <yang@trustcomputing.de>
1 parent 6b334cd commit 5f1f4b0

15 files changed

+1101
-552
lines changed

parachain/ts-tests/common/setup/register-parathread.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import '@polkadot/api-augment';
33
import { ApiPromise, Keyring, WsProvider } from '@polkadot/api';
44
import { TypeRegistry } from '@polkadot/types/create';
55
import { Bytes } from '@polkadot/types';
6-
import { loadConfig, signAndSend } from '../utils';
6+
import { loadConfig, signAndSend } from '../utils/index.js';
77

88
async function registerParathread(api: ApiPromise, config: any) {
99
// Get keyring of Alice, who is also the sudo in dev chain spec

parachain/ts-tests/common/setup/setup-enclave.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import '@polkadot/api-augment';
22
import { ApiPromise, Keyring, WsProvider } from '@polkadot/api';
3-
import { loadConfig, signAndSend, sudoWrapperGc } from '../utils';
3+
import { loadConfig, signAndSend, sudoWrapperGc } from '../utils/index.js';
44
import { hexToU8a } from '@polkadot/util';
55

66
const mrenclave = process.argv[2];

parachain/ts-tests/common/setup/teebag-set-dev-mode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import '@polkadot/api-augment';
22
import { ApiPromise, Keyring, WsProvider } from '@polkadot/api';
3-
import { loadConfig, signAndSend, sudoWrapperGc } from '../utils';
3+
import { loadConfig, signAndSend, sudoWrapperGc } from '../utils/index.js';
44

55
async function setAliceAsAdmin(api: ApiPromise, config: any) {
66
// Get keyring of Alice, who is also the sudo in dev chain spec

parachain/ts-tests/common/setup/upgrade-parathread.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import '@polkadot/api-augment';
22
import { ApiPromise, Keyring, WsProvider } from '@polkadot/api';
33
import type { ISubmittableResult } from '@polkadot/types/types';
4-
import { loadConfig } from '../utils';
4+
import { loadConfig } from '../utils/index.js';
55

66
// upgrade the parathread to parachain by forcibly leasing a certain period
77
// can be used to extend the leasing period if it's already in onboarding process

parachain/ts-tests/common/setup/wait-finalized-block.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import '@polkadot/api-augment';
22
import { ApiPromise, Keyring, WsProvider } from '@polkadot/api';
33
import type { VoidFn } from '@polkadot/api/types';
44
import type { ISubmittableResult } from '@polkadot/types/types';
5-
import { loadConfig } from '../utils';
5+
import { loadConfig } from '../utils/index.js';
66

77
const FINALIZED_BLOCKS_COUNT = 1;
88
const TIMEOUT_MIN = 5;
Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
1+
import { config as dotenvConfig } from 'dotenv';
2+
import { readFileSync } from 'fs';
3+
import { fileURLToPath } from 'url';
4+
import { dirname, join } from 'path';
5+
6+
const __filename = fileURLToPath(import.meta.url);
7+
const __dirname = dirname(__filename);
8+
19
export function loadConfig() {
2-
require('dotenv').config();
10+
dotenvConfig();
11+
12+
let configPath: string;
313
switch (process.env.NODE_ENV) {
414
case 'local':
5-
return require('../../config.local.json');
15+
configPath = join(__dirname, '../../config.local.json');
16+
break;
617
case 'test':
718
case 'ci':
8-
return require('../../config.ci.json');
19+
configPath = join(__dirname, '../../config.ci.json');
20+
break;
921
case 'prod':
10-
return require('../../config.prod.json');
22+
configPath = join(__dirname, '../../config.prod.json');
23+
break;
1124
default:
1225
throw new Error(`Invalid NODE_ENV: ${process.env.NODE_ENV}`);
1326
}
27+
28+
return JSON.parse(readFileSync(configPath, 'utf-8'));
1429
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export * from './config';
2-
export * from './integration-setup';
3-
export * from './function';
1+
export * from './config.js';
2+
export * from './integration-setup.js';
3+
export * from './function.js';

parachain/ts-tests/common/utils/integration-setup.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import 'mocha';
1+
import { describe, beforeAll, afterAll } from 'vitest';
22
import '@polkadot/api-augment';
33
import { ApiPromise, Keyring, WsProvider } from '@polkadot/api';
44
import { KeyringPair } from '@polkadot/keyring/types';
5-
import { loadConfig } from './config';
5+
import { loadConfig } from './config.js';
66

77
export class ParachainConfig {
88
api!: ApiPromise;
@@ -54,10 +54,7 @@ export async function initApiPromise(config: any): Promise<ParachainConfig> {
5454
}
5555

5656
export function describeLitentry(title: string, specFilename: string, cb: (context: ParachainConfig) => void) {
57-
describe(title, function () {
58-
// Set timeout to 6000 seconds (Because of 50-blocks delay of rococo, so called "training wheels")
59-
this.timeout(6000000);
60-
57+
describe(title, () => {
6158
let context: ParachainConfig = {
6259
api: {} as ApiPromise,
6360
parachain: {} as string,
@@ -66,18 +63,24 @@ export function describeLitentry(title: string, specFilename: string, cb: (conte
6663
eve: {} as KeyringPair,
6764
ferdie: {} as KeyringPair,
6865
};
69-
// Making sure the Litentry node has started
70-
before('Starting Litentry Test Node', async function () {
66+
67+
beforeAll(async () => {
68+
console.log('Starting Litentry Test Node');
7169
const config = loadConfig();
7270
const initApi = await initApiPromise(config);
7371
context.parachain = initApi.parachain;
7472
context.api = initApi.api;
7573
context.alice = initApi.alice;
7674
context.bob = initApi.bob;
7775
context.eve = initApi.eve;
78-
});
76+
context.ferdie = initApi.ferdie;
77+
}, 60000);
7978

80-
after(async function () {});
79+
afterAll(async () => {
80+
if (context.api) {
81+
await context.api.disconnect();
82+
}
83+
});
8184

8285
cb(context);
8386
});

parachain/ts-tests/integration-tests/base-filter.test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { expect } from 'chai';
2-
import { step } from 'mocha-steps';
3-
import { signAndSend, describeLitentry } from '../common/utils';
1+
import { expect, test } from 'vitest';
2+
import { signAndSend, describeLitentry } from '../common/utils/index.js';
43

54
describeLitentry('Test Base Filter', ``, (context) => {
65
console.log(`Test Base Filter`);
76

8-
step('Transfer 1000 unit from Eve to Bob', async function () {
7+
test('Transfer 1000 unit from Eve to Bob', async () => {
98
// Get the initial balance of Eve and Bob
109
const { nonce: eveInitNonce, data: eveInitBalance } = await context.api.query.system.account(
1110
context.eve.address
@@ -24,12 +23,12 @@ describeLitentry('Test Base Filter', ``, (context) => {
2423
context.bob.address
2524
);
2625

27-
expect(eveCurrentNonce.toNumber()).to.equal(eveInitNonce.toNumber() + 1);
26+
expect(eveCurrentNonce.toNumber()).toBe(eveInitNonce.toNumber() + 1);
2827
// the balance transfer should work for rococo and litentry
29-
expect(bobCurrentBalance.free.toBigInt()).to.equal(bobInitBalance.free.toBigInt() + BigInt(1000));
28+
expect(bobCurrentBalance.free.toBigInt()).toBe(bobInitBalance.free.toBigInt() + BigInt(1000));
3029
});
3130

32-
step('Transfer 1000 unit from Eve to Bob with Sudo', async function () {
31+
test('Transfer 1000 unit from Eve to Bob with Sudo', async () => {
3332
// only work for rococo
3433
const parachain = (await context.api.rpc.system.chain()).toString().toLowerCase();
3534
if (parachain !== 'rococo-dev') {
@@ -58,7 +57,7 @@ describeLitentry('Test Base Filter', ``, (context) => {
5857
);
5958

6059
// The transfer should always succeed
61-
expect(aliceCurrentNonce.toNumber()).to.equal(aliceInitNonce.toNumber() + 1);
62-
expect(bobCurrentBalance.free.toBigInt()).to.equal(bobInitBalance.free.toBigInt() + BigInt(1000));
60+
expect(aliceCurrentNonce.toNumber()).toBe(aliceInitNonce.toNumber() + 1);
61+
expect(bobCurrentBalance.free.toBigInt()).toBe(bobInitBalance.free.toBigInt() + BigInt(1000));
6362
});
6463
});

parachain/ts-tests/integration-tests/evm-contract.test.ts

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { assert, expect } from 'chai';
2-
import { step } from 'mocha-steps';
3-
import { signAndSend, describeLitentry, loadConfig, sudoWrapperTc } from '../common/utils';
1+
import { expect, test } from 'vitest';
2+
import { signAndSend, describeLitentry, loadConfig, sudoWrapperTc } from '../common/utils/index.js';
43
import { compiled } from '../common/utils/compile';
54
import { evmToAddress } from '@polkadot/util-crypto';
65
import { hexToU8a, u8aToHex } from '@polkadot/util';
@@ -16,12 +15,12 @@ describeLitentry('Test EVM Module Contract', ``, (context) => {
1615
mappedAddress: evmToAddress('0xaaafB3972B05630fCceE866eC69CdADd9baC2771', 31),
1716
};
1817

19-
step('Set ExtrinsicFilter mode to Test', async function () {
18+
test('Set ExtrinsicFilter mode to Test', async () => {
2019
let extrinsic = await sudoWrapperTc(context.api, context.api.tx.extrinsicFilter.setMode('Test'));
2120
await signAndSend(extrinsic, context.alice);
2221
});
2322

24-
step('Transfer Value from Eve to EVM external account', async function () {
23+
test('Transfer Value from Eve to EVM external account', async () => {
2524
let eveMappedEVMAccount = context.eve.publicKey.slice(0, 20);
2625
let eveMappedSustrateAccount = evmToAddress(eveMappedEVMAccount, 31);
2726

@@ -58,13 +57,11 @@ describeLitentry('Test EVM Module Contract', ``, (context) => {
5857
// If a substrate account using pallet_evm to trigger evm transaction,
5958
// it will bump 2 for nonce (one for substrate extrinsic, one for evm).
6059
// +1 nonce for original substrate account, plus another 1 nonce for original substrate account's truncated evm address's mapped susbtrate account.
61-
expect(eveCurrentNonce.toNumber()).to.equal(eveInitNonce.toNumber() + 1);
62-
expect(evmAccountCurrentBalance.free.toBigInt()).to.equal(
63-
evmAccountInitBalance.free.toBigInt() + BigInt(value)
64-
);
60+
expect(eveCurrentNonce.toNumber()).toBe(eveInitNonce.toNumber() + 1);
61+
expect(evmAccountCurrentBalance.free.toBigInt()).toBe(evmAccountInitBalance.free.toBigInt() + BigInt(value));
6562
});
6663

67-
step('Transfer some value back to Eve Mapped account from EVM external account', async function () {
64+
test('Transfer some value back to Eve Mapped account from EVM external account', async () => {
6865
// Get the initial balance of Eve and EVM external account
6966
let eveMappedEVMAccount = context.eve.publicKey.slice(0, 20);
7067
let eveMappedSustrateAccount = evmToAddress(eveMappedEVMAccount, 31);
@@ -99,11 +96,11 @@ describeLitentry('Test EVM Module Contract', ``, (context) => {
9996

10097
console.log(`evmAccount Balance: ${evmAccountCurrentBalance}`);
10198

102-
expect(evmAccountCurrentNonce.toNumber()).to.equal(evmAccountInitNonce.toNumber() + 1);
103-
expect(eveCurrentBalance.free.toBigInt()).to.equal(eveInitBalance.free.toBigInt() + BigInt(value));
99+
expect(evmAccountCurrentNonce.toNumber()).toBe(evmAccountInitNonce.toNumber() + 1);
100+
expect(eveCurrentBalance.free.toBigInt()).toBe(eveInitBalance.free.toBigInt() + BigInt(value));
104101
});
105102

106-
step('Test substrate signature can not access ultra vires evm/substrate account', async function () {
103+
test('Test substrate signature can not access ultra vires evm/substrate account', async () => {
107104
// Get the initial balance of Eve and EVM external account
108105
const eveInitNonce = (await context.api.query.system.account(context.eve.address)).nonce;
109106
const evmAccountInitBalance = (await context.api.query.system.account(evmAccountRaw.mappedAddress)).data;
@@ -130,12 +127,12 @@ describeLitentry('Test EVM Module Contract', ``, (context) => {
130127

131128
// Extrinsic succeed with failed origin
132129
// So the evm transaction nonce bump will not be triggered
133-
expect(eveCurrentNonce.toNumber()).to.equal(eveInitNonce.toNumber() + 1);
130+
expect(eveCurrentNonce.toNumber()).toBe(eveInitNonce.toNumber() + 1);
134131
// Which means balance unchanged
135-
expect(evmAccountCurrentBalance.free.toBigInt()).to.equal(evmAccountInitBalance.free.toBigInt());
132+
expect(evmAccountCurrentBalance.free.toBigInt()).toBe(evmAccountInitBalance.free.toBigInt());
136133
});
137134

138-
step('Deploy and test contract by EVM external account', async function () {
135+
test('Deploy and test contract by EVM external account', async () => {
139136
// Get the bytecode and API
140137
const bytecode = compiled.evm.bytecode.object;
141138
const abi = compiled.abi;
@@ -183,8 +180,7 @@ describeLitentry('Test EVM Module Contract', ``, (context) => {
183180
};
184181

185182
const message = await sayMessage(deployed.contractAddress!);
186-
const initialResult = message === 'Hello World' ? 1 : 0;
187-
assert.equal(1, initialResult, 'Contract initial storage query mismatch');
183+
expect(message).toBe('Hello World');
188184

189185
// Test set message contract method
190186
const setMessage = async (contractAddress: string, accountFrom: any, message: string) => {
@@ -209,11 +205,10 @@ describeLitentry('Test EVM Module Contract', ``, (context) => {
209205
};
210206
const setMsg = await setMessage(deployed.contractAddress!, evmAccountRaw, 'Goodbye World');
211207
const sayMsg = await sayMessage(deployed.contractAddress!);
212-
const setResult = sayMsg === 'Goodbye World' ? 1 : 0;
213-
assert.equal(1, setResult, 'Contract modified storage query mismatch');
208+
expect(sayMsg).toBe('Goodbye World');
214209
});
215210

216-
step('Set ExtrinsicFilter mode to Normal', async function () {
211+
test('Set ExtrinsicFilter mode to Normal', async () => {
217212
let extrinsic = await sudoWrapperTc(context.api, context.api.tx.extrinsicFilter.setMode('Normal'));
218213
await signAndSend(extrinsic, context.alice);
219214
});

0 commit comments

Comments
 (0)