Skip to content

Commit

Permalink
feat: unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
AbigailDeng authored and AbigailDeng committed Sep 26, 2024
1 parent 8bf2640 commit f11bb20
Show file tree
Hide file tree
Showing 7 changed files with 787 additions and 75 deletions.
4 changes: 2 additions & 2 deletions examples/browser/multiTransaction.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
// return contract's instance and you can call the methods on this instance
return aelf.chain.contractAt(tokenContractAddress,wallet,{
refBlockNumberStrategy: {
AELF: -8,
tDVW: -8
9992731: -8,
1931928: -8
},
multi: {
9992731: {
Expand Down
516 changes: 512 additions & 4 deletions jest-report.xml

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions jest.browser.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,10 @@ module.exports = {

// The glob patterns Jest uses to detect test files
testMatch: [
// '**/test/unit/**/contractMethod.test.js'
'**/test/unit/**/multiTransaction.test.js'
// '**/test/unit/**/?(*.)+(test).[jt]s?(x)',
// '**/test/unit/util/httpProvider.browser-test.js'
// '**/test/unit/chain/index.test.js'
// '**/test/unit/**/multiTransaction.test.js'
'**/test/unit/**/?(*.)+(test).[jt]s?(x)',
'**/test/unit/util/httpProvider.browser-test.js'
// "**/?(*.)+(spec|test).[tj]s?(x)"
],
testTimeout: 20000,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aelf-sdk",
"version": "3.4.16-alpha.1",
"version": "3.4.16-alpha.2",
"description": "aelf-sdk js library",
"main": "dist/aelf.cjs.js",
"browser": "dist/aelf.umd.js",
Expand Down
65 changes: 34 additions & 31 deletions src/contract/contractMethod.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export default class ContractMethod {
this._option = option || {};
this._gatewayUrl = this._option.gatewayUrl;
this._multiOptions = this._option.multi || {};
// multi chainId ['AELF', 'tDVW']
this._chainIds = Object.keys(this._multiOptions);
const { resolvedRequestType, resolvedResponseType } = method;
this._inputType = resolvedRequestType;
Expand Down Expand Up @@ -126,13 +125,14 @@ export default class ContractMethod {
throw new Error('refBlockNumberStrategy must be less than 0');
}
}
let { refBlockNumberStrategy } = this._option;
// if _chainIds is empty, init refBlockNumberStrategy to undefined
let { refBlockNumberStrategy = this._chainIds.length ? {} : undefined } = this._option;
args.forEach(arg => {
if (arg.refBlockNumberStrategy) {
if (isObject(arg.refBlockNumberStrategy)) {
const keys = Object.keys(arg.refBlockNumberStrategy);
for (let i = 0; i < keys.length; i++) {
validateItem(arg.refBlockNumberStrategy(keys[i]));
validateItem(arg.refBlockNumberStrategy[keys[i]]);
refBlockNumberStrategy[keys[i]] = arg.refBlockNumberStrategy[keys[i]];
}
} else {
Expand Down Expand Up @@ -239,30 +239,37 @@ export default class ContractMethod {
this._chainIds.forEach(ele => {
encoded[ele] = this.packInput(filterArgs[0][ele]);
});
// if (isView) {
// return this.handleMultiTransaction({}, {}, encoded);
// }
const refBlockNumberStrategy = this.validateRefBlockNumberStrategy(args);
const chainHeight = {};
const chainHash = {};
this._chainIds.forEach(chainId => {
// get chain height and hash
const httpProvider = new HttpProvider(this._multiOptions[chainId].chainUrl);
const url = 'api/blockChain/chainStatus';
const statusRes = httpProvider.send({
url,
method: 'GET'
});
let { BestChainHeight, BestChainHash } = statusRes;
if (refBlockNumberStrategy[chainId]) {
BestChainHeight += refBlockNumberStrategy[chainId];
const block = this._chain.getBlockByHeight(BestChainHeight, true, {
sync: true
const url = 'blockChain/chainStatus';
try {
const statusRes = httpProvider.send({
url,
method: 'GET'
});
BestChainHash = block.BlockHash;
let { BestChainHeight, BestChainHash } = statusRes;
if (refBlockNumberStrategy?.[chainId]) {
BestChainHeight += refBlockNumberStrategy[chainId];
const blockUrl = 'blockChain/blockByHeight';
const block = httpProvider.send({
url: blockUrl,
method: 'GET',
params: {
blockHeight: BestChainHeight
}
});
BestChainHash = block.BlockHash;
}
chainHeight[chainId] = BestChainHeight;
chainHash[chainId] = BestChainHash;
} catch (error) {
console.error(`Error fetching status for chain ${chainId}:`, error);
throw error;
}
chainHeight[chainId] = BestChainHeight;
chainHash[chainId] = BestChainHash;
});
return this.handleMultiTransaction(chainHeight, chainHash, encoded);
}
Expand All @@ -275,21 +282,13 @@ export default class ContractMethod {
this._chainIds.forEach(ele => {
encoded[ele] = this.packInput(filterArgs[0][ele]);
});

// if (isView) {
// return this.handleMultiTransaction({}, {}, encoded);
// }

const refBlockNumberStrategy = this.validateRefBlockNumberStrategy(args);
// console.log(refBlockNumberStrategy, 'refBlockNumberStrategy');
const chainHeight = {};
const chainHash = {};

await Promise.all(
this._chainIds.map(async chainId => {
const httpProvider = new HttpProvider(this._multiOptions[chainId].chainUrl);
const httpProvider = new HttpProvider(this._multiOptions[chainId]?.chainUrl);
const url = 'blockChain/chainStatus';

try {
const statusRes = await httpProvider.sendAsync({
url,
Expand All @@ -298,12 +297,16 @@ export default class ContractMethod {
let { BestChainHeight, BestChainHash } = statusRes;
if (refBlockNumberStrategy?.[chainId]) {
BestChainHeight += refBlockNumberStrategy[chainId];
const block = this._chain.getBlockByHeight(BestChainHeight, true, {
sync: true
const blockUrl = 'blockChain/blockByHeight';
const block = await httpProvider.sendAsync({
url: blockUrl,
method: 'GET',
params: {
blockHeight: BestChainHeight
}
});
BestChainHash = block.BlockHash;
}

chainHeight[chainId] = BestChainHeight;
chainHash[chainId] = BestChainHash;
} catch (error) {
Expand Down
104 changes: 71 additions & 33 deletions test/unit/chain/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,37 +35,30 @@ describe('chain should work', () => {
test('test refBlockNumberStrategy argument into object', () => {
// Arrange
const args = [{ refBlockNumberStrategy: 10 }];

// Act
const result = chain.extractArgumentsIntoObject(args);

// Assert
expect(result.refBlockNumberStrategy).toBe(10);
});
test('test is concrete contract when sync', async () => {
const aelf = new AElf(new AElf.providers.HttpProvider(stageEndpoint));
const { GenesisContractAddress } = await aelf.chain.getChainStatus();
const args = [{ sync: true }];
const contract = await chain.contractAt(
GenesisContractAddress,
null,
...args
);
const contract = await chain.contractAt(GenesisContractAddress, null, ...args);
expect(contract.deserializeLog).toBeInstanceOf(Function);
});
test('test is invalid contract when sync', async () => {
const address =
'ELF_iUY5CLwzU8L8vjVgH95vx3ZRuvD5d9hVK3EdPMVD8v9EaQT75_AELF';
const address = 'ELF_iUY5CLwzU8L8vjVgH95vx3ZRuvD5d9hVK3EdPMVD8v9EaQT75_AELF';
const args = [{ sync: true }];
// mock contractFileDescriptorSet
chain.getContractFileDescriptorSet = jest.fn(() => {
return {
file: [],
file: []
};
});
expect(() => chain.contractAt(address, null, ...args)).toThrow(
'no such contract'
);
expect(() => chain.contractAt(address, null, ...args)).toThrow('no such contract');
});
test('test is concrete contract when async', async () => {
const aelf = new AElf(new AElf.providers.HttpProvider(stageEndpoint));
Expand All @@ -74,53 +67,45 @@ describe('chain should work', () => {
expect(contract.deserializeLog).toBeInstanceOf(Function);
});
test('test is invalid contract when async', async () => {
const address =
'ELF_iUY5CLwzU8L8vjVgH95vx3ZRuvD5d9hVK3EdPMVD8v9EaQT75_AELF';
const address = 'ELF_iUY5CLwzU8L8vjVgH95vx3ZRuvD5d9hVK3EdPMVD8v9EaQT75_AELF';
chain.getContractFileDescriptorSet = jest.fn(() => {
return Promise.resolve({
file: [],
file: []
});
});
let error;
chain.extractArgumentsIntoObject = jest.fn(() => {
return {
callback: (e) => {
callback: e => {
error = e;
},
isSync: false,
isSync: false
};
});
await chain.contractAt(address, null);
expect(error).toEqual(new Error('no such contract'));
}, 5000);
test('test is invalid contract with noop callback', async () => {
const address =
'ELF_iUY5CLwzU8L8vjVgH95vx3ZRuvD5d9hVK3EdPMVD8v9EaQT75_AELF';
const address = 'ELF_iUY5CLwzU8L8vjVgH95vx3ZRuvD5d9hVK3EdPMVD8v9EaQT75_AELF';
chain.getContractFileDescriptorSet = jest.fn(() => {
return Promise.resolve({
file: [],
file: []
});
});
await expect(chain.contractAt(address, null)).rejects.toEqual(
new Error('no such contract')
);
await expect(chain.contractAt(address, null)).rejects.toEqual(new Error('no such contract'));
}, 5000);
test('test txId has corresponding transaction in the block with height when sync', async () => {
const aelf = new AElf(new AElf.providers.HttpProvider(stageEndpoint));
const blockInfo = await aelf.chain.getBlockByHeight(1, true);
const txId = blockInfo.Body.Transactions[0];
const result = Array.isArray(
aelf.chain.getMerklePath(txId, 1, { sync: true })
);
const result = Array.isArray(aelf.chain.getMerklePath(txId, 1, { sync: true }));
expect(result).toBe(true);
}, 5000);
test('test txId has no corresponding transaction in the block with height when sync', async () => {
const aelf = new AElf(new AElf.providers.HttpProvider(stageEndpoint));
const blockInfo = await chain.getBlockByHeight(1, true);
const txId = blockInfo.Body.Transactions[0];
await expect(() =>
aelf.chain.getMerklePath(txId, 2, { sync: true })
).toThrow(
await expect(() => aelf.chain.getMerklePath(txId, 2, { sync: true })).toThrow(
'txId dce643d5c142945dc9f0665819dbf0b268b8423a94fa7a488d24cd89c0b67a23 has no correspond transaction in the block with height 2'
);
}, 20000);
Expand All @@ -136,10 +121,63 @@ describe('chain should work', () => {
const aelf = new AElf(new AElf.providers.HttpProvider(stageEndpoint));
const blockInfo = await aelf.chain.getBlockByHeight(1, true);
const txId = blockInfo.Body.Transactions[0];
await expect(
async () => await aelf.chain.getMerklePath(txId, 2)
).rejects.toThrow(
await expect(async () => await aelf.chain.getMerklePath(txId, 2)).rejects.toThrow(
'txId dce643d5c142945dc9f0665819dbf0b268b8423a94fa7a488d24cd89c0b67a23 has no correspond transaction in the block with height 2'
);
});
}, 20000);

describe('test multi transaction', () => {
beforeEach(() => {
httpProvider = new HttpProvider(stageEndpoint);
requestManager = new RequestManager(httpProvider);
chain = new Chain(requestManager);
});
test('multi transaction option with number object refBlockNumberStrategy', async () => {
const aelf = new AElf(new AElf.providers.HttpProvider(stageEndpoint));
const { GenesisContractAddress } = await aelf.chain.getChainStatus();
expect(
chain.contractAt(GenesisContractAddress, null, {
refBlockNumberStrategy: {
9992731: -8,
1931928: -8
},
multi: {
9992731: {
chainUrl: 'https://aelf-test-node.aelf.io/',
contractAddress: 'JRmBduh4nXWi1aXgdUsj5gJrzeZb2LxmrAbf7W99faZSvoAaE'
},
1931928: {
chainUrl: 'https://tdvw-test-node.aelf.io/',
contractAddress: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx'
}
},
gatewayUrl: 'https://gateway-test.aelf.io'
})
).resolves.not.toThrow();
});

test('multi transaction option without number object refBlockNumberStrategy', async () => {
const aelf = new AElf(new AElf.providers.HttpProvider(stageEndpoint));
const { GenesisContractAddress } = await aelf.chain.getChainStatus();
expect(
chain.contractAt(GenesisContractAddress, null, {
refBlockNumberStrategy: {
9992731: 'test',
1931928: 'invalid'
},
multi: {
9992731: {
chainUrl: 'https://aelf-test-node.aelf.io/',
contractAddress: 'JRmBduh4nXWi1aXgdUsj5gJrzeZb2LxmrAbf7W99faZSvoAaE'
},
1931928: {
chainUrl: 'https://tdvw-test-node.aelf.io/',
contractAddress: 'ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx'
}
},
gatewayUrl: 'https://gateway-test.aelf.io'
})
).resolves.not.toThrow();
});
});
Loading

0 comments on commit f11bb20

Please sign in to comment.