difftreelog
Merge pull request #60 from usetech-llc/feature/NFTPAR-241
in: master
Feature/nftpar 241
4 files changed
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -27,6 +27,7 @@
"testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts",
"testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts",
"testCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",
+ "testCreateMultipleItems": "mocha --timeout 9999999 -r ts-node/register ./**/createMultipleItems.test.ts",
"testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts",
"testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",
"testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",
tests/src/createMultipleItems.test.tsdiffbeforeafterboth--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -2,68 +2,177 @@
// This file is subject to the terms and conditions defined in
// file 'LICENSE', which is part of this source code package.
//
+import { ApiPromise } from '@polkadot/api';
+import BN from 'bn.js';
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import privateKey from './substrate/privateKey';
+import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
+import {
+ createCollectionExpectSuccess,
+ destroyCollectionExpectSuccess,
+ IReFungibleTokenDataType,
+} from './util/helpers';
-import { assert } from 'chai';
-import { alicesPublicKey } from './accounts';
-import privateKey from './substrate/privateKey';
-import usingApi from './substrate/substrate-api';
-import waitNewBlocks from './substrate/wait-new-blocks';
+chai.use(chaiAsPromised);
+const expect = chai.expect;
-const idCollection = 12;
+interface ITokenDataType {
+ Owner: number[];
+ ConstData: number[];
+ VariableData: number[];
+}
-describe.skip('integration test: ext. createMultipleItems():', () => {
- it('Create two NFT tokens in active NFT collection', async () => {
- await usingApi(async (api) => {
- const AitemListIndex = await api.query.nft.itemListIndex(idCollection);
- console.log(`itemListIndex count (before): ${AitemListIndex}`);
- const args = ['NFT', 'NFT'];
- const alicePrivateKey = privateKey('//Alice');
- const createMultipleItems = await api.tx.nft
- .createMultipleItems(idCollection, alicesPublicKey, args)
- .signAndSend(alicePrivateKey);
- // tslint:disable-next-line: no-unused-expression
- assert.exists(createMultipleItems, 'createMultipleItems is neither `null` or `undefined`');
- console.log(`Ext. createMultipleItems submitted with hash: ${createMultipleItems}`);
- await waitNewBlocks(api);
- const BitemListIndex = await api.query.nft.itemListIndex(idCollection);
- console.log(`itemListIndex count (after): ${BitemListIndex}`);
- if (BitemListIndex === AitemListIndex) { assert.fail('Corret token not added in collection!'); }
+describe('Integration Test createMultipleItems(collection_id, owner, items_data):', () => {
+ it('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => {
+ await usingApi(async (api: ApiPromise) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const itemsListIndexBefore = await api.query.nft.itemListIndex(collectionId) as unknown as BN;
+ expect(itemsListIndexBefore.toNumber()).to.be.equal(0);
+ const Alice = privateKey('//Alice');
+ const args = [{ nft: ['0x31', '0x31'] }, { nft: ['0x32', '0x32'] }, { nft: ['0x33', '0x33'] }];
+ const createMultipleItemsTx = await api.tx.nft
+ .createMultipleItems(collectionId, Alice.address, args);
+ await submitTransactionAsync(Alice, createMultipleItemsTx);
+ const itemsListIndexAfter = await api.query.nft.itemListIndex(collectionId) as unknown as BN;
+ expect(itemsListIndexAfter.toNumber()).to.be.equal(3);
+ const token1Data = await api.query.nft.nftItemList(collectionId, 1) as unknown as ITokenDataType;
+ const token2Data = await api.query.nft.nftItemList(collectionId, 2) as unknown as ITokenDataType;
+ const token3Data = await api.query.nft.nftItemList(collectionId, 3) as unknown as ITokenDataType;
+
+ expect(token1Data.Owner.toString()).to.be.equal(Alice.address);
+ expect(token2Data.Owner.toString()).to.be.equal(Alice.address);
+ expect(token3Data.Owner.toString()).to.be.equal(Alice.address);
+
+ expect(token1Data.ConstData.toString()).to.be.equal('0x31');
+ expect(token2Data.ConstData.toString()).to.be.equal('0x32');
+ expect(token3Data.ConstData.toString()).to.be.equal('0x33');
+
+ expect(token1Data.VariableData.toString()).to.be.equal('0x31');
+ expect(token2Data.VariableData.toString()).to.be.equal('0x32');
+ expect(token3Data.VariableData.toString()).to.be.equal('0x33');
});
});
- it('(!negative test!) Create two Fungible tokens in active NFT collection', async () => {
- await usingApi(async (api) => {
- const AitemListIndex = await api.query.nft.itemListIndex(idCollection);
- console.log(`itemListIndex count (before): ${AitemListIndex}`);
- const args = ['Fungible', 'Fungible'];
- const alicePrivateKey = privateKey('//Alice');
- const createMultipleItems = await api.tx.nft
- .createMultipleItems(idCollection, alicesPublicKey, args)
- .signAndSend(alicePrivateKey);
- // tslint:disable-next-line: no-unused-expression
- assert.exists(createMultipleItems, 'createMultipleItems is neither `null` or `undefined`');
- console.log(`Ext. createMultipleItems submitted with hash: ${createMultipleItems}`);
- await waitNewBlocks(api);
- const BitemListIndex = await api.query.nft.itemListIndex(idCollection);
- console.log(`itemListIndex count (after): ${BitemListIndex}`);
- if (BitemListIndex > AitemListIndex) { assert.fail('Incorrect token added in collection!'); }
+
+ it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
+ await usingApi(async (api: ApiPromise) => {
+ const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+ const itemsListIndexBefore = await api.query.nft.itemListIndex(collectionId) as unknown as BN;
+ expect(itemsListIndexBefore.toNumber()).to.be.equal(0);
+ const Alice = privateKey('//Alice');
+ const args = [
+ { Refungible: ['0x31', '0x31'] },
+ { Refungible: ['0x32', '0x32'] },
+ { Refungible: ['0x33', '0x33'] },
+ ];
+ const createMultipleItemsTx = await api.tx.nft
+ .createMultipleItems(collectionId, Alice.address, args);
+ await submitTransactionAsync(Alice, createMultipleItemsTx);
+ const itemsListIndexAfter = await api.query.nft.itemListIndex(collectionId) as unknown as BN;
+ expect(itemsListIndexAfter.toNumber()).to.be.equal(3);
+ const token1Data = await api.query.nft.reFungibleItemList(collectionId, 1) as unknown as IReFungibleTokenDataType;
+ const token2Data = await api.query.nft.reFungibleItemList(collectionId, 2) as unknown as IReFungibleTokenDataType;
+ const token3Data = await api.query.nft.reFungibleItemList(collectionId, 3) as unknown as IReFungibleTokenDataType;
+
+ expect(token1Data.Owner[0].Owner.toString()).to.be.equal(Alice.address);
+ expect(token1Data.Owner[0].Fraction.toNumber()).to.be.equal(1);
+
+ expect(token2Data.Owner[0].Owner.toString()).to.be.equal(Alice.address);
+ expect(token2Data.Owner[0].Fraction.toNumber()).to.be.equal(1);
+
+ expect(token3Data.Owner[0].Owner.toString()).to.be.equal(Alice.address);
+ expect(token3Data.Owner[0].Fraction.toNumber()).to.be.equal(1);
+
+ expect(token1Data.ConstData.toString()).to.be.equal('0x31');
+ expect(token2Data.ConstData.toString()).to.be.equal('0x32');
+ expect(token3Data.ConstData.toString()).to.be.equal('0x33');
+
+ expect(token1Data.VariableData.toString()).to.be.equal('0x31');
+ expect(token2Data.VariableData.toString()).to.be.equal('0x32');
+ expect(token3Data.VariableData.toString()).to.be.equal('0x33');
});
});
- it('(!negative test!) Create two ReFungible tokens in active NFT collection', async () => {
- await usingApi(async (api) => {
- const AitemListIndex = await api.query.nft.itemListIndex(idCollection);
- console.log(`itemListIndex count (before): ${AitemListIndex}`);
- const args = ['ReFungible', 'ReFungible'];
- const alicePrivateKey = privateKey('//Alice');
- const createMultipleItems = await api.tx.nft
- .createMultipleItems(idCollection, alicesPublicKey, args)
- .signAndSend(alicePrivateKey);
- // tslint:disable-next-line: no-unused-expression
- assert.exists(createMultipleItems, 'createMultipleItems is neither `null` or `undefined`');
- console.log(`Ext. createMultipleItems submitted with hash: ${createMultipleItems}`);
- await waitNewBlocks(api);
- const BitemListIndex = await api.query.nft.itemListIndex(idCollection);
- console.log(`itemListIndex count (after): ${BitemListIndex}`);
- if (BitemListIndex > AitemListIndex) { assert.fail('Incorrect token added in collection!'); }
+});
+
+describe('Negative Integration Test createMultipleItems(collection_id, owner, items_data):', () => {
+ it('Create token with not existing type', async () => {
+ await usingApi(async (api: ApiPromise) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const Alice = privateKey('//Alice');
+ try {
+ const args = [{ invalid: null }, { invalid: null }, { invalid: null }];
+ const createMultipleItemsTx = await api.tx.nft
+ .createMultipleItems(collectionId, Alice.address, args);
+ await expect(submitTransactionExpectFailAsync(Alice, createMultipleItemsTx)).to.be.rejected;
+ } catch (e) {
+ // tslint:disable-next-line:no-unused-expression
+ expect(e).to.be.exist;
+ }
+ });
+ });
+
+ it('Create token in not existing collection', async () => {
+ await usingApi(async (api: ApiPromise) => {
+ const collectionId = parseInt((await api.query.nft.createdCollectionCount()).toString()) + 1;
+ const Alice = privateKey('//Alice');
+ const createMultipleItemsTx = await api.tx.nft
+ .createMultipleItems(collectionId, Alice.address, ['NFT', 'NFT', 'NFT']);
+ await expect(submitTransactionExpectFailAsync(Alice, createMultipleItemsTx)).to.be.rejected;
+ });
+ });
+
+ it('Create NFT and Re-fungible tokens that has reached the maximum data limit', async () => {
+ await usingApi(async (api: ApiPromise) => {
+ // NFT
+ const collectionId = await createCollectionExpectSuccess();
+ const Alice = privateKey('//Alice');
+ const args = [
+ { nft: ['A'.repeat(2049), 'A'.repeat(2049)] },
+ { nft: ['B'.repeat(2049), 'B'.repeat(2049)] },
+ { nft: ['C'.repeat(2049), 'C'.repeat(2049)] },
+ ];
+ const createMultipleItemsTx = await api.tx.nft
+ .createMultipleItems(collectionId, Alice.address, args);
+ await expect(submitTransactionExpectFailAsync(Alice, createMultipleItemsTx)).to.be.rejected;
+
+ // ReFungible
+ const collectionIdReFungible =
+ await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+ const argsReFungible = [
+ { ReFungible: ['1'.repeat(2049), '1'.repeat(2049)] },
+ { ReFungible: ['2'.repeat(2049), '2'.repeat(2049)] },
+ { ReFungible: ['3'.repeat(2049), '3'.repeat(2049)] },
+ ];
+ const createMultipleItemsTxFungible = await api.tx.nft
+ .createMultipleItems(collectionIdReFungible, Alice.address, argsReFungible);
+ await expect(submitTransactionExpectFailAsync(Alice, createMultipleItemsTxFungible)).to.be.rejected;
+ });
+ });
+
+ it('Create tokens with different types', async () => {
+ await usingApi(async (api: ApiPromise) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const Alice = privateKey('//Alice');
+ const createMultipleItemsTx = await api.tx.nft
+ .createMultipleItems(collectionId, Alice.address, ['NFT', 'Fungible', 'ReFungible']);
+ await expect(submitTransactionExpectFailAsync(Alice, createMultipleItemsTx)).to.be.rejected;
+ // garbage collection :-D
+ await destroyCollectionExpectSuccess(collectionId);
+ });
+ });
+
+ it('Create tokens with different data limits <> maximum data limit', async () => {
+ await usingApi(async (api: ApiPromise) => {
+ const collectionId = await createCollectionExpectSuccess();
+ const Alice = privateKey('//Alice');
+ const args = [
+ { nft: ['A', 'A'] },
+ { nft: ['B', 'B'.repeat(2049)] },
+ { nft: ['C'.repeat(2049), 'C'] },
+ ];
+ const createMultipleItemsTx = await api.tx.nft
+ .createMultipleItems(collectionId, Alice.address, args);
+ await expect(submitTransactionExpectFailAsync(Alice, createMultipleItemsTx)).to.be.rejected;
});
});
});
tests/src/substrate/substrate-api.tsdiffbeforeafterboth1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { WsProvider, ApiPromise } from "@polkadot/api";7import { EventRecord } from '@polkadot/types/interfaces/system/types';8import { ExtrinsicStatus } from '@polkadot/types/interfaces/author/types';9import { IKeyringPair } from "@polkadot/types/types";1011import config from "../config";12import promisifySubstrate from "./promisify-substrate";13import { ApiOptions, SubmittableExtrinsic, ApiTypes } from "@polkadot/api/types";14import rtt from "../../../runtime_types.json";1516function defaultApiOptions(): ApiOptions {17 const wsProvider = new WsProvider(config.substrateUrl);18 return { provider: wsProvider, types: rtt };19}2021export default async function usingApi(action: (api: ApiPromise) => Promise<void>, settings: ApiOptions | undefined = undefined): Promise<void> {22 settings = settings || defaultApiOptions();23 let api: ApiPromise = new ApiPromise(settings);2425 // TODO: Remove, this is temporary: Filter unneeded API output 26 // (Jaco promised it will be removed in the next version)27 const consoleLog = console.log;28 console.log = (message: string) => {29 if (message.includes("API/INIT: Capabilities detected") || message.includes("2021-")) {}30 else if (message.includes("StorageChangeSet:: WebSocket is not connected") || message.includes("2021-")) {}31 else consoleLog(message);32 };33 const consoleErr = console.error;34 console.error = (message: string) => {35 if (message.includes("StorageChangeSet:: WebSocket is not connected") || message.includes("2021-")) {}36 else consoleErr(message);37 };3839 try {40 await promisifySubstrate(api, async () => {41 if(api) {42 await api.isReadyOrError;43 await action(api);44 }45 })();46 } finally {47 await api.disconnect();48 console.log = consoleLog;49 console.error = consoleErr;50 }51}5253enum TransactionStatus {54 Success,55 Fail,56 NotReady57}5859function getTransactionStatus(events: EventRecord[], status: ExtrinsicStatus): TransactionStatus {60 if (status.isReady) {61 return TransactionStatus.NotReady;62 }63 if (status.isBroadcast) {64 return TransactionStatus.NotReady;65 } 66 if (status.isInBlock || status.isFinalized) {67 if(events.filter(e => e.event.data.method === 'ExtrinsicFailed').length > 0) {68 return TransactionStatus.Fail;69 }70 if(events.filter(e => e.event.data.method === 'ExtrinsicSuccess').length > 0) {71 return TransactionStatus.Success;72 }73 }7475 return TransactionStatus.Fail;76}7778export function79submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {80 return new Promise(async (resolve, reject) => {81 try {82 await transaction.signAndSend(sender, ({ events = [], status }) => {83 const transactionStatus = getTransactionStatus(events, status);8485 if (transactionStatus === TransactionStatus.Success) {86 resolve(events);87 } else if (transactionStatus === TransactionStatus.Fail) {88 console.log(`Something went wrong with transaction. Status: ${status}`);89 reject(events);90 }91 });92 } catch (e) {93 console.log('Error: ', e);94 reject(e);95 }96 });97}9899export function submitTransactionExpectFailAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {100 const consoleError = console.error;101 const consoleLog = console.log;102 console.error = () => {};103 console.log = () => {};104105 return new Promise<EventRecord[]>(async function(res, rej) {106 const resolve = (rec: EventRecord[]) => {107 setTimeout(() => {108 res(rec);109 console.error = consoleError;110 console.log = consoleLog;111 });112 };113 const reject = (errror: any) => {114 setTimeout(() => {115 rej(errror);116 console.error = consoleError;117 console.log = consoleLog;118 });119 };120 try {121 await transaction.signAndSend(sender, ({ events = [], status }) => {122 const transactionStatus = getTransactionStatus(events, status);123124 // console.log('transactionStatus', transactionStatus, 'events', events);125126 if (transactionStatus == TransactionStatus.Success) {127 resolve(events);128 } else if (transactionStatus == TransactionStatus.Fail) {129 reject(events);130 }131 });132 } catch (e) {133 reject(e);134 }135 });136}tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -51,7 +51,7 @@
Value: BN;
}
-interface IReFungibleTokenDataType {
+export interface IReFungibleTokenDataType {
Owner: IReFungibleOwner[];
ConstData: number[];
VariableData: number[];