@unique-nft/api
Version:
Definitely typed JS API for the Unique Network blockchain
316 lines (258 loc) • 12.7 kB
text/typescript
import {SchemaTools, UniqueCollectionSchemaDecoded} from "../schema";
import {Substrate, SubstrateUnique} from "../substrate";
import {init, KeyringPair} from "../index";
import {beforeAll, describe, expect, test} from "vitest";
import * as dotenv from "dotenv";
import fs from "fs";
import {Address} from "../utils";
import {dungeonsAndHeroesSchema, assassinToken, knightToken, wizardToken} from './samples/dungeonsAndHeroes.sample';
interface Context {
chain: SubstrateUnique
keyring1: KeyringPair
keyring2: KeyringPair
collectionId: number
decodedSchema: UniqueCollectionSchemaDecoded
}
let context: Context | undefined;
describe('Integration tests for validateCollectionAttributesSchema', () => {
beforeAll(async () => {
const config = dotenv.parse(fs.readFileSync('./src/test/.test.env').toString('utf8'))
await init()
const chain = new Substrate.Unique()
await chain.connect(config.NODE_SUB, {uniqueRpcDefinitionsName: 'unique'})
const api = chain.getApi();
if (!api) {
throw Error('Api is not connected.')
}
const keyring1 = Substrate.signer.keyringFromSeed(config.SUB_SEED_1)
const keyring2 = Substrate.signer.keyringFromSeed(config.SUB_SEED_2)
const collectionProperties = SchemaTools.encodeUnique.collectionSchema(dungeonsAndHeroesSchema)
const tokenPropertyPermissions = SchemaTools.encodeUnique.collectionTokenPropertyPermissions(dungeonsAndHeroesSchema)
const knightTokenProperties = SchemaTools.encodeUnique.token(knightToken, dungeonsAndHeroesSchema)
const assassinTokenProperties = SchemaTools.encodeUnique.token(assassinToken, dungeonsAndHeroesSchema)
const wizardTokenProperties = SchemaTools.encodeUnique.token(wizardToken, dungeonsAndHeroesSchema)
const createCollectionResult = await chain.createCollection({collection: {
name: 'Dungeons and heroes',
description: 'Various heroes from the worldwide famous game dungeons and heroes',
tokenPrefix: 'dnh',
properties: collectionProperties,
tokenPropertyPermissions: tokenPropertyPermissions
}
}).signAndSend(keyring1)
const collectionId = createCollectionResult.collectionId;
const tokenData = [
{
owner: Address.to.crossAccountId(keyring1.address),
properties: [
{ key: 'n', value: 'knight (valid token)' },
{ key: 'a.0', value: '0' },
{ key: 'a.1', value: '0' },
{ key: 'i.c', value: '1600081522768-cb2e80ed4491' }
]
},
{ // invalid value 1/3
owner: Address.to.crossAccountId(keyring1.address),
properties: [
{ key: 'n', value: 'assassin test token (invalid token)' },
{ key: 'd', value: 'test' },
{ key: 'a.0', value: '1/3' },
{ key: 'a.1', value: '1,3' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' },
{ key: 'v.c', value: 'mixkit-forest-stream-in-the-sunlight-529-small' }
]
},
{ // Valid name, invalid value
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 123},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '0:2' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
{ // Valid name, invalid i.c
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '0,2' },
{ key: 'i.c', value: '{invalid: image}' }
]
},
{ // invalid v.c
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '0,2' },
{ key: 'v.c', value: '{invalid: video}' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
{ // invalid so.c
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '0,2' },
{ key: 'so.c', value: '{invalid: spatial object}' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
{ // Valid name, invalid i.c
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '0,2' },
{ key: 'i.c', value: '[invalid, image]' }
]
},
{ // invalid v.c
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '0,2' },
{ key: 'v.c', value: '[invalid, video]' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
{ // invalid so.c
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '0,2' },
{ key: 'so.c', value: '[invalid, spatial object]' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
{ // invalid a.1: empty value
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
{ // invalid a.1: string instead of string of numbers
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: 'asdf' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
{ // invalid a.1: object
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: 'test-token'},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '{simple: object}' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
{ // invalid n: empty
owner: Address.to.crossAccountId(keyring2.address),
properties: [
{ key: 'n', value: ''},
{ key: 'a.0', value: '2' },
{ key: 'a.1', value: '1' },
{ key: 'i.c', value: '1598284188955-497134dbc08b' }
]
},
]
const res = await api.tx.unique.createMultipleItemsEx(collectionId, {
NFT: tokenData
}).signAndSend(keyring1)
const getCollectionRes = await chain.getCollection(collectionId)
expect(getCollectionRes?.uniqueSchema).toBeDefined()
console.log('Valid collection created, id:', collectionId)
context = {
chain: chain,
keyring1: keyring1,
keyring2: keyring2,
collectionId: collectionId,
decodedSchema: (getCollectionRes?.uniqueSchema as any).decoded
}
})
test('get valid token', async () => {
const {chain, keyring1, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 1)
const expectedProperties = [
{ key: 'n', value: 'knight (valid token)' },
{ key: 'a.0', value: '0' },
{ key: 'a.1', value: '0' },
{ key: 'i.c', value: '1600081522768-cb2e80ed4491' }
]
const expectedOwner = Address.to.crossAccountId(keyring1.address)
expect(
getTokenRes?.properties.sort((a, b) => a.key > b.key ? 1 : -1)
).toStrictEqual(expectedProperties.sort((a, b) => a.key > b.key ? 1 : -1))
expect(getTokenRes?.owner).toStrictEqual(expectedOwner)
expect(getTokenRes?.uniqueToken).toBeDefined()
})
test('invalid value a.0 == 1/3', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 2)
expect(getTokenRes?.uniqueToken).not.toBeDefined()
})
test('invalid value a.1 == 1:3', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 3, decodedSchema)
expect(getTokenRes?.uniqueToken).not.toBeDefined()
})
test('invalid i.c: object', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 4, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('invalid v.c: object', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 5, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('invalid so.c: object', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 6, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('invalid i.c: array', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 7, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('invalid v.c: array', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 8, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('invalid so.c: array', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 9, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('empty a.1 value', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 10, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('invalid a.1: string instead of string of numbers', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 11, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('invalid a.1: object', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 12, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
test('invalid n: empty', async () => {
const {chain, collectionId, decodedSchema} = context!
const getTokenRes = await chain.getToken(collectionId, 13, decodedSchema)
expect(getTokenRes?.uniqueToken.isValid).toBe(false)
})
})