Skip to content
This repository has been archived by the owner on Aug 24, 2023. It is now read-only.

chore(ts-tests): add e2e contracts #66

Merged
merged 63 commits into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
c923da8
add e2e testcontainer
canonbrother Aug 22, 2022
df865a2
br
canonbrother Aug 22, 2022
17fe3d8
ts-test package ver 0.0.0
canonbrother Aug 22, 2022
c6ec290
test defich/metachain img
canonbrother Aug 24, 2022
569ad80
ci e2e
canonbrother Aug 24, 2022
105b46a
merge conflicts
canonbrother Aug 24, 2022
23b6be9
fix ci e2e
canonbrother Aug 24, 2022
8bd47b9
rm ts-test/gitignore
canonbrother Aug 24, 2022
e7b9301
update bal.test.ts
canonbrother Aug 24, 2022
6727c93
use non-null assertion op
canonbrother Aug 25, 2022
aee4952
move to constant
canonbrother Aug 25, 2022
ea8be11
typing provider and call -> resp.result
canonbrother Aug 25, 2022
36f83d8
wip
canonbrother Aug 25, 2022
9c424c9
update image tag
canonbrother Aug 25, 2022
d3b2335
syntax err
canonbrother Aug 25, 2022
cd25102
Merge branch 'main' into canonbrother/e2e-testcontainer
canonbrother Aug 26, 2022
ed1f92c
proper docker conn
canonbrother Aug 26, 2022
c58a2aa
Merge branch 'canonbrother/e2e-testcontainer' into canonbrother/e2e-c…
canonbrother Aug 26, 2022
ff0352e
bump(deps): bump actions/github-script from 6.1.0 to 6.1.1 (#35)
dependabot[bot] Aug 25, 2022
9f971f5
proper docker conn
canonbrother Aug 26, 2022
b7f9622
fix(workflow): docker supports multi platform (#38)
canonbrother Aug 25, 2022
aa971eb
merge base
canonbrother Aug 26, 2022
fb3c06a
Merge branch 'main' into canonbrother/e2e-testcontainer
canonbrother Aug 26, 2022
33023a6
Merge branch 'canonbrother/e2e-testcontainer' into canonbrother/e2e-c…
canonbrother Aug 26, 2022
5f62c51
proper docker conn
canonbrother Aug 26, 2022
8506594
fix(workflow): docker supports multi platform (#38)
canonbrother Aug 25, 2022
2cf6a00
rename ethersjs to ethers
canonbrother Aug 26, 2022
cbda49a
add network differentiate container
canonbrother Aug 26, 2022
2654b37
extend timeout
canonbrother Aug 26, 2022
1d27ae2
Merge branch 'main' into canonbrother/e2e-testcontainer
canonbrother Aug 26, 2022
574e6fc
fix conflicts
canonbrother Aug 26, 2022
b1a10c4
merge main
canonbrother Aug 29, 2022
5d66a9b
sol lint
canonbrother Aug 30, 2022
fcc9516
constant blockhashcount 2400
canonbrother Aug 30, 2022
132198b
skip environmental block hash
canonbrother Aug 30, 2022
1f264b4
log
canonbrother Aug 30, 2022
16a170a
desc why need alice (validator) on running node
canonbrother Aug 30, 2022
39f0487
switch ethers
canonbrother Sep 1, 2022
8e88a08
addr alphabetize
canonbrother Sep 5, 2022
21e4632
prettier max len 120
canonbrother Sep 5, 2022
2997622
dockerignore ts-test
canonbrother Sep 5, 2022
5484255
simplize contract
canonbrother Sep 5, 2022
3eda4fc
test with ethers in balances.test.ts
canonbrother Sep 5, 2022
25949f8
refine contract.test.ts
canonbrother Sep 5, 2022
25b4b62
refine prettier
canonbrother Sep 5, 2022
704688b
rm chain-spec config
canonbrother Sep 5, 2022
0768902
Merge branch 'main' into canonbrother/e2e-contracts
canonbrother Sep 5, 2022
a512c58
refine
canonbrother Sep 5, 2022
4864e44
rm unuse web3 jsonrpc call
canonbrother Sep 5, 2022
abae99b
refine contract.test.ts
canonbrother Sep 5, 2022
edb7484
add npm build on ci
canonbrother Sep 5, 2022
ceea719
ordering
canonbrother Sep 5, 2022
34d81fa
test count
canonbrother Sep 6, 2022
e095f15
npm i truffle
canonbrother Sep 6, 2022
b44b888
test set
canonbrother Sep 6, 2022
754236b
minor pr req
canonbrother Sep 8, 2022
335c60f
Merge branch 'main' into canonbrother/e2e-contracts
canonbrother Sep 8, 2022
ca5b759
Merge branch 'main' into canonbrother/e2e-contracts
canonbrother Sep 8, 2022
3b4919c
Merge branch 'main' into canonbrother/e2e-contracts
canonbrother Sep 8, 2022
2e4c2c9
rm web3
canonbrother Sep 8, 2022
658c256
replace truffle by hardhat
canonbrother Sep 8, 2022
cc4c8bc
combine hardhat compile with jest in one script
canonbrother Sep 8, 2022
2dc64c5
Merge branch 'main' into canonbrother/e2e-contracts
canonbrother Sep 9, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ target
netlify.toml
*.md
Dockerfile
ts-tests
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,4 @@ jobs:
node-version: '16'
cache: 'npm'
cache-dependency-path: 'ts-tests/package-lock.json'
- run: cd ts-tests && npm ci && npm t
- run: cd ts-tests && npm ci && npm run build && npm t
weiyuan95 marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 2 additions & 1 deletion ts-tests/.prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"singleQuote": true
"printWidth": 120
}
119 changes: 76 additions & 43 deletions ts-tests/__tests__/balances.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ethers } from 'ethers';
import { MetaDContainer } from '../containers';
import {
GENESIS_ACCOUNT,
Expand All @@ -9,54 +10,86 @@ import {
const container = new MetaDContainer();
const TEST_ACCOUNT = '0x1111111111111111111111111111111111111111';

beforeAll(async () => {
await container.start();
});
const value = '0x200'; // 512, must be higher than ExistentialDeposit
const gasPrice = '0x3B9ACA00'; // 1000000000
canonbrother marked this conversation as resolved.
Show resolved Hide resolved

afterAll(async () => {
await container.stop();
});
// GENESIS_ACCOUNT_BALANCE - (21000 * gasPrice) - value;
const expectedGenesisBalance = (
BigInt(GENESIS_ACCOUNT_BALANCE) -
BigInt(21000) * BigInt(gasPrice) -
BigInt(value)
).toString();

const expectedTestBalance = (Number(value) - EXISTENTIAL_DEPOSIT).toString();

describe('web3', () => {
beforeAll(async () => {
await container.start();
});

afterAll(async () => {
await container.stop();
});

it('should genesis balance setup correctly', async () => {
const bal = await container.web3.eth.getBalance(GENESIS_ACCOUNT);
expect(bal).toStrictEqual(GENESIS_ACCOUNT_BALANCE);
});

it('should transfer balance', async () => {
const tx = await container.web3.eth.accounts.signTransaction(
{
from: GENESIS_ACCOUNT,
to: TEST_ACCOUNT,
value: value,
gasPrice: gasPrice,
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
gas: '0x100000'
},
GENESIS_ACCOUNT_PRIVATE_KEY
);

await container.call('eth_sendRawTransaction', [tx?.rawTransaction]);

expect(await container.web3.eth.getBalance(GENESIS_ACCOUNT, 'pending')).toStrictEqual(expectedGenesisBalance);
expect(await container.web3.eth.getBalance(TEST_ACCOUNT, 'pending')).toStrictEqual(expectedTestBalance);

it('should genesis balance setup correctly', async () => {
const bal = await container.web3.eth.getBalance(GENESIS_ACCOUNT);
expect(bal).toStrictEqual(GENESIS_ACCOUNT_BALANCE);
await container.generate();

expect(await container.web3.eth.getBalance(GENESIS_ACCOUNT)).toStrictEqual(expectedGenesisBalance);
expect(await container.web3.eth.getBalance(TEST_ACCOUNT)).toStrictEqual(expectedTestBalance);
});
});

it('should transfer balance', async () => {
const value = '0x200'; // 512, must be higher than ExistentialDeposit
const gasPrice = '0x3B9ACA00'; // 1000000000
const tx = await container.web3.eth.accounts.signTransaction(
{
from: GENESIS_ACCOUNT,
describe('ethers', () => {
beforeAll(async () => {
await container.start();
});

afterAll(async () => {
await container.stop();
});

it('should genesis balance setup correctly', async () => {
const bal = await container.ethers.getBalance(GENESIS_ACCOUNT);
expect(bal.toString()).toStrictEqual(GENESIS_ACCOUNT_BALANCE);
});

it('should transfer balance', async () => {
const wallet = new ethers.Wallet(GENESIS_ACCOUNT_PRIVATE_KEY, container.ethers);

await wallet.sendTransaction({
to: TEST_ACCOUNT,
value: value,
gasPrice: gasPrice,
gas: '0x100000'
},
GENESIS_ACCOUNT_PRIVATE_KEY
);
await container.call('eth_sendRawTransaction', [tx?.rawTransaction]);

// GENESIS_ACCOUNT_BALANCE - (21000 * gasPrice) - value;
const expectedGenesisBalance = (
BigInt(GENESIS_ACCOUNT_BALANCE) -
BigInt(21000) * BigInt(gasPrice) -
BigInt(value)
).toString();
const expectedTestBalance = (Number(value) - EXISTENTIAL_DEPOSIT).toString();
expect(
await container.web3.eth.getBalance(GENESIS_ACCOUNT, 'pending')
).toStrictEqual(expectedGenesisBalance);
expect(
await container.web3.eth.getBalance(TEST_ACCOUNT, 'pending')
).toStrictEqual(expectedTestBalance);

await container.generate();

expect(await container.web3.eth.getBalance(GENESIS_ACCOUNT)).toStrictEqual(
expectedGenesisBalance
);
expect(await container.web3.eth.getBalance(TEST_ACCOUNT)).toStrictEqual(
expectedTestBalance
);
gasLimit: 0x100000
});

await container.generate();

const gBal = await container.ethers.getBalance(GENESIS_ACCOUNT);
expect(gBal.toString()).toStrictEqual(expectedGenesisBalance);

const tBal = await container.ethers.getBalance(TEST_ACCOUNT);
expect(tBal.toString()).toStrictEqual(expectedTestBalance);
});
});
62 changes: 62 additions & 0 deletions ts-tests/__tests__/contract.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { MetaDContainer } from '../containers';
import { GENESIS_ACCOUNT, GENESIS_ACCOUNT_PRIVATE_KEY, CONTRACT_ADDRESS } from '../utils/constant';
import Test from '../build/contracts/Test.json';
import { ethers } from 'ethers';

const container = new MetaDContainer();

beforeAll(async () => {
await container.start();
});

afterAll(async () => {
await container.stop();
});

it('should create and call contract', async () => {
// create contract
fuxingloh marked this conversation as resolved.
Show resolved Hide resolved
const wallet = new ethers.Wallet(GENESIS_ACCOUNT_PRIVATE_KEY, container.ethers);

const factory = new ethers.ContractFactory(Test.abi, Test.bytecode, wallet);

const contract = await factory.deploy();
expect(contract.address).toStrictEqual(CONTRACT_ADDRESS);

await container.generate();

// call contract
expect(await contract.name()).toStrictEqual('Meta');
expect(await contract.owner()).toStrictEqual(GENESIS_ACCOUNT);

// test environmental
const currentBlock = (await contract.getCurrentBlock()).toNumber();
expect(currentBlock).toStrictEqual(1);

const blockHash = await contract.getBlockHash(currentBlock);
expect(blockHash).toStrictEqual(expect.any(String));

const gasLimit = (await contract.getGasLimit()).toNumber();
expect(gasLimit).toStrictEqual(75000000);

// test functional
const mul = (await contract.mul(3, 7)).toNumber();
expect(mul).toStrictEqual(21);

const c0 = (await contract.getCount()).toNumber();
expect(c0).toStrictEqual(0);

await contract.incr();
await container.generate();

const c1 = (await contract.getCount()).toNumber();
expect(c1).toStrictEqual(1);

await contract.setCount(25);
await container.generate();

const c25 = (await contract.getCount()).toNumber();
expect(c25).toStrictEqual(25);

const promise = contract.max10(11);
await expect(promise).rejects.toThrow('Value must not be greater than 10');
});
91 changes: 42 additions & 49 deletions ts-tests/containers/MetaDContainer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { ethers } from 'ethers';
import Web3 from 'web3';
canonbrother marked this conversation as resolved.
Show resolved Hide resolved
import { JsonRpcResponse } from 'web3-core-helpers';
import {
GenericContainer,
StartedTestContainer,
Network,
StartedNetwork
} from 'testcontainers';
import { GenericContainer, StartedTestContainer, Network, StartedNetwork } from 'testcontainers';
import { CHAIN_ID } from '../utils/constant';
import { HttpProvider, WebsocketProvider } from 'web3-core';
import { META_LOG } from '../utils/constant';

type MetaDNetwork = 'mainnet' | 'testnet';

Expand Down Expand Up @@ -65,9 +61,7 @@ export class MetaDContainer {
'--no-telemetry', // disable connecting to substrate telemtry server
'--no-prometheus', // do not expose a Prometheus exporter endpoint
'--no-grandpa',
// TODO(canonbrother): set up chain spec exclusively for test
// '--chain= ./spec.json',
// `-l${FRONTIER_LOG}`,
`-l${META_LOG}`,
`--port=${opts.port}`,
`--rpc-port=${opts.rpcPort}`,
`--ws-port=${opts.wsPort}`,
Expand All @@ -76,52 +70,56 @@ export class MetaDContainer {
'--sealing=manual',
'--force-authoring', // enable authoring even when offline
'--rpc-cors=all',
'--alice', // shortcut for `--name Alice --validator` with session keys for `Alice` added to keystore
'--alice', // shortcut for `--name Alice --validator` with session keys for `Alice` added to keystore, required by manual sealing to author the blocks
'--tmp' // run a temporary node
];
}

async start(startOptions: StartOptions = {}): Promise<void> {
this.network = await new Network().start();

this.startOptions = Object.assign(
MetaDContainer.MetaDPorts[this.metaDNetwork],
startOptions
);
this.startOptions = Object.assign(MetaDContainer.MetaDPorts[this.metaDNetwork], startOptions);
const timeout = this.startOptions.timeout ?? 100_000;

this.startedContainer = await this.genericContainer
.withName(this.generateName())
.withNetworkMode(this.network.getName())
.withCmd(this.getCmd(this.startOptions))
.withExposedPorts(
...Object.values(MetaDContainer.MetaDPorts[this.metaDNetwork])
)
.withExposedPorts(...Object.values(MetaDContainer.MetaDPorts[this.metaDNetwork]))
.withStartupTimeout(timeout)
.start();

this.web3 =
this.provider !== 'http'
? new Web3(
`ws://127.0.0.1:${this.startedContainer.getMappedPort(
MetaDContainer.MetaDPorts[this.metaDNetwork].wsPort
)}`
`ws://127.0.0.1:${this.startedContainer.getMappedPort(MetaDContainer.MetaDPorts[this.metaDNetwork].wsPort)}`
)
: new Web3(
`http://127.0.0.1:${this.startedContainer.getMappedPort(
MetaDContainer.MetaDPorts[this.metaDNetwork].rpcPort
)}`
);

this.ethers = new ethers.providers.StaticJsonRpcProvider(
`http://127.0.0.1:${this.startedContainer.getMappedPort(
MetaDContainer.MetaDPorts[this.metaDNetwork].rpcPort
)}`,
{
chainId: CHAIN_ID,
name: 'meta'
}
);
this.ethers =
this.provider !== 'http'
? new ethers.providers.JsonRpcProvider(
`ws://127.0.0.1:${this.startedContainer.getMappedPort(
MetaDContainer.MetaDPorts[this.metaDNetwork].wsPort
)}`,
{
chainId: CHAIN_ID,
name: 'meta'
}
)
: new ethers.providers.JsonRpcProvider(
`http://127.0.0.1:${this.startedContainer.getMappedPort(
MetaDContainer.MetaDPorts[this.metaDNetwork].rpcPort
)}`,
{
chainId: CHAIN_ID,
name: 'meta'
}
);
}

async stop(): Promise<void> {
Expand All @@ -130,26 +128,12 @@ export class MetaDContainer {
}

async call(method: string, params: any[]): Promise<any> {
return new Promise<JsonRpcResponse>((resolve, reject) => {
(this.web3.currentProvider as HttpProvider | WebsocketProvider).send(
{
jsonrpc: '2.0',
id: Math.floor(Math.random() * 100000000000000),
method,
params
},
(error: Error | null, response: JsonRpcResponse | undefined) => {
if (error) {
reject(
`Failed to send custom request (${method} (${params.join(
','
)})): ${error.message || error.toString()}`
);
}
resolve(response?.result);
}
);
});
try {
return this.ethers.send(method, params);
} catch (err: any) {
const { error } = JSON.parse(err.body);
throw new MetaDRpcError(error);
}
}

// Create a block and finalize it.
Expand All @@ -168,3 +152,12 @@ export class MetaDContainer {
return `${MetaDContainer.PREFIX}-${this.metaDNetwork}-${rand}`;
}
}

/**
* RPC error from container
*/
export class MetaDRpcError extends Error {
constructor(error: { code: number; message: string }) {
super(`MetaDRpcError: ' ${error.message}', code: ${error.code}`);
}
}
Loading