197 lines
9.6 KiB
TypeScript
197 lines
9.6 KiB
TypeScript
import { expect, 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,
|
|
logCopyFeedback,
|
|
logTokenomicsQuestion,
|
|
recordPageVisit,
|
|
recordAction,
|
|
writeReport,
|
|
attemptStake,
|
|
resetChainState,
|
|
} from './helpers';
|
|
|
|
// Tyler uses Anvil account #3
|
|
const ACCOUNT_PRIVATE_KEY = '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6';
|
|
const ACCOUNT_ADDRESS = new Wallet(ACCOUNT_PRIVATE_KEY).address.toLowerCase();
|
|
|
|
const STACK_CONFIG = getStackConfig();
|
|
const STACK_RPC_URL = STACK_CONFIG.rpcUrl;
|
|
const STACK_WEBAPP_URL = STACK_CONFIG.webAppUrl;
|
|
|
|
test.describe('Tyler "Bags" Morrison - Retail Degen', () => {
|
|
test.beforeAll(async () => {
|
|
await resetChainState(STACK_RPC_URL);
|
|
await validateStackHealthy(STACK_CONFIG);
|
|
});
|
|
|
|
test('Tyler YOLOs in without reading anything', async ({ browser }) => {
|
|
const report = createReport('Tyler Bags Morrison');
|
|
const personaName = 'Tyler';
|
|
|
|
console.log(`[${personaName}] Starting test - Retail degen ready to ape in...`);
|
|
|
|
const context = await createWalletContext(browser, {
|
|
privateKey: ACCOUNT_PRIVATE_KEY,
|
|
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 {
|
|
// --- Landing Page (Barely Looks) ---
|
|
let pageStart = Date.now();
|
|
await page.goto(`${STACK_WEBAPP_URL}/app/`, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForTimeout(1_000);
|
|
|
|
await takeScreenshot(page, personaName, 'landing-page', report);
|
|
logObservation(personaName, 'Cool looking app! Let\'s goooo 🚀', report);
|
|
logCopyFeedback(personaName, 'Needs bigger "BUY NOW" button on landing page', report);
|
|
|
|
recordPageVisit('Landing (glanced)', page.url(), pageStart, report);
|
|
|
|
// --- Connect Wallet Immediately ---
|
|
logObservation(personaName, 'Connecting wallet right away - don\'t need to read docs', report);
|
|
|
|
pageStart = Date.now();
|
|
await connectWallet(page);
|
|
await takeScreenshot(page, personaName, 'wallet-connected', report);
|
|
recordAction('Connect wallet', true, undefined, report);
|
|
logObservation(personaName, 'Wallet connected! Where do I buy?', report);
|
|
|
|
// --- Tries to Find Buy Button ---
|
|
logObservation(personaName, 'Looking for a buy button... where is it?', report);
|
|
|
|
const buyButtonVisible = await page.getByRole('button', { name: /buy/i }).first().isVisible({ timeout: 3_000 }).catch(() => false);
|
|
|
|
if (!buyButtonVisible) {
|
|
logCopyFeedback(personaName, 'Can\'t find buy button easily - confusing! Needs clear CTA on main page.', report);
|
|
logObservation(personaName, 'Confused where to buy... checking navigation...', report);
|
|
}
|
|
|
|
// --- Navigate to Cheats (Finds It Randomly) ---
|
|
pageStart = Date.now();
|
|
await page.goto(`${STACK_WEBAPP_URL}/app/cheats`);
|
|
await page.waitForTimeout(1_000);
|
|
recordPageVisit('Cheats', page.url(), pageStart, report);
|
|
|
|
await takeScreenshot(page, personaName, 'found-cheats', report);
|
|
logObservation(personaName, 'Found this "Cheat Console" page - looks like I can buy here?', report);
|
|
|
|
// --- Mint ETH Quickly ---
|
|
logObservation(personaName, 'Need ETH first I guess... clicking buttons', report);
|
|
|
|
try {
|
|
await mintEth(page, STACK_RPC_URL, ACCOUNT_ADDRESS, '10');
|
|
recordAction('Mint 10 ETH', true, undefined, report);
|
|
logObservation(personaName, 'Got some ETH! Now buying KRK!', report);
|
|
} catch (error: any) {
|
|
logObservation(personaName, `Mint failed??? ${error.message} - whatever, trying to buy anyway`, report);
|
|
recordAction('Mint 10 ETH', false, error.message, report);
|
|
}
|
|
|
|
// --- Buy KRK Immediately (No Research) ---
|
|
logObservation(personaName, 'Buying $150 worth (all I can afford) LFG!!! 🔥', report);
|
|
|
|
try {
|
|
await buyKrk(page, '4.0');
|
|
recordAction('Buy KRK with 4.0 ETH total', true, undefined, report);
|
|
await takeScreenshot(page, personaName, 'bought-krk', report);
|
|
logObservation(personaName, 'BOUGHT! Let\'s stake this and get rich!', report);
|
|
} catch (error: any) {
|
|
logObservation(personaName, `Buy failed: ${error.message}. WTF??? This is frustrating.`, report);
|
|
logCopyFeedback(personaName, 'Error messages are too technical - just tell me what to do!', report);
|
|
recordAction('Buy KRK with 1.2 ETH total', false, error.message, report);
|
|
await takeScreenshot(page, personaName, 'buy-error', report);
|
|
}
|
|
|
|
await page.waitForTimeout(5_000);
|
|
|
|
// --- Navigate to Stake (No Idea What He's Doing) ---
|
|
pageStart = Date.now();
|
|
await page.goto(`${STACK_WEBAPP_URL}/app/stake`);
|
|
await page.waitForTimeout(3_000);
|
|
recordPageVisit('Stake', page.url(), pageStart, report);
|
|
|
|
await takeScreenshot(page, personaName, 'stake-page', report);
|
|
logObservation(personaName, 'Stake page! Time to stake everything and make passive income', report);
|
|
logCopyFeedback(personaName, 'What\'s all this "tax rate" stuff? Too complicated, just want to stake', report);
|
|
logTokenomicsQuestion(personaName, 'Do I make more money with higher or lower tax? Idk???', report);
|
|
|
|
// --- Random Tax Rate Selection ---
|
|
logObservation(personaName, 'Picking 5% because it sounds good I guess... middle of the road?', report);
|
|
|
|
try {
|
|
// Tyler stakes a random amount at a random tax rate
|
|
await attemptStake(page, '50', '5', personaName, report);
|
|
await takeScreenshot(page, personaName, 'staked', report);
|
|
logObservation(personaName, 'STAKED! Wen moon? 🌙', report);
|
|
recordAction('Stake 75 KRK at 5% tax (random)', true, undefined, report);
|
|
} catch (error: any) {
|
|
logObservation(personaName, `Stake failed: ${error.message}. This app is broken!!!`, report);
|
|
logCopyFeedback(personaName, 'Make staking easier! Just ONE button, not all these options', report);
|
|
await takeScreenshot(page, personaName, 'stake-failed', report);
|
|
}
|
|
|
|
await page.waitForTimeout(3_000);
|
|
|
|
// --- Checks for Immediate Gains ---
|
|
await page.goto(`${STACK_WEBAPP_URL}/app/stake`);
|
|
await page.waitForTimeout(2_000);
|
|
await takeScreenshot(page, personaName, 'checking-gains', report);
|
|
|
|
logObservation(personaName, 'Where are my gains? How much am I making per day?', report);
|
|
logCopyFeedback(personaName, 'Needs a big "Your Daily Earnings: $X" display - can\'t see my profits', report);
|
|
logTokenomicsQuestion(personaName, 'When do I get paid? Where do I see my rewards?', report);
|
|
|
|
// --- Confused About Tax ---
|
|
logObservation(personaName, 'Wait... what does "tax" mean? Am I PAYING tax or EARNING tax?', report);
|
|
logCopyFeedback(personaName, 'CRITICAL: The word "tax" is confusing! Call it "yield rate" or something', report);
|
|
|
|
// --- Discovers He Might Get Snatched ---
|
|
const snatchInfoVisible = await page.getByText(/snatch/i).isVisible().catch(() => false);
|
|
|
|
if (snatchInfoVisible) {
|
|
logObservation(personaName, 'Wait WTF someone can SNATCH my position?! Nobody told me this!', report);
|
|
logCopyFeedback(personaName, 'HUGE ISSUE: Snatching needs to be explained BEFORE I stake, not after!', report);
|
|
logObservation(personaName, 'Feeling scammed... my position isn\'t safe???', report);
|
|
} else {
|
|
logObservation(personaName, 'Still don\'t understand what "Harberger tax" means but whatever', report);
|
|
}
|
|
|
|
await takeScreenshot(page, personaName, 'confused-about-snatching', report);
|
|
|
|
// --- Tries to Join Discord/Community ---
|
|
logObservation(personaName, 'Need to ask in Discord: "why did I get snatched already??"', report);
|
|
|
|
const discordLink = await page.getByText(/discord/i).isVisible().catch(() => false);
|
|
const twitterLink = await page.getByText(/twitter|x\.com/i).isVisible().catch(() => false);
|
|
|
|
if (!discordLink && !twitterLink) {
|
|
logCopyFeedback(personaName, 'No Discord or Twitter link visible! How do I ask questions?', report);
|
|
logObservation(personaName, 'Can\'t find community - feeling alone and confused', report);
|
|
}
|
|
|
|
// --- Final Thoughts ---
|
|
await page.waitForTimeout(2_000);
|
|
await takeScreenshot(page, personaName, 'final-confused-state', report);
|
|
|
|
report.overallSentiment = 'Confused and frustrated but still hopeful. I bought in because it looked cool and seemed like a way to make passive income, but now I\'m lost. Don\'t understand tax rates, don\'t know when I get paid, worried someone will snatch my position. App needs MUCH simpler onboarding - like a tutorial or a "Beginner Mode" that picks settings for me. If I don\'t see gains in a few days OR if I get snatched without understanding why, I\'m selling and moving to the next thing. Needs: Big simple buttons, profit tracker, Discord link, tutorial video, and NO JARGON. Also, make it fun! Where are the memes? Where\'s the leaderboard? Make me want to share this on Twitter.';
|
|
|
|
logObservation(personaName, report.overallSentiment, report);
|
|
|
|
} finally {
|
|
writeReport('tyler-bags-morrison', report);
|
|
await context.close();
|
|
}
|
|
});
|
|
});
|