E2E test automation framework for SlotsOne iGaming platform — built with Playwright, TypeScript, and modern QA best practices
pyavchik/slotsone-playwrightpages/ that encapsulates
locators and interaction methods. Tests never reference raw selectors — they call
descriptive methods on page objects, making tests readable and maintenance trivial when the
UI changes.
15 page objects covering public site, admin panel, and game screens:
Example — GamePage class:
export class GamePage {
readonly spinButton: Locator;
readonly balance: Locator;
readonly errorToast: Locator;
constructor(private page: Page) {
this.spinButton = page.getByRole('button', { name: /spin/i });
this.balance = page.getByTestId('hud-balance');
this.errorToast = page.locator('.slots-error-toast');
}
async goto(slug: string) { await this.page.goto(`/slots/${slug}`); }
async spin() { await this.spinButton.click(); }
}
base.fixture.ts extends Playwright's built-in test object.
Every spec imports test and expect from this fixture rather than
from @playwright/test directly. This central point injects Allure metadata
(epic & feature labels) and captures failure screenshots automatically.
export const test = base.extend({
page: async ({ page }, use, testInfo) => {
// Auto-label for Allure Behaviors tab
const dir = relPath.split(path.sep)[0];
const file = path.basename(testInfo.file);
if (EPICS[dir]) await allure.parentSuite(EPICS[dir]);
if (FEATURES[file]) await allure.suite(FEATURES[file]);
await use(page);
// Auto-attach screenshot on failure
if (testInfo.status !== testInfo.expectedStatus) {
const screenshot = await page.screenshot().catch(() => null);
if (screenshot) await testInfo.attach('screenshot', { body: screenshot });
}
},
});
Why it matters: zero Allure boilerplate in specs, consistent failure artifacts, and a single place to add cross-cutting concerns (logging, performance marks, etc.).
context.route() to intercept API calls and return
deterministic mock responses. This decouples E2E UI tests from backend availability,
making the suite fast, reliable, and runnable without a live server.
fixtures/helpers.ts provides composable mock functions that can be combined per test scenario:
// Individual mocks
await mockAuth(context); // auth/refresh → 200
await mockGameInit(context); // game/init → valid session
await mockSpin(context); // spin → winning result (auto-increments spin_id)
await mockSpinError(context); // spin → 500 server error
// Convenience bundles
await mockGameApis(context); // auth + init + spin + images
await mockRouletteApis(context);
await mockHistoryApis(context);
fixtures/mock-data.ts contains typed factory functions (makeGameInitResponse,
makeSpinResponse, etc.) with override support for edge-case testing:
// Default winning spin
makeSpinResponse();
// Custom: no-win spin
makeNoWinSpinResponse();
// Custom: big win (12x multiplier)
makeBigWinSpinResponse(bet);
// Override any field
makeSpinResponse({ balance: { amount: 0, currency: 'USD' } });
playwright.config.ts defines four test projects with dependency chains. The admin
setup project runs first to save storageState, which downstream admin specs reuse
— avoiding repeated login flows while maintaining proper test isolation.
projects: [
{ name: 'Public Site', testIgnore: '**/admin/**' },
{ name: 'Admin Setup', testMatch: '**/admin.setup.ts' },
{ name: 'Admin Login', testMatch: '**/admin/login.spec.ts' },
{
name: 'Admin Panel',
dependencies: ['Admin Setup'],
use: { storageState: '.auth/admin.json' },
},
]
Auth setup logs in via the real admin UI, then saves browser state to
.auth/admin.json. All authenticated admin tests inherit this state without any
extra login steps.
Jenkinsfile automates the full test lifecycle: install dependencies,
install Chromium, run tests, generate Allure reports, and publish both Allure and Playwright
HTML reports as build artifacts.
pipeline {
stages {
stage('Clean') { sh 'rm -rf allure-results allure-report playwright-report' }
stage('Install') { sh 'npm ci'; sh 'npx playwright install chromium' }
stage('Run Tests') { sh 'npx playwright test' }
}
post {
always {
sh 'allure generate allure-results -o allure-report --clean'
publishHTML(reportName: 'Allure Report')
publishHTML(reportName: 'Playwright Report')
}
}
}
Key CI settings: forbidOnly: !!process.env.CI prevents
accidental .only commits; retries: 2 in CI for flake resilience;
workers: 1 for deterministic execution on shared agents.
reporter: [
['list'], // terminal output
['html', { open: 'never' }], // Playwright HTML report
['allure-playwright'], // Allure integration
]
Environment metadata is written to allure-results/environment.properties at
config time, so every report shows the browser, base URL, and CI vs. local context.
dotenv for environment variables, conditional CI settings,
and built-in Playwright features like screenshot-on-every-test, video-on-failure, and
trace-on-first-retry for maximum debuggability.
use: {
baseURL: 'https://pyavchik.space',
actionTimeout: 10_000,
screenshot: 'on', // every test gets a screenshot
video: 'retain-on-failure', // video saved only when test fails
trace: 'on-first-retry', // trace captured on retry for debugging
}
.env.example documents required variables (ADMIN_EMAIL, ADMIN_PASSWORD),
keeping secrets out of the repository while making setup straightforward for new contributors.
Test Coverage Overview
25+ spec files organized by feature domain across 7 epics