feat(sasch40): multi-room tavern, authentic character portraits, pre-level start screens & bollerwagen redesign
This commit is contained in:
@@ -9,7 +9,7 @@ if (!fs.existsSync(SCREENSHOTS_DIR)) {
|
||||
}
|
||||
|
||||
async function runPlaytest() {
|
||||
console.log('🚀 Starting Chrome Playtest for Saschas Kronkorken Kreuzzug...');
|
||||
console.log('🚀 Starting Comprehensive Chrome Playtest for Saschas Kronkorken Kreuzzug...');
|
||||
|
||||
const logs = [];
|
||||
const errors = [];
|
||||
@@ -60,165 +60,206 @@ async function runPlaytest() {
|
||||
|
||||
try {
|
||||
console.log('🌐 Navigating to https://sasch40.haumdaucher.de...');
|
||||
await page.goto('https://sasch40.haumdaucher.de', { waitUntil: 'networkidle0', timeout: 30000 });
|
||||
await page.goto('https://sasch40.haumdaucher.de', { waitUntil: 'networkidle0', timeout: 35000 });
|
||||
|
||||
// 1. INTRO SCREEN
|
||||
console.log('📸 Capturing Intro Screen...');
|
||||
// 1. INTRO / PREQUEL SCREEN
|
||||
console.log('📸 01: Capturing Intro Screen...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '01_intro_screen.png') });
|
||||
|
||||
// Inspect layout and controls presence in Intro
|
||||
const introControlsVisible = await page.evaluate(() => {
|
||||
const dpad = document.querySelector('.dpad');
|
||||
const intro = document.querySelector('.intro-screen');
|
||||
const chassis = document.querySelector('.gameboy-chassis');
|
||||
return {
|
||||
hasDpad: !!dpad,
|
||||
dpadOffsetHeight: dpad ? (dpad.offsetHeight > 0) : false,
|
||||
hasIntro: !!intro,
|
||||
layoutClass: chassis ? chassis.className : ''
|
||||
};
|
||||
});
|
||||
console.log('Intro Layout Check:', introControlsVisible);
|
||||
|
||||
// Click Start Button
|
||||
console.log('🖱️ Clicking Start Button...');
|
||||
await page.click('.start-btn');
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
|
||||
// 2. PROLOGUE SCREEN
|
||||
console.log('📸 Capturing Prologue Screen...');
|
||||
// 2. PROLOGUE SCREEN (Balcony Scene)
|
||||
console.log('📸 02: Capturing Prologue Screen (Verifying banner/portrait alignment)...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02_prologue_screen.png') });
|
||||
|
||||
// Advance Prologue Dialogues
|
||||
console.log('💬 Advancing Prologue Dialogues (clicking choice buttons)...');
|
||||
// Click choice 1 on 'start'
|
||||
await page.waitForSelector('.choice-btn', { timeout: 5000 });
|
||||
const firstChoice = await page.$('.choice-btn');
|
||||
if (firstChoice) {
|
||||
await firstChoice.click();
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
console.log('📸 Capturing Mop Appears Prologue Dialogue...');
|
||||
console.log('📸 02b: Capturing Prologue Mop Dialog...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '02b_prologue_mop.png') });
|
||||
}
|
||||
|
||||
// Click choice on 'mop_appears' -> triggers 'startPlatformer'
|
||||
// Advance to Platformer
|
||||
const mopChoice = await page.$('.choice-btn');
|
||||
if (mopChoice) {
|
||||
await mopChoice.click();
|
||||
await new Promise(r => setTimeout(r, 1200));
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
}
|
||||
|
||||
// 3. PLATFORMER SCREEN
|
||||
console.log('📸 Capturing Platformer (Jump & Run)...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '03_platformer_screen.png') });
|
||||
// 3. PLATFORMER PRE-LEVEL START SCREEN (Act II)
|
||||
console.log('📸 03: Capturing Platformer Start Screen Modal...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '03_platformer_start_modal.png') });
|
||||
|
||||
const platformerControls = await page.evaluate(() => {
|
||||
const dpad = document.querySelector('.dpad');
|
||||
const btnA = document.querySelector('.btn-a');
|
||||
const canvas = document.querySelector('canvas');
|
||||
return {
|
||||
hasDpad: !!dpad,
|
||||
hasBtnA: !!btnA,
|
||||
hasCanvas: !!canvas,
|
||||
canvasW: canvas?.width,
|
||||
canvasH: canvas?.height
|
||||
};
|
||||
});
|
||||
console.log('Platformer Controls Check:', platformerControls);
|
||||
// Click Start Act Button on the modal
|
||||
const startPlatformerBtn = await page.$('.start-act-btn');
|
||||
if (startPlatformerBtn) {
|
||||
await startPlatformerBtn.click();
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
}
|
||||
|
||||
// Test Jump & Move
|
||||
console.log('🎮 Testing Jump & Move Controls in Platformer...');
|
||||
// 4. PLATFORMER GAMEPLAY
|
||||
console.log('📸 04: Capturing Platformer Gameplay...');
|
||||
const btnA = await page.$('.btn-a');
|
||||
if (btnA) {
|
||||
await btnA.click();
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
await btnA.click();
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
}
|
||||
const dpadRight = await page.$('.dpad-right');
|
||||
if (dpadRight) {
|
||||
await dpadRight.hover();
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '03b_platformer_jump.png') });
|
||||
await new Promise(r => setTimeout(r, 300));
|
||||
}
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '04_platformer_gameplay.png') });
|
||||
|
||||
// Directly set act to 'tavern' to test Tavern Point & Click
|
||||
console.log('🍺 Advancing to Tavern Act...');
|
||||
// 5. TAVERN: SCHANKRAUM (Gaststube)
|
||||
console.log('🍺 Advancing to Tavern Act (Schankraum)...');
|
||||
await page.evaluate(() => {
|
||||
const chassis = document.querySelector('.gameboy-chassis');
|
||||
// access pinia store from window if exposed, or trigger level finish
|
||||
// We can click the level finish or evaluate store change
|
||||
window.dispatchEvent(new CustomEvent('test-set-act', { detail: 'tavern' }));
|
||||
});
|
||||
|
||||
// Check if act switched, or use page.evaluate to trigger store change
|
||||
await page.evaluate(() => {
|
||||
// Find Pinia root if possible
|
||||
const app = document.querySelector('#app')?.__vue_app__;
|
||||
if (app && app.config?.globalProperties?.$pinia) {
|
||||
const pinia = app.config.globalProperties.$pinia;
|
||||
// find game store
|
||||
for (const [id, store] of pinia._s.entries()) {
|
||||
if (id === 'game') {
|
||||
store.setAct('tavern');
|
||||
}
|
||||
if (id === 'game') store.setAct('tavern');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
console.log('📸 Capturing Tavern Screen...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '04_tavern_screen.png') });
|
||||
console.log('📸 05: Capturing Tavern Gaststube (Schankraum)...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '05_tavern_schankraum.png') });
|
||||
|
||||
// Test Tavern Hotspots
|
||||
console.log('👥 Testing Verena Hotspot...');
|
||||
// Test Verena Hotspot
|
||||
console.log('👥 Testing Verena Dialog...');
|
||||
const verenaBtn = await page.$('.hotspot-verena');
|
||||
if (verenaBtn) {
|
||||
await verenaBtn.click();
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '05_tavern_verena_dialog.png') });
|
||||
await new Promise(r => setTimeout(r, 700));
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '06_tavern_verena_dialog.png') });
|
||||
const actionBtn = await page.$('.dialog-actions .action-btn');
|
||||
if (actionBtn) await actionBtn.click();
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
}
|
||||
|
||||
console.log('🔨 Testing Armend Hotspot...');
|
||||
// Test Armend Hotspot
|
||||
console.log('🔨 Testing Armend Dialog...');
|
||||
const armendBtn = await page.$('.hotspot-armend');
|
||||
if (armendBtn) {
|
||||
await armendBtn.click();
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '06_tavern_armend_dialog.png') });
|
||||
await new Promise(r => setTimeout(r, 700));
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '07_tavern_armend_dialog.png') });
|
||||
const actionBtn = await page.$('.dialog-actions .action-btn');
|
||||
if (actionBtn) await actionBtn.click();
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
}
|
||||
|
||||
console.log('🪞 Testing Zuluman Magic Mirror Hotspot...');
|
||||
// 6. TAVERN: MARKTPLATZ (Mario with spinning chainsaws)
|
||||
console.log('🎪 Navigating to Marktplatz...');
|
||||
const marktplatzTab = await page.$('.room-tab:nth-child(2)');
|
||||
if (marktplatzTab) {
|
||||
await marktplatzTab.click();
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
console.log('📸 08: Capturing Marktplatz (Mario chainsaws)...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '08_tavern_marktplatz.png') });
|
||||
|
||||
// Click Mario
|
||||
const marioBtn = await page.$('.hotspot-mario');
|
||||
if (marioBtn) {
|
||||
await marioBtn.click();
|
||||
await new Promise(r => setTimeout(r, 700));
|
||||
console.log('📸 09: Capturing Mario Dialog...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09_tavern_mario_dialog.png') });
|
||||
const actionBtn = await page.$('.dialog-actions .action-btn');
|
||||
if (actionBtn) await actionBtn.click();
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
}
|
||||
}
|
||||
|
||||
// 7. TAVERN: HINTERLAND (Mane hiking)
|
||||
console.log('🌲 Navigating to Hinterland...');
|
||||
const hinterlandTab = await page.$('.room-tab:nth-child(3)');
|
||||
if (hinterlandTab) {
|
||||
await hinterlandTab.click();
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
console.log('📸 10: Capturing Hinterland (Mane hiking)...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '10_tavern_hinterland.png') });
|
||||
|
||||
// Click Mane
|
||||
const maneBtn = await page.$('.hotspot-mane');
|
||||
if (maneBtn) {
|
||||
await maneBtn.click();
|
||||
await new Promise(r => setTimeout(r, 700));
|
||||
console.log('📸 11: Capturing Mane Dialog...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '11_tavern_mane_dialog.png') });
|
||||
const actionBtn = await page.$('.dialog-actions .action-btn');
|
||||
if (actionBtn) await actionBtn.click();
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
}
|
||||
}
|
||||
|
||||
// 8. TAVERN: SECRET HINTERZIMMER (VIP Rave via Secret Tap)
|
||||
console.log('🗝️ Returning to Schankraum to trigger Secret Tap...');
|
||||
const schankraumTab = await page.$('.room-tab:nth-child(1)');
|
||||
if (schankraumTab) {
|
||||
await schankraumTab.click();
|
||||
await new Promise(r => setTimeout(r, 600));
|
||||
}
|
||||
|
||||
console.log('🪩 Triggering Secret Tap Easter Egg...');
|
||||
const secretTap = await page.$('.secret-tap-hotspot');
|
||||
if (secretTap) {
|
||||
await secretTap.click();
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
console.log('📸 12: Capturing Secret VIP Hinterzimmer...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '12_tavern_hinterzimmer_vip.png') });
|
||||
|
||||
// Click Pü in Hinterzimmer
|
||||
const pueBtn = await page.$('.hotspot-pue');
|
||||
if (pueBtn) {
|
||||
await pueBtn.click();
|
||||
await new Promise(r => setTimeout(r, 700));
|
||||
console.log('📸 13: Capturing Pü Dialog...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '13_tavern_pue_dialog.png') });
|
||||
const actionBtn = await page.$('.dialog-actions .action-btn');
|
||||
if (actionBtn) await actionBtn.click();
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
}
|
||||
}
|
||||
|
||||
// 9. ZULUMAN MAGIC MIRROR & GSTANZL DUEL
|
||||
console.log('🪞 Testing Zuluman Magic Mirror...');
|
||||
const backToGaststube = await page.$('.hotspot-door-back-vip');
|
||||
if (backToGaststube) {
|
||||
await backToGaststube.click();
|
||||
await new Promise(r => setTimeout(r, 600));
|
||||
}
|
||||
const mirrorBtn = await page.$('.hotspot-mirror');
|
||||
if (mirrorBtn) {
|
||||
await mirrorBtn.click();
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '07_tavern_zuluman_mirror.png') });
|
||||
await new Promise(r => setTimeout(r, 700));
|
||||
console.log('📸 14: Capturing Zuluman Mirror...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '14_tavern_zuluman_mirror.png') });
|
||||
const closeBtn = await page.$('.mirror-box .action-btn');
|
||||
if (closeBtn) await closeBtn.click();
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
}
|
||||
|
||||
console.log('⚔️ Testing Gstanzl-Duel...');
|
||||
const duelBtn = await page.$('.duel-trigger');
|
||||
if (duelBtn) {
|
||||
await duelBtn.click();
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '08_tavern_gstanzl_duel.png') });
|
||||
|
||||
// Answer Gstanzl question
|
||||
const correctOption = await page.$('.option-btn');
|
||||
if (correctOption) {
|
||||
await correctOption.click();
|
||||
await new Promise(r => setTimeout(r, 600));
|
||||
await new Promise(r => setTimeout(r, 700));
|
||||
console.log('📸 15: Capturing Gstanzl Duel...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '15_tavern_gstanzl_duel.png') });
|
||||
const firstAnswer = await page.$('.choice-btn');
|
||||
if (firstAnswer) {
|
||||
await firstAnswer.click();
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
}
|
||||
// Close duel if won or modal
|
||||
const actionBtn = await page.$('.duel-box .action-btn');
|
||||
if (actionBtn) await actionBtn.click();
|
||||
}
|
||||
|
||||
// 4. PARTY EXPRESS (Act IV)
|
||||
// 10. PARTY EXPRESS (Act IV)
|
||||
console.log('🚂 Advancing to Party Express (Act IV)...');
|
||||
await page.evaluate(() => {
|
||||
const app = document.querySelector('#app')?.__vue_app__;
|
||||
@@ -230,10 +271,26 @@ async function runPlaytest() {
|
||||
}
|
||||
});
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
console.log('📸 Capturing Party Express...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '09_party_express.png') });
|
||||
console.log('📸 16: Capturing Party Express Start Screen Modal...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '16_party_express_start_modal.png') });
|
||||
|
||||
// 5. FINALE / CERTIFICATE (Act V)
|
||||
// Start Party Express
|
||||
const startExpressBtn = await page.$('.start-act-btn');
|
||||
if (startExpressBtn) {
|
||||
await startExpressBtn.click();
|
||||
await new Promise(r => setTimeout(r, 800));
|
||||
}
|
||||
|
||||
console.log('📸 17: Capturing Party Express Gameplay (Redesigned Bollerwagen)...');
|
||||
// Serve beer
|
||||
const throwBeerBtn = await page.$('.throw-beer-btn');
|
||||
if (throwBeerBtn) {
|
||||
await throwBeerBtn.click();
|
||||
await new Promise(r => setTimeout(r, 400));
|
||||
}
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '17_party_express_gameplay.png') });
|
||||
|
||||
// 11. FINALE / CERTIFICATE (Act V)
|
||||
console.log('👑 Advancing to Finale Certificate (Act V)...');
|
||||
await page.evaluate(() => {
|
||||
const app = document.querySelector('#app')?.__vue_app__;
|
||||
@@ -241,7 +298,7 @@ async function runPlaytest() {
|
||||
const pinia = app.config.globalProperties.$pinia;
|
||||
for (const [id, store] of pinia._s.entries()) {
|
||||
if (id === 'game') {
|
||||
store.addKronkorken(25);
|
||||
store.addKronkorken(35);
|
||||
store.serveGuest();
|
||||
store.serveGuest();
|
||||
store.setAct('finale');
|
||||
@@ -250,10 +307,10 @@ async function runPlaytest() {
|
||||
}
|
||||
});
|
||||
await new Promise(r => setTimeout(r, 1500));
|
||||
console.log('📸 Capturing Certificate Modal...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '10_certificate_screen.png') });
|
||||
console.log('📸 18: Capturing Certificate Modal...');
|
||||
await page.screenshot({ path: path.join(SCREENSHOTS_DIR, '18_certificate_screen.png') });
|
||||
|
||||
// Check images in document
|
||||
// Verify all images loaded properly
|
||||
const brokenImages = await page.evaluate(() => {
|
||||
const imgs = Array.from(document.querySelectorAll('img'));
|
||||
return imgs
|
||||
@@ -265,7 +322,7 @@ async function runPlaytest() {
|
||||
console.log('Total Console Logs:', logs.length);
|
||||
console.log('Console Errors:', errors);
|
||||
console.log('Failed Requests:', failedRequests);
|
||||
console.log('Broken Images on Certificate Page:', brokenImages);
|
||||
console.log('Broken Images:', brokenImages);
|
||||
|
||||
const report = {
|
||||
timestamp: new Date().toISOString(),
|
||||
|
||||
Reference in New Issue
Block a user