git.delta.rocks / unique-network / refs/commits / 2390e1641b99

difftreelog

Merge pull request #67 from usetech-llc/feature/NFTPAR-257

Greg Zaitsev2021-01-19parents: #567e35d #fdbcd55.patch.diff
in: master
Feature/nftpar 257

6 files changed

modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -28,7 +28,8 @@
     "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",
     "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",
     "testToggleContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/toggleContractWhiteList.test.ts",
-    "testAddToContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractWhiteList.test.ts"
+    "testAddToContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractWhiteList.test.ts",
+    "testTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/transfer.test.ts"
   },
   "author": "",
   "license": "Apache 2.0",
modifiedtests/src/burnItem.test.tsdiffbeforeafterboth
before · tests/src/burnItem.test.ts
1import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';2import { Keyring } from "@polkadot/api";3import { IKeyringPair } from "@polkadot/types/types";4import { 5  createCollectionExpectSuccess, 6  createItemExpectSuccess,7  getGenericResult,8  destroyCollectionExpectSuccess9} from './util/helpers';10import { nullPublicKey } from "./accounts";1112import chai from 'chai';13import chaiAsPromised from 'chai-as-promised';14chai.use(chaiAsPromised);15const expect = chai.expect;1617let alice: IKeyringPair;18let bob: IKeyringPair;1920describe('integration test: ext. burnItem():', () => {21  before(async () => {22    await usingApi(async (api) => {23      const keyring = new Keyring({ type: 'sr25519' });24      alice = keyring.addFromUri(`//Alice`);25      bob = keyring.addFromUri(`//Bob`);26    });27  });2829  it('Burn item in NFT collection', async () => {30    const createMode = 'NFT';31    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});32    const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);3334    await usingApi(async (api) => {35      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);36      const events = await submitTransactionAsync(alice, tx);37      const result = getGenericResult(events);38  39      // Get the item 40      const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();41 42      // What to expect43      expect(result.success).to.be.true;44      expect(item).to.be.not.null;45      expect(item.Owner).to.be.equal(nullPublicKey);46    });47  48  });49  it('Burn item in Fungible collection', async () => {50    const createMode = 'Fungible';51    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0 }});52    await createItemExpectSuccess(alice, collectionId, createMode); // Helper creates 10 fungible tokens53    const tokenId = 0; // ignored5455    await usingApi(async (api) => {56      // Destroy 1 of 1057      const tx = api.tx.nft.burnItem(collectionId, tokenId, 1);58      const events = await submitTransactionAsync(alice, tx);59      const result = getGenericResult(events);60  61      // Get alice balance 62      const balance: any = (await api.query.nft.fungibleItemList(collectionId, alice.address)).toJSON();63 64      // What to expect65      expect(result.success).to.be.true;66      expect(balance).to.be.not.null;67      expect(balance.Value).to.be.equal(9);68    });6970  });71  it('Burn item in ReFungible collection', async () => {72    const createMode = 'ReFungible';73    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 2 }});74    const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);7576    await usingApi(async (api) => {77      const tx = api.tx.nft.burnItem(collectionId, tokenId, 1);78      const events = await submitTransactionAsync(alice, tx);79      const result = getGenericResult(events);80  81      // Get alice balance 82      const balance: any = (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON();83      84      // What to expect85      expect(result.success).to.be.true;86      expect(balance).to.be.not.null;87      expect(balance.Owner.length).to.be.equal(0);88    });8990  });9192  it('Burn owned portion of item in ReFungible collection', async () => {93    const createMode = 'ReFungible';94    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 2 }});95    const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);9697    await usingApi(async (api) => {98      // Transfer 1/100 of the token to Bob99      const transfertx = api.tx.nft.transfer(bob.address, collectionId, tokenId, 1);100      const events1 = await submitTransactionAsync(alice, transfertx);101      const result1 = getGenericResult(events1);102103      // Get balances104      const balanceBefore: any = (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON();105106      // Bob burns his portion107      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);108      const events2 = await submitTransactionAsync(bob, tx);109      const result2 = getGenericResult(events2);110  111      // Get balances 112      const balance: any = (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON();113      // console.log(balance);114      115      // What to expect before burning116      expect(result1.success).to.be.true;117      expect(balanceBefore).to.be.not.null;118      expect(balanceBefore.Owner.length).to.be.equal(2);119      expect(balanceBefore.Owner[0].Owner).to.be.equal(alice.address);120      expect(balanceBefore.Owner[0].Fraction).to.be.equal(99);121      expect(balanceBefore.Owner[1].Owner).to.be.equal(bob.address);122      expect(balanceBefore.Owner[1].Fraction).to.be.equal(1);123124      // What to expect after burning125      expect(result2.success).to.be.true;126      expect(balance).to.be.not.null;127      expect(balance.Owner.length).to.be.equal(1);128      expect(balance.Owner[0].Fraction).to.be.equal(99);129      expect(balance.Owner[0].Owner).to.be.equal(alice.address);130    });131132  });133134});135136describe('Negative integration test: ext. burnItem():', () => {137  before(async () => {138    await usingApi(async (api) => {139      const keyring = new Keyring({ type: 'sr25519' });140      alice = keyring.addFromUri(`//Alice`);141      bob = keyring.addFromUri(`//Bob`);142    });143  });144145  it('Burn a token in a destroyed collection', async () => {146    const createMode = 'NFT';147    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }});148    const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);149    await destroyCollectionExpectSuccess(collectionId);150151    await usingApi(async (api) => {152      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);153      const badTransaction = async function () { 154        await submitTransactionExpectFailAsync(alice, tx);155      };156      await expect(badTransaction()).to.be.rejected;157    });158159  });160161  it('Burn a token that was never created', async () => {162    const createMode = 'NFT';163    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }});164    const tokenId = 10;165166    await usingApi(async (api) => {167      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);168      const badTransaction = async function () { 169        await submitTransactionExpectFailAsync(alice, tx);170      };171      await expect(badTransaction()).to.be.rejected;172    });173174  });175176  it('Burn a token using the address that does not own it', async () => {177    const createMode = 'NFT';178    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }});179    const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);180181    await usingApi(async (api) => {182      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);183      const badTransaction = async function () { 184        await submitTransactionExpectFailAsync(bob, tx);185      };186      await expect(badTransaction()).to.be.rejected;187    });188189  });190191  it('Transfer a burned a token', async () => {192    const createMode = 'NFT';193    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }});194    const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);195196    await usingApi(async (api) => {197198      const burntx = api.tx.nft.burnItem(collectionId, tokenId, 0);199      const events1 = await submitTransactionAsync(alice, burntx);200      const result1 = getGenericResult(events1);201      expect(result1.success).to.be.true;202  203      const tx = api.tx.nft.transfer(bob.address, collectionId, tokenId, 0);204      const badTransaction = async function () { 205        await submitTransactionExpectFailAsync(alice, tx);206      };207      await expect(badTransaction()).to.be.rejected;208    });209210  });211212  it('Burn more than owned in Fungible collection', async () => {213    const createMode = 'Fungible';214    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0 }});215    // Helper creates 10 fungible tokens216    await createItemExpectSuccess(alice, collectionId, createMode);217    const tokenId = 0; // ignored218219    await usingApi(async (api) => {220      // Destroy 11 of 10221      const tx = api.tx.nft.burnItem(collectionId, tokenId, 11);222      const badTransaction = async function () { 223        await submitTransactionExpectFailAsync(alice, tx);224      };225      await expect(badTransaction()).to.be.rejected;226      227      // Get alice balance 228      const balance: any = (await api.query.nft.fungibleItemList(collectionId, alice.address)).toJSON();229 230      // What to expect231      expect(balance).to.be.not.null;232      expect(balance.Value).to.be.equal(10);233    });234235  });236237});
modifiedtests/src/substrate/get-balance.tsdiffbeforeafterboth
--- a/tests/src/substrate/get-balance.ts
+++ b/tests/src/substrate/get-balance.ts
@@ -3,12 +3,12 @@
 // file 'LICENSE', which is part of this source code package.
 //
 
-import { ApiPromise } from "@polkadot/api";
-import promisifySubstrate from "./promisify-substrate";
-import {AccountInfo} from "@polkadot/types/interfaces/system";
+import { ApiPromise } from '@polkadot/api';
+import {AccountInfo} from '@polkadot/types/interfaces/system';
+import promisifySubstrate from './promisify-substrate';
 
-export default async function getBalance(api: ApiPromise, accounts: string[]): Promise<bigint[]> {
-  const balance = promisifySubstrate(api, (accounts: string[]) => api.query.system.account.multi(accounts));
+export default async function getBalance(api: ApiPromise, accounts: string[]): Promise<Array<bigint>> {
+  const balance = promisifySubstrate(api, (acc: string[]) => api.query.system.account.multi(acc));
   const responce = await balance(accounts) as unknown as AccountInfo[];
-  return responce.map(r => r.data.free.toBigInt().valueOf());
+  return responce.map((r) => r.data.free.toBigInt().valueOf());
 }
modifiedtests/src/substrate/substrate-api.tsdiffbeforeafterboth
--- a/tests/src/substrate/substrate-api.ts
+++ b/tests/src/substrate/substrate-api.ts
@@ -58,21 +58,22 @@
   return TransactionStatus.Fail;
 }
 
-export function submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {
-  return new Promise(async function(resolve, reject) {
+export function
+submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {
+  return new Promise(async (resolve, reject) => {
     try {
       await transaction.signAndSend(sender, ({ events = [], status }) => {
         const transactionStatus = getTransactionStatus(events, status);
 
-        if (transactionStatus == TransactionStatus.Success) {
+        if (transactionStatus === TransactionStatus.Success) {
           resolve(events);
-        } else if (transactionStatus == TransactionStatus.Fail) {
+        } else if (transactionStatus === TransactionStatus.Fail) {
           console.log(`Something went wrong with transaction. Status: ${status}`);
           reject(events);
         }
       });
     } catch (e) {
-      console.log("Error: ", e);
+      console.log('Error: ', e);
       reject(e);
     }
   });
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -3,49 +3,174 @@
 // file 'LICENSE', which is part of this source code package.
 //
 
-import { expect, assert } from "chai";
-import { default as usingApi, submitTransactionAsync } from "./substrate/substrate-api";
-import { alicesPublicKey, bobsPublicKey, ferdiesPublicKey } from "./accounts";
-import privateKey from "./substrate/privateKey";
-import getBalance from "./substrate/get-balance";
-import { BigNumber } from 'bignumber.js';
-import { findUnusedAddress } from './util/helpers'
+import { ApiPromise } from '@polkadot/api';
+import { IKeyringPair } from '@polkadot/types/types';
+import { expect } from 'chai';
+import { alicesPublicKey, bobsPublicKey } from './accounts';
+import getBalance from './substrate/get-balance';
+import privateKey from './substrate/privateKey';
+import { default as usingApi, submitTransactionAsync } from './substrate/substrate-api';
+import {
+  burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess,
+  destroyCollectionExpectSuccess,
+  findUnusedAddress,
+  getCreateCollectionResult,
+  getCreateItemResult,
+  transferExpectFail,
+  transferExpectSuccess,
+} from './util/helpers';
 
-describe('Transfer', () => {
-  it('Balance transfers', async () => {
-    await usingApi(async api => {
+let Alice: IKeyringPair;
+let Bob: IKeyringPair;
+let Charlie: IKeyringPair;
+
+describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
+  it('Balance transfers and check balance', async () => {
+    await usingApi(async (api: ApiPromise) => {
       const [alicesBalanceBefore, bobsBalanceBefore] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);
 
       const alicePrivateKey = privateKey('//Alice');
-      
+
       const transfer = api.tx.balances.transfer(bobsPublicKey, 1n);
-      const result = await submitTransactionAsync(alicePrivateKey, transfer);
+      const events = await submitTransactionAsync(alicePrivateKey, transfer);
+      const result = getCreateItemResult(events);
+      // tslint:disable-next-line:no-unused-expression
+      expect(result.success).to.be.true;
 
       const [alicesBalanceAfter, bobsBalanceAfter] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);
 
+      // tslint:disable-next-line:no-unused-expression
       expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;
+      // tslint:disable-next-line:no-unused-expression
       expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;
     });
   });
 
   it('Inability to pay fees error message is correct', async () => {
-    await usingApi(async api => {
+    await usingApi(async (api) => {
       // Find unused address
       const pk = await findUnusedAddress(api);
 
-      const error = console.error;
-      const log = console.log;
-      console.log = function () {};
-      console.error = function () {};
-  
       const badTransfer = api.tx.balances.transfer(bobsPublicKey, 1n);
-      const badTransaction = async function () { 
-        const result = await submitTransactionAsync(pk, badTransfer);
+      // const events = await submitTransactionAsync(pk, badTransfer);
+      const badTransaction = async () => {
+        const events = await submitTransactionAsync(pk, badTransfer);
+        const result = getCreateCollectionResult(events);
+        // tslint:disable-next-line:no-unused-expression
+        expect(result.success).to.be.false;
       };
-      await expect(badTransaction()).to.be.rejectedWith("Inability to pay some fees");
+      expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees , e.g. account balance too low');
+    });
+  });
 
-      console.log = log;
-      console.error = error;
+  it('Create collection, balance transfers and check balance', async () => {
+    await usingApi(async (api) => {
+      const Alice = privateKey('//Alice');
+      const Bob = privateKey('//Bob');
+      // nft
+      const nftCollectionId = await createCollectionExpectSuccess();
+      const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
+      await transferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');
+      // fungible
+      const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+      const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
+      await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
+      // reFungible
+      const reFungibleCollectionId = await
+        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
+      await transferExpectSuccess(reFungibleCollectionId,
+        newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');
     });
   });
 });
+
+describe('Negative Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
+  before(async () => {
+    await usingApi(async (api: ApiPromise) => {
+      Alice = privateKey('//Alice');
+      Bob = privateKey('//Bob');
+      Charlie = privateKey('//Charlie');
+    });
+  });
+  it('Transfer with not existed collection_id', async () => {
+    await usingApi(async (api) => {
+      // nft
+      const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
+      await transferExpectFail(nftCollectionCount + 1, 1, Alice, Bob, 1);
+      // fungible
+      const fungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
+      await transferExpectFail(fungibleCollectionCount + 1, 1, Alice, Bob, 1);
+      // reFungible
+      const reFungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
+      await transferExpectFail(reFungibleCollectionCount + 1, 1, Alice, Bob, 1);
+    });
+  });
+  it('Transfer with deleted collection_id', async () => {
+    // nft
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
+    await destroyCollectionExpectSuccess(nftCollectionId);
+    await transferExpectFail(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');
+    // fungible
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
+    await destroyCollectionExpectSuccess(fungibleCollectionId);
+    await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
+    // reFungible
+    const reFungibleCollectionId = await
+      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
+    await destroyCollectionExpectSuccess(reFungibleCollectionId);
+    await transferExpectFail(reFungibleCollectionId,
+      newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');
+  });
+  it('Transfer with not existed item_id', async () => {
+    // nft
+    const nftCollectionId = await createCollectionExpectSuccess();
+    await transferExpectFail(nftCollectionId, 2, Alice, Bob, 1, 'NFT');
+    // fungible
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    await transferExpectFail(fungibleCollectionId, 2, Alice, Bob, 1, 'Fungible');
+    // reFungible
+    const reFungibleCollectionId = await
+      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    await transferExpectFail(reFungibleCollectionId,
+      2, Alice, Bob, 1, 'ReFungible');
+  });
+  it('Transfer with deleted item_id', async () => {
+    // nft
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
+    await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, 1);
+    await transferExpectFail(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');
+    // fungible
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
+    await burnItemExpectSuccess(Alice, fungibleCollectionId, newFungibleTokenId, 10);
+    await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
+    // reFungible
+    const reFungibleCollectionId = await
+      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
+    await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1);
+    await transferExpectFail(reFungibleCollectionId,
+      newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');
+  });
+  it('Transfer with recipient that is not owner', async () => {
+    // nft
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
+    await transferExpectFail(nftCollectionId, newNftTokenId, Charlie, Bob, 1, 'NFT');
+    // fungible
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
+    await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Charlie, Bob, 1, 'Fungible');
+    // reFungible
+    const reFungibleCollectionId = await
+      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
+    await transferExpectFail(reFungibleCollectionId,
+      newReFungibleTokenId, Charlie, Bob, 1, 'ReFungible');
+  });
+});
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -391,6 +391,22 @@
   ReFungible: CreateReFungibleData;
 }
 
+export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {
+  await usingApi(async (api) => {
+    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);
+    const events = await submitTransactionAsync(owner, tx);
+    const result = getGenericResult(events);
+    // Get the item
+    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();
+    // What to expect
+    // tslint:disable-next-line:no-unused-expression
+    expect(result.success).to.be.true;
+    // tslint:disable-next-line:no-unused-expression
+    expect(item).to.be.not.null;
+    expect(item.Owner).to.be.equal(nullPublicKey);
+  });
+}
+
 export async function
 approveExpectSuccess(collectionId: number,
                      tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number = 1) {
@@ -462,6 +478,58 @@
 }
 
 export async function
+transferExpectSuccess(collectionId: number,
+                      tokenId: number,
+                      sender: IKeyringPair,
+                      recipient: IKeyringPair,
+                      value: number = 1,
+                      type: string = 'NFT') {
+  await usingApi(async (api: ApiPromise) => {
+    let balanceBefore = new BN(0);
+    if (type === 'Fungible') {
+      balanceBefore = await api.query.nft.balance(collectionId, recipient.address) as unknown as BN;
+    }
+    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value);
+    const events = await submitTransactionAsync(sender, transferTx);
+    const result = getCreateItemResult(events);
+    // tslint:disable-next-line:no-unused-expression
+    expect(result.success).to.be.true;
+    if (type === 'NFT') {
+      const nftItemData = await api.query.nft.nftItemList(collectionId, tokenId) as unknown as ITokenDataType;
+      expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);
+    }
+    if (type === 'Fungible') {
+      const balanceAfter = await api.query.nft.balance(collectionId, recipient.address) as unknown as BN;
+      expect(balanceAfter.sub(balanceBefore).toNumber()).to.be.equal(value);
+    }
+    if (type === 'ReFungible') {
+      const nftItemData =
+        await api.query.nft.reFungibleItemList(collectionId, tokenId) as unknown as IReFungibleTokenDataType;
+      expect(nftItemData.Owner[0].Owner.toString()).to.be.equal(recipient.address);
+      expect(nftItemData.Owner[0].Fraction.toNumber()).to.be.equal(value);
+    }
+  });
+}
+
+export async function
+transferExpectFail(collectionId: number,
+                   tokenId: number,
+                   sender: IKeyringPair,
+                   recipient: IKeyringPair,
+                   value: number = 1,
+                   type: string = 'NFT') {
+  await usingApi(async (api: ApiPromise) => {
+    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value);
+    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;
+    if (events && Array.isArray(events)) {
+      const result = getCreateCollectionResult(events);
+      // tslint:disable-next-line:no-unused-expression
+      expect(result.success).to.be.false;
+    }
+  });
+}
+
+export async function
 approveExpectFail(collectionId: number,
                   tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number = 1) {
   await usingApi(async (api: ApiPromise) => {
@@ -473,7 +541,8 @@
   });
 }
 
-export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: string = '') {
+export async function createItemExpectSuccess(
+  sender: IKeyringPair, collectionId: number, createMode: string, owner: string = '') {
   let newItemId: number = 0;
   await usingApi(async (api) => {
     const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);
@@ -525,6 +594,7 @@
     const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
 
     // What to expect
+    // tslint:disable-next-line:no-unused-expression
     expect(result.success).to.be.true;
     expect(collection.Access).to.be.equal('WhiteList');
   });
@@ -559,6 +629,7 @@
     const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
 
     // What to expect
+    // tslint:disable-next-line:no-unused-expression
     expect(result.success).to.be.true;
     expect(collection.MintMode).to.be.equal(true);
   });