mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-22 21:47:56 +00:00
1e1c2310c9
- Remove root /home/mamostehp/package.json workspace config - Each project now independent (aligned with CI workflow) - Add SafeAreaProvider mock to jest setup - Add __DEV__ global for React Native tests - Update 4 snapshots for SafeAreaView changes - All 29 test suites pass (122 tests)
349 lines
11 KiB
JavaScript
349 lines
11 KiB
JavaScript
// Jest setup for React Native testing
|
|
// @testing-library/react-native v12.4+ includes matchers by default
|
|
|
|
// Disable Expo's winter module system for tests
|
|
process.env.EXPO_USE_STATIC_RENDERING = 'true';
|
|
global.__ExpoImportMetaRegistry__ = {};
|
|
|
|
// Mock navigation context for @react-navigation/core
|
|
const mockNavigationObject = {
|
|
navigate: jest.fn(),
|
|
goBack: jest.fn(),
|
|
setOptions: jest.fn(),
|
|
addListener: jest.fn(() => () => {}),
|
|
removeListener: jest.fn(),
|
|
replace: jest.fn(),
|
|
reset: jest.fn(),
|
|
canGoBack: jest.fn(() => true),
|
|
isFocused: jest.fn(() => true),
|
|
dispatch: jest.fn(),
|
|
getParent: jest.fn(),
|
|
getState: jest.fn(() => ({
|
|
routes: [],
|
|
index: 0,
|
|
})),
|
|
setParams: jest.fn(),
|
|
};
|
|
|
|
jest.mock('@react-navigation/core', () => {
|
|
const actualCore = jest.requireActual('@react-navigation/core');
|
|
return {
|
|
...actualCore,
|
|
useNavigation: () => mockNavigationObject,
|
|
useRoute: () => ({
|
|
params: {},
|
|
key: 'test-route',
|
|
name: 'TestScreen',
|
|
}),
|
|
useFocusEffect: jest.fn(),
|
|
useIsFocused: () => true,
|
|
};
|
|
});
|
|
|
|
// Mock @react-navigation/native
|
|
jest.mock('@react-navigation/native', () => {
|
|
const actualNav = jest.requireActual('@react-navigation/native');
|
|
return {
|
|
...actualNav,
|
|
useNavigation: () => mockNavigationObject,
|
|
useRoute: () => ({
|
|
params: {},
|
|
key: 'test-route',
|
|
name: 'TestScreen',
|
|
}),
|
|
useFocusEffect: jest.fn(),
|
|
useIsFocused: () => true,
|
|
};
|
|
});
|
|
|
|
// Mock PezkuwiContext globally
|
|
jest.mock('./src/contexts/PezkuwiContext', () => require('./src/__mocks__/contexts/PezkuwiContext'));
|
|
|
|
// Mock AuthContext globally
|
|
jest.mock('./src/contexts/AuthContext', () => require('./src/__mocks__/contexts/AuthContext'));
|
|
|
|
// Mock ThemeContext globally
|
|
jest.mock('./src/contexts/ThemeContext', () => require('./src/__mocks__/contexts/ThemeContext'));
|
|
|
|
// Mock BiometricAuthContext globally
|
|
jest.mock('./src/contexts/BiometricAuthContext', () => require('./src/__mocks__/contexts/BiometricAuthContext'));
|
|
|
|
// Mock react-native-safe-area-context
|
|
jest.mock('react-native-safe-area-context', () => {
|
|
const insets = { top: 0, right: 0, bottom: 0, left: 0 };
|
|
return {
|
|
SafeAreaProvider: ({ children }) => children,
|
|
SafeAreaView: ({ children }) => children,
|
|
useSafeAreaInsets: () => insets,
|
|
useSafeAreaFrame: () => ({ x: 0, y: 0, width: 390, height: 844 }),
|
|
initialWindowMetrics: { insets, frame: { x: 0, y: 0, width: 390, height: 844 } },
|
|
};
|
|
});
|
|
|
|
// Mock expo modules
|
|
jest.mock('expo-linear-gradient', () => ({
|
|
LinearGradient: 'LinearGradient',
|
|
}));
|
|
|
|
// Mock react-native-webview
|
|
jest.mock('react-native-webview', () => ({
|
|
WebView: 'WebView',
|
|
WebViewMessageEvent: {},
|
|
}));
|
|
|
|
jest.mock('expo-secure-store', () => ({
|
|
setItemAsync: jest.fn(() => Promise.resolve()),
|
|
getItemAsync: jest.fn(() => Promise.resolve(null)),
|
|
deleteItemAsync: jest.fn(() => Promise.resolve()),
|
|
}));
|
|
|
|
jest.mock('expo-local-authentication', () => ({
|
|
authenticateAsync: jest.fn(() =>
|
|
Promise.resolve({ success: true })
|
|
),
|
|
hasHardwareAsync: jest.fn(() => Promise.resolve(true)),
|
|
isEnrolledAsync: jest.fn(() => Promise.resolve(true)),
|
|
supportedAuthenticationTypesAsync: jest.fn(() => Promise.resolve([1])), // 1 = FINGERPRINT
|
|
AuthenticationType: {
|
|
FINGERPRINT: 1,
|
|
FACIAL_RECOGNITION: 2,
|
|
IRIS: 3,
|
|
},
|
|
}));
|
|
|
|
// Mock AsyncStorage
|
|
jest.mock('@react-native-async-storage/async-storage', () =>
|
|
require('@react-native-async-storage/async-storage/jest/async-storage-mock')
|
|
);
|
|
|
|
// Mock Polkadot.js (virtual: true because package may not be installed in CI)
|
|
jest.mock('@polkadot/api', () => ({
|
|
ApiPromise: {
|
|
create: jest.fn(() =>
|
|
Promise.resolve({
|
|
isReady: Promise.resolve(true),
|
|
query: {},
|
|
tx: {},
|
|
rpc: {},
|
|
disconnect: jest.fn(),
|
|
})
|
|
),
|
|
},
|
|
WsProvider: jest.fn(),
|
|
}), { virtual: true });
|
|
|
|
// Mock @pezkuwi packages (aliases for @polkadot packages)
|
|
jest.mock('@pezkuwi/api', () => ({
|
|
ApiPromise: {
|
|
create: jest.fn(() =>
|
|
Promise.resolve({
|
|
isReady: Promise.resolve(true),
|
|
query: {
|
|
treasury: {
|
|
treasury: jest.fn(() => Promise.resolve({ toString: () => '1000000000000000' })),
|
|
proposals: {
|
|
entries: jest.fn(() => Promise.resolve([])),
|
|
},
|
|
},
|
|
democracy: {
|
|
referendumInfoOf: {
|
|
entries: jest.fn(() => Promise.resolve([])),
|
|
},
|
|
},
|
|
dynamicCommissionCollective: {
|
|
proposals: jest.fn(() => Promise.resolve([])),
|
|
voting: jest.fn(() => Promise.resolve({ isSome: false })),
|
|
},
|
|
},
|
|
tx: {},
|
|
rpc: {},
|
|
disconnect: jest.fn(),
|
|
})
|
|
),
|
|
},
|
|
WsProvider: jest.fn(),
|
|
}), { virtual: true });
|
|
|
|
jest.mock('@pezkuwi/keyring', () => ({
|
|
Keyring: jest.fn().mockImplementation(() => ({
|
|
addFromUri: jest.fn((mnemonic, meta, type) => ({
|
|
address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
|
|
meta: meta || {},
|
|
type: type || 'sr25519',
|
|
publicKey: new Uint8Array(32),
|
|
sign: jest.fn(),
|
|
verify: jest.fn(),
|
|
})),
|
|
addFromMnemonic: jest.fn((mnemonic, meta, type) => ({
|
|
address: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
|
|
meta: meta || {},
|
|
type: type || 'sr25519',
|
|
publicKey: new Uint8Array(32),
|
|
sign: jest.fn(),
|
|
verify: jest.fn(),
|
|
})),
|
|
getPairs: jest.fn(() => []),
|
|
getPair: jest.fn((address) => ({
|
|
address: address,
|
|
meta: {},
|
|
type: 'sr25519',
|
|
publicKey: new Uint8Array(32),
|
|
sign: jest.fn(),
|
|
verify: jest.fn(),
|
|
})),
|
|
})),
|
|
}), { virtual: true });
|
|
|
|
jest.mock('@pezkuwi/util-crypto', () => ({
|
|
cryptoWaitReady: jest.fn(() => Promise.resolve(true)),
|
|
mnemonicGenerate: jest.fn(() => 'test test test test test test test test test test test junk'),
|
|
mnemonicValidate: jest.fn(() => true),
|
|
}), { virtual: true });
|
|
|
|
// Mock shared lib modules (they use @pezkuwi/api which is not available in CI)
|
|
jest.mock('../shared/lib/tiki', () => ({
|
|
Tiki: {
|
|
Welati: 'Welati',
|
|
Parlementer: 'Parlementer',
|
|
Serok: 'Serok',
|
|
},
|
|
RoleAssignmentType: {},
|
|
TIKI_DISPLAY_NAMES: {},
|
|
TIKI_SCORES: {},
|
|
ROLE_CATEGORIES: {},
|
|
fetchUserTikis: jest.fn(() => Promise.resolve([])),
|
|
isCitizen: jest.fn(() => Promise.resolve(false)),
|
|
calculateTikiScore: jest.fn(() => 0),
|
|
getPrimaryRole: jest.fn(() => 'Welati'),
|
|
getTikiDisplayName: jest.fn((tiki) => tiki),
|
|
getUserRoleCategories: jest.fn(() => []),
|
|
hasTiki: jest.fn(() => false),
|
|
getTikiColor: jest.fn(() => '#22C55E'),
|
|
getTikiEmoji: jest.fn(() => '👤'),
|
|
getTikiBadgeVariant: jest.fn(() => 'default'),
|
|
fetchUserTikiNFTs: jest.fn(() => Promise.resolve([])),
|
|
getCitizenNFTDetails: jest.fn(() => Promise.resolve(null)),
|
|
getAllTikiNFTDetails: jest.fn(() => Promise.resolve([])),
|
|
generateCitizenNumber: jest.fn(() => 'CIT-001'),
|
|
}), { virtual: true });
|
|
|
|
jest.mock('../shared/lib/referral', () => ({
|
|
initiateReferral: jest.fn(() => Promise.resolve()),
|
|
getPendingReferral: jest.fn(() => Promise.resolve(null)),
|
|
getReferralCount: jest.fn(() => Promise.resolve(0)),
|
|
getReferralInfo: jest.fn(() => Promise.resolve(null)),
|
|
calculateReferralScore: jest.fn(() => 0),
|
|
getReferralStats: jest.fn(() => Promise.resolve({ totalReferred: 0, pendingCount: 0, confirmedCount: 0 })),
|
|
getMyReferrals: jest.fn(() => Promise.resolve([])),
|
|
subscribeToReferralEvents: jest.fn(() => jest.fn()),
|
|
}), { virtual: true });
|
|
|
|
jest.mock('../shared/lib/scores', () => ({
|
|
getTrustScore: jest.fn(() => Promise.resolve(0)),
|
|
getTrustScoreDetails: jest.fn(() => Promise.resolve(null)),
|
|
getReferralScore: jest.fn(() => Promise.resolve(0)),
|
|
getReferralCount: jest.fn(() => Promise.resolve(0)),
|
|
getStakingScoreFromPallet: jest.fn(() => Promise.resolve(0)),
|
|
getTikiScore: jest.fn(() => Promise.resolve(0)),
|
|
getAllScores: jest.fn(() => Promise.resolve({
|
|
trustScore: 0,
|
|
referralScore: 0,
|
|
stakingScore: 0,
|
|
tikiScore: 0,
|
|
totalScore: 0,
|
|
})),
|
|
getScoreColor: jest.fn(() => '#22C55E'),
|
|
getScoreRating: jest.fn(() => 'Good'),
|
|
formatScore: jest.fn((score) => String(score)),
|
|
}), { virtual: true });
|
|
|
|
// Mock Supabase
|
|
jest.mock('./src/lib/supabase', () => ({
|
|
supabase: {
|
|
auth: {
|
|
signInWithPassword: jest.fn(),
|
|
signUp: jest.fn(),
|
|
signOut: jest.fn(),
|
|
getSession: jest.fn(() => Promise.resolve({ data: { session: null }, error: null })),
|
|
onAuthStateChange: jest.fn(() => ({
|
|
data: {
|
|
subscription: {
|
|
unsubscribe: jest.fn(),
|
|
},
|
|
},
|
|
})),
|
|
},
|
|
from: jest.fn(() => ({
|
|
select: jest.fn().mockReturnThis(),
|
|
insert: jest.fn().mockReturnThis(),
|
|
update: jest.fn().mockReturnThis(),
|
|
delete: jest.fn().mockReturnThis(),
|
|
eq: jest.fn().mockReturnThis(),
|
|
order: jest.fn().mockReturnThis(),
|
|
single: jest.fn().mockReturnThis(),
|
|
})),
|
|
},
|
|
}));
|
|
|
|
// Mock shared blockchain utilities
|
|
jest.mock('../shared/blockchain', () => ({
|
|
PEZKUWI_NETWORK: {
|
|
name: 'Pezkuwi',
|
|
endpoint: 'wss://rpc.pezkuwichain.io:9944',
|
|
chainId: 'pezkuwi',
|
|
},
|
|
DEFAULT_ENDPOINT: 'ws://127.0.0.1:9944',
|
|
getExplorerUrl: jest.fn((txHash) => `https://explorer.pezkuwichain.app/tx/${txHash}`),
|
|
}));
|
|
|
|
// Mock shared DEX utilities
|
|
jest.mock('../shared/utils/dex', () => ({
|
|
formatTokenBalance: jest.fn((amount, decimals) => '0.00'),
|
|
parseTokenInput: jest.fn((input, decimals) => '0'),
|
|
calculatePriceImpact: jest.fn(() => '0'),
|
|
getAmountOut: jest.fn(() => '0'),
|
|
calculateMinAmount: jest.fn((amount, slippage) => '0'),
|
|
fetchPools: jest.fn(() => Promise.resolve([])),
|
|
fetchUserPositions: jest.fn(() => Promise.resolve([])),
|
|
}));
|
|
|
|
// Mock shared P2P fiat utilities
|
|
jest.mock('../shared/lib/p2p-fiat', () => ({
|
|
getActiveOffers: jest.fn(() => Promise.resolve([])),
|
|
createOffer: jest.fn(() => Promise.resolve({ id: '123' })),
|
|
acceptOffer: jest.fn(() => Promise.resolve(true)),
|
|
}));
|
|
|
|
// Mock shared wallet utilities (handles import.meta)
|
|
jest.mock('../shared/lib/wallet', () => ({
|
|
formatBalance: jest.fn((amount, decimals) => '0.00'),
|
|
parseBalance: jest.fn((amount) => '0'),
|
|
NETWORK_ENDPOINTS: {
|
|
local: 'ws://127.0.0.1:9944',
|
|
testnet: 'wss://testnet.pezkuwichain.io',
|
|
mainnet: 'wss://mainnet.pezkuwichain.io',
|
|
staging: 'wss://staging.pezkuwichain.io',
|
|
beta: 'wss://rpc.pezkuwichain.io:9944',
|
|
},
|
|
}));
|
|
|
|
// Mock shared staking utilities (handles import.meta)
|
|
jest.mock('../shared/lib/staking', () => ({
|
|
formatBalance: jest.fn((amount) => '0.00'),
|
|
NETWORK_ENDPOINTS: {},
|
|
}));
|
|
|
|
// Mock shared citizenship workflow (handles polkadot/extension-dapp)
|
|
jest.mock('../shared/lib/citizenship-workflow', () => ({
|
|
createCitizenshipRequest: jest.fn(() => Promise.resolve({ id: '123' })),
|
|
}));
|
|
|
|
// Note: Alert is mocked in individual test files where needed
|
|
|
|
// Silence console warnings in tests
|
|
global.console = {
|
|
...console,
|
|
warn: jest.fn(),
|
|
error: jest.fn(),
|
|
};
|