Commit dc1f2ef7 authored by Mahmoud Aglan's avatar Mahmoud Aglan

koko

parent ad92b88a
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
// 1. Initial board state (all pieces in base)
console.log('1. Board with pieces in base...');
await page.goto(BASE + '/ludo-game?mode=bot&bots=3&difficulty=hard', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'centered-01-base.png'), fullPage: true });
// 2. Play until pieces move out
console.log('2. Playing until pieces on track...');
for (let i = 0; i < 50; i++) {
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
await page.click('#ludo-roll-btn');
await page.waitForTimeout(1200);
await page.evaluate(() => {
var hl = document.querySelectorAll('.ludo-piece--highlight');
if (hl.length > 0) hl[0].click();
});
}
await page.waitForTimeout(1000);
}
await page.screenshot({ path: path.join(DIR, 'centered-02-playing.png'), fullPage: true });
// 3. Continue more
for (let i = 0; i < 40; i++) {
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
await page.click('#ludo-roll-btn');
await page.waitForTimeout(1000);
await page.evaluate(() => {
var hl = document.querySelectorAll('.ludo-piece--highlight');
if (hl.length > 0) hl[0].click();
});
}
await page.waitForTimeout(900);
}
await page.screenshot({ path: path.join(DIR, 'centered-03-advanced.png'), fullPage: true });
// 4. Local 4-player initial state
console.log('3. Local 4-player initial...');
await page.goto(BASE + '/ludo-game?mode=local&players=4', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'centered-04-local4p.png'), fullPage: true });
// 5. Mobile view
console.log('4. Mobile view...');
await page.setViewportSize({ width: 390, height: 844 });
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
// Play a few turns
for (let i = 0; i < 30; i++) {
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
await page.click('#ludo-roll-btn');
await page.waitForTimeout(1200);
await page.evaluate(() => {
var hl = document.querySelectorAll('.ludo-piece--highlight');
if (hl.length > 0) hl[0].click();
});
}
await page.waitForTimeout(1000);
}
await page.screenshot({ path: path.join(DIR, 'centered-05-mobile.png'), fullPage: true });
await browser.close();
console.log('Done!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
// Login
console.log('Logging in...');
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
const token = await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
return data.access_token;
}
return null;
});
if (!token) {
console.error('Login failed!');
await browser.close();
process.exit(1);
}
console.log('Logged in');
// Desktop screenshots
const desktopPages = [
{ name: 'ludo-01-menu', path: '/ludo' },
{ name: 'ludo-02-local-4p', path: '/ludo-game?mode=local&players=4' },
{ name: 'ludo-03-bot-easy', path: '/ludo-game?mode=bot&bots=1&difficulty=easy' },
{ name: 'ludo-04-bot-hard-3', path: '/ludo-game?mode=bot&bots=3&difficulty=hard' },
{ name: 'ludo-05-matchmaking', path: '/ludo-matchmaking' },
{ name: 'ludo-06-live-create', path: '/ludo-live?action=create' },
];
for (const p of desktopPages) {
console.log('Desktop:', p.name);
try {
await page.goto(BASE + p.path, { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, p.name + '.png'), fullPage: true });
} catch (e) {
console.log(' Error:', e.message.substring(0, 100));
try { await page.screenshot({ path: path.join(DIR, p.name + '-error.png'), fullPage: true }); } catch (e2) {}
}
}
// Test bot game interaction - wait for bot to roll dice
console.log('Testing bot game with dice interaction...');
try {
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
// Click roll button if visible
const rollBtn = await page.$('#ludo-roll-btn');
if (rollBtn) {
const isDisabled = await rollBtn.getAttribute('disabled');
if (isDisabled === null) {
await rollBtn.click();
await page.waitForTimeout(2000);
}
}
await page.waitForTimeout(3000); // Wait for bot turn
await page.screenshot({ path: path.join(DIR, 'ludo-07-game-playing.png'), fullPage: true });
} catch (e) {
console.log(' Error:', e.message.substring(0, 100));
}
// Check console errors
const errors = [];
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text());
});
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
if (errors.length) {
console.log('\nConsole errors found:');
errors.forEach(e => console.log(' -', e.substring(0, 150)));
}
// Mobile screenshots
console.log('\nMobile views...');
await page.setViewportSize({ width: 390, height: 844 });
const mobilePages = [
{ name: 'ludo-08-mobile-menu', path: '/ludo' },
{ name: 'ludo-09-mobile-game', path: '/ludo-game?mode=bot&bots=1&difficulty=easy' },
{ name: 'ludo-10-mobile-local', path: '/ludo-game?mode=local&players=2' },
];
for (const p of mobilePages) {
console.log('Mobile:', p.name);
try {
await page.goto(BASE + p.path, { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, p.name + '.png'), fullPage: true });
} catch (e) {
console.log(' Error:', e.message.substring(0, 100));
try { await page.screenshot({ path: path.join(DIR, p.name + '-error.png'), fullPage: true }); } catch (e2) {}
}
}
// Mobile bot game with dice
console.log('Mobile bot game interaction...');
try {
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
const rollBtn = await page.$('#ludo-roll-btn');
if (rollBtn) {
const isDisabled = await rollBtn.getAttribute('disabled');
if (isDisabled === null) {
await rollBtn.click();
await page.waitForTimeout(2000);
}
}
await page.waitForTimeout(3000);
await page.screenshot({ path: path.join(DIR, 'ludo-11-mobile-playing.png'), fullPage: true });
} catch (e) {
console.log(' Error:', e.message.substring(0, 100));
}
await browser.close();
console.log('\nDone! Ludo screenshots saved to:', DIR);
})();
const { chromium } = require('playwright');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const SCREENSHOTS_DIR = __dirname;
const pages = [
{ name: '01-login', path: '/login' },
{ name: '02-home', path: '/' },
{ name: '03-play', path: '/play' },
{ name: '04-bots', path: '/bots' },
{ name: '05-game-bot', path: '/game?bot=nour&color=w&time=300&inc=0&rated=true' },
{ name: '06-puzzles', path: '/puzzles' },
{ name: '07-tournaments', path: '/tournaments' },
{ name: '08-leaderboard', path: '/leaderboard' },
{ name: '09-friends', path: '/friends' },
{ name: '10-orgs', path: '/orgs' },
{ name: '11-shop', path: '/shop' },
{ name: '12-achievements', path: '/achievements' },
{ name: '13-profile', path: '/profile' },
{ name: '14-settings', path: '/settings' },
{ name: '15-notifications', path: '/notifications' },
{ name: '16-matchmaking', path: '/matchmaking?tc=blitz_5_0&time=300000&inc=0' },
];
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
// Screenshot login page first (before auth)
console.log('Capturing: login');
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.screenshot({ path: SCREENSHOTS_DIR + '/01-login.png', fullPage: true });
// Login
console.log('Logging in...');
await page.fill('input[type="email"], input[name="email"], #email', 'uitest@el3ab.com');
await page.fill('input[type="password"], input[name="password"], #password', 'UiTest2026!');
await page.click('button[type="submit"], .btn-gold, button:has-text("دخول")');
await page.waitForTimeout(3000);
// Set token in localStorage in case the login redirect didn't work via UI
const token = await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
return data.access_token;
}
return null;
});
if (!token) {
console.error('Failed to login!');
await browser.close();
process.exit(1);
}
console.log('Logged in successfully');
// Capture all pages
for (const p of pages) {
if (p.name === '01-login') continue; // already captured
console.log('Capturing:', p.name, p.path);
try {
await page.goto(BASE + p.path, { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: SCREENSHOTS_DIR + '/' + p.name + '.png', fullPage: true });
} catch (e) {
console.log(' Error on', p.name, ':', e.message.substring(0, 80));
try {
await page.screenshot({ path: SCREENSHOTS_DIR + '/' + p.name + '-error.png', fullPage: true });
} catch (e2) {}
}
}
// Special: game page after making a move (wait for bot to move too)
console.log('Capturing: game in progress (with bot move)');
try {
await page.goto(BASE + '/game?bot=amina&color=w&time=600&inc=0&rated=true', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
// Click e2 square then e4 to make a move
const board = await page.$('#board');
if (board) {
const box = await board.boundingBox();
if (box) {
const sqSize = box.width / 8;
// e2 = file 4, rank 6 (from top) for white
const e2x = box.x + sqSize * 4 + sqSize / 2;
const e2y = box.y + sqSize * 6 + sqSize / 2;
const e4x = box.x + sqSize * 4 + sqSize / 2;
const e4y = box.y + sqSize * 4 + sqSize / 2;
await page.mouse.click(e2x, e2y);
await page.waitForTimeout(300);
await page.mouse.click(e4x, e4y);
await page.waitForTimeout(4000); // wait for bot response
}
}
await page.screenshot({ path: SCREENSHOTS_DIR + '/17-game-in-progress.png', fullPage: true });
} catch (e) {
console.log(' Error on game-in-progress:', e.message.substring(0, 80));
}
// Capture analysis page (if accessible)
console.log('Capturing: analysis');
try {
await page.goto(BASE + '/analysis', { waitUntil: 'networkidle', timeout: 10000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: SCREENSHOTS_DIR + '/18-analysis.png', fullPage: true });
} catch (e) {
console.log(' Skipped analysis');
}
// Mobile viewport captures
console.log('Capturing mobile views...');
await page.setViewportSize({ width: 390, height: 844 });
const mobilePages = [
{ name: '19-mobile-home', path: '/' },
{ name: '20-mobile-play', path: '/play' },
{ name: '21-mobile-game', path: '/game?bot=nour&color=w&time=300&inc=0&rated=true' },
{ name: '22-mobile-profile', path: '/profile' },
];
for (const p of mobilePages) {
console.log('Capturing mobile:', p.name);
try {
await page.goto(BASE + p.path, { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: SCREENSHOTS_DIR + '/' + p.name + '.png', fullPage: true });
} catch (e) {
console.log(' Error:', e.message.substring(0, 60));
}
}
await browser.close();
console.log('\nDone! Screenshots saved to:', SCREENSHOTS_DIR);
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
const errors = [];
const logs = [];
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text());
else logs.push(msg.type() + ': ' + msg.text());
});
page.on('pageerror', err => errors.push('PAGE ERROR: ' + err.message));
// Login
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
// Test LOCAL 4-player mode
console.log('Testing LOCAL 4-player mode...');
await page.goto(BASE + '/ludo-game?mode=local&players=4', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
// Check DOM state
const domState = await page.evaluate(() => {
const board = document.querySelector('.ludo-board');
const cells = document.querySelectorAll('.ludo-cell');
const pieces = document.querySelectorAll('.ludo-piece');
const dice = document.querySelector('.ludo-dice');
const rollBtn = document.querySelector('#ludo-roll-btn');
return {
boardExists: !!board,
boardChildren: board ? board.children.length : 0,
cellCount: cells.length,
pieceCount: pieces.length,
diceExists: !!dice,
rollBtnExists: !!rollBtn,
rollBtnDisabled: rollBtn ? rollBtn.hasAttribute('disabled') : null,
boardHTML: board ? board.innerHTML.substring(0, 500) : 'NO BOARD'
};
});
console.log('\nDOM State:', JSON.stringify(domState, null, 2));
console.log('\nConsole errors:', errors.length ? errors.join('\n') : 'NONE');
console.log('\nConsole logs:', logs.slice(0, 10).join('\n'));
await page.screenshot({ path: path.join(DIR, 'debug-local-4p.png'), fullPage: true });
// Also test local 2-player
console.log('\n\nTesting LOCAL 2-player mode...');
errors.length = 0;
logs.length = 0;
await page.goto(BASE + '/ludo-game?mode=local&players=2', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
const domState2 = await page.evaluate(() => {
const board = document.querySelector('.ludo-board');
const cells = document.querySelectorAll('.ludo-cell');
const pieces = document.querySelectorAll('.ludo-piece');
return {
boardExists: !!board,
cellCount: cells.length,
pieceCount: pieces.length,
};
});
console.log('DOM State 2P:', JSON.stringify(domState2, null, 2));
console.log('Console errors:', errors.length ? errors.join('\n') : 'NONE');
await page.screenshot({ path: path.join(DIR, 'debug-local-2p.png'), fullPage: true });
await browser.close();
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ viewport: { width: 390, height: 844 }, locale: 'ar' });
const page = await context.newPage();
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84' },
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) { localStorage.setItem('el3ab_token', data.access_token); localStorage.setItem('el3ab_user', JSON.stringify(data.user)); }
});
// 1. Profile (stat grid fix)
await page.goto(BASE + '/profile', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'final-profile.png'), fullPage: true });
console.log('1. profile');
// 2. Games (new icons + subtitle)
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'final-games.png'), fullPage: true });
console.log('2. games');
// 3. Ludo game (spacing fix)
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'final-ludo-game.png'), fullPage: true });
console.log('3. ludo game');
// 4. Chess lobby (scroll test)
await page.goto(BASE + '/play', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'final-chess-lobby.png'), fullPage: true });
console.log('4. chess lobby');
// 5. Settings (scroll below nav)
await page.goto(BASE + '/settings', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'final-settings.png'), fullPage: true });
console.log('5. settings');
// Check for JS errors
const errors = [];
page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); });
await page.goto(BASE + '/', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
// Test sound system loads
const soundTest = await page.evaluate(() => {
return typeof App.playSound === 'function' && typeof App.vibrate === 'function';
});
console.log('Sound system:', soundTest ? 'OK' : 'FAIL');
if (errors.length) console.log('ERRORS:', errors);
else console.log('No errors!');
await browser.close();
console.log('Done!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ viewport: { width: 390, height: 844 }, locale: 'ar' });
const page = await context.newPage();
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84' },
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) { localStorage.setItem('el3ab_token', data.access_token); localStorage.setItem('el3ab_user', JSON.stringify(data.user)); }
});
// Mobile screenshots of all pages
const pages = [
['/', 'audit-home-mobile'],
['/games', 'audit-games-mobile'],
['/play', 'audit-chess-lobby-mobile'],
['/ludo', 'audit-ludo-lobby-mobile'],
['/profile', 'audit-profile-mobile'],
['/shop', 'audit-shop-mobile'],
['/friends', 'audit-friends-mobile'],
['/leaderboard', 'audit-leaderboard-mobile'],
['/settings', 'audit-settings-mobile'],
['/achievements', 'audit-achievements-mobile'],
];
for (const [url, name] of pages) {
await page.goto(BASE + url, { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, name + '.png'), fullPage: true });
console.log(name);
}
// Ludo game mobile
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'audit-ludo-game-mobile.png'), fullPage: true });
console.log('audit-ludo-game-mobile');
await browser.close();
console.log('Done!');
})();
const { chromium } = require('playwright');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
(async () => {
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, locale: 'ar' });
const page = await ctx.newPage();
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84' },
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await page.waitForTimeout(500);
await page.goto(BASE + '/ludo-game?mode=local&players=4', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
// Measure the board and all base slots
const measurements = await page.evaluate(() => {
const board = document.querySelector('.ludo-board');
if (!board) return { error: 'no board found' };
const boardRect = board.getBoundingClientRect();
const result = {
board: { left: boardRect.left, top: boardRect.top, width: boardRect.width, height: boardRect.height },
bases: {}
};
// Get each base and its slots
['p1', 'p2', 'p3', 'p4'].forEach(player => {
const base = board.querySelector('.ludo-base--' + player);
if (!base) return;
const baseRect = base.getBoundingClientRect();
const inner = base.querySelector('.ludo-base-inner');
const innerRect = inner ? inner.getBoundingClientRect() : null;
const slots = base.querySelectorAll('.ludo-base-slot');
const slotPositions = [];
slots.forEach(slot => {
const slotRect = slot.getBoundingClientRect();
// Get center of slot relative to board
const centerX = slotRect.left + slotRect.width / 2 - boardRect.left;
const centerY = slotRect.top + slotRect.height / 2 - boardRect.top;
// Convert to percentage of board
const pctX = (centerX / boardRect.width) * 100;
const pctY = (centerY / boardRect.height) * 100;
// Convert to coordinate system: coord = (pct - halfStep) / STEP_LENGTH
const STEP = 6.66;
const HALF = 3.33;
const coordX = (pctX - HALF) / STEP;
const coordY = (pctY - HALF) / STEP;
slotPositions.push({
coordX: Math.round(coordX * 100) / 100,
coordY: Math.round(coordY * 100) / 100,
pctX: Math.round(pctX * 100) / 100,
pctY: Math.round(pctY * 100) / 100
});
});
result.bases[player] = {
base: {
left: Math.round((baseRect.left - boardRect.left) / boardRect.width * 10000) / 100,
top: Math.round((baseRect.top - boardRect.top) / boardRect.height * 10000) / 100,
width: Math.round(baseRect.width / boardRect.width * 10000) / 100,
height: Math.round(baseRect.height / boardRect.height * 10000) / 100
},
inner: innerRect ? {
left: Math.round((innerRect.left - boardRect.left) / boardRect.width * 10000) / 100,
top: Math.round((innerRect.top - boardRect.top) / boardRect.height * 10000) / 100,
width: Math.round(innerRect.width / boardRect.width * 10000) / 100,
height: Math.round(innerRect.height / boardRect.height * 10000) / 100
} : null,
slots: slotPositions
};
});
return result;
});
console.log(JSON.stringify(measurements, null, 2));
await browser.close();
})();
{
"name": "screenshots",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"playwright": "^1.60.0"
}
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/playwright": {
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz",
"integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==",
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.60.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz",
"integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==",
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
}
}
}
{
"dependencies": {
"playwright": "^1.60.0"
}
}
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
// Login
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
// 1. Home page (streak strip + new button)
console.log('1. Home page...');
await page.goto(BASE + '/', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'phase1-01-home-desktop.png'), fullPage: true });
// 2. Games Hub
console.log('2. Games Hub desktop...');
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'phase1-02-games-desktop.png'), fullPage: true });
// 3. Chess lobby (breadcrumb)
console.log('3. Chess lobby...');
await page.goto(BASE + '/play', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1000);
await page.screenshot({ path: path.join(DIR, 'phase1-03-chess-lobby.png'), fullPage: true });
// 4. Ludo lobby (breadcrumb)
console.log('4. Ludo lobby...');
await page.goto(BASE + '/ludo', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1000);
await page.screenshot({ path: path.join(DIR, 'phase1-04-ludo-lobby.png'), fullPage: true });
// 5. Mobile Games Hub
console.log('5. Mobile games hub...');
await page.setViewportSize({ width: 390, height: 844 });
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'phase1-05-games-mobile.png'), fullPage: true });
// 6. Mobile Home
console.log('6. Mobile home...');
await page.goto(BASE + '/', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'phase1-06-home-mobile.png'), fullPage: true });
// 7. Tablet Games Hub
console.log('7. Tablet games...');
await page.setViewportSize({ width: 768, height: 1024 });
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'phase1-07-games-tablet.png'), fullPage: true });
await browser.close();
console.log('Done!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
// Login
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
// 1. Games Hub with animated background
console.log('1. Games Hub...');
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'phase23-01-games.png'), fullPage: true });
// 2. Home page (streak + fire badge + number animations)
console.log('2. Home...');
await page.goto(BASE + '/', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'phase23-02-home.png'), fullPage: true });
// 3. Ludo game with 3D dice + capture particles
console.log('3. Ludo game (playing for captures)...');
await page.goto(BASE + '/ludo-game?mode=bot&bots=3&difficulty=hard', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
// Play several turns for captures
for (let i = 0; i < 60; i++) {
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
await page.click('#ludo-roll-btn');
await page.waitForTimeout(800);
await page.evaluate(() => {
var hl = document.querySelectorAll('.ludo-piece--highlight');
if (hl.length > 0) hl[0].click();
});
}
await page.waitForTimeout(700);
}
await page.screenshot({ path: path.join(DIR, 'phase23-03-ludo-playing.png'), fullPage: true });
// 4. Test toast
console.log('4. Toast test...');
await page.evaluate(() => { App.toast('هذا اختبار توست!', 'success'); });
await page.waitForTimeout(500);
await page.screenshot({ path: path.join(DIR, 'phase23-04-toast.png'), fullPage: true });
// 5. Test celebration
console.log('5. Celebration...');
await page.evaluate(() => { App.celebrate('مبروك! فزت!'); });
await page.waitForTimeout(1000);
await page.screenshot({ path: path.join(DIR, 'phase23-05-celebrate.png'), fullPage: true });
// 6. Mobile with bottom sheet
console.log('6. Bottom sheet...');
await page.setViewportSize({ width: 390, height: 844 });
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.evaluate(() => {
App.showSheet('<h3 style="font-size:16px;font-weight:700;margin-bottom:12px;">اختر وضع اللعب</h3><button class="btn btn-gold btn-block" style="margin-bottom:8px;">سريع 5+0</button><button class="btn btn-cyan btn-block">كلاسيكي 10+5</button>');
});
await page.waitForTimeout(500);
await page.screenshot({ path: path.join(DIR, 'phase23-06-sheet-mobile.png'), fullPage: true });
// 7. Check console errors
const errors = [];
page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); });
await page.goto(BASE + '/', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
if (errors.length > 0) console.log('ERRORS:', errors.join('\n'));
else console.log('No console errors!');
await browser.close();
console.log('Done!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
async function login(page) {
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84' },
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await page.waitForTimeout(500);
}
(async () => {
const browser = await chromium.launch({ headless: true });
// Desktop 1440x900
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, locale: 'ar' });
const page = await ctx.newPage();
await login(page);
// Mobile 390x844
const mCtx = await browser.newContext({ viewport: { width: 390, height: 844 }, locale: 'ar', isMobile: true });
const mobile = await mCtx.newPage();
await login(mobile);
// ==================== GAMES HUB ====================
console.log('\n=== GAMES HUB ===');
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, '01-games-hub-desktop.png') });
console.log('✓ 01-games-hub-desktop.png');
// ==================== LUDO ====================
console.log('\n=== LUDO ===');
// Ludo local 4P
await page.goto(BASE + '/ludo-game?mode=local&players=4', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, '02-ludo-local-4p.png') });
console.log('✓ 02-ludo-local-4p.png');
// Ludo vs bot - roll dice
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=medium', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
const ludoRoll = await page.$('.ludo-roll-btn, #ludo-roll-btn');
if (ludoRoll && await ludoRoll.isVisible()) {
await ludoRoll.click();
await page.waitForTimeout(1500);
}
await page.screenshot({ path: path.join(DIR, '03-ludo-bot-rolled.png') });
console.log('✓ 03-ludo-bot-rolled.png');
// Ludo mobile
await mobile.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(2500);
const ludoMRoll = await mobile.$('.ludo-roll-btn, #ludo-roll-btn');
if (ludoMRoll && await ludoMRoll.isVisible()) {
await ludoMRoll.click();
await mobile.waitForTimeout(1500);
}
await mobile.screenshot({ path: path.join(DIR, '04-ludo-mobile-bot.png') });
console.log('✓ 04-ludo-mobile-bot.png');
// ==================== DOMINO ====================
console.log('\n=== DOMINO ===');
// Domino bot 2P
await page.goto(BASE + '/domino-game?mode=2p&type=bot&players=2&difficulty=medium', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, '05-domino-bot-2p.png') });
console.log('✓ 05-domino-bot-2p.png');
// Domino local
await page.goto(BASE + '/domino-game?mode=2p&type=local&players=2', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, '06-domino-local.png') });
console.log('✓ 06-domino-local.png');
// Domino mobile
await mobile.goto(BASE + '/domino-game?mode=2p&type=bot&players=2&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(2500);
await mobile.screenshot({ path: path.join(DIR, '07-domino-mobile-bot.png') });
console.log('✓ 07-domino-mobile-bot.png');
// ==================== BACKGAMMON ====================
console.log('\n=== BACKGAMMON ===');
// Backgammon bot easy
await page.goto(BASE + '/backgammon-game?mode=bot&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
await page.screenshot({ path: path.join(DIR, '08-backgammon-bot-start.png') });
console.log('✓ 08-backgammon-bot-start.png');
// Click a white checker and show selection
const bgClicked = await page.evaluate(() => {
const pts = document.querySelectorAll('.bg-point');
for (let p of pts) {
if (p.querySelector('.bg-checker--white')) {
p.click();
return p.dataset.point;
}
}
return null;
});
await page.waitForTimeout(600);
await page.screenshot({ path: path.join(DIR, '09-backgammon-selected.png') });
console.log('✓ 09-backgammon-selected.png (point ' + bgClicked + ')');
// Click valid target to make a move
const moved = await page.evaluate(() => {
const valid = document.querySelector('.bg-point--valid');
if (valid) { valid.click(); return valid.dataset.point; }
return null;
});
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, '10-backgammon-moved.png') });
console.log('✓ 10-backgammon-moved.png (to ' + moved + ')');
// Backgammon local
await page.goto(BASE + '/backgammon-game?mode=local', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, '11-backgammon-local.png') });
console.log('✓ 11-backgammon-local.png');
// Backgammon mobile
await mobile.goto(BASE + '/backgammon-game?mode=bot&difficulty=medium', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(3000);
await mobile.screenshot({ path: path.join(DIR, '12-backgammon-mobile.png') });
console.log('✓ 12-backgammon-mobile.png');
// ==================== LOBBIES ====================
console.log('\n=== LOBBIES ===');
await page.goto(BASE + '/ludo', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1000);
await page.screenshot({ path: path.join(DIR, '13-ludo-lobby.png') });
console.log('✓ 13-ludo-lobby.png');
await page.goto(BASE + '/domino', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1000);
await page.screenshot({ path: path.join(DIR, '14-domino-lobby.png') });
console.log('✓ 14-domino-lobby.png');
await page.goto(BASE + '/backgammon', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1000);
await page.screenshot({ path: path.join(DIR, '15-backgammon-lobby.png') });
console.log('✓ 15-backgammon-lobby.png');
await browser.close();
console.log('\n✅ All game screenshots complete!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
async function login(page) {
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await page.waitForTimeout(500);
}
(async () => {
const browser = await chromium.launch({ headless: true });
// Desktop
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, locale: 'ar' });
const page = await ctx.newPage();
await login(page);
// Mobile
const mCtx = await browser.newContext({ viewport: { width: 390, height: 844 }, locale: 'ar', isMobile: true });
const mobile = await mCtx.newPage();
await login(mobile);
console.log('\n=== BACKGAMMON ===');
// 1. Lobby
await page.goto(BASE + '/backgammon', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'backgammon-01-lobby.png'), fullPage: true });
console.log('✓ backgammon-01-lobby.png');
// 2. Bot game (medium)
await page.goto(BASE + '/backgammon-game?mode=bot&difficulty=medium', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
await page.screenshot({ path: path.join(DIR, 'backgammon-02-game-bot.png') });
console.log('✓ backgammon-02-game-bot.png');
// 3. Local game
await page.goto(BASE + '/backgammon-game?mode=local', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, 'backgammon-03-game-local.png') });
console.log('✓ backgammon-03-game-local.png');
// 4. Mobile lobby
await mobile.goto(BASE + '/backgammon', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(1500);
await mobile.screenshot({ path: path.join(DIR, 'backgammon-04-mobile-lobby.png') });
console.log('✓ backgammon-04-mobile-lobby.png');
// 5. Mobile game
await mobile.goto(BASE + '/backgammon-game?mode=bot&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(3000);
await mobile.screenshot({ path: path.join(DIR, 'backgammon-05-mobile-game.png') });
console.log('✓ backgammon-05-mobile-game.png');
// 6. Games hub (verify backgammon shows)
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'backgammon-06-games-hub.png') });
console.log('✓ backgammon-06-games-hub.png');
// 7. Check for JS errors
const errors = [];
page.on('pageerror', err => errors.push(err.message));
await page.goto(BASE + '/backgammon-game?mode=bot&difficulty=hard', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
await page.screenshot({ path: path.join(DIR, 'backgammon-07-hard-bot.png') });
console.log('✓ backgammon-07-hard-bot.png');
if (errors.length > 0) {
console.log('⚠ JS Errors:', errors.join('; '));
}
await browser.close();
console.log('\n✅ Backgammon screenshots complete!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, locale: 'ar' });
const page = await ctx.newPage();
// Collect JS errors
const errors = [];
page.on('pageerror', err => errors.push(err.message));
page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); });
// Login
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84' },
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await page.waitForTimeout(500);
console.log('\n=== BACKGAMMON GAMEPLAY ===');
// 1. Start a bot game - initial state
await page.goto(BASE + '/backgammon-game?mode=bot&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
await page.screenshot({ path: path.join(DIR, 'bg-gameplay-01-initial.png') });
console.log('✓ bg-gameplay-01-initial.png');
// 2. Click roll button if visible
const rollBtn = await page.$('#bg-roll-btn');
if (rollBtn) {
const isVisible = await rollBtn.isVisible();
if (isVisible) {
await rollBtn.click();
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'bg-gameplay-02-rolled.png') });
console.log('✓ bg-gameplay-02-rolled.png');
} else {
console.log(' Roll btn hidden (bot turn)');
await page.screenshot({ path: path.join(DIR, 'bg-gameplay-02-bot-turn.png') });
console.log('✓ bg-gameplay-02-bot-turn.png');
}
}
// 3. Try clicking a checker to see highlights
const points = await page.$$('.bg-point');
if (points.length > 0) {
// Click a point with white checkers (player 0)
for (let p of points) {
const checker = await p.$('.bg-checker--white');
if (checker) {
await p.click();
await page.waitForTimeout(500);
break;
}
}
await page.screenshot({ path: path.join(DIR, 'bg-gameplay-03-selected.png') });
console.log('✓ bg-gameplay-03-selected.png');
}
// 4. Fresh game - local mode, wider view
await page.goto(BASE + '/backgammon-game?mode=local', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, 'bg-gameplay-04-local.png') });
console.log('✓ bg-gameplay-04-local.png');
// 5. Mobile view
const mCtx = await browser.newContext({ viewport: { width: 390, height: 844 }, locale: 'ar', isMobile: true });
const mobile = await mCtx.newPage();
await mobile.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84' },
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await mobile.waitForTimeout(500);
await mobile.goto(BASE + '/backgammon-game?mode=bot&difficulty=medium', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(3000);
await mobile.screenshot({ path: path.join(DIR, 'bg-gameplay-05-mobile.png') });
console.log('✓ bg-gameplay-05-mobile.png');
// 6. Zoomed in board screenshot for detail
const boardEl = await page.$('.bg-board');
if (boardEl) {
await boardEl.screenshot({ path: path.join(DIR, 'bg-gameplay-06-board-zoom.png') });
console.log('✓ bg-gameplay-06-board-zoom.png');
}
if (errors.length > 0) {
console.log('\n⚠ JS Errors:');
errors.forEach(e => console.log(' ' + e));
} else {
console.log('\n✓ No JS errors detected');
}
await browser.close();
console.log('\n✅ Done!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, locale: 'ar' });
const page = await ctx.newPage();
// Login
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await page.waitForTimeout(500);
// Start a 2P bot game
await page.goto(BASE + '/domino-game?mode=2p&type=bot&players=2&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(3000);
await page.screenshot({ path: path.join(DIR, 'domino-play-01-start.png') });
console.log('✓ domino-play-01-start.png (game started, bot may have played)');
// Try to click first playable tile
const tiles = await page.$$('.domino-tile--playable');
console.log(` Found ${tiles.length} playable tiles`);
if (tiles.length > 0) {
await tiles[0].click();
await page.waitForTimeout(500);
await page.screenshot({ path: path.join(DIR, 'domino-play-02-selected.png') });
console.log('✓ domino-play-02-selected.png (tile selected)');
// Click an end button if visible
const endBtns = await page.$$('.domino-end-btn');
console.log(` Found ${endBtns.length} end buttons`);
if (endBtns.length > 0) {
await endBtns[0].click();
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'domino-play-03-placed.png') });
console.log('✓ domino-play-03-placed.png (tile placed, bot responds)');
}
}
// Wait for more bot turns
await page.waitForTimeout(3000);
await page.screenshot({ path: path.join(DIR, 'domino-play-04-progress.png') });
console.log('✓ domino-play-04-progress.png (game progressed)');
// Try playing a few more tiles
for (let i = 0; i < 3; i++) {
const playable = await page.$$('.domino-tile--playable');
if (playable.length > 0) {
await playable[0].click();
await page.waitForTimeout(300);
const ends = await page.$$('.domino-end-btn');
if (ends.length > 0) {
await ends[0].click();
await page.waitForTimeout(2000);
}
} else {
// Try draw button
const drawBtn = await page.$('.domino-draw-btn');
if (drawBtn) {
await drawBtn.click();
await page.waitForTimeout(1500);
}
}
}
await page.screenshot({ path: path.join(DIR, 'domino-play-05-midgame.png') });
console.log('✓ domino-play-05-midgame.png (after several turns)');
await browser.close();
console.log('\n✅ Domino gameplay test complete!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
// Desktop context
const desktopCtx = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await desktopCtx.newPage();
// Login
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await page.waitForTimeout(500);
// 1. Domino Lobby (desktop)
await page.goto(BASE + '/domino', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1000);
await page.screenshot({ path: path.join(DIR, 'domino-01-lobby-desktop.png'), fullPage: true });
console.log('✓ domino-01-lobby-desktop.png');
// 2. Domino Game - Bot 2P
await page.goto(BASE + '/domino-game?mode=2p&type=bot&players=2&difficulty=medium', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'domino-02-game-2p-bot.png') });
console.log('✓ domino-02-game-2p-bot.png');
// 3. Domino Game - 4P Teams Bot
await page.goto(BASE + '/domino-game?mode=4p_teams&type=bot&players=4&difficulty=hard', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'domino-03-game-4p-teams.png') });
console.log('✓ domino-03-game-4p-teams.png');
// 4. Domino Game - Local 2P
await page.goto(BASE + '/domino-game?mode=2p&type=local&players=2', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'domino-04-game-local-2p.png') });
console.log('✓ domino-04-game-local-2p.png');
// 5. Games Hub showing domino
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'domino-05-games-hub.png') });
console.log('✓ domino-05-games-hub.png');
// Mobile context
const mobileCtx = await browser.newContext({
viewport: { width: 390, height: 844 },
locale: 'ar',
isMobile: true,
});
const mobile = await mobileCtx.newPage();
await mobile.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await mobile.waitForTimeout(500);
// 6. Mobile lobby
await mobile.goto(BASE + '/domino', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(1000);
await mobile.screenshot({ path: path.join(DIR, 'domino-06-lobby-mobile.png') });
console.log('✓ domino-06-lobby-mobile.png');
// 7. Mobile game
await mobile.goto(BASE + '/domino-game?mode=2p&type=bot&players=2&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(2000);
await mobile.screenshot({ path: path.join(DIR, 'domino-07-game-mobile.png') });
console.log('✓ domino-07-game-mobile.png');
// 8. Ludo game (for piece/dice fix reference)
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'domino-08-ludo-reference.png') });
console.log('✓ domino-08-ludo-reference.png (for piece/dice fix)');
// 9. Ludo mobile
await mobile.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(2000);
await mobile.screenshot({ path: path.join(DIR, 'domino-09-ludo-mobile-ref.png') });
console.log('✓ domino-09-ludo-mobile-ref.png');
await browser.close();
console.log('\nDone! All screenshots saved.');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
const errors = [];
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text());
});
page.on('pageerror', err => errors.push('PAGE ERROR: ' + err.message));
// Login
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
// Start bot game (easy, 1 bot)
console.log('Starting bot game...');
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
// Play multiple turns to see pieces move
let turnCount = 0;
let pieceMoved = false;
for (let i = 0; i < 20; i++) {
// Check if roll button is enabled
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
turnCount++;
console.log('Turn ' + turnCount + ': Rolling dice...');
await page.click('#ludo-roll-btn');
await page.waitForTimeout(1500); // Wait for dice animation
// Check dice value and if pieces are highlighted
const state = await page.evaluate(() => {
const dice = document.querySelector('.ludo-dice');
const diceValue = dice ? dice.dataset.value : null;
const highlighted = document.querySelectorAll('.ludo-piece--highlight');
const pieces = document.querySelectorAll('.ludo-piece');
const piecesOnTrack = [];
pieces.forEach(p => {
const style = p.getAttribute('style') || '';
if (style.includes('left') && !style.includes('display: none')) {
piecesOnTrack.push({ player: p.dataset.player, piece: p.dataset.piece, style: style.substring(0, 80) });
}
});
return {
diceValue: diceValue,
highlightedCount: highlighted.length,
totalPieces: pieces.length,
piecesOnTrack: piecesOnTrack.slice(0, 4)
};
});
console.log(' Dice: ' + state.diceValue + ', Highlighted pieces: ' + state.highlightedCount);
// Click a highlighted piece if available
if (state.highlightedCount > 0) {
await page.click('.ludo-piece--highlight');
pieceMoved = true;
console.log(' Clicked highlighted piece!');
await page.waitForTimeout(1500); // Wait for move animation
}
}
// Wait for bot turn
await page.waitForTimeout(1500);
}
// Take final screenshot showing game progress
await page.screenshot({ path: path.join(DIR, 'ludo-gameplay-test.png'), fullPage: true });
// Get final game state
const finalState = await page.evaluate(() => {
const log = document.getElementById('ludo-log');
const logEntries = log ? log.innerText.split('\n').filter(l => l.trim()).slice(-10) : [];
const pieces = document.querySelectorAll('.ludo-piece');
const onTrack = [];
pieces.forEach(p => {
const left = p.style.left;
const top = p.style.top;
if (left && top && left !== '' && top !== '') {
onTrack.push(p.dataset.player + '-' + p.dataset.piece + ' at ' + left + ',' + top);
}
});
return { logEntries, onTrack, totalPieces: pieces.length };
});
console.log('\n--- Final State ---');
console.log('Pieces on track:', finalState.onTrack.length > 0 ? finalState.onTrack.join('; ') : 'NONE (all in base)');
console.log('Game log (last 10):');
finalState.logEntries.forEach(l => console.log(' ' + l));
console.log('\nPiece moved by player: ' + pieceMoved);
console.log('Console errors: ' + (errors.length ? errors.join('\n ') : 'NONE'));
console.log('Total turns played: ' + turnCount);
await browser.close();
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
const errors = [];
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text());
});
page.on('pageerror', err => errors.push('PAGE ERROR: ' + err.message));
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
console.log('Starting bot game (will play many turns)...');
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
let playerMoved = false;
let turnCount = 0;
let diceValues = [];
for (let i = 0; i < 60 && !playerMoved; i++) {
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
turnCount++;
await page.click('#ludo-roll-btn');
await page.waitForTimeout(1200);
// Get dice value from the dots rendered
const diceInfo = await page.evaluate(() => {
const dots = document.querySelectorAll('.ludo-dice .ludo-dice-dot');
return { dotCount: dots.length };
});
diceValues.push(diceInfo.dotCount);
// Check if any pieces are highlighted
const highlighted = await page.$$('.ludo-piece--highlight');
if (highlighted.length > 0) {
console.log('Turn ' + turnCount + ': Rolled ' + diceInfo.dotCount + ' - ' + highlighted.length + ' pieces highlighted!');
// Take screenshot showing highlighted pieces
await page.screenshot({ path: path.join(DIR, 'ludo-gameplay-highlight.png'), fullPage: true });
// Click the highlighted piece
await highlighted[0].click();
playerMoved = true;
console.log(' Clicked piece! Waiting for move...');
await page.waitForTimeout(2000);
// Take screenshot after move
await page.screenshot({ path: path.join(DIR, 'ludo-gameplay-after-move.png'), fullPage: true });
}
}
await page.waitForTimeout(1200);
}
if (!playerMoved) {
console.log('Player never rolled 6 in ' + turnCount + ' turns (very unlucky!)');
}
// Now let game play more turns to show progression
console.log('\nLetting game run for more turns...');
for (let i = 0; i < 30; i++) {
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
await page.click('#ludo-roll-btn');
await page.waitForTimeout(1200);
const hl = await page.$$('.ludo-piece--highlight');
if (hl.length > 0) {
await hl[0].click();
await page.waitForTimeout(1500);
}
}
await page.waitForTimeout(1200);
}
await page.screenshot({ path: path.join(DIR, 'ludo-gameplay-progress.png'), fullPage: true });
// Get game log
const finalLog = await page.evaluate(() => {
const log = document.getElementById('ludo-log');
return log ? log.innerText.split('\n').filter(l => l.trim()).slice(-15) : [];
});
console.log('\nGame log (last 15):');
finalLog.forEach(l => console.log(' ' + l));
console.log('\nDice values rolled by player:', diceValues.join(', '));
console.log('Console errors:', errors.length ? errors.join('\n ') : 'NONE');
await browser.close();
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
const errors = [];
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text());
});
page.on('pageerror', err => errors.push('PAGE ERROR: ' + err.message));
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
console.log('Starting bot game...');
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
let playerMoved = false;
let turnCount = 0;
for (let i = 0; i < 60; i++) {
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
turnCount++;
await page.click('#ludo-roll-btn');
await page.waitForTimeout(1500);
// Check highlighted pieces using evaluate + click via JS (bypass Playwright stability check)
const clicked = await page.evaluate(() => {
var hl = document.querySelectorAll('.ludo-piece--highlight');
if (hl.length > 0) {
hl[0].click();
return true;
}
return false;
});
if (clicked && !playerMoved) {
playerMoved = true;
console.log('Turn ' + turnCount + ': Player moved a piece!');
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'ludo-gameplay-first-move.png'), fullPage: true });
}
}
await page.waitForTimeout(1200);
}
// Continue playing for more progression
for (let i = 0; i < 40; i++) {
const canRoll = await page.evaluate(() => {
const btn = document.getElementById('ludo-roll-btn');
return btn && !btn.hasAttribute('disabled');
});
if (canRoll) {
await page.click('#ludo-roll-btn');
await page.waitForTimeout(1500);
await page.evaluate(() => {
var hl = document.querySelectorAll('.ludo-piece--highlight');
if (hl.length > 0) hl[0].click();
});
}
await page.waitForTimeout(1200);
}
await page.screenshot({ path: path.join(DIR, 'ludo-gameplay-advanced.png'), fullPage: true });
// Get final state
const finalState = await page.evaluate(() => {
var log = document.getElementById('ludo-log');
var entries = log ? log.innerText.split('\n').filter(function(l) { return l.trim(); }) : [];
var pieces = document.querySelectorAll('.ludo-piece');
var positions = [];
pieces.forEach(function(p) {
if (p.style.left && p.style.top) {
positions.push(p.dataset.player + '-' + p.dataset.piece + ': ' + p.style.left + ',' + p.style.top);
}
});
var result = document.querySelector('.ludo-result');
return {
log: entries.slice(-15),
positions: positions,
gameOver: !!result,
resultText: result ? result.innerText : null
};
});
console.log('\nFinal game log (last 15):');
finalState.log.forEach(l => console.log(' ' + l));
console.log('\nPiece positions:', finalState.positions.join('; '));
console.log('Game over:', finalState.gameOver);
if (finalState.resultText) console.log('Result:', finalState.resultText);
console.log('Console errors:', errors.length ? errors.join('\n ') : 'NONE');
await browser.close();
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
// Desktop
const ctx = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await ctx.newPage();
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await page.waitForTimeout(500);
// 1. Ludo game initial state (shows dice + pieces in base)
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'ludo-fix-01-initial.png') });
console.log('✓ ludo-fix-01-initial.png');
// 2. Roll the dice to see dots
const rollBtn = await page.$('.ludo-roll-btn, #ludo-roll-btn');
if (rollBtn) {
await rollBtn.click();
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'ludo-fix-02-rolled.png') });
console.log('✓ ludo-fix-02-rolled.png');
} else {
console.log('⚠ No roll button found');
}
// 3. 4-player local game
await page.goto(BASE + '/ludo-game?mode=local&players=4', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'ludo-fix-03-4player.png') });
console.log('✓ ludo-fix-03-4player.png');
// Roll in 4p
const rollBtn2 = await page.$('.ludo-roll-btn, #ludo-roll-btn');
if (rollBtn2) {
await rollBtn2.click();
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'ludo-fix-04-4player-rolled.png') });
console.log('✓ ludo-fix-04-4player-rolled.png');
}
// Mobile
const mCtx = await browser.newContext({
viewport: { width: 390, height: 844 },
locale: 'ar',
isMobile: true,
});
const mobile = await mCtx.newPage();
await mobile.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await mobile.waitForTimeout(500);
// 5. Mobile ludo
await mobile.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(2000);
await mobile.screenshot({ path: path.join(DIR, 'ludo-fix-05-mobile.png') });
console.log('✓ ludo-fix-05-mobile.png');
const mobileRoll = await mobile.$('.ludo-roll-btn, #ludo-roll-btn');
if (mobileRoll) {
await mobileRoll.click();
await mobile.waitForTimeout(1500);
await mobile.screenshot({ path: path.join(DIR, 'ludo-fix-06-mobile-rolled.png') });
console.log('✓ ludo-fix-06-mobile-rolled.png');
}
await browser.close();
console.log('\nDone!');
})();
{
"status": "failed",
"failedTests": []
}
\ No newline at end of file
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
(async () => {
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
locale: 'ar',
});
const page = await context.newPage();
// Navigate first so fetch works
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
// Login
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
// 1. Save a test theme override (change ludo-p1 to purple)
console.log('1. Saving test theme override (ludo-p1 = #9C27B0)...');
const saveRes = await page.evaluate(async () => {
const res = await fetch('/api/theme', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
admin_user: 'admin',
admin_pass: 'Alarcade123#',
action: 'save',
settings: [{ key: 'ludo-p1', value: '#9C27B0', category: 'ludo', label: 'ludo-p1' }]
})
});
return await res.json();
});
console.log(' Save result:', JSON.stringify(saveRes));
// Delete theme cache so override takes effect immediately
// The server caches for 60s but we need to reload anyway
await page.waitForTimeout(1000);
// 2. Load ludo page and check if the override is applied
console.log('2. Loading ludo game page to check override...');
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
const themeCheck = await page.evaluate(() => {
const style = document.getElementById('theme-overrides');
const hasOverride = style ? style.textContent.includes('ludo-p1') : false;
const computedColor = getComputedStyle(document.documentElement).getPropertyValue('--ludo-p1').trim();
return {
hasStyleTag: !!style,
hasOverride: hasOverride,
computedColor: computedColor,
styleContent: style ? style.textContent : 'NO STYLE TAG'
};
});
console.log(' Theme <style> tag exists:', themeCheck.hasStyleTag);
console.log(' Contains ludo-p1 override:', themeCheck.hasOverride);
console.log(' Computed --ludo-p1 value:', themeCheck.computedColor);
console.log(' Full style content:', themeCheck.styleContent);
await page.screenshot({ path: path.join(DIR, 'theme-test-purple-p1.png'), fullPage: true });
// 3. Remove the test override
console.log('\n3. Removing test override...');
const delRes = await page.evaluate(async () => {
const res = await fetch('/api/theme', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
admin_user: 'admin',
admin_pass: 'Alarcade123#',
action: 'delete',
key: 'ludo-p1'
})
});
return await res.json();
});
console.log(' Delete result:', JSON.stringify(delRes));
await browser.close();
console.log('\nDone!');
})();
const { chromium } = require('playwright');
const path = require('path');
const BASE = 'https://el3ab-player.caprover.al-arcade.com';
const DIR = __dirname;
async function login(page) {
await page.goto(BASE + '/login', { waitUntil: 'networkidle', timeout: 15000 });
await page.evaluate(async () => {
const res = await fetch('https://safe-supabase-kong.caprover.al-arcade.com/auth/v1/token?grant_type=password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'
},
body: JSON.stringify({ email: 'uitest@el3ab.com', password: 'UiTest2026!' })
});
const data = await res.json();
if (data.access_token) {
localStorage.setItem('el3ab_token', data.access_token);
localStorage.setItem('el3ab_user', JSON.stringify(data.user));
}
});
await page.waitForTimeout(500);
}
(async () => {
const browser = await chromium.launch({ headless: true });
// Desktop
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, locale: 'ar' });
const page = await ctx.newPage();
await login(page);
// Mobile
const mCtx = await browser.newContext({ viewport: { width: 390, height: 844 }, locale: 'ar', isMobile: true });
const mobile = await mCtx.newPage();
await login(mobile);
// ====== LUDO VERIFICATION ======
console.log('\n=== LUDO ===');
// Ludo initial (dice + pieces in base)
await page.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, 'verify-ludo-01-desktop.png') });
console.log('✓ verify-ludo-01-desktop.png');
// Roll dice
const rollBtn = await page.$('.ludo-roll-btn, #ludo-roll-btn');
if (rollBtn) {
await rollBtn.click();
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'verify-ludo-02-rolled.png') });
console.log('✓ verify-ludo-02-rolled.png');
}
// 4-player local
await page.goto(BASE + '/ludo-game?mode=local&players=4', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'verify-ludo-03-4player.png') });
console.log('✓ verify-ludo-03-4player.png');
// Mobile ludo
await mobile.goto(BASE + '/ludo-game?mode=bot&bots=1&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(2500);
await mobile.screenshot({ path: path.join(DIR, 'verify-ludo-04-mobile.png') });
console.log('✓ verify-ludo-04-mobile.png');
const mRoll = await mobile.$('.ludo-roll-btn, #ludo-roll-btn');
if (mRoll) {
await mRoll.click();
await mobile.waitForTimeout(1500);
await mobile.screenshot({ path: path.join(DIR, 'verify-ludo-05-mobile-rolled.png') });
console.log('✓ verify-ludo-05-mobile-rolled.png');
}
// ====== DOMINO VERIFICATION ======
console.log('\n=== DOMINO ===');
// Domino lobby desktop
await page.goto(BASE + '/domino', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'verify-domino-01-lobby.png') });
console.log('✓ verify-domino-01-lobby.png');
// Domino 2P bot game
await page.goto(BASE + '/domino-game?mode=2p&type=bot&players=2&difficulty=medium', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, 'verify-domino-02-game-2p.png') });
console.log('✓ verify-domino-02-game-2p.png');
// Domino 4P teams bot
await page.goto(BASE + '/domino-game?mode=4p_teams&type=bot&players=4&difficulty=hard', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2500);
await page.screenshot({ path: path.join(DIR, 'verify-domino-03-game-4p.png') });
console.log('✓ verify-domino-03-game-4p.png');
// Domino local 2P
await page.goto(BASE + '/domino-game?mode=2p&type=local&players=2', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(2000);
await page.screenshot({ path: path.join(DIR, 'verify-domino-04-local.png') });
console.log('✓ verify-domino-04-local.png');
// Domino mobile lobby
await mobile.goto(BASE + '/domino', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(1500);
await mobile.screenshot({ path: path.join(DIR, 'verify-domino-05-mobile-lobby.png') });
console.log('✓ verify-domino-05-mobile-lobby.png');
// Domino mobile game
await mobile.goto(BASE + '/domino-game?mode=2p&type=bot&players=2&difficulty=easy', { waitUntil: 'networkidle', timeout: 15000 });
await mobile.waitForTimeout(2500);
await mobile.screenshot({ path: path.join(DIR, 'verify-domino-06-mobile-game.png') });
console.log('✓ verify-domino-06-mobile-game.png');
// Games hub (shows both chess, ludo, domino)
await page.goto(BASE + '/games', { waitUntil: 'networkidle', timeout: 15000 });
await page.waitForTimeout(1500);
await page.screenshot({ path: path.join(DIR, 'verify-games-hub.png') });
console.log('✓ verify-games-hub.png');
await browser.close();
console.log('\n✅ All verification screenshots saved!');
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment