Added derive e2e tests and documentation (#898)

* export IExtrinsic

* Switch to localhos & enable tests in promise.spec

* Derive.accounts docs (copy from my other branch) + code examples

* Fixed existing accounts tests and added tests for all accounts.derive methods

* e2e tests and docs/ examples for balances.all and balances.fees

* Removed emty lines below jsdoc info

* tests & documentation dor derive.chain

* Addressed comments from former PR https://github.com/polkadot-js/api/pull/869

* Removed unused import

* obseralbe -> observable

* undo keith' commit

* use correct jsdocs syntax

* Re-enable skip
This commit is contained in:
Stefanie Doll
2019-05-15 11:50:28 +02:00
committed by Jaco Greeff
parent 4da52c8d76
commit c30d3a80e8
14 changed files with 295 additions and 50 deletions
@@ -15,6 +15,19 @@ import { drr } from '../util/drr';
export type AccountIdAndIndex = [AccountId?, AccountIndex?];
/**
* @name idAndIndex
* @param {(Address | AccountId | AccountIndex | string | null)} address - An accounts address in various formats.
* @description An array containing the [[AccountId]] and [[AccountIndex]] as optional values.
* @example
* <BR>
*
* ```javascript
* api.derive.accounts.idAndIndex('F7Hs', ([id, ix]) => {
* console.log(`AccountId #${id} with corresponding AccountIndex ${ix}`);
* });
* ```
*/
export function idAndIndex (api: ApiInterface$Rx) {
return (address?: Address | AccountId | AccountIndex | string | null): Observable<AccountIdAndIndex> => {
try {
@@ -10,6 +10,20 @@ import { AccountId, AccountIndex } from '@polkadot/types';
import { indexes, AccountIndexes } from './indexes';
import { drr } from '../util/drr';
/**
* @name idToIndex
* @param {( AccountId | string )} accountId - An accounts Id in different formats.
* @returns Returns the corresponding AccountIndex.
* @example
* <BR>
*
* ```javascript
* const ALICE = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
* api.derive.accounts.idToIndex(ALICE, (accountIndex) => {
* console.log(`The AccountIndex of ${ALICE} is ${accountIndex}`);
* });
* ```
*/
export function idToIndex (api: ApiInterface$Rx) {
return (accountId: AccountId | string): Observable<AccountIndex | undefined> =>
indexes(api)()
@@ -10,6 +10,19 @@ import { AccountId, AccountIndex, Vector } from '@polkadot/types';
import { drr } from '../util/drr';
/**
* @name indexToId
* @param {( AccountIndex | string )} accountIndex - An accounts index in different formats.
* @returns Returns the corresponding AccountId.
* @example
* <BR>
*
* ```javascript
* api.derive.accounts.indexToId('F7Hs', (accountId) => {
* console.log(`The AccountId of F7Hs is ${accountId}`);
* });
* ```
*/
export function indexToId (api: ApiInterface$Rx) {
return (_accountIndex: AccountIndex | string): Observable<AccountId> => {
const querySection = api.query.indices || api.query.balances;
+11 -1
View File
@@ -15,9 +15,19 @@ export type AccountIndexes = { [index: string]: AccountIndex };
const enumsetSize = ENUMSET_SIZE.toNumber();
/**
* Returns all the indexes on the system - this is an unwieldly query since it loops through
* @name indexes
* @returns Returns all the indexes on the system.
* @description This is an unwieldly query since it loops through
* all of the enumsets and returns all of the values found. This could be up to 32k depending
* on the number of active accounts in the system
* @example
* <BR>
*
* ```javascript
* api.derive.accounts.indexes((indexes) => {
* console.log('All existing AccountIndexes', indexes);
* });
* ```
*/
export function indexes (api: ApiInterface$Rx) {
return (): Observable<AccountIndexes> => {
+16
View File
@@ -14,6 +14,22 @@ import { drr } from '../util/drr';
const EMPTY_ACCOUNT = new AccountId();
/**
* @name all
* @param {( ccountIndex | AccountId | Address | string )} address - An accounts Id in different formats.
* @returns An object containing the combined results of the storage queries for
* all relevant fees as declared in the substrate chain spec.
* @example
* <BR>
*
* ```javascript
* const ALICE = 'F7Hs';
*
* api.derive.balances.all(ALICE, ([accountId, lockedBalance]) => {
* console.log(`The account ${accountId} has a locked balance ${lockedBalance} units.`);
* });
* ```
*/
export function all (api: ApiInterface$Rx) {
return (address: AccountIndex | AccountId | Address | string): Observable<DerivedBalances> => {
return idAndIndex(api)(address).pipe(
+13
View File
@@ -10,6 +10,19 @@ import BN from 'bn.js';
import { DerivedFees } from '../types';
import { drr } from '../util/drr';
/**
* @name fees
* @returns An object containing the combined results of the storage queries for
* all relevant fees as declared in the substrate chain spec.
* @example
* <BR>
*
* ```javascript
* api.derive.balances.fees(([creationFee, transferFee]) => {
* console.log(`The fee for creating a new account on this chain is ${transferFee} units. The fee required for making a transfer is ${transferFee} units.`);
* });
* ```
*/
export function fees (api: ApiInterface$Rx) {
return (): Observable<DerivedFees> => {
return (api.queryMulti([
+2 -1
View File
@@ -10,7 +10,8 @@ import { BlockNumber, Header } from '@polkadot/types';
import { drr } from '../util/drr';
/**
* @description Get the latest block number.
* @name bestNumber
* @returns The latest block number.
* @example
* <BR>
*
@@ -10,8 +10,10 @@ import { BlockNumber, Header } from '@polkadot/types';
import { drr } from '../util/drr';
/**
* @name bestNumberFinalized
* @returns A BlockNumber
* @description Get the latest finalized block number.
* example
* @example
* <BR>
*
* ```javascript
@@ -12,6 +12,8 @@ import { bestNumber } from './bestNumber';
import { bestNumberFinalized } from './bestNumberFinalized';
/**
* @name bestNumberLag
* @returns A number of blocks
* @description Calculates the lag between finalized head and best head
* @example
* <BR>
+4 -2
View File
@@ -11,8 +11,10 @@ import { drr } from '../util/drr';
import { HeaderAndValidators } from './subscribeNewHead';
/**
* @description Get the a specific block header and extend it with the author
* @param hash: Uint8Array | string
* @name bestNumberFinalized
* @param {( Uint8Array | string )} hash - A block hash as U8 array or string.
* @returns An array containing the block header and the block author
* @description Get a specific block header and extend it with the author
* @example
* <BR>
*
@@ -12,7 +12,9 @@ import { drr } from '../util/drr';
export type HeaderAndValidators = [Header, Array<AccountId>];
/**
* @description Subscribe to block headers and extend it with the author
* @name subscribeNewHead
* @returns An array containing the block header and the block author
* @description An observable of the current block header and it's author
* @example
* <BR>
*
+1 -1
View File
@@ -32,7 +32,7 @@ describe.skip('derive e2e', () => {
it('subscribes to newHead, retrieving the actual validator', (done) => {
return api.derive.chain.subscribeNewHead(({ author }) => {
console.error('author', author.toString());
console.log('author', author.toString());
if (author) {
done();
+187 -39
View File
@@ -3,14 +3,19 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import BN from 'bn.js';
import ApiRx from '@polkadot/api/rx/Api';
import { ApiInterface$Rx } from '@polkadot/api/types';
import { BlockNumber } from '@polkadot/types';
import { AccountId, AccountIndex, Balance, BlockNumber } from '@polkadot/types';
import { WsProvider } from '@polkadot/rpc-provider';
const WS_LOCAL = 'ws://127.0.0.1:9944/';
// const WS_POC3 = 'wss://poc3-rpc.polkadot.io/';
// Dev account Alice
const ID = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const IX = 'F7Hs';
describe.skip('derive e2e', () => {
let api: ApiInterface$Rx;
@@ -23,49 +28,192 @@ describe.skip('derive e2e', () => {
done();
});
it('derive.chain.bestNumber', async (done) => {
api.derive.chain.bestNumber().subscribe((blockNumber) => {
expect(blockNumber instanceof BlockNumber).toBe(true);
expect((blockNumber as BlockNumber).gten(0)).toBe(true);
done();
});
});
it('derive.session.sessionProgress', async (done) => {
api.derive.session.sessionProgress().subscribe((progress) => {
expect(progress instanceof BN).toBe(true);
done();
});
});
it('returns the intentions with balances', async (done) => {
api.derive.staking.intentionsBalances().subscribe((balances) => {
expect(Object.keys(balances as object)).not.toHaveLength(0);
done();
});
});
// these only work on localhost, not the poc-3 URL
// These derive.accounts tests only work on localhost, not the poc-3 URL
// (and it is assuming it sent at least 1 tx)
describe('accounts', () => {
const ID = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const IX = 'F7Gh';
describe('derive.accounts', () => {
it('looks up id & index from id', async (done) => {
// @ts-ignore silence warning until we have static types here
api.derive.accounts.idAndIndex(ID).subscribe(([id, ix]) => {
expect(id.toString()).toEqual(ID);
expect(ix.toString()).toEqual(IX);
done();
describe('idAndIndex', () => {
it('looks up AccountId & AccountIndex from AccountId', async (done) => {
// @ts-ignore silence warning until we have static types here
api.derive.accounts.idAndIndex(ID).subscribe(([accountId, accountIndex]) => {
expect(accountId.toString()).toEqual(ID);
// The first emitted value for ix is undefined when passing the ID
if (accountIndex) {
expect(accountIndex.toString()).toEqual(IX);
} else {
expect(accountIndex).toEqual(undefined);
}
done();
});
});
it('looks up AccountId & AccountIndex from AccountIndex', async (done) => {
// @ts-ignore silence warning until we have static types here
api.derive.accounts.idAndIndex(IX).subscribe(([accountId, accountIndex]) => {
// The first emitted value for id is undefined when passing the IX
if (accountId) {
expect(accountId.toString()).toEqual(ID);
} else {
expect(accountId).toEqual(undefined);
}
expect(accountIndex.toString()).toEqual(IX);
done();
});
});
});
it('looks up id & index from index', async (done) => {
// @ts-ignore silence warning until we have static types here
api.derive.accounts.idAndIndex(IX).subscribe(([id, ix]) => {
expect(id.toString()).toEqual(ID);
expect(ix.toString()).toEqual(IX);
done();
describe('indexToId', () => {
it('looks up AccountId from AccountIndex', async (done) => {
// @ts-ignore silence warning until we have static types here
api.derive.accounts.indexToId(IX).subscribe((accountId) => {
// The first emitted value for accountId is undefined when passing the IX
if (accountId) {
expect(accountId instanceof AccountId).toBe(true);
expect(accountId.toString()).toEqual(ID);
} else {
expect(accountId).toEqual(undefined);
}
done();
});
});
});
describe('idToIndex', () => {
it('looks up AccountIndex from AccountId', async (done) => {
// @ts-ignore silence warning until we have static types here
api.derive.accounts.idToIndex(ID).subscribe((accountIndex) => {
// The first emitted value for AccountIndex is undefined when passing the ID
if (accountIndex) {
expect(accountIndex instanceof AccountIndex).toBe(true);
expect(accountIndex.toString()).toEqual(IX);
} else {
expect(accountIndex).toEqual(undefined);
}
done();
});
});
});
describe('indexes', () => {
it('looks up all AccountIndexes', async (done) => {
// @ts-ignore silence warning until we have static types here
api.derive.accounts.indexes().subscribe((accountIndexes) => {
// A local dev chain should have the AccountIndex of Alice
expect(accountIndexes).toHaveProperty(
ID,
new AccountIndex(IX)
);
done();
});
});
});
});
// these only work on localhost, not the poc-3 URL
// (and it is assuming it sent at least 1 tx)
describe('derive.balances', () => {
describe('all', () => {
it('It returns an object with all relevant balance information of an account', async (done) => {
api.derive.balances.all(ID).subscribe((balances) => {
expect(balances).toEqual(expect.objectContaining({
accountId: expect.any(AccountId),
availableBalance: expect.any(Balance),
freeBalance: expect.any(Balance),
lockedBalance: expect.any(Balance),
reservedBalance: expect.any(Balance),
vestedBalance: expect.any(Balance),
votingBalance: expect.any(Balance)
}));
done();
});
});
});
describe('fees', () => {
it('fees: It returns an object with all relevant fees of type BN', async (done) => {
api.derive.balances.fees().subscribe((fees) => {
expect(fees).toEqual(expect.objectContaining({
creationFee: expect.any(BN),
existentialDeposit: expect.any(BN),
transactionBaseFee: expect.any(BN),
transactionByteFee: expect.any(BN),
transferFee: expect.any(BN)
}));
done();
});
});
});
});
describe('derive.chain', () => {
describe('bestNumber', () => {
it('Get the latest block number', async (done) => {
api.derive.chain.bestNumber().subscribe((blockNumber) => {
expect(blockNumber instanceof BlockNumber).toBe(true);
expect((blockNumber as BlockNumber).gten(0)).toBe(true);
done();
});
});
});
describe('bestNumberFinalized', () => {
it('Get the latest finalised block number', async (done) => {
api.derive.chain.bestNumberFinalized().subscribe((blockNumber) => {
expect(blockNumber instanceof BlockNumber).toBe(true);
expect((blockNumber as BlockNumber).gten(0)).toBe(true);
done();
});
});
});
describe('bestNumberLag', () => {
it('lag between finalised head and best head', async (done) => {
api.derive.chain.bestNumberLag().subscribe((numberLag) => {
expect(numberLag instanceof BlockNumber).toBe(true);
expect((numberLag as BlockNumber).gten(0)).toBe(true);
done();
});
});
});
describe('getHeader', () => {
it('gets a specific block header and extended with it\`s author', async (done) => {
api.derive.chain.getHeader().subscribe((headerExtended) => {
// WIP
expect(headerExtended).toEqual(expect.arrayContaining([]));
done();
});
});
});
describe('subscribeNewHead', () => {
it('gets an observable of the current block header and it\'s author', async (done) => {
api.derive.chain.subscribeNewHead().subscribe((headerExtended) => {
// WIP
done();
});
});
});
});
describe('derive.session', () => {
describe('sessionProgress', () => {
it('derive.session.sessionProgress', async (done) => {
api.derive.session.sessionProgress().subscribe((progress) => {
expect(progress instanceof BN).toBe(true);
done();
});
});
});
});
describe('derive.staking', () => {
describe('intentionsBalances', () => {
it('returns the intentions with balances', async (done) => {
api.derive.staking.intentionsBalances().subscribe((balances) => {
expect(Object.keys(balances as object)).not.toHaveLength(0);
done();
});
});
});
});
+13 -4
View File
@@ -8,7 +8,7 @@ On the Rust side, the codec types and primitive types are implemented via the [p
These are the base types of the codec. They are typically not used directly, but rather inherited from to create specific types. They are the building blocks for declaring custom types:
| Type | Description |
| **Types** | |
| --- | --- |
| [[AbstractArray]] | Manages codec arrays. It is an extension to Array |
| [[Base]] | A type extends the Base class, when it holds a value |
@@ -31,7 +31,7 @@ These are the base types of the codec. They are typically not used directly, but
These primitive types are available:
| Type | Description |
| **Types** | |
| --- | --- |
| [[Bool]] | Representation for a boolean value in the system |
| [[Bytes]] | A Bytes wrapper for `Vec<u8>` |
@@ -65,7 +65,7 @@ These primitive types are available:
These custom types implement specific types that are found as part of the Substrate core. They're all extensions of one of the codec types:
| Type | Description |
| **Types** | |
| --- | --- |
| [[AccountId]] | A wrapper around an AccountId/PublicKey representation |
| [[AccountIndex]] | A wrapper around an AccountIndex, which is a shortened, variable-length encoding for an Account |
@@ -147,7 +147,7 @@ These custom types implement specific types that are found as part of the Substr
These types are not used in the runtime, but are rather used in RPC results:
| Type | Description |
| **Types** | |
| --- | --- |
| [[ChainProperties]] | Wraps the properties retrieved from the chain via the `system.properties` RPC call |
| [[ExtrinsicStatus]] | An EnumType that indicates the status of the Extrinsic as been submitted |
@@ -160,3 +160,12 @@ These types are not used in the runtime, but are rather used in RPC results:
| [[RuntimeVersion]] | A [[Tuple]] that conatins the [[ApiId]] and [[U32]] version |
| [[SignedBlock]] | A [[Block]] that has been signed and contains a [[Justification]] |
| [[StorageChangeSet]] | A set of storage changes. It contains the [[Block]] hash and a list of the actual changes |
## Derive types
These types are are specific for the Polkadot-JS API, so you won't find a representation of them in the SCALE codec or the Substrate core. They are used in the [api-derive](https://www.npmjs.com/package/@polkadot/api-derive) methods.
| **Types** | |
| --- | --- |
| [[HeaderExtended]] | A [[Block]] header with an additional `author` field that indicates the block author] |