2026-02-18 00:19:05 +01:00
import { test } from '@playwright/test' ;
import { Wallet } from 'ethers' ;
import { createWalletContext } from '../../setup/wallet-provider' ;
import { getStackConfig , validateStackHealthy } from '../../setup/stack' ;
import {
createReport ,
connectWallet ,
mintEth ,
buyKrk ,
takeScreenshot ,
logObservation ,
recordAction ,
writeReport ,
attemptStake ,
resetChainState ,
} from './helpers' ;
const STACK_CONFIG = getStackConfig ( ) ;
const STACK_RPC_URL = STACK_CONFIG . rpcUrl ;
const STACK_WEBAPP_URL = STACK_CONFIG . webAppUrl ;
// Persona accounts (Anvil #1-5)
// Note: Pool has limited liquidity - 0.05 ETH buy yields ~3.99 KRK
// Staking 3 KRK leaves enough for upfront tax payment
const PERSONAS = [
{
name : 'Marcus Flash Chen' ,
shortName : 'Marcus' ,
privateKey : '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d' ,
ethToMint : '10' ,
ethToSpend : '0.05' ,
stakeAmount : '3' , // Conservative amount that fits within ~3.99 KRK balance
taxRate : '2' ,
} ,
{
name : 'Sarah Park' ,
shortName : 'Sarah' ,
privateKey : '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a' ,
ethToMint : '10' ,
ethToSpend : '0.05' ,
stakeAmount : '3' ,
taxRate : '2' ,
} ,
{
name : 'Tyler Brooks' ,
shortName : 'Tyler' ,
privateKey : '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6' ,
ethToMint : '10' ,
ethToSpend : '0.05' ,
stakeAmount : '3' ,
taxRate : '2' ,
} ,
{
name : 'Priya Sharma' ,
shortName : 'Priya' ,
privateKey : '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a' ,
ethToMint : '10' ,
ethToSpend : '0.05' ,
stakeAmount : '3' ,
taxRate : '2' ,
} ,
{
name : 'Alex Rivera' ,
shortName : 'Alex' ,
privateKey : '0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba' ,
ethToMint : '10' ,
ethToSpend : '0.05' ,
stakeAmount : '3' ,
taxRate : '2' ,
} ,
] ;
test . describe ( 'All Personas - Fresh Pool State' , ( ) = > {
for ( const persona of PERSONAS ) {
test ( ` ${ persona . name } completes full journey ` , async ( { browser } ) = > {
// Reset chain state before THIS persona
// First call takes initial snapshot, subsequent calls revert to it
console . log ( ` \ n[ORCHESTRATOR] Resetting chain state for ${ persona . name } ... ` ) ;
await resetChainState ( STACK_RPC_URL ) ;
// Validate stack health once at start
if ( persona === PERSONAS [ 0 ] ) {
console . log ( '[ORCHESTRATOR] Validating stack health...' ) ;
await validateStackHealthy ( STACK_CONFIG ) ;
}
const report = createReport ( persona . name ) ;
const address = new Wallet ( persona . privateKey ) . address . toLowerCase ( ) ;
console . log ( ` [ ${ persona . shortName } ] Starting test - fresh pool state ` ) ;
const context = await createWalletContext ( browser , {
privateKey : persona.privateKey ,
rpcUrl : STACK_RPC_URL ,
} ) ;
const page = await context . newPage ( ) ;
page . on ( 'console' , msg = > console . log ( ` [BROWSER] ${ msg . type ( ) } : ${ msg . text ( ) } ` ) ) ;
page . on ( 'pageerror' , error = > console . log ( ` [BROWSER ERROR] ${ error . message } ` ) ) ;
try {
// 1. Navigate to app
await page . goto ( ` ${ STACK_WEBAPP_URL } /app/ ` , { waitUntil : 'domcontentloaded' } ) ;
await page . waitForTimeout ( 2 _000 ) ;
await takeScreenshot ( page , persona . shortName , '1-landing' , report ) ;
logObservation ( persona . shortName , 'Arrived at app' , report ) ;
// 2. Connect wallet
await connectWallet ( page ) ;
await takeScreenshot ( page , persona . shortName , '2-wallet-connected' , report ) ;
recordAction ( 'Connect wallet' , true , undefined , report ) ;
console . log ( ` [ ${ persona . shortName } ] ✅ Wallet connected ` ) ;
// 3. Mint ETH
2026-02-20 17:28:59 +01:00
await page . goto ( ` ${ STACK_WEBAPP_URL } /app/cheats ` ) ;
2026-02-18 00:19:05 +01:00
await page . waitForTimeout ( 1 _000 ) ;
await mintEth ( page , STACK_RPC_URL , address , persona . ethToMint ) ;
await takeScreenshot ( page , persona . shortName , '3-eth-minted' , report ) ;
recordAction ( ` Mint ${ persona . ethToMint } ETH ` , true , undefined , report ) ;
console . log ( ` [ ${ persona . shortName } ] ✅ Minted ${ persona . ethToMint } ETH ` ) ;
// 4. Buy KRK
await buyKrk ( page , persona . ethToSpend ) ;
await takeScreenshot ( page , persona . shortName , '4-krk-purchased' , report ) ;
recordAction ( ` Buy KRK with ${ persona . ethToSpend } ETH ` , true , undefined , report ) ;
console . log ( ` [ ${ persona . shortName } ] ✅ Bought KRK with ${ persona . ethToSpend } ETH ` ) ;
await page . waitForTimeout ( 2 _000 ) ;
// 5. Navigate to stake page
2026-02-20 17:28:59 +01:00
await page . goto ( ` ${ STACK_WEBAPP_URL } /app/stake ` ) ;
2026-02-18 00:19:05 +01:00
await page . waitForTimeout ( 3 _000 ) ;
await takeScreenshot ( page , persona . shortName , '5-stake-page' , report ) ;
// 6. Stake KRK with known working amount
const stakeAmount = persona . stakeAmount ;
console . log ( ` [ ${ persona . shortName } ] Attempting to stake ${ stakeAmount } KRK at ${ persona . taxRate } % tax... ` ) ;
await attemptStake ( page , stakeAmount , persona . taxRate , persona . shortName , report ) ;
await takeScreenshot ( page , persona . shortName , '6-stake-complete' , report ) ;
console . log ( ` [ ${ persona . shortName } ] ✅ Staked ${ stakeAmount } KRK at ${ persona . taxRate } % tax ` ) ;
await page . waitForTimeout ( 2 _000 ) ;
// 7. Verify position exists
2026-02-20 17:28:59 +01:00
await page . goto ( ` ${ STACK_WEBAPP_URL } /app/stake ` ) ;
2026-02-18 00:19:05 +01:00
await page . waitForTimeout ( 2 _000 ) ;
const myPositionsSection = page . locator ( '.my-positions-list, [class*="my-position"], [class*="MyPosition"]' ) . first ( ) ;
const hasPosition = await myPositionsSection . isVisible ( { timeout : 5_000 } ) . catch ( ( ) = > false ) ;
if ( hasPosition ) {
await takeScreenshot ( page , persona . shortName , '7-position-verified' , report ) ;
recordAction ( 'Verify staked position exists' , true , undefined , report ) ;
console . log ( ` [ ${ persona . shortName } ] ✅ Position verified in UI ` ) ;
} else {
await takeScreenshot ( page , persona . shortName , '7-position-check-failed' , report ) ;
recordAction ( 'Verify staked position exists' , false , 'Position not visible in UI' , report ) ;
console . log ( ` [ ${ persona . shortName } ] ⚠️ Position not visible in UI - may still exist on-chain ` ) ;
}
report . overallSentiment = ` ${ persona . name } completed full journey: connected wallet → bought KRK → staked → ${ hasPosition ? 'verified position' : 'stake attempted but position not visible' } ` ;
logObservation ( persona . shortName , report . overallSentiment , report ) ;
console . log ( ` [ ${ persona . shortName } ] ✅ FULL JOURNEY COMPLETE ` ) ;
} catch ( error : any ) {
const errorMsg = error . message || String ( error ) ;
console . error ( ` [ ${ persona . shortName } ] ❌ Test failed: ${ errorMsg } ` ) ;
await takeScreenshot ( page , persona . shortName , 'error-state' , report ) . catch ( ( ) = > { } ) ;
report . overallSentiment = ` Test failed: ${ errorMsg } ` ;
throw error ;
} finally {
writeReport ( persona . name . toLowerCase ( ) . replace ( /\s+/g , '-' ) , report ) ;
await context . close ( ) ;
}
} ) ;
}
} ) ;