Címke: Playwright

Playwright testing framework.

  • Playwright 1.64 újdonságok

    A Playwright 1.64-es verziója számos olyan új funkciót és finomítást hozott, amelyek megkönnyítik az elemkeresést, a tesztek futtatását, valamint a videófelvételek testreszabását.

    1. Új Locator API: locator.within()

    A locator.within() segítségével két már létező locatort lehet természetes módon kombinálni, és a relatív pozicionálók (pl. .first(), .nth()) a szülő elemen belül értékelődnek ki.

    TypeScript

    // Összekapcsol két külön definíciót
    const dialog = page.getByRole('dialog');
    const saveButton = page.getByRole('button', { name: 'Mentés' });
    
    // Mentés gomb keresése kifejezetten a párbeszédablakon belül
    await saveButton.within(dialog).click();
    

    2. Véletlenszerű tesztfuttatás: --shuffle

    Segít kiszűrni a tesztek közötti rejtett függőségeket a futtatási sorrend megkeverésével. A tesztfutás végén megadott seed kód segítségével pontosan reprodukálható a hibás futási sorrend.

    Bash

    # Tesztek véletlenszerű sorrendben történő futtatása
    npx playwright test --shuffle
    
    # Pontos futási sorrend újrajátszása a kapott seed alapján
    npx playwright test --shuffle 271828182
    

    3. Tesztzárolások (Test Locks) csoportszinten

    Míg a 1.63-ban megjelent zárolások csak egyes tesztekre vonatkoztak, a 1.64-ben már egész fájlokra vagy tesztcsoportokra (describe) is alkalmazhatóak. Az azonos zárolási névvel rendelkező tesztek nem futnak párhuzamosan.

    TypeScript

    import { test } from '@playwright/test';
    
    // Az ebben a csoportban lévő tesztek nem futnak párhuzamosan más 'user-settings' zárral ellátott tesztekkel
    test.describe.configure({ lock: 'user-settings' });
    
    test('profil frissítése', async ({ page }) => {
      // ...
    });
    

    4. default: false beállítás a projekt konfigurációban

    A playwright.config.ts-ben megjelölhetők olyan böngészők vagy projektek, amelyeket alapértelmezetten ki szeretnél hagyni a sima npx playwright test futtatásból anélkül, meglévő konfigurációkat kellene törölni.

    TypeScript

    // playwright.config.ts
    export default {
      projects: [
        { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
        { name: 'firefox', use: { ...devices['Desktop Firefox'] }, default: false },
        { name: 'webkit', use: { ...devices['Desktop Safari'] }, default: false },
      ],
    };
    
    • Futtatás csak chromium-on: npx playwright test
    • Kifejezett futtatás firefox-on: npx playwright test --project=firefox

    5. Videófelvételek fejlesztése (VP9, CSS stílusok, FPS)

    A videók rögzítése hatékonyabbá és jobban testreszabhatóvá vált:

    • VP9 kódolás: Kisebb fájlméret és alacsonyabb CPU-használat.
    • Egyedi képkockasebesség (FPS): Testreszabható fps opció.
    • CSS stílusok a műveletjelzőkhöz: A korábbi fontSize opció helyett CSS szabályok adhatók meg a mutatók és kiemelések testreszabására.

    TypeScript

    // playwright.config.ts
    export default {
      use: {
        video: {
          mode: 'on',
          fps: 60,
          style: {
            pointMarker: 'background-color: red;',
            targetHighlight: 'border: 2px solid blue;',
          },
        },
      },
    };
    

    6. Kísérleti WebMCP támogatás (page.webmcp)

    A Playwright kiegészült a böngésző alapú AI modellek eszközeinek (WebMCP) tesztelésére szolgáló felülettel (page.webmcp.tools() és page.webmcp.callTool()), amellyel ellenőrizhetők az oldalak által az AI-ágensek felé regisztrált eszközök.

    Fontosabb breaking change-ek / Viselkedésbeli változások

    • Rejtett iframe-ek: A nem látható iframe-ben lévő elemeket (pl. visibility: hidden) a Playwright mostantól automatikusan rejtettként kezeli az akciók és a toBeVisible() ellenőrzések során.
    • Emulált képernyőméret: A devices['Desktop Chrome'] típusú eszközleírók átadják a screen tulajdonságot, így a window.screen felbontása és a media query-k az emulált kijelzőméretet tükrözik.
    • Snapshot frissítés: A --update-snapshots=missing opció használata esetén a hiányzó screenshotok létrehozása után a teszt sikeresként értékelődik.
  • Report Portal

    Hol is kezdjem? Ma is elégettem nem kevés tokent, bár szerencsére ezek ingyen vannak/voltak. Amit ki akartam próbálni, hogy telepítettem egy Rider-t, ami egy IDE, és nekem a .net miatt van rá szükség, majd pedig a Copilot-tal és Gemini-vel elkezdtem ebből egy Playwright, Nunit és .net projectet faragni. Aztán jött a szokásos nehézség, kell egy jelentést generáló eszköz, ami többet vagy épp másképpen tud, mint az Allure. Az AI azt mondta, hogy Report Portal.

    Nem volt mit tenni, elkezdtem belefaragni ezt, és az API kulcs generáláson kívül minden lépést az AI CLI-on keresztül csináltam meg. Szerintem elég pofás lett a végeredmény, de majd erről egy másik bejegyzésben írok részletesebben.

    Most inkább megmutatom, hogy mit tud a Report Portal.

    Mit mond a Gemini?

    A ReportPortal egy nyílt forráskódú (Open Source), AI-alapú tesztriportáló és analitikai platform. Elsősorban automatizált tesztek eredményeinek gyűjtésére, vizualizálására és elemzésére szolgál.

    Főbb jellemzők és előnyök

    • Központi dashboard: Egységes felületen gyűjti össze a különböző tesztkeretrendszerekből és CI/CD csatornákból származó teszteredményeket.
    • AI / Machine Learning alapú hibaelemzés: A korábbi futtatások alapján automatikusan felcímkézi a hibákat (pl. termékhiba, teszthiba, infrastruktúra-probléma), így drasztikusan csökkenti a manuális triázsolásra fordított időt.
    • Valós idejű analitika: A tesztek futása közben élőben láthatók az eredmények, trendek és statisztikák.
    • Integrációk: Szorosan együttműködik hibakövető rendszerekkel (Jira, Rally, Redmine) és CI/CD eszközökkel (Jenkins, GitLab CI, GitHub Actions).

    A ReportPortal architektúrája

    A ReportPortal mikroszolgáltatás-alapú architektúrát használ, amely több konténerből áll (API Service, UI, Index Service/AI Engine, PostgreSQL, RabbitMQ, OpenSearch/Elasticsearch). Ezért a legegyszerűbb és legajánlottabb módja a lokális futtatásnak a Docker / Docker Compose.

    Integráció lokális projektbe (Lépésről lépésre)

    1. Lokális ReportPortal szerver elindítása (Docker Compose)

    Helyi teszteléshez futtasd a ReportPortal szervert a saját gépeden:

    1. Töltsd le a hivatalos Docker Compose fájlt:
      Bash curl -LO https://raw.githubusercontent.com/reportportal/reportportal/master/docker-compose.yml
    2. Indítsd el a konténereket:
      Bashdocker compose up -d
    3. Nyisd meg a böngészőben a http://localhost:8080 címet.
    4. Lépj be az alapértelmezett adatokkal (User: superadmin, Jelszó: erebus).
    5. Hozz létre egy új Projectet, és a profilbeállításoknál másold ki az API Access Token-t.

    2. Tesztkeretrendszer integrálása a projektedbe

    A ReportPortal szinte minden népszerű nyelvhez és tesztkeretrendszerhez biztosít kliens könyvtárat (Agent):

    • Java: JUnit, TestNG, Cucumber
    • Python: Pytest, Robot Framework, Behave
    • JavaScript / TypeScript: Playwright, Cypress, Jest, Mocha
    • .NET: NUnit, xUnit, SpecFlow
    Példa: Pytest (Python) integráció
    1. Telepítsd a pytest agentet:
      Bash pip install pytest-reportportal
    2. Hozz létre egy pytest.ini fájlt a projekt gyökerében:
      Ini, TOML[pytest] rp_api_key = az_a_token_amit_a_profilodban_masoltal rp_endpoint = http://localhost:8080 rp_project = a_projekt_neve rp_launch = Helyi_Pytest_Futtatas rp_launch_attributes = 'Env:Local' 'Type:Smoke'
    3. Futtasd a teszteket a ReportPortal plugin aktiválásával:
      Bash pytest --reportportal
    Példa: Playwright (Node.js / TypeScript) integráció
    1. Telepítsd az agentet:
      Bash npm install --save-dev @reportportal/agent-js-playwright
    2. Add hozzá a playwright.config.ts fájlhoz a riportert:
      TypeScript const RPconfigFile = { apiKey: 'az_a_token_amit_a_profilodban_masoltal', endpoint: 'http://localhost:8080/api/v1', project: 'a_projekt_neve', launch: 'Playwright_Helyi_Futtatas', attributes: [{ key: 'Env', value: 'Local' }], }; export default defineConfig({ reporter: [['@reportportal/agent-js-playwright', RPconfigFile]], });
    3. Futtasd a teszteket a megszokott módon:Bash npx playwright test
  • Készítsünk Playwright project-et Copilot-tal

    Készítsünk Playwright project-et Copilot-tal

    Megkésve, de törve nem, én is elkezdtem egyre több dologra használni az AI-t, ahogy az a korábbi bejegyzéseimből is látszik. Reggel gondoltam egy merészet, és megkértem a Copilot-ot, hogy kezdjünk el csinálni egy Playwright, TypeScript projectet, mindezt VSCode-ban, és csak CLI-jal. Meg kell mondjam, egész jól sikerültek az alapok, és időben is lényegesen hamarabb készült el, mintsem, ha kézzel kezdem el.

    Felbuzdulva ezen, megkértem, hogy integrálja bele az Allure riport készítést, ami elsőre nem volt teljes siker, mert nem tartalmazta a korábbi futásokat a kérésem ellenére, de ez is hamar javítva lett.

    Folytattam azzal, hogy egy ingyenes és publikus API hívásra írattam vele 3 tesztet, majd pedig kértem, hogy legyen 2 negatív is, amit ő elsőre úgy értett, hogy átírta a meglévőket. Ezt is hamar javítottuk.

    Kértem, hogy amit csináltunk, azt tegye bele egy Word fájlba, illetve még készítettem vele egy readme.md fájlt is. Szerintem egész jól sikerült, mindezt relatív kevés idő alatt, szóval biztosan fogom még folytatni vele a munkát.

    Íme a teljes lista:

    Project path: D:\Repositories\ai-playwright
    Earliest retrievable project record:
    approximately 08:55 local time (06:55 UTC)

    08:53 ? Initial workspace session

    • Opened the working area under D:\Repositories.

    08:55 ? Created the Playwright project

    • Created D:\Repositories\ai-playwright as a TypeScript Playwright project.
    • Configured Chromium, added example tests and a GitHub Actions workflow.
    • Installed dependencies and Chromium.
    • Verified that the two starter tests passed with npx playwright test.

    09:01 ? Changed reporting to Allure

    • Switched the default Playwright reporter to Allure.
    • Added Allure report generation and execution-history persistence.
    • Updated package.json, playwright.config.ts, .github/workflows/playwright.yml, .gitignore, and scripts/allure-history.js.
    • Configured CI to restore and save Allure history.
    • Verified the initial tests and report generation.

    09:07?09:23 ? Opened and fixed Allure history

    • Generated allure-report and started it with npm run allure:open.
    • Investigated why previous executions were not visible.
    • Fixed the issue by clearing old result files before each run while preserving history.
    • Verified that the report showed three executions per test instead of treating earlier executions as retries.

    09:26 ? Added Open-Meteo API tests

    • Added tests in tests/open-meteo-api.spec.ts.
    • Covered a valid forecast request, invalid latitude, and invalid longitude.
    • All three tests passed.

    09:28?09:34 ? Regenerated the report and improved assertions

    • Regenerated Allure with the API tests.
    • Added descriptive failure messages to the expect assertions.

    09:49?09:51 ? Added more negative API scenarios

    • Added a request missing required longitude.
    • Added a request with an unsupported current-weather variable.
    • The API test file reached five tests total.

    09:52 ? Verified all tests

    • Ran the full suite.
    • All seven tests passed.
    • Regenerated the Allure report with all tests.

    09:55?10:03 ? Fixed Allure generation in GitHub Actions

    • Investigated why the report was not generated in CI.
    • Updated the workflow to restore history, run Playwright, always generate the report, and upload the report artifact when possible.
    • Local verification passed.

    10:07?10:12 ? Discussed opening reports from CI

    • Clarified that GitHub Actions cannot directly open a browser on the runner.
    • Discussed GitHub Pages as the way to automatically host and view the report.
    • Explained how to open a downloaded report locally with npx allure open.

    10:20 ? Opened the Allure report again

    10:31 ? Added Playwright Codegen

    • Added the codegen script to package.json.
    • Usage: npm run codegen — https://example.com.
    • Discussed saving recorded tests with –output tests/recorded.spec.ts.

    10:34?10:48 ? Reviewed the project and exported coverage

    • Explained that the project is a Playwright test project, not the application under test.
    • Identified that baseURL and webServer are not configured.
    • Created D:\Repositories\ai-playwright\test-coverage.xlsx.
    • The workbook contains all seven test cases, behaviors, assertions, Allure statuses, and a test-scope coverage summary.

    Note: The earliest project-creation record available is the summarized 08:55 local-time session; the initial setup session does not contain a complete message-by-message transcript.

    10:56 – Added project README documentation

    • Created README.md in the project root.
    • Documented prerequisites and installation from scratch.
    • Documented browser and API test execution.
    • Documented Allure report generation, opening, and execution-history handling.
    • Documented Playwright Codegen usage.
    • Documented project configuration, structure, GitHub Actions CI behavior, and troubleshooting.
  • POM avagy Page Object Model

    Mire jó az AI? Hát például arra, hogy ha írni szeretnék egy témáról, de lusta vagyok, az egyébként is Google segítsével összeszedett információkat rendszerbe szedni, akkor relatív gyorsan kézhez kapok egy bejegyzést.

    A Page Object Model (POM) a szoftvertesztelés-automatizálás egyik legnépszerűbb és leghatékonyabb tervezési mintája (Design Pattern). A lényege, hogy az alkalmazás egyes weboldalait (vagy oldalrészeit) különálló objektumokként képezi le a kód szintjén.

    Miért érdemes használni?

    • Karbantarthatóság: Ha megváltozik egy gomb ID-ja vagy egy mező elhelyezkedése, elegendő azt egyetlen helyen (a Page Object osztályban) átírni, a teszteseteket nem kell bántani.
    • Kód újrafelhasználhatósága: A gyakori műveletek (pl. bejelentkezés, keresés) egyszer vannak megírva, és bármelyik tesztből meghívhatók.
    • Olvashatóság: A tesztkód tiszta, átlátható és üzleti logikát követő lesz, rejtve a techniai megvalósítást (pl. DOM-lekérdezéseket).

    Minta megvalósítás (Python + Selenium)

    Az alábbiakban egy klasszikus bejelentkezési folyamat példáján keresztül látható a POM működése.

    A Page Object osztály (login_page.py)

    Ez az osztály tartalmazza az oldal elemeinek azonosítóit (lokátorait) és a végezhető műveleteket.

    Python

    from selenium.webdriver.common.by import By
    
    class LoginPage:
        def __init__(self, driver):
            self.driver = driver
            
            # Lokátorok (különválasztva a logikától)
            self._username_input = (By.ID, "username")
            self._password_input = (By.ID, "password")
            self._login_button = (By.CSS_SELECTOR, "button[type='submit']")
            self._error_message = (By.CLASS_NAME, "flash-error")
    
        # Akciók / Műveletek
        def enter_username(self, username: str):
            self.driver.find_element(*self._username_input).send_keys(username)
    
        def enter_password(self, password: str):
            self.driver.find_element(*self._password_input).send_keys(password)
    
        def click_login(self):
            self.driver.find_element(*self._login_button).click()
    
        # Összetett folyamat (Láncolt / Magasabb szintű akció)
        def login(self, username: str, password: str):
            self.enter_username(username)
            self.enter_password(password)
            self.click_login()
    
        def get_error_message(self) -> str:
            return self.driver.find_element(*self._error_message).text
    

    A Teszteset (test_login.py)

    A tesztkód csak a Page Object által nyújtott metódusokat használja, így végtelenül egyszerű és olvasható.

    Python

    import pytest
    from selenium import webdriver
    from login_page import LoginPage
    
    @pytest.fixture
    def driver():
        driver = webdriver.Chrome()
        driver.get("https://example.com/login")
        yield driver
        driver.quit()
    
    def test_successful_login(driver):
        login_page = LoginPage(driver)
        
        # Bejelentkezés végrehajtása
        login_page.login("valid_user", "correct_password")
        
        # Ellenőrzés (Assertion)
        assert driver.current_url == "https://example.com/dashboard"
    
    def test_failed_login(driver):
        login_page = LoginPage(driver)
        
        login_page.login("invalid_user", "wrong_password")
        
        # Hibaüzenet ellenőrzése
        assert "Érvénytelen adatok" in login_page.get_error_message()
    

    Jó tanácsok a gyakorlati alkalmazáshoz

    • Ne tegyél assertion-öket a Page Object-be: A assert kifejezések a tesztfájlban maradjanak, a Page Object csak adatot adjon vissza vagy állapotot módosítson.
    • Page Factory használata: Bizonyos keretrendszerekben (pl. Java + Selenium) a @FindBy annotációkkal még tisztább szerkezet érhető el.
    • Lazy loading: Az elemeket csak akkor kérd le a DOM-ból, amikor ténylegesen szükség van rájuk (például dinamikus felületek esetén).

    A Page Object Model (POM) megvalósítása a modernebb eszközökkel (mint a Playwright vagy a Selenium Java-alapú változata) még letisztultabbá válik, mivel ezek a keretrendszerek beépített architektúrával támogatják a megbízhatóbb elemkezelést.

    Az alábbiakban mindkét megközelítésre találsz egy-egy komplett kódmintát.

    Playwright + TypeScript (Ajánlott / Modern megközelítés)

    A Playwright eleve magában foglalja az automatikus várakozást (Auto-waiting), így nincs szükség explicit wait-ek kézi kezelésére.

    A Page Object osztály (pages/LoginPage.ts)

    TypeScript

    import { Page, Locator } from '@playwright/test';
    
    export class LoginPage {
      readonly page: Page;
      readonly usernameInput: Locator;
      readonly passwordInput: Locator;
      readonly loginButton: Locator;
      readonly errorMessage: Locator;
    
      constructor(page: Page) {
        self.page = page;
        // A Playwright-ban a lokátorok deklaratívak, nem kérdezik le azonnal a DOM-ot
        this.usernameInput = page.locator('#username');
        this.passwordInput = page.locator('#password');
        this.loginButton = page.locator('button[type="submit"]');
        this.errorMessage = page.locator('.flash-error');
      }
    
      async goto() {
        await this.page.goto('https://example.com/login');
      }
    
      async login(username: string, password: string) {
        await this.usernameInput.fill(username);
        await this.passwordInput.fill(password);
        await this.loginButton.click();
      }
    
      async getErrorMessage(): Promise<string> {
        return await this.errorMessage.textContent() || '';
      }
    }
    

    A Tesztfájl (tests/login.spec.ts)

    TypeScript

    import { test, expect } from '@playwright/test';
    import { LoginPage } from '../pages/LoginPage';
    
    test.describe('Bejelentkezés tesztek', () => {
      let loginPage: LoginPage;
    
      test.beforeEach(async ({ page }) => {
        loginPage = new LoginPage(page);
        await loginPage.goto();
      });
    
      test('Sikeres bejelentkezés', async ({ page }) => {
        await loginPage.login('valid_user', 'correct_password');
        
        // Ellenőrzés Playwright assert-tel
        await expect(page).toHaveURL('https://example.com/dashboard');
      });
    
      test('Hibás bejelentkezés', async () => {
        await loginPage.login('invalid_user', 'wrong_password');
        
        await expect(loginPage.errorMessage).toBeVisible();
        await expect(loginPage.errorMessage).toContainText('Érvénytelen adatok');
      });
    });
    

    Java + Selenium (Klasszikus keretrendszer)

    Java környezetben a PageFactory és a @FindBy annotációk használata a legelterjedtebb POM minta.

    A Page Object osztály (LoginPage.java)

    Java

    package pages;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.support.FindBy;
    import org.openqa.selenium.support.PageFactory;
    
    public class LoginPage {
        private WebDriver driver;
    
        // Lokátorok deklarálása annotációkkal
        @FindBy(id = "username")
        private WebElement usernameInput;
    
        @FindBy(id = "password")
        private WebElement passwordInput;
    
        @FindBy(css = "button[type='submit']")
        private WebElement loginButton;
    
        @FindBy(className = "flash-error")
        private WebElement errorMessage;
    
        // Konstruktor: inicializálja a PageFactory elemeit
        public LoginPage(WebDriver driver) {
            this.driver = driver;
            PageFactory.initElements(driver, this);
        }
    
        public void enterUsername(String username) {
            usernameInput.clear();
            usernameInput.sendKeys(username);
        }
    
        public void enterPassword(String password) {
            passwordInput.clear();
            passwordInput.sendKeys(password);
        }
    
        public void clickLogin() {
            loginButton.click();
        }
    
        public void login(String username, String password) {
            enterUsername(username);
            enterPassword(password);
            clickLogin();
        }
    
        public String getErrorMessageText() {
            return errorMessage.getText();
        }
    }
    

    A Tesztosztály (JUnit 5 használatával) (LoginTest.java)

    Java

    package tests;
    
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import pages.LoginPage;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertTrue;
    
    public class LoginTest {
        private WebDriver driver;
        private LoginPage loginPage;
    
        @BeforeEach
        public void setUp() {
            driver = new ChromeDriver();
            driver.manage().window().maximize();
            driver.get("https://example.com/login");
            loginPage = new LoginPage(driver);
        }
    
        @Test
        public void testSuccessfulLogin() {
            loginPage.login("valid_user", "correct_password");
            assertEquals("https://example.com/dashboard", driver.getCurrentUrl());
        }
    
        @Test
        public void testFailedLogin() {
            loginPage.login("invalid_user", "wrong_password");
            assertTrue(loginPage.getErrorMessageText().contains("Érvénytelen adatok"));
        }
    
        @AfterEach
        public void tearDown() {
            if (driver != null) {
                driver.quit();
            }
        }
    }
    

    Főbb különbségek a két megközelítés között

    SzempontPlaywright (TypeScript)Selenium (Java)
    LokátorokA Locator objektumok deklaratívak (auto-wait)A @FindBy elemek lekezeléséhez várakozás (WebDriverWait) kellhet
    PárhuzamosításAlapból támogatott a tesztfutztatóbanTestNG vagy JUnit szálkezelést igényel
    InicializálásEgyszerű objektumkonstruktorPageFactory.initElements() hívás szükséges

    A Playwright Custom Fixture funkciója segítségével a Page Object osztályok példányosítását teljesen kiszervezheted a tesztekből. Ezzel elkerülhető, hogy minden egyes tesztfájlban manuálisan kelljen megadni a const loginPage = new LoginPage(page) sorokat.

    A tesztek így közvetlenül paraméterként kérhetik el a szükséges oldalobjektumokat, az infrastruktúra pedig automatikusan példányosítja és előkészíti azokat.

    A Page Object osztályok (pages/)

    A megszokott módon hozzuk létre az oldalklasszokat.

    TypeScript

    // pages/LoginPage.ts
    import { Page, Locator } from '@playwright/test';
    
    export class LoginPage {
      readonly page: Page;
      readonly usernameInput: Locator;
    
      constructor(page: Page) {
        this.page = page;
        this.usernameInput = page.locator('#username');
      }
    
      async goto() {
        await this.page.goto('/login');
      }
    }
    
    // pages/DashboardPage.ts
    import { Page, Locator } from '@playwright/test';
    
    export class DashboardPage {
      readonly page: Page;
      readonly userMenu: Locator;
    
      constructor(page: Page) {
        this.page = page;
        this.userMenu = page.locator('#user-menu');
      }
    }
    

    A Custom Fixture létrehozása (fixtures/baseTest.ts)

    Itt terjesztjük ki a Playwright alapértelmezett test objektumát, megadva a saját Page Object fixture-jeinket.

    TypeScript

    import { test as base } from '@playwright/test';
    import { LoginPage } from '../pages/LoginPage';
    import { DashboardPage } from '../pages/DashboardPage';
    
    // 1. Típusdefiníció a fixture-ökhöz
    type MyFixtures = {
      loginPage: LoginPage;
      dashboardPage: DashboardPage;
    };
    
    // 2. A 'base.extend' használatával regisztráljuk a saját fixture-jeinket
    export const test = base.extend<MyFixtures>({
      // Automatikusan példányosítja a LoginPage-t és igény esetén megnyitja az oldalt
      loginPage: async ({ page }, use) => {
        const loginPage = new LoginPage(page);
        await loginPage.goto(); // Akár előkészítő lépéseket is tehetünk ide
        await use(loginPage);   // Átadja az objektumot a tesztnek
      },
    
      // Példányosítja a DashboardPage-t
      dashboardPage: async ({ page }, use) => {
        const dashboardPage = new DashboardPage(page);
        await use(dashboardPage);
      },
    });
    
    // Az 'expect'-et is exportáljuk a kényelmes importálásért
    export { expect } from '@playwright/test';
    

    A Fixture-ök használata a tesztekben (tests/login.spec.ts)

    A @playwright/test helyett a saját fixtures/baseTest fájlunkból importáljuk a test objektumot. A tesztfüggvény paramétereként megadott nevek alapján a Playwright automatikusan beadagolja a megfelelő példányokat.

    TypeScript

    // Figyelem: A saját kiterjesztett test objektumunkat importáljuk!
    import { test, expect } from '../fixtures/baseTest';
    
    test('Sikeres bejelentkezés custom fixture-rel', async ({ loginPage, dashboardPage }) => {
      // A loginPage.goto() már lefutott a fixture-ben!
      await loginPage.usernameInput.fill('standard_user');
      
      // A dashboardPage is azonnal használható, nem kellett 'new'-val példányosítani
      await expect(dashboardPage.userMenu).toBeVisible();
    });
    

    Miért ez a legnépszerűbb Playwright architektúra?

    • Nulla boilerplate kód: Nem kell beforeEach blokkokban példányosítani az osztályokat.
    • Lazy loading (Lusta betöltés): Csak azok a Page Object-ek példányosulnak, amiket a teszt fejlécében ({ loginPage, dashboardPage }) kifejezetten elkérsz.
    • Beépített tear-down: A fixture-ben a use() hívás utáni kódrészlet automatikusan lefut a teszt végén (takarításra, kijelentkezésre ideális).
  • Playwright 1.63 újdonságok

    Playwright 1.63 újdonságok

    Újdonságok

    A Playwright 1.63 frissítése megérkezett, és számtalan olyan funkciót hoz, amelyek lényegesen egyszerűbbé teszik a komplex tesztelési munkafolyamatokat, a párhuzamosítást és a hibakeresést.

    Az alábbiakban összefoglaltuk a kiadás legfontosabb újdonságait és fejlesztéseit.

    Key Features & Újdonságok

    1. Test Locks (Tesztreteszek)

    • Megoldást nyújt a közös erőforrások (pl. központi adatbázis, globális fiókbeállítások vagy külső API-k) használata miatti ütközésekre.
    • Lehetővé teszi zárolások (locks) megadását, így a tesztek automatikusan sorba állnak a kritikus erőforrások eléréséhez, elkerülve a párhuzamos futtatásból eredő hibákat.

    2. Step paraméterek és feliratok (test.step)

    • A test.step() mostantól elfogad egy params opciót, amellyel saját metaadatokat és paramétereket adhatsz át a lépésekhez.
    • A riportokban és a Trace Viewerben tisztábban nyomon követhetők az egyedi lépésekhez tartozó változók és hívási argumentumok.

    3. Aria Traces & Bővített Tracing

    • A Trace Viewer új aria pillanatképeket (snapshots) támogat.
    • Megkönnyíti a hozzáférhetőségi (accessibility) elemek és az ARIA fa állapotának elemzését hibakeresés közben.

    4. Új Scroll Opciók az akcióknál

    • A legtöbb akciónál (pl. .click()) megjelent egy új scroll opció ("auto" | "none").
    • Lehetőséget biztosít arra, hogy kikapcsold a Playwright automatikus „scroll-into-view” viselkedését, ha egy elem pozícióját manuálisan szeretnéd kezelni.

    5. Új teszt opciók és CLI parancsok

    • Nagyobb hozzáférhetőség tesztelése: Új reducedMotion, forcedColors és contrast opciók a testOptions alatt.
    • --add-reporter parancssori opció: Bővítheted a meglévő riporterek listáját ahelyett, hogy felülírnád a playwright.config.ts-ben megadottakat.
    • omitTags opció: Letisztultabb tesztcímek a riportokban (suppress-eli az automatikusan hozzáfűzött tegeket a list, line, dot, github és junit riportereknél).

    Eltávolított (Deprecated) API-k

    A 1.63-as verzió végleg kivezeti a régen elavultnak jelölt funkciókat:

    • Locator.ariaRef() (használd helyette a locator.ariaSnapshot() funkciót).
    • handle opció a BrowserContext.exposeBinding és Page.exposeBinding esetében.
    • logger opció a BrowserType.connect és connectOverCDP metódusoknál.
    • videosPath és videoSize konfig opciók (használd a recordVideo-t).

    Frissítés

    A legújabb verzióra való átálláshoz futtasd a projekt gyökerében az alábbi parancsot:

    Bash

    npm install -D @playwright/test@latest
    npx playwright install

    Test Lock minta

    A Playwright 1.63-ban megjelent Test Locks (Tesztreteszek) opció segítségével megakadályozhatod, hogy bizonyos tesztek egyszerre futjanak és ütközzenek a közös erőforrásokon (pl. ugyanazon tesztfiók beállításai, adatbázis vagy külső API-k), miközben a többi független teszt továbbra is párhuzamosan fut.

    Az alábbiakban bemutatjuk a legfontosabb használati módokat kódpéldákkal.

    1. Egyedi teszt zárolása egy megnevezett retesszel (lock)

    Ha van két vagy több teszted, amelyek ugyanazt a megosztott erőforrást módosítják, megadhatsz nekik egy azonos lock nevet az opciók között:

    TypeScript

    import { test, expect } from '@playwright/test';
    
    // Ez a teszt lefoglalja az 'admin-account' reteszt
    test('Adminisztrátor frissíti a cég nevét', { lock: 'admin-account' }, async ({ page }) => {
      await page.goto('https://example.com/admin/settings');
      await page.getByLabel('Cégnév').fill('Új Cégnév Kft.');
      await page.getByRole('button', { name: 'Mentés' }).click();
    
      await expect(page.getByText('Sikeres mentés')).toBeVisible();
    });
    
    // Ez a teszt megvárja, amíg az előző teszt elengedi az 'admin-account' reteszt
    test('Adminisztrátor módosítja az időzónát', { lock: 'admin-account' }, async ({ page }) => {
      await page.goto('https://example.com/admin/settings');
      await page.getByLabel('Időzóna').selectOption('Europe/Budapest');
      await page.getByRole('button', { name: 'Mentés' }).click();
    
      await expect(page.getByText('Sikeres mentés')).toBeVisible();
    });
    

    Hogyan működik? Amíg a Worker 1 az első tesztet futtatja az admin-account retesszel, addig a Worker 2 nem kezdi el a második tesztet. A két teszt egymás után fog lefutni, de a csomag többi, független tesztje (pl. termékkeresés, kosárkezelés) továbbra is teljesen párhuzamosan fut a többi workeren.

    2. Egész tesztcsoport zárolása (test.describe)

    Ha egy egész blokknyi teszt egyetlen közös erőforráson dolgozik, a lock opciót közvetlenül a test.describe() csoportra is ráteheted:

    TypeScript

    import { test, expect } from '@playwright/test';
    
    test.describe('Adatbázis konfigurációs tesztek', { lock: 'database-config' }, () => {
      
      test('Alapértelmezett nyelv beállítása', async ({ page }) => {
        // ... teszt kód
      });
    
      test('Rendszerértesítések kikapcsolása', async ({ page }) => {
        // ... teszt kód
      });
    
    });
    

    3. Több retesz egyidejű használata (Array)

    Egy teszt akár több megosztott erőforrás zárolását is kérheti egyszerre. Ehhez adj meg egy tömböt a lock paraméterben:

    TypeScript

    import { test, expect } from '@playwright/test';
    
    test(
      'Fizetési átjáró és szállítási beállítások egyidejű frissítése',
      { lock: ['payment-sandbox', 'shipping-api'] },
      async ({ page }) => {
        // Ez a teszt csak akkor indul el, ha mindkét retesz szabad
        await page.goto('https://example.com/admin/integrations');
        // ... teszt kód
      }
    );
  • Playwright lokátorok

    Egy újabb, gyorsan elsajátítható dolog, a Playwright lokátorok kezelése.

  • Playwright & Typescript cheat sheet

    LinkedIn-en találtam. Hasznos tud lenni, bár az ilyet egérpadon tudnám elképzelni.

  • Playwright struktúra

    Néha hasznos tud lenni, ámbár nem gyakran fordul elő, hogy a semmiből kell építkezni, de akkor jól tud jönni, ha követünk egyfajta standardot. Talán azt mondanám, hogy a lokátorokat nem tenném külön, de van az a méretű projekt, ahol van ennek létjogosultsága.

  • Playwright & expect.poll

    Bár nagyon sokat használtam, mégsincs kéznél egy darab példakódom sem ezzel kapcsolatban. Így hát a Playwright bibliát fogom segítségül hozni a példák bemutatására.

    Mire való?

    Nekem ez akkor volt nagyon hasznos, amikor API teszteket írtam, és a GET endpoint válaszánál nem volt elég egy 200-as válaszkód, mivel a háttérben a szinkronizációs folyamat nem ért be, tehát a GET endpoint-ot addig kellett hívni, amíg a megfelelő válasz meg nem érkezett.

    Elsőre én is, mint egy kis cserkész, betettem egy while loop-ba, és működött tökéletesen. Aztán rátaláltam a Playwright által támogatott gyári megoldásra, és azt kell mondanom, hogy zseniálisan jól működőtt.

    Példa kód a hivatalos oldalról

    await expect.poll(async () => {
      const response = await page.request.get('https://api.example.com');
      return response.status();
    }, {
      // Custom expect message for reporting, optional.
      message: 'make sure API eventually succeeds',
      // Poll for 10 seconds; defaults to 5 seconds. Pass 0 to disable timeout.
      timeout: 10000,
    }).toBe(200);

    Mi is történik itt? A GET endpoint válaszkódjával térünk vissza, és azt hasonlítjük össze az elvárttal. Teszük ezt addig, amíg tart a timeout-ban megadott érték.

    Következő példa: intervals

    await expect.poll(async () => {
      const response = await page.request.get('https://api.example.com');
      return response.status();
    }, {
      // Probe, wait 1s, probe, wait 2s, probe, wait 10s, probe, wait 10s, probe
      // ... Defaults to [100, 250, 500, 1000].
      intervals: [1_000, 2_000, 10_000],
      timeout: 60_000
    }).toBe(200);

    Ekkor az intervals-ban megadott értékek fogják jelenteni a próbálkozások közt eltelt időt. Ezt érdemes úgy beállítani, hogy lehetőleg ne generáljuk túl nagy extra terhelést a rendszer számára.

    Példa a soft-ra

    await expect.soft.poll(async () => {
      const response = await page.request.get('https://api.example.com');
      return response.status();
    }).toBe(200);

    Az expect.soft kapcsán nekem az a megélésem, hogy nagyon megoszlanak a vélemények. Vannak, akik teljes mértékben ellenzik a használatát, mások pedig – mint én is – úgy vannak vele, hogy vannak olyan esetek, amikor szükséges lehet. Ugye, soft esetén ha hibára fut, nem áll meg a futás, hanem megy tovább a teszt.

    Szóval nagyon hasznos tud lenni a Playwright online elérhető dokumentációja. Ha bármi kérdés merülne fel, ajánlom, hogy ott kezdödjön a kutatás.

  • Automatizáló framework-ök a szakmám során

    Eddigi pályafutásom során jó pár framework-höz volt szerencsém különféle programnyelvek mellett, és hát azt kell mondanom, hogy ideje ezeket összegyűjtenem, mert kezdem egy részét elfelejteni.

    • Selenium WebDriver (#C, JAVA)
    • HP UFT (Visual Basic Script)
    • Katalon Studio (Kotlin)
    • Cypress (JavaScript)
    • Playwright (TypeScript)

    Selenium + C# + NUnit

    Kezdjünk is bele. Szóval még az automatizáló pályám elején volt lehetőségem a munkám mellett gyakorolni, és az épp aktuális Selenium volt a választott C#-pal. Ez akkoriban azt jelentette, hogy ahogy ma egy demó kód kinéz, kb úgy írtam én is meg Visual Studioban, majd pedig NUnitban a saját gépemről futottak a tesztek. Attól függetlenül, hogy messze volt egy professziónális megoldástól, szépen fogta a regressziós hibákat.

    Valahogy így kell elképzelni, ahogy a tesztek futottak.

    HP UFT + Visual Basic Script + HP ALM

    Ez volt az első hivatalos automatizálós projektem, ami előtt még kaptam HP képzést is, bár ennél a munka és a szükséges tudás összeszedése internetről sokkal hasznosabbnak bizonyult. Ahogy nézem, a HP dolgai igencsak megváltoztak, más kezeli őket.

    HP ALM kapcsán a Gurunál találtam egy értékelhető leírást, és a jól emlékszem, én ennek az oldalnak használtam fel a tudásanyagát annak idején. Viszont jól látszik, hogy elszaladt az idő felette. Talán az egyik cimborám kérdezte pár éve, hogy mi a véleményem egy ilyen projektről, és már akkor azt mondtam, hogy kerülje el, mert nincs jövője.

    Annak idején ez az ökoszisztéma igencsak jól működött, bár ára is volt (cég fizette). Az ALM végezte a központosítást, az UFT pedig az automata tesztek fejlesztésért volt felelős.

    Így nézett ki az UFT.

    Az ALM pedig így.

    Szerintem ez a kettő együtt akkoriban zseniális párost alkotott.

    Katalon Studio

    Kísérletezgettem vele annak idején. Még tetszett is, de valahogy körülményesnek ítéltem meg a használatát. Ennél egy IDEs kódszerkesztővel jobban és minőségibben lehet/lehetett dolgozni. Az pozitív volt, hogy próbálta egy IDE-n belül kezelni a dolgokat, mint a HP UFT, viszont egy idő után kezdett átláthatatlanná válni számomra. Azóta egyébként valószínűleg ez is sokat fejlődött, bár nekem nem volt időm követni a változásokat.

    Valami ilyesmire emlékszem.

    Cypress + JavaScript

    Na ezt imádtam. Könnyedén és gyorsan lehetett benne dolgozni, bár csak 1 évet töltöttem vele. Egy negatívuma azért van/volt, hogy az async/await dolgokat maga kezeli. Ez az esetek túlnyomó többségében nagyon jól működik, de amikor valamiért ez nem jó, az fájdalmas tud lenni.

    Ha jól rémlik, én is VS Code-dal használtam, illetve GitLab-ban futottak a tesztek.

    Ha jól sejtem VS Codeban.

    Playwright + TypeScript

    Abszolút kedvenc. 3 évet töltöttem vele, és imádtam minden percet. Annyira könnyed és légies, és gyorsan lehet vele haladni annak köszönhetően, hogy zseniálisan van felépítve benne szinte minden, hogy csak ajánlani tudom.

    Több különböző nyelvet is támogat, bár nekem a TypeScript volt használatban. Illetve nagyon jól dokumentált. Nem volt szükség sok Google keresésre, mivel a leírás hozzá megválaszolt mindent.

    Ez pedig ilyen volt.