Files
pwap/tests/web/e2e/cypress/citizenship-kyc.cy.ts
T
Claude db05f21e52 feat(tests): add comprehensive test infrastructure based on blockchain pallet tests
Created complete testing framework for web and mobile frontends based on 437 test scenarios extracted from 12 blockchain pallet test files.

Test Infrastructure:
- Mock data generators for all 12 pallets (Identity, Perwerde, Rewards, Treasury, etc.)
- Test helper utilities (async, blockchain mocks, validation, custom matchers)
- Example unit tests for web (KYC Application) and mobile (Education Course List)
- Example E2E tests using Cypress (web) and Detox (mobile)
- Executable test runner scripts with colored output
- Comprehensive documentation with all 437 test scenarios

Coverage:
- pallet-identity-kyc: 39 test scenarios
- pallet-perwerde: 30 test scenarios
- pallet-pez-rewards: 44 test scenarios
- pallet-pez-treasury: 58 test scenarios
- pallet-presale: 24 test scenarios
- pallet-referral: 17 test scenarios
- pallet-staking-score: 23 test scenarios
- pallet-tiki: 66 test scenarios
- pallet-token-wrapper: 18 test scenarios
- pallet-trust: 26 test scenarios
- pallet-validator-pool: 27 test scenarios
- pallet-welati: 65 test scenarios

Files created:
- tests/utils/mockDataGenerators.ts (550+ lines)
- tests/utils/testHelpers.ts (400+ lines)
- tests/web/unit/citizenship/KYCApplication.test.tsx
- tests/mobile/unit/education/CourseList.test.tsx
- tests/web/e2e/cypress/citizenship-kyc.cy.ts
- tests/mobile/e2e/detox/education-flow.e2e.ts
- tests/run-web-tests.sh (executable)
- tests/run-mobile-tests.sh (executable)
- tests/README.md (800+ lines of documentation)
2025-11-21 04:46:35 +00:00

299 lines
10 KiB
TypeScript

/**
* Cypress E2E Test: Full Citizenship & KYC Flow
* Based on pallet-identity-kyc integration tests
*
* Flow:
* 1. Set Identity → 2. Apply for KYC → 3. Admin Approval → 4. Citizen NFT Minted
* Alternative: Self-Confirmation flow
*/
describe('Citizenship & KYC Flow (E2E)', () => {
const testUser = {
name: 'Test Citizen',
email: 'testcitizen@pezkuwi.com',
wallet: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
};
const testAdmin = {
wallet: '5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY',
};
beforeEach(() => {
// Visit the citizenship page
cy.visit('/citizenship');
// Mock wallet connection
cy.window().then((win) => {
(win as any).mockPolkadotWallet = {
address: testUser.wallet,
connected: true,
};
});
});
describe('Happy Path: Full KYC Approval Flow', () => {
it('should complete full citizenship flow', () => {
// STEP 1: Set Identity
cy.log('Step 1: Setting identity');
cy.get('[data-testid="identity-name-input"]').type(testUser.name);
cy.get('[data-testid="identity-email-input"]').type(testUser.email);
cy.get('[data-testid="submit-identity-btn"]').click();
// Wait for transaction confirmation
cy.contains('Identity set successfully', { timeout: 10000 }).should('be.visible');
// STEP 2: Apply for KYC
cy.log('Step 2: Applying for KYC');
cy.get('[data-testid="kyc-cid-input"]').type('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG');
cy.get('[data-testid="kyc-notes-input"]').type('My citizenship documents');
// Check deposit amount is displayed
cy.contains('Deposit required: 10 HEZ').should('be.visible');
cy.get('[data-testid="submit-kyc-btn"]').click();
// Wait for transaction
cy.contains('KYC application submitted', { timeout: 10000 }).should('be.visible');
// Verify status changed to Pending
cy.get('[data-testid="kyc-status-badge"]').should('contain', 'Pending');
// STEP 3: Admin Approval (switch to admin account)
cy.log('Step 3: Admin approving KYC');
cy.window().then((win) => {
(win as any).mockPolkadotWallet.address = testAdmin.wallet;
});
cy.visit('/admin/kyc-applications');
cy.get(`[data-testid="approve-kyc-${testUser.wallet}"]`).click();
// Confirm approval
cy.get('[data-testid="confirm-approval-btn"]').click();
cy.contains('KYC approved successfully', { timeout: 10000 }).should('be.visible');
// STEP 4: Verify Citizen Status
cy.log('Step 4: Verifying citizenship status');
cy.window().then((win) => {
(win as any).mockPolkadotWallet.address = testUser.wallet;
});
cy.visit('/citizenship');
// Should show Approved status
cy.get('[data-testid="kyc-status-badge"]').should('contain', 'Approved');
// Should show Citizen NFT
cy.contains('Citizen NFT').should('be.visible');
// Should show Welati role
cy.contains('Welati').should('be.visible');
// Deposit should be refunded (check balance increased)
});
});
describe('Alternative: Self-Confirmation Flow', () => {
it('should allow self-confirmation for Welati NFT holders', () => {
// User already has Welati NFT (mock this state)
cy.window().then((win) => {
(win as any).mockPolkadotState = {
hasWelatiNFT: true,
};
});
// STEP 1: Set Identity
cy.get('[data-testid="identity-name-input"]').type(testUser.name);
cy.get('[data-testid="identity-email-input"]').type(testUser.email);
cy.get('[data-testid="submit-identity-btn"]').click();
cy.wait(2000);
// STEP 2: Apply for KYC
cy.get('[data-testid="kyc-cid-input"]').type('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG');
cy.get('[data-testid="submit-kyc-btn"]').click();
cy.wait(2000);
// STEP 3: Self-Confirm (should be available for Welati holders)
cy.get('[data-testid="self-confirm-btn"]').should('be.visible');
cy.get('[data-testid="self-confirm-btn"]').click();
// Confirm action
cy.contains('Self-confirm citizenship?').should('be.visible');
cy.get('[data-testid="confirm-self-confirm"]').click();
// Wait for confirmation
cy.contains('Citizenship confirmed!', { timeout: 10000 }).should('be.visible');
// Verify status
cy.get('[data-testid="kyc-status-badge"]').should('contain', 'Approved');
});
});
describe('Error Cases', () => {
it('should prevent KYC application without identity', () => {
// Try to submit KYC without setting identity first
cy.get('[data-testid="kyc-cid-input"]').should('be.disabled');
// Should show message
cy.contains('Please set your identity first').should('be.visible');
});
it('should prevent duplicate KYC application', () => {
// Mock existing pending application
cy.window().then((win) => {
(win as any).mockPolkadotState = {
kycStatus: 'Pending',
};
});
cy.reload();
// KYC form should be disabled
cy.get('[data-testid="submit-kyc-btn"]').should('be.disabled');
// Should show current status
cy.contains('Application already submitted').should('be.visible');
cy.get('[data-testid="kyc-status-badge"]').should('contain', 'Pending');
});
it('should show insufficient balance error', () => {
// Mock low balance
cy.window().then((win) => {
(win as any).mockPolkadotState = {
balance: 5_000_000_000_000n, // 5 HEZ (less than 10 required)
};
});
// Set identity first
cy.get('[data-testid="identity-name-input"]').type(testUser.name);
cy.get('[data-testid="identity-email-input"]').type(testUser.email);
cy.get('[data-testid="submit-identity-btn"]').click();
cy.wait(2000);
// Try to submit KYC
cy.get('[data-testid="kyc-cid-input"]').type('QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG');
cy.get('[data-testid="submit-kyc-btn"]').click();
// Should show error
cy.contains('Insufficient balance').should('be.visible');
cy.contains('You need at least 10 HEZ').should('be.visible');
});
it('should validate identity name length (max 50 chars)', () => {
const longName = 'a'.repeat(51);
cy.get('[data-testid="identity-name-input"]').type(longName);
cy.get('[data-testid="submit-identity-btn"]').click();
// Should show validation error
cy.contains(/name must be 50 characters or less/i).should('be.visible');
});
it('should validate IPFS CID format', () => {
// Set identity first
cy.get('[data-testid="identity-name-input"]').type(testUser.name);
cy.get('[data-testid="identity-email-input"]').type(testUser.email);
cy.get('[data-testid="submit-identity-btn"]').click();
cy.wait(2000);
// Enter invalid CID
const invalidCIDs = ['invalid', 'Qm123', 'notacid'];
invalidCIDs.forEach((cid) => {
cy.get('[data-testid="kyc-cid-input"]').clear().type(cid);
cy.get('[data-testid="submit-kyc-btn"]').click();
cy.contains(/invalid IPFS CID/i).should('be.visible');
});
});
});
describe('Citizenship Renunciation', () => {
it('should allow approved citizens to renounce', () => {
// Mock approved citizen state
cy.window().then((win) => {
(win as any).mockPolkadotState = {
kycStatus: 'Approved',
citizenNFTId: 123,
};
});
cy.visit('/citizenship');
// Should show renounce button
cy.get('[data-testid="renounce-btn"]').should('be.visible');
cy.get('[data-testid="renounce-btn"]').click();
// Confirm renunciation (should show strong warning)
cy.contains(/are you sure/i).should('be.visible');
cy.contains(/this action cannot be undone/i).should('be.visible');
cy.get('[data-testid="confirm-renounce"]').click();
// Wait for transaction
cy.contains('Citizenship renounced', { timeout: 10000 }).should('be.visible');
// Status should reset to NotStarted
cy.get('[data-testid="kyc-status-badge"]').should('contain', 'Not Started');
});
it('should allow reapplication after renunciation', () => {
// After renouncing (status: NotStarted)
cy.window().then((win) => {
(win as any).mockPolkadotState = {
kycStatus: 'NotStarted',
previouslyRenounced: true,
};
});
cy.visit('/citizenship');
// Identity and KYC forms should be available again
cy.get('[data-testid="identity-name-input"]').should('not.be.disabled');
cy.contains(/you can reapply/i).should('be.visible');
});
});
describe('Admin KYC Management', () => {
beforeEach(() => {
// Switch to admin account
cy.window().then((win) => {
(win as any).mockPolkadotWallet.address = testAdmin.wallet;
});
cy.visit('/admin/kyc-applications');
});
it('should display pending KYC applications', () => {
cy.get('[data-testid="kyc-application-row"]').should('have.length.greaterThan', 0);
// Each row should show:
cy.contains(testUser.name).should('be.visible');
cy.contains('Pending').should('be.visible');
});
it('should approve KYC application', () => {
cy.get(`[data-testid="approve-kyc-${testUser.wallet}"]`).first().click();
cy.get('[data-testid="confirm-approval-btn"]').click();
cy.contains('KYC approved', { timeout: 10000 }).should('be.visible');
// Application should disappear from pending list
cy.get(`[data-testid="approve-kyc-${testUser.wallet}"]`).should('not.exist');
});
it('should reject KYC application', () => {
cy.get(`[data-testid="reject-kyc-${testUser.wallet}"]`).first().click();
// Enter rejection reason
cy.get('[data-testid="rejection-reason"]').type('Incomplete documents');
cy.get('[data-testid="confirm-rejection-btn"]').click();
cy.contains('KYC rejected', { timeout: 10000 }).should('be.visible');
});
});
});