Files
pwap/backend/integration-tests/kyc.test.js
T
pezkuwichain 1295c36241 Rebrand: polkadot → pezkuwi build fixes
- Fixed TypeScript type assertion issues
- Updated imports from api-augment/substrate to api-augment/bizinikiwi
- Fixed imgConvert.mjs header and imports
- Added @ts-expect-error for runtime-converted types
- Fixed all @polkadot copyright headers to @pezkuwi
2026-01-07 02:32:54 +03:00

131 lines
5.2 KiB
JavaScript

import request from 'supertest';
import { ApiPromise, WsProvider, Keyring } from '@pezkuwi/api';
import { app, supabase } from '../src/server.js';
// ========================================
// TEST SETUP
// ========================================
let api;
let keyring;
let sudo;
let councilMember1;
let userToApprove;
const API_URL = 'http://localhost:3001';
// Helper function to wait for the next block to be finalized
const nextBlock = () => new Promise(res => api.rpc.chain.subscribeNewHeads(head => res()));
beforeAll(async () => {
const wsProvider = new WsProvider(process.env.WS_ENDPOINT || 'ws://127.0.0.1:9944');
api = await ApiPromise.create({ provider: wsProvider });
keyring = new Keyring({ type: 'sr25519' });
sudo = keyring.addFromUri('//Alice');
councilMember1 = keyring.addFromUri('//Bob');
userToApprove = keyring.addFromUri('//Charlie');
// Ensure accounts have funds if needed (dev node usually handles this)
console.log('Test accounts initialized.');
}, 40000); // Increase timeout for initial connection
afterAll(async () => {
if (api) await api.disconnect();
});
beforeEach(async () => {
// Clean database tables before each test
await supabase.from('votes').delete().neq('voter_address', 'null');
await supabase.from('kyc_proposals').delete().neq('user_address', 'null');
await supabase.from('council_members').delete().neq('address', 'null');
// Reset relevant blockchain state if necessary
// For example, revoking KYC for the test user to ensure a clean slate
try {
const status = await api.query.identityKyc.kycStatusOf(userToApprove.address);
if (status.isApproved || status.isPending) {
await new Promise((resolve, reject) => {
api.tx.sudo.sudo(
api.tx.identityKyc.revokeKyc(userToApprove.address)
).signAndSend(sudo, ({ status }) => {
if (status.isFinalized) resolve();
});
});
}
} catch(e) { /* Ignore if pallet or storage doesn't exist */ }
}, 20000);
// ========================================
// LIVE INTEGRATION TESTS
// ========================================
describe('KYC Approval Workflow via API', () => {
it('should process a KYC application from proposal to approval', async () => {
// ===============================================================
// PHASE 1: SETUP (Direct Blockchain Interaction & API Setup)
// ===============================================================
// 1a. Add council member to the DB via API
// Note: We are skipping signature checks for now as per previous discussions.
// The endpoint must be temporarily adjusted to allow this for the test.
const addMemberRes = await request(app)
.post('/api/council/add-member')
.send({
newMemberAddress: councilMember1.address,
signature: '0x00',
message: `addCouncilMember:${councilMember1.address}`
});
expect(addMemberRes.statusCode).toBe(200);
// 1b. User sets identity and applies for KYC (direct blockchain tx)
await api.tx.identityKyc.setIdentity("Charlie", "charlie@test.com").signAndSend(userToApprove);
await api.tx.identityKyc.applyForKyc([], "Notes").signAndSend(userToApprove);
await nextBlock(); // Wait for tx to be included
let kycStatus = await api.query.identityKyc.kycStatusOf(userToApprove.address);
expect(kycStatus.toString()).toBe('Pending');
// ===============================================================
// PHASE 2: ACTION (API Interaction)
// ===============================================================
// 2a. Council member proposes the user for KYC approval via API
const proposeRes = await request(app)
.post('/api/kyc/propose')
.send({
userAddress: userToApprove.address,
proposerAddress: councilMember1.address,
signature: '0x00', // Skipped
message: `proposeKYC:${userToApprove.address}`
});
expect(proposeRes.statusCode).toBe(201);
// In a multi-member scenario, more votes would be needed here.
// Since our checkAndExecute has a threshold of 60% and we have 1 member,
// this single "propose" action (which includes an auto "aye" vote)
// should be enough to trigger the `approve_kyc` transaction.
// Wait for the backend's async `checkAndExecute` to finalize the tx
console.log("Waiting for backend to execute and finalize the transaction...");
await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
// ===============================================================
// PHASE 3: VERIFICATION (Direct Blockchain Query)
// ===============================================================
// 3a. Verify the user's KYC status is now "Approved" on-chain
kycStatus = await api.query.identityKyc.kycStatusOf(userToApprove.address);
expect(kycStatus.toString()).toBe('Approved');
// 3b. Verify the proposal is marked as "executed" in the database
const { data: proposal, error } = await supabase
.from('kyc_proposals')
.select('executed')
.eq('user_address', userToApprove.address)
.single();
expect(error).toBeNull();
expect(proposal.executed).toBe(true);
});
});