Files
pokerogue-type-pokemon/something.ts
2026-02-14 14:48:46 +00:00

337 lines
13 KiB
TypeScript

/**
* PokeRogue Extension E2E Test - v2
*/
const { chromium } = require('playwright');
const path = require('path');
const fs = require('fs');
const EXTENSION_PATH = '/home/ceo/Desktop/poke-extension';
const USER_DATA_DIR = '/tmp/poke-ext-test-profile-' + Date.now();
const SCREENSHOT_DIR = '/home/ceo/Desktop/poke-extension';
const USERNAME = 'ClaudeCode';
const PASSWORD = '5454%penilesurgery%5656';
const consoleMessages = [];
const extMessages = [];
const sleep = ms => new Promise(r => setTimeout(r, ms));
async function shot(page, name) {
const fp = path.join(SCREENSHOT_DIR, `test-${name}.png`);
await page.screenshot({ path: fp });
console.log(`[SHOT] ${fp}`);
}
async function main() {
console.log('[TEST] === PokeRogue Extension E2E Test v2 ===');
// Step 1: Launch
console.log('\n[STEP 1] Launching Chromium with extension...');
const context = await chromium.launchPersistentContext(USER_DATA_DIR, {
headless: false,
args: [
'--ignore-gpu-blacklist',
'--disable-gpu-sandbox',
`--disable-extensions-except=${EXTENSION_PATH}`,
`--load-extension=${EXTENSION_PATH}`,
'--no-first-run',
'--disable-blink-features=AutomationControlled',
'--window-size=1280,900',
],
viewport: { width: 1280, height: 900 },
ignoreDefaultArgs: ['--disable-extensions'],
});
let page = context.pages()[0] || await context.newPage();
page.on('console', msg => {
const t = msg.text();
consoleMessages.push({ type: msg.type(), text: t });
if (t.includes('[PokeRogue Ext]')) {
extMessages.push(t);
console.log(` [EXT] ${t}`);
}
});
page.on('pageerror', err => console.log(` [PERR] ${err.message.substring(0, 150)}`));
// Step 2: Navigate
console.log('\n[STEP 2] Navigating to pokerogue.net...');
await page.goto('https://pokerogue.net/', { waitUntil: 'domcontentloaded', timeout: 60000 });
console.log(' Waiting 20s for Phaser...');
await sleep(20000);
await shot(page, '01-initial-load');
// Step 3: Check messages
console.log('\n[STEP 3] Extension messages check:');
for (const c of ['Game bridge loaded', 'SceneManager prototype patch installed', 'Game instance captured']) {
console.log(` ${extMessages.some(m => m.includes(c)) ? '✓' : '✗'} ${c}`);
}
const gameCheck = await page.evaluate(() => ({
exists: !!window.__POKEXT_GAME__,
hasScene: !!(window.__POKEXT_GAME__?.scene),
hasCanvas: !!(window.__POKEXT_GAME__?.canvas),
}));
console.log(` __POKEXT_GAME__: ${JSON.stringify(gameCheck)}`);
// Step 4: Login
console.log('\n[STEP 4] Logging in...');
// Focus canvas and press Enter to get to login screen
await page.mouse.click(640, 450);
await sleep(1000);
await page.keyboard.press('Enter');
await sleep(2000);
await shot(page, '02-login-screen');
// Find visible inputs by coordinates
const inputInfo = await page.evaluate(() => {
const all = Array.from(document.querySelectorAll('input'));
return all.map((inp, i) => {
const r = inp.getBoundingClientRect();
const s = window.getComputedStyle(inp);
return {
i, type: inp.type,
vis: r.width > 0 && r.height > 0 && s.display !== 'none' && s.visibility !== 'hidden',
x: r.x, y: r.y, w: r.width, h: r.height,
};
}).filter(x => x.vis);
});
console.log(` Visible inputs: ${JSON.stringify(inputInfo)}`);
const textInputs = inputInfo.filter(i => i.type === 'text');
const pwdInputs = inputInfo.filter(i => i.type === 'password');
if (textInputs.length > 0 && pwdInputs.length > 0) {
const ui = textInputs[0];
const pi = pwdInputs[0];
// Click username field and type
await page.mouse.click(ui.x + ui.w / 2, ui.y + ui.h / 2);
await sleep(300);
await page.keyboard.press('Control+a');
await sleep(100);
await page.keyboard.type(USERNAME, { delay: 30 });
await sleep(300);
// Click password field and type
await page.mouse.click(pi.x + pi.w / 2, pi.y + pi.h / 2);
await sleep(300);
await page.keyboard.press('Control+a');
await sleep(100);
await page.keyboard.type(PASSWORD, { delay: 30 });
await sleep(300);
await shot(page, '03-login-filled');
// Verify
const vals = await page.evaluate(({ uIdx, pIdx }) => {
const inputs = document.querySelectorAll('input');
return { u: inputs[uIdx]?.value, pLen: inputs[pIdx]?.value?.length };
}, { uIdx: ui.i, pIdx: pi.i });
console.log(` Filled: user="${vals.u}", pwdLen=${vals.pLen}`);
// Submit - press Enter
await page.keyboard.press('Enter');
console.log(' Submitted login form');
await sleep(5000);
await shot(page, '04-after-login');
// Check if we need to retry
const loginResult = await page.evaluate(() => {
const text = document.body.innerText || '';
return {
hasError: text.includes('incorrect') || text.includes('must not be empty') || text.includes('Invalid'),
snippet: text.substring(0, 200),
};
});
if (loginResult.hasError) {
console.log(` Login may have failed: ${loginResult.snippet.substring(0, 100)}`);
// Try again - click username, clear, retype
await page.mouse.click(ui.x + ui.w / 2, ui.y + ui.h / 2);
await sleep(200);
await page.keyboard.press('Control+a');
await page.keyboard.press('Backspace');
await sleep(100);
await page.keyboard.type(USERNAME, { delay: 50 });
await sleep(200);
await page.mouse.click(pi.x + pi.w / 2, pi.y + pi.h / 2);
await sleep(200);
await page.keyboard.press('Control+a');
await page.keyboard.press('Backspace');
await sleep(100);
await page.keyboard.type(PASSWORD, { delay: 50 });
await sleep(200);
// Now find and click the Login button in the canvas area
// The button is below the password field typically
// Try pressing Enter from password field
await page.keyboard.press('Enter');
await sleep(5000);
await shot(page, '05-login-retry');
}
} else {
console.log(' No visible login inputs found!');
}
// Wait for login to complete and main menu to appear
await sleep(3000);
await shot(page, '06-post-login');
// Step 5: Start battle
console.log('\n[STEP 5] Starting a battle...');
// Focus canvas
await page.mouse.click(640, 450);
await sleep(500);
// Check current game phase/state
const preMenuState = await page.evaluate(() => {
const g = window.__POKEXT_GAME__;
if (!g?.scene) return { noGame: true };
const scenes = g.scene.scenes || [];
const battleScene = scenes.find(s => s.currentBattle !== undefined);
return {
sceneKeys: scenes.map(s => s.sys?.settings?.key).slice(0, 10),
hasBattleScene: !!battleScene,
currentPhase: battleScene?.currentPhase?.constructor?.name || 'none',
currentBattle: battleScene?.currentBattle ? {
waveIndex: battleScene.currentBattle.waveIndex,
turn: battleScene.currentBattle.turn,
} : null,
};
});
console.log(` Pre-menu state: ${JSON.stringify(preMenuState)}`);
// Navigate through menus
// After login: main menu appears. Press Enter to select first option.
// If "Continue" is available, it starts from last save.
// If "New Game", it starts character selection.
let battleFound = false;
for (let attempt = 0; attempt < 25; attempt++) {
const bc = await page.evaluate(() => {
const g = window.__POKEXT_GAME__;
if (!g?.scene) return { battle: false };
const scenes = g.scene.scenes || [];
for (const s of scenes) {
if (s.currentBattle) {
const pf = typeof s.getPlayerField === 'function' ? s.getPlayerField() : [];
const ef = typeof s.getEnemyField === 'function' ? s.getEnemyField() : [];
if (pf.length > 0 && ef.length > 0) {
return { battle: true, wave: s.currentBattle.waveIndex, players: pf.length, enemies: ef.length };
}
return { battle: false, partial: true, wave: s.currentBattle.waveIndex };
}
}
return { battle: false };
});
if (bc.battle) {
console.log(` Battle found at attempt ${attempt + 1}! Wave: ${bc.wave}, Players: ${bc.players}, Enemies: ${bc.enemies}`);
battleFound = true;
break;
}
if (attempt % 5 === 0 && attempt > 0) {
console.log(` Attempt ${attempt}: no battle yet (${JSON.stringify(bc)})`);
await shot(page, `07-nav-attempt-${attempt}`);
}
// Press Enter to advance through menus/dialogs
await page.keyboard.press('Enter');
await sleep(1500);
}
if (!battleFound) {
console.log(' Battle not found after Enter presses, trying arrow navigation...');
// Try selecting different menu options
for (let i = 0; i < 3; i++) {
await page.keyboard.press('ArrowDown');
await sleep(500);
}
await page.keyboard.press('Enter');
await sleep(3000);
for (let attempt = 0; attempt < 10; attempt++) {
const bc = await page.evaluate(() => {
const g = window.__POKEXT_GAME__;
if (!g?.scene) return { battle: false };
return { battle: (g.scene.scenes || []).some(s => s.currentBattle) };
});
if (bc.battle) {
battleFound = true;
console.log(` Battle found after arrow nav!`);
break;
}
await page.keyboard.press('Enter');
await sleep(2000);
}
}
// Wait for battle to fully load
await sleep(5000);
await shot(page, '08-battle-state');
// Step 6: Verify overlay
console.log('\n[STEP 6] Verifying overlay...');
await sleep(3000); // Let polling catch up
const finalState = await page.evaluate(() => {
const g = window.__POKEXT_GAME__;
const overlay = document.getElementById('poke-ext-overlay');
let battleInfo = null;
if (g?.scene) {
for (const s of (g.scene.scenes || [])) {
if (s.currentBattle) {
try {
const pf = typeof s.getPlayerField === 'function' ? s.getPlayerField() : [];
const ef = typeof s.getEnemyField === 'function' ? s.getEnemyField() : [];
battleInfo = {
wave: s.currentBattle.waveIndex,
double: !!s.currentBattle.double,
player: pf.filter(Boolean).map(p => ({
name: typeof p.getNameToRender === 'function' ? p.getNameToRender() : (p.name || '?'),
types: typeof p.getTypes === 'function' ? p.getTypes() : [],
moves: (p.moveset || []).filter(Boolean).map(m => {
const mv = typeof m.getMove === 'function' ? m.getMove() : m;
return { name: typeof m.getName === 'function' ? m.getName() : (mv?.name || '?'), type: mv?.type ?? -1, power: mv?.power ?? 0, cat: mv?.category ?? -1 };
}),
})),
enemy: ef.filter(Boolean).map(p => ({
name: typeof p.getNameToRender === 'function' ? p.getNameToRender() : (p.name || '?'),
types: typeof p.getTypes === 'function' ? p.getTypes() : [],
})),
};
} catch (e) { battleInfo = { error: e.message }; }
}
}
}
return {
gameExists: !!g,
battleInfo,
overlay: {
exists: !!overlay,
visible: overlay ? overlay.style.display !== 'none' : false,
html: overlay ? overlay.innerHTML : '',
text: overlay ? overlay.innerText : '',
},
};
});
console.log(` Game exists: ${finalState.gameExists}`);
console.log(` Battle: ${JSON.stringify(finalState.battleInfo, null, 2)}`);
console.log(` Overlay exists: ${finalState.overlay.exists}, visible: ${finalState.overlay.visible}`);
console.log(` Overlay text:\n${finalState.overlay.text}`);
console.log(` Overlay HTML (1500 chars):\n${finalState.overlay.html.substring(0, 1500)}`);
await shot(page, '09-final-with-overlay');
// Try to get overlay closeup
if (finalState.overlay.exists) {
try {
const el = await page.$('#poke-ext-overlay');
if (el) {
await el.screenshot({ path: path.join(SCREENSHOT_DIR, 'test-10-overlay-closeup.png') });
console.log('[SHOT] test-10-overlay-closeup.png');
}
} catch (_) {}
}
// Step 7: All ext messages
console.log('\n[STEP 7] All [PokeRogue Ext] messages:');
console.log('─'.repeat(60));
extMessages.forEach((m, i) => console.log(` ${i + 1}. ${m}`));
if (!extMessages.length) console.log(' (none)');
console.log('─'.repeat(60));
const errs = consoleMessages.filter(m => m.type === 'error');
if (errs.length) {
console.log(`\n Errors (${errs.length}):`);
errs.slice(0, 10).forEach(e => console.log(` ${e.text.substring(0, 200)}`));
}
console.log('\n[SUMMARY]');
console.log(` ${gameCheck.exists ? '✓' : '✗'} Game captured via SceneManager patch`);
console.log(` ${finalState.overlay.exists ? '✓' : '✗'} Overlay created`);
console.log(` ${finalState.battleInfo ? '✓' : '✗'} Battle detected`);
if (finalState.battleInfo && !finalState.battleInfo.error) {
console.log(` ${finalState.overlay.text.includes('Effectiveness') ? '✓' : '✗'} Overlay shows type effectiveness`);
}
console.log(` Extension messages: ${extMessages.length}`);
await context.close();
try { fs.rmSync(USER_DATA_DIR, { recursive: true, force: true }); } catch (_) {}
console.log('\n[TEST] Done!');
}
main().catch(err => {
console.error('[FATAL]', err.message);
process.exit(1);
});