/** * @file: tiki.live.test.js * @description: Live integration tests for the Tiki pallet. * * @preconditions: * 1. A local Pezkuwi dev node must be running and accessible at `ws://127.0.0.1:8082`. * 2. The node must have the `tiki` pallet. * 3. The tests require a funded sudo account (`//Alice`). */ import { ApiPromise, WsProvider, Keyring } from '@pezkuwi/api'; import { jest } from '@jest/globals'; // ======================================== // TEST CONFIGURATION // ======================================== const WS_ENDPOINT = 'ws://127.0.0.1:8082'; jest.setTimeout(90000); // 90 seconds // ======================================== // TEST SETUP & TEARDOWN // ======================================== let api; let keyring; let sudo, user1, user2; // Helper to send a transaction and wait for it to be finalized const sendAndFinalize = (tx, signer) => { return new Promise((resolve, reject) => { tx.signAndSend(signer, ({ status, dispatchError }) => { if (status.isFinalized) { if (dispatchError) { const decoded = api.registry.findMetaError(dispatchError.asModule); reject(new Error(`${decoded.section}.${decoded.name}`)); } else { resolve(); } } }).catch(reject); }); }; beforeAll(async () => { const wsProvider = new WsProvider(WS_ENDPOINT); api = await ApiPromise.create({ provider: wsProvider }); keyring = new Keyring({ type: 'sr25519' }); sudo = keyring.addFromUri('//Alice'); user1 = keyring.addFromUri('//Charlie'); user2 = keyring.addFromUri('//Dave'); console.log('Connected to node and initialized accounts for Tiki tests.'); }, 40000); afterAll(async () => { if (api) await api.disconnect(); }); // ======================================== // LIVE PALLET TESTS // ======================================== describe('Tiki Pallet Live Workflow', () => { it('should mint a Citizen NFT, grant/revoke roles, and calculate score correctly', async () => { // ----------------------------------------------------------------- // PHASE 1: MINT CITIZEN NFT // ----------------------------------------------------------------- console.log('PHASE 1: Minting Citizen NFT for User1...'); await sendAndFinalize(api.tx.tiki.forceMintCitizenNft(user1.address), sudo); // Verify NFT exists and Welati role is granted const citizenNft = await api.query.tiki.citizenNft(user1.address); expect(citizenNft.isSome).toBe(true); const userTikis = await api.query.tiki.userTikis(user1.address); expect(userTikis.map(t => t.toString())).toContain('Welati'); console.log('Citizen NFT minted. User1 now has Welati tiki.'); // Verify initial score (Welati = 10 points) let tikiScore = await api.query.tiki.getTikiScore(user1.address); expect(tikiScore.toNumber()).toBe(10); console.log(`Initial Tiki score is ${tikiScore.toNumber()}.`); // ----------------------------------------------------------------- // PHASE 2: GRANT & SCORE // ----------------------------------------------------------------- console.log('PHASE 2: Granting additional roles and verifying score updates...'); // Grant an Appointed role (Wezir = 100 points) await sendAndFinalize(api.tx.tiki.grantTiki(user1.address, { Appointed: 'Wezir' }), sudo); tikiScore = await api.query.tiki.getTikiScore(user1.address); expect(tikiScore.toNumber()).toBe(110); // 10 (Welati) + 100 (Wezir) console.log('Granted Wezir. Score is now 110.'); // Grant an Earned role (Axa = 250 points) await sendAndFinalize(api.tx.tiki.grantEarnedRole(user1.address, { Earned: 'Axa' }), sudo); tikiScore = await api.query.tiki.getTikiScore(user1.address); expect(tikiScore.toNumber()).toBe(360); // 110 + 250 (Axa) console.log('Granted Axa. Score is now 360.'); // ----------------------------------------------------------------- // PHASE 3: REVOKE & SCORE // ----------------------------------------------------------------- console.log('PHASE 3: Revoking a role and verifying score update...'); // Revoke Wezir role (-100 points) await sendAndFinalize(api.tx.tiki.revokeTiki(user1.address, { Appointed: 'Wezir' }), sudo); tikiScore = await api.query.tiki.getTikiScore(user1.address); expect(tikiScore.toNumber()).toBe(260); // 360 - 100 console.log('Revoked Wezir. Score is now 260.'); const finalUserTikis = await api.query.tiki.userTikis(user1.address); expect(finalUserTikis.map(t => t.toString())).not.toContain('Wezir'); }); it('should enforce unique roles', async () => { console.log('Testing unique role enforcement (Serok)...'); const uniqueRole = { Elected: 'Serok' }; // Mint Citizen NFT for user2 await sendAndFinalize(api.tx.tiki.forceMintCitizenNft(user2.address), sudo); // Grant unique role to user1 await sendAndFinalize(api.tx.tiki.grantElectedRole(user1.address, uniqueRole), sudo); const tikiHolder = (await api.query.tiki.tikiHolder(uniqueRole)).unwrap(); expect(tikiHolder.toString()).toBe(user1.address); console.log('Granted unique role Serok to User1.'); // Attempt to grant the same unique role to user2 await expect( sendAndFinalize(api.tx.tiki.grantElectedRole(user2.address, uniqueRole), sudo) ).rejects.toThrow('tiki.RoleAlreadyTaken'); console.log('Verified: Cannot grant the same unique role to a second user.'); }); it('should fail to grant roles to a non-citizen', async () => { console.log('Testing failure for granting role to non-citizen...'); const nonCitizenUser = keyring.addFromUri('//Eve'); await expect( sendAndFinalize(api.tx.tiki.grantTiki(nonCitizenUser.address, { Appointed: 'Wezir' }), sudo) ).rejects.toThrow('tiki.CitizenNftNotFound'); console.log('Verified: Cannot grant role to a user without a Citizen NFT.'); }); });