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) }) })