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ótconstdialog=page.getByRole('dialog');constsaveButton=page.getByRole('button',{ name:'Mentés'});// Mentés gomb keresése kifejezetten a párbeszédablakon belülawaitsaveButton.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.
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 tesztekkeltest.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.
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.
Egyre lustább vagyok, és az idő is nagy ellenség lett a munkában, így sok esetben jól tud jönni az extra segítség, amit manapság AI formájában kaphatunk meg. Én személy szerint nagyon sok szakmai témában konzultálok vele, mielőbb neki kezdenek, de vannak olyan témák is, amiről kevés információm van, csak hallottam valahol, így időm engedtével rákeresek. Ilyen az AI-val történő exploratory tesztelés is.
Az exploratory testing (magyarul felfedező tesztelés) a szoftvertesztelés egy olyan megközelítése, ahol a tesztek megtervezése, végrehajtása és a szoftver megismerése egyszerre, párhuzamosan történik.
A hagyományos (szkriptelt) teszteléssel ellentétben – ahol a tesztelő előre megírt, lépésről lépésre követendő teszteseteket (test cases) hajt végre – a felfedező tesztelésnél a tesztelő a saját intuitív tudására, domain-ismeretére, tapasztalatára és kíváncsiságára támaszkodik.
A felfedező tesztelés fő jellemzői:
Szabadság és rugalmasság: Nincsenek szigorúan előre leírt tesztlépések. A tesztelő menet közben dönt arról, hogy az alkalmazás melyik részét milyen irányban vizsgálja tovább, reagálva a szoftver tényleges viselkedésére.
Tanulás és alkalmazkodás: Ahogy a tesztelő használja a szoftvert, egyre jobban megérti annak működését és gyenge pontjait. Ha a szoftver egy ponton gyanúsan viselkedik, a tesztelő azonnal mélyebbre áshat abban a témában.
Kreativitás és hibatalálgatás (Error Guessing): Olyan egyedi, nem szokványos felhasználói útvonalakat és szélsőséges eseteket (edge case-eket) igyekszik feltárni, amelyekre a fejlesztők vagy a specifikációt írók nem gondoltak.
Alacsony előkészítési igény: Mivel nem kell előre bonyolult tesztdokumentációt írni, nagyon gyorsan elindítható, így ideális agilis (Agile/Scrum) környezetben.
Mit nem jelent az exploratory tesztelés?
Nem ad-hoc kattintgatás („monkey testing”): A felfedező tesztelés nem céltalan próbálkozás. Bár nincs előre megírt forgatókönyv, a tesztelőnek világos célja és stratégiája van.
Célzott keretek (Session-Based Testing): A gyakorlatban a felfedező tesztelést gyakran strukturált keretek között végzik:
Charter (Küldetés): Meghatározzák a tesztelés célját (pl. „Fedezd fel a fizetési folyamatot a lejárt bankkártyák kezelésének szempontjából”).
Időkeret (Time-box): A tesztelést egy rögzített idősávra korlátozzák (pl. 60–90 perc).
Jegyzőkönyv / Összefoglaló: A tesztelő rögzíti, mit tapasztalt, milyen problémákat talált és merre érdemes tovább kutatni.
Összességében a felfedező tesztelés nem a szkriptelt vagy automatizált tesztek helyettesítője, hanem azok kiegészítője: az automatizált tesztek ellenőrzik, hogy a már meglévő funkciók működnek-e, míg a felfedező tesztelés segít megtalálni az új, váratlan hibákat.
Az exploratory (felfedező) tesztelés természeténél fogva egy ember-központú, kreatív folyamat, ahol a tesztelő intuíciója, domain-ismerete és kíváncsisága vezet. Az AI itt nem a tesztelőt váltja fel, hanem hihetetlenül hatékony asszisztensként (co-pilot) működik, amely leveszi a válláról a monoton feladatokat, és új, nem várt tesztforgatókönyveket javasol.
Mivel hallottam róla, hogy vannak, akik AI segítéséggel csinálják ezt, megkérdeztem az AI-t, hogy mit tud róla, és kaptam is egy listát. Ahogy lesz időm, kedvem, bele fogom ásni magam a témába.
Addig is itt a válasz a Gemini-től:
Az AI-alapú exploratory tesztelés megközelítései és eszközei méret és cél szerint három fő kategóriába oszthatók:
1. AI-alapú Böngésző- és Autonóm Tesztelő Ügynökök (Autonomous AI Testing Agents)
Ezek az eszközök képesek önállóan „bejárni” a webalkalmazásokat, feltérképezni a felületet, hibákat keresni, és közben segítik a felfedezést.
Stagehandvagy Browser-use / Explorbot: Ezek modern, nyílt forráskódú keretrendszerek, amelyek ráköthetők a nagyobb nyelvi modellekre (pl. Claude vagy GPT). Természetes nyelven vagy célok megadásával (pl. „Keresd meg az űrlapon a hiányzó validációkat”) képesek irányítani a böngészőt, elemezni a DOM-ot, és olyan edge case-eket (szélsőséges eseteket) is letesztelni, amiket egy hagyományos script nem érne el.
Kereskedelmi platformok (Mabl, Functionize, Testim):
Ezekben az AI-alapú platformokban van ún. Agentic vagy intelligens felfedező funkció is.Amikor új funkciót raksz ki, az AI képes önállóan „körbejárni” az oldalt, vizuális anomáliákat és hibaüzeneteket keresni a konzolon, így támogatva az exploratory tesztelési fázist.
2. AI Asszisztensek és Teszttervező Co-pilotok (Ötleteléshez és Charterekhez)
Ha hagyományos, session-based exploratory tesztelést (SBET) csinálsz, az AI kiválóan használható partnerré válik a tesztelési „charterek” és ötletek generálásában.
ChatGPT / Claude / Cursor (Prompt alapú teszttervezés):
Hogyan használd? Másold be egy új funkció specifikációját vagy user story-ját, és kérd meg az AI-t: „Készíts nekem 5 darab exploratory testing charter-t a Boundary Value Analysis (határérték-elemzés) és a Error Guessing (hibatalálgatás) heurisztikái alapján erre a funkcióra.”
Segít feltárni olyan logikai vakfoltokat, amikre fejlesztőként vagy tesztelőként nem gondoltál volna.
3. Vizuális és Interaktív AI Eszközök
Applitools (Eyes):
Exploratory tesztelés közben a legnagyobb ellenség a vizuális hiba, ami elkerüli a figyelmet. Az Applitools AI-alapú vizuális motorja azonnal észleli a renderelési hibákat, elcsúszásokat bármilyen eszközön, miközben te szabadon kattintgatsz és tesztelsz.
Mit érdemes választani?
Ha gyorsan és olcsón akarsz egyedi megoldást: Használj LLM alapú szkripteket / open-source keretrendszereket (Stagehand vagy custom Playwright szkriptek AI integrációval), amikkel autonóm módon át tudod vizsgáltatni a felületet.
Ha strukturált, emberi exploratory tesztelést végzel: Használj AI-t (Claude/GPT) ötletgenerálásra és kockázatelemzésre a tesztelés előtt (hová érdemes kaparni, milyen inputokat próbálj ki), majd a session végén rögzítsd a tapasztalatokat egy Test Management eszközben (pl. Xray vagy TestRail), ahol az AI összefoglalja a bug riportokat.
Megkérdeztem a Gemini-t, hogy megoldható-e, és ha igen, hogyan egy 50.000 useres performancia tesztelés az Apache JMeter-rel. A válasz itt következik:
Igen, teljesen megoldható, de van egy kritikus technikai feltétel: egyetlen gépről (például egy laptopról vagy egyetlen virtuális gépről) nem lehet elindítani 50 000 egyidejű felhasználót, mert a hardveres korlátok (CPU, RAM, hálózati socketek kimerülése) miatt maga a tesztelő eszköz fog összeomlani. Ehhez elosztott (distributed) architektúrára vagy felhőalapú futtatásra lesz szükség.
Így kezdenék neki lépésről lépésre:
1. Célok és workload modell tisztázása
Pontosan mit jelent az 50 000 user? 50 000 egyidejűleg aktív felhasználó, akik folyamatosan kattintgatnak, vagy 50 000 egyidejű kapcsolat (session), de az aktivitásuk eloszlik?
Milyen a felhasználói útvonal (User Journey)? Nem mindegy, hogy csak a főoldalt hívják le (ez könnyű), vagy bejelentkeznek, keresnek, terméket raknak a kosárba és fizetnek (ez bonyolultabb, adatbázis- és tranzakcióigényes).
Milyen mérőszámokat vársz el? (pl. 95%-os válaszidő 2 másodperc alatt, 0% hibaarány mellett).
2. A tesztinfrastruktúra felépítése (Distributed JMeter)
Mivel egy átlagos JMeter worker gép maximum 1000–2000 szálat bír stabilan, 50 000 userhez 25-50 darab worker gépre lesz szükség:
Master-Worker (Slave) felállás: Egy központi JMeter Master irányítja a tesztet, és gyűjti az adatokat a worker gépekről (ezek lehetnek olcsó AWS EC2 instance-ok vagy Docker konténerek).
Alternatíva: Használhatsz dedikált terheléses felhőszolgáltatásokat is (pl. BlazeMeter), amelyek mögött ugyanez az elv fut, de nem kell manuálisan menedzselni a 30-40 szervert.
3. A JMeter script megírása
Thread Group beállítások: A 50 000 szálat érdemes fokozatosan ráengedni a rendszerre (Ramp-up period, pl. 30–45 perc alatt), hogy látsd, hol kezd el lassulni a rendszer.
Valósághű viselkedés: Használj Think Time-ot (szüneteket a kérések között), különben a szkript robotként viselkedik, amit egy WAF (Web Application Firewall) vagy cache réteg azonnal blokkolhat.
Dinamikus adatok:CSV Data Set Config segítségével biztosítsd, hogy a felhasználók különböző nevekkel, jelszódal vagy tokenekkel jelentkezzenek be, ne ugyanazzal az egy fiókkal indítsa mind az 50k szál a kérést.
A JMeter csak azt mutatja meg, mit tapasztal a felhasználó (válaszidő, hiba), azt nem, hogy miért lassult be a szerver. Ehhez kell a backend monitoring:
Alkalmazásszerverek, adatbázisok, cache (Redis) CPU, RAM és I/O terhelésének figyelése (pl. Prometheus + Grafana vagy Datadog).
Adatbázis lassan futó lekérdezéseinek és connection pool telítettségének mérése.
5. Tesztfutás és finomhangolás
Soha ne használd a JMeter GUI-t (grafikus felületet) terheléses teszt alatt! Csak parancssorból, non-gui módban futtasd a master gépet.
Fokozatosság elve: Ne 50 000 userrel kezdd. Először futtass le egy 1000 useres tesztet, javítsd ki az azonnal előjövő hibákat, majd skálázd fel 5000-re, 10 000-re, és így tovább, ambron eléred a célt.
Milyen típusú rendszert (pl. webshop, REST API, banki backend) kell tesztelni, és milyen környezetben fut jelenleg?
Egy REST API terheléses tesztelése 50 000 felhasználóval specifikus technikai kihívásokat rejt, amelyekre különösen figyelned kell a JMeter konfigurálása során:
1. Hitelesítés és token-kezelés (Authentication)
A REST API-k túlnyomó többsége token alapú (JWT vagy OAuth2).
Ne kérj le tokent minden egyes kérésnél: Ha mind az 50 000 szál a POST /api/login végponttal kezdi a tesztet, azzal azonnal túlterheled a hitelesítőszervert, még mielőtt a valódi API funkciókat tesztelnéd.
Megoldás: Előre generálj le egy token-készletet (pl. egy külön scripttel vagy adatbázis-lekérdezéssel), töltsd be egy CSV fájlba, és a JMeterben ezt olvastasd be. Így a felhasználók már eleve érvényes tokenekkel küldhetik a kéréseket.
2. HTTP Request Defaults és Keep-Alive
Magas koncurrencia esetén kritikus a hálózati kapcsolatok hatékonysága:
HTTP Request Defaults: Állítsd be a központi URL-t, portot és a Content-Type-ot (application/json), hogy ne kelljen minden egyes kérésnél megismételni.
Keep-Alive: A JMeter alapértelmezésben engedélyezi a Keep-Alive-ot. REST API-knál ez elengedhetetlen, mert így nem nyit és zár le TCP kapcsolatot minden egyes apró API híváshoz, ami drasztikusan csökkenti a hálózati terhelést a kliens oldalon, és valósághűbb képet ad a szerver teljesítményéről.
3. Dinamikus adatok és JSON Extractor
Egy REST API láncolt hívásokból áll (pl. létrehozol egy erőforrást POST-tal, majd annak az ID-jét lekéred GET-tel).
Használj JSON Extractor elemet a válaszokból (pl. létrehozott objektum ID-je, státusza) való adatkigyűjtésre.
Ezeket az értékeket mentsd el JMeter változókba (${id}), hogy a következő kérésben dinamikusan fel tudd használni.
4. Payload (Adatcsomag) optimalizálás
Ha a tesztben nagy JSON payloadokat küldesz (pl. tömeges adatfeltöltés), kerüld a bonyolult, dinamikusan generált szövegeket a JMeter belső függvényeivel, mert az leterheli a JMeter saját CPU-ját.
A tesztadatokat (JSON törzseket) előre generált fájlokból (CSV vagy JSON file) olvasd be, így a worker gépek erőforrásai tisztán a hálózati kérésekre fognak fókuszálni.
5. Válaszidő és aszinkronitás
Határozd meg, hogy az API-n belül vannak-e aszinkron műveletek (pl. üzenetssorba, RabbitMQ-ba vagy Kafka-ba küldött események). Ha igen, a válaszidő alacsony lehet (mert a szerver csak átvette az üzenetet), de a valódi feldolgozást a háttérben lévő worker service-eknek kell bírniuk, így a monitoringot kötelező kiterjeszteni a háttérfolyamatokra is.
Szerintem elég jól megválaszolta a kérdést. Egy részével tisztában voltam, sejtettem, de akadt jó pár jó tanács is. Gondoltam megkérdezem, hogy JMeteren kívül milyen mást eszközt ajánlana ehhez.
Ha a JMeter elosztott architektúrájának (a 25-50 worker gépnek a) manuális konfigurálása és karbantartása túl bonyolultnak tűnik, a modern teljesítménytesztelő eszköztárban kifejezetten REST API-khoz sokkal gördülékenyebb megoldások is léteznek:
1. k6 (Grafana k6) – A legjobb választás REST API-khoz
A k6 jelenleg a legnépszerűbb fejlesztőbarát alternatíva. C-ben íródott (Go runtime-mal), így nagyságrendekkel kevesebb memóriát és CPU-t fogyaszt, mint a Java-alapú JMeter.
Miért ideális 50k userhez? Egyetlen erősebb szerverről lényegesen több szálat (virtuális usert) tud futtatni, mint a JMeter, így kevesebb infrastruktúrára lesz szükséged.
Szkriptelés: JavaScriptben írod a teszteket, ami nagyon természetes a REST API JSON válaszok és dinamikus tokenek kezelésénél.
Integráció: Kiemelkedően jó Grafana, Prometheus és CI/CD (GitHub Actions, GitLab) támogatása van.
2. Gatling – Ha elképesztő skálázhatóságra és szép riportokra van szükség
A Gatling aszinkron (Netty-alapú) architektúrát használ, így nem rendel egy külön operációs rendszer szálat minden egyes felhasználóhoz.
Miért ideális 50k userhez? Brutálisan jó az erőforrás-kihasználása. Egyetlen közepes gépről képes több tízezer egyidejű kapcsolatot felépíteni és kezelni.
Szkriptelés: Scala, Java vagy Kotlin nyelven írhatsz szép, olvasható domain-specifikus kódot (DSL).
Riportok: Alapból nagyon részletes és vizuálisan tetszetős HTML riportokat generál a teszt végén.
3. Locust – Ha Python-alapú veremből dolgozol
A Locust egy nyílt forráskódú, Python-alapú tesztelőeszköz, ahol a felhasználói viselkedést tiszta Python kódban definiálod.
Miért ideális 50k userhez? Nagyon egyszerűen összefűzhető elosztott (distributed) módba (Master-Worker architektúra), és menet közben, a böngészős UI-ról is állítható a terhelés mértéke.
Előny: Ha a csapat már ismeri a Pythont, a tesztek megírása és karbantartása minimális időt vesz igénybe.
Menedzselt felhős alternatívák (SaaS)
Ha egyáltalán nem szeretnél szervereket bérelni és konfigurálni:
Grafana Cloud k6 / BlazeMeter / Loader.io / AWS Distributed Load Testing:Ezeknél a szolgáltatásoknál csak feltöltöd a k6, JMeter vagy saját konfigurációs scriptjeidet, kiválasztod a régiót és a 50 000 felhasználós terhelést, ők pedig a háttérben azonnal felhúzzák a szükséges infrastruktúrát, majd a teszt végén leállítják azt.
Összegzés – Melyiket válaszd?
Ha kódból írnál teszteket és a legjobb erőforrás-kihasználást akarod minimalizált szerverköltséggel: k6 vagy Gatling.
Ha a csapat Pythonban erős: Locust.
Ha nulla infrastruktúra-üzemeltetést szeretnél: Grafana Cloud k6 vagy BlazeMeter.
Mennyi mindent használunk, de igazából lehet, hogy fogalmunk sincs róla, hogy mire is jó pontosan, és mikor is érdemes használni. A miértről nem is beszélve…
Mit mesél erről a Gemini?
A .NET-ben (C#) a yield kulcsszó pontosan ugyanazt a célt szolgálja, mint a Pythonban: IEnumerable<T> vagy IAsyncEnumerable<T> típusú adatfolyamokat hozhatsz vele létre úgy, hogy a kód lusta kiértékeléssel (lazy evaluation), elemenként adja vissza az eredményeket.
C#-ban két formája létezik:
yield return <érték>: Visszaad egy elemet, majd felfüggeszti a metódus futását a következő elem kéréséig.
yield break: Azonnal leállítja az iterációt (megszakítja a generálást).
Mire jó C#-ban?
1. Memóriatakarékosság nagy adathalmazoknál
Ha nem List<T>-et adsz vissza, nem kell a teljes gyűjteményt lefoglalni a RAM-ban.
C#
usingSystem;usingSystem.Collections.Generic;// PÉLDA 1: Hagyományos megközelítés (Memóriatakaréktalan)publicList<int>GetNumbersList(){varlist=newList<int>();for (inti=0;i<1_000_000;i++){list.Add(i);// Mind az 1 milló elem belekerül a RAM-ba}returnlist;}// PÉLDA 2: yield használata (Memóriatakarékos)publicIEnumerable<int>GetNumbersYield(){for (inti=0;i<1_000_000;i++){yieldreturni;// Mindig csak az aktuális számot generálja le}}
2. Szűrés és adatfeldolgozás yield break-kel
A yield break használatával feltételhez kötheted az adatfolyam végét anélkül, hogy bonyolult feltételkezelést kellene írnod a ciklus köré:
C#
publicIEnumerable<string>GetActiveUsers(List<string>users){foreach (varuserinusers){if (user=="ADMIN_STOP"){yieldbreak;// Azonnal leállítja az elemek kiadását}if (!string.IsNullOrEmpty(user)){yieldreturnuser;}}}
3. Óriási fájlok feldolgozása soronként
Nem kell a gigabájtos fájlokat egyszerre a memóriába tölteni (File.ReadAllLines helyett):
C#
usingSystem.IO;usingSystem.Collections.Generic;publicIEnumerable<string>ReadLargeFile(stringfilePath){using (StreamReaderreader=newStreamReader(filePath)){string?line;while ((line=reader.ReadLine()) !=null){ yield return line; // Mindig csak egyetlen sort tart a memóriában} }}// Használat:foreach (stringlineinReadLargeFile("huge_log.txt")){if(line.Contains("ERROR")){Console.WriteLine(line);}}
Modern .NET-ben hálózati kéréseknél vagy adatbázis-lekérdezéseknél aszinkron módon is használhatod:
C#
publicasyncIAsyncEnumerable<int>FetchDataAsync(){for (inti=1;i<=5;i++){awaitTask.Delay(1000);// Pl. hálózati várakozás szimulálásayieldreturni;}}// Használat:awaitforeach (variteminFetchDataAsync()){Console.WriteLine(item);// Másodpercenként jelenik meg egy elem}
Hagyományos visszatérés vs. yield C#-ban
Szempont
List<T> / Tömb
yield return (IEnumerable<T>)
Kiértékelés ideje
Azonnali (A metódus hívásakor lefut a teljes ciklus)
Lusta / Halasztott (Csak akkor fut, amikor a foreach kéri a következő elemet)
Igen, pontosan ugyanígy működik TypeScriptben és JavaScriptben is.
A TypeScript a JavaScript generátor függvényeit (Generator Functions) használja, amelyeket az function* (csillaggal jelölt) szintaxisról lehet felismerni.
A működési elv teljesen megegyezik a Python és a C# esetében látottakkal: a yield felfüggeszti a függvény futását, megőrzi a belső állapotot, és lusta kiértékeléssel (lazy evaluation) adja vissza az elemeket egy Generator objektumon keresztül.
Alapvető példa TypeScriptben
A generátor függvény visszatérési típusa Generator<T, TNext TReturn,>, ahol a T a yield-elt értékek típusa.
TypeScript
// A csillag (function*) jelzi, hogy ez egy generátor függvényfunction*szamGeneraltor():Generator<number>{yield1;yield2;yield3;}// Használat for...of ciklussal:for (constszamofszamGeneraltor()) {console.log(szam);// Kiírja egymás után: 1, 2, 3}
A TypeScriptben létezik a yield* utasítás is, amellyel átadhatod a vezérlést egy másik generátornak vagy tömbnek (bejárható objektumnak):
TypeScript
function*elsoResz():Generator<number>{yield1;yield2;}function*teljesSorozat():Generator<number>{yield*elsoResz();// Delegálja az elemeket az elsoResz-bőlyield* [3,4,5];// Tömb elemeit is ki tudja adni egymás után}console.log([...teljesSorozat()]);// [1, 2, 3, 4, 5]
3. Aszinkron generátorok (yield + async)
Ahogy C#-ban az IAsyncEnumerable, TypeScriptben és JS-ben is létezik az AsyncGenerator (async function*). Ez hálózati adatok, lapozott API-k vagy adatfolyamok (stream) feldolgozásánál nagyon hasznos:
TypeScript
asyncfunction*adatokLetolteseAPIrol():AsyncGenerator<string>{constoldalak= [1,2,3];for (constoldalofoldalak) {// Szimulált hálózati kérés (API hívás)constvalasz=awaitfetch(`https://api.example.com/data?page=${oldal}`);constadat=awaitvalasz.text();yieldadat;// Mindig csak az aktuális oldal adatait adja vissza}}// Használat for await...of ciklussal:asyncfunctionfeldolgozas(){forawait (constoldalAdatofadatokLetolteseAPIrol()) {console.log("Megérkezett egy oldal:",oldalAdat);}}
Tegnap egész sok mindennel kísérleteztem, majd eszembe jutott, hogy szerettem volna már egy ideje saját adatokat menteni a WordPress blog-omba, de sose volt elég időm, kedvem újra elővenni a PHP-t, és belekezdeni a fejlesztésbe. Szóval most, hogy van AI meg Gemini, megkértem, hogy csináljon egy alap plugin-t. Semmi extra, egy egyszerű CRUD, ahol a create, update, delete az admin felületen keresztül történik, a read pedig short code-ként kirakható bárhová.
Azt azért látom, hogy ahhoz, ami a végső célom lenne, be kell húznom egy IDE-t, és abban prompt-olva a fejlesztést, de szerintem ez így elsőre nem tűnik rossznak.Döbbenetesen gyorsan és pontosan dolgozott.
Gondoltam egy merészet, és megkértem a Gemini-t, hogy készítsen nekem egy WordPress Plugint, ami random Mészáros Lőrinc idézeteket jelenít meg. Megcsinálta.
“Az élet egészen szélsőséges dolgokat is hozhat.”— Mészáros Lőrinc
Nem álltam itt meg, megkértem, hogy csináljon egy névnap megjelenítőt, az aktuálisra, és a soron következőre.
Ma:Nárcisz
Holnap:Alfonz
Íme:
Itt egy komplett, egyfájlos WordPress bővítmény, amelyet közvetlenül beépíthetsz a weboldaladba. A bővítmény a látogató böngészőjének aktuális dátumát veszi alapul, kezeli a szökőéveket (a februári névnapeltolódást is), és shortcode segítségével bárhova könnyen elhelyezhető.
Bővítmény kóda
Hozz létre egy magyar-nevnapok.php fájlt a /wp-content/plugins/magyar-nevnapok/ mappában, és másold bele az alábbi kódot:
PHP
<?php/** * Plugin Name: Magyar Névnapok (Mai és Holnapi) * Description: Megjeleníti a mai és a holnapi névnapot shortcode segítségével. * Version: 1.0 * Author: AI Assistant*/if(!defined('ABSPATH')){exit;// Közvetlen hozzáférés tiltása}classMagyar_Nevnapok_Plugin{// Névnap adatbázis (Hónap -> Nap -> Névnapok)privatestatic$nevnapok=[1=>[1=>'Fruzsina',2=>'Ábel',3=>'Genovéva, Benjámin',4=>'Titusz, Leona',5=>'Simon',6=>'Boldizsár',7=>'Attila, Ramóna',8=>'Gyöngyvér',9=>'Marcell',10=>'Melánia',11=>'Ágota',12=>'Ernő',13=>'Veronika',14=>'Bódog',15=>'Lóránt, Lóránd',16=>'Gusztáv',17=>'Antal, Antónia',18=>'Piroska',19=>'Sára, Márió',20=>'Fábián, Sebestyén',21=>'Ágnes',22=>'Vince, Artúr',23=>'Zelma, Rajmund',24=>'Timót',25=>'Pál',26=>'Vanda, Paula',27=>'Angéla, Anzelm',28=>'Károly, Karola',29=>'Adél',30=>'Martina, Gerda',31=>'Marcella'],2=>[1=>'Ignác',2=>'Karolina, Aida',3=>'Balázs',4=>'Ráhel, Csenge',5=>'Ágota, Ingrid',6=>'Dorottya, Dóra',7=>'Tódor, Rómeó',8=>'Aranka',9=>'Abigél, Alex',10=>'Elvira',11=>'Bertold, Marietta',12=>'Lívia, Lídia',13=>'Ella, Linda',14=>'Bálint, Valentin',15=>'Kolos, Georgina',16=>'Julianna, Lilla',17=>'Donát',18=>'Bernadett',19=>'Zsuzsanna',20=>'Aladár, Álmos',21=>'Eleonóra',22=>'Gerzson',23=>'Alfréd',24=>'Mátyás',25=>'Géza',26=>'Edina',27=>'Ákos, Bátor',28=>'Elemér',29=>'Névnap szökőévben'],3=>[1=>'Albin',2=>'Lujza',3=>'Kornélia',4=>'Kázmér',5=>'Adorján, Adrián',6=>'Leonóra, Inez',7=>'Tamás',8=>'Zoltán',9=>'Franciska, Fanni',10=>'Ildikó',11=>'Szilárd',12=>'Gergely',13=>'Krisztián, Ajtony',14=>'Matild',15=>'Kristóf',16=>'Henrietta',17=>'Patrick, Gertrúd',18=>'Ede, Sándor',19=>'József, Bánk',20=>'Klaudia',21=>'Benedek',22=>'Beáta, Izolda',23=>'Emőke',24=>'Gábor, Karina',25=>'Irén, Írisz',26=>'Emánuel',27=>'Hajnalka',28=>'Gedeon, Johanna',29=>'Auguszta',30=>'Zalán',31=>'Árpád'],4=>[1=>'Hugó',2=>'Áron',3=>'Buda, Richárd',4=>'Izidor',5=>'Vince',6=>'Vilmos, Bíbor',7=>'Herman',8=>'Dénes',9=>'Erhard',10=>'Zsolt',11=>'Leó, Szaniszló',12=>'Gyula',13=>'Ida',14=>'Tibor',15=>'Anasztázia, Tas',16=>'Csongor',17=>'Rudolf',18=>'Andrea, Ilma',19=>'Emma',20=>'Tivadar',21=>'Konrád',22=>'Csilla, Noémi',23=>'Béla',24=>'György',25=>'Márk',26=>'Ervin',27=>'Zita',28=>'Valéria',29=>'Péter',30=>'Katalin, Kitti'],5=>[1=>'Fülöp, Jakab',2=>'Zsigmond',3=>'Tímea, Irma',4=>'Mónika, Flórián',5=>'Györgyi',6=>'Ivett, Frida',7=>'Gizella',8=>'Mihály',9=>'Gergely',10=>'Ármin, Pálmira',11=>'Ferenc',12=>'Pongrác',13=>'Szervác, Imelda',14=>'Bonifác',15=>'Zsófia, Szonja',16=>'Mózes, Botond',17=>'Paszkál',18=>'Erik, Alexandra',19=>'Ivó, Milán',20=>'Bernát, Felícia',21=>'Konstantin',22=>'Júlia, Rita',23=>'Dezső',24=>'Eszter, Eliza',25=>'Orbán',26=>'Fülöp, Evelin',27=>'Hella',28=>'Emil, Csanád',29=>'Magdolna',30=>'Janka, Zsanett',31=>'Angéla, Petronella'],6=>[1=>'Tünde',2=>'Kármen, Anita',3=>'Klotild, Cecília',4=>'Bulcsú',5=>'Fatime, Fatima',6=>'Norbert, Cintia',7=>'Róbert',8=>'Medárd',9=>'Félix',10=>'Margit, Gréta',11=>'Barnabás',12=>'Villő',13=>'Antal, Anett',14=>'Vazul',15=>'Jolán, Vid',16=>'Jusztin',17=>'Laura, Alida',18=>'Arnold, Levente',19=>'Gyárfás',20=>'Rafael',21=>'Alajos, Leila',22=>'Paulina',23=>'Zoltán',24=>'Iván',25=>'Vilmos',26=>'János, Pál',27=>'László',28=>'Levente, Irén',29=>'Péter, Pál',30=>'Pál'],7=>[1=>'Tihamér, Annamária',2=>'Ottó',3=>'Kornél, Soma',4=>'Ulrik',5=>'Emese, Sarolta',6=>'Csaba',7=>'Apollónia',8=>'Ellák',9=>'Lukrécia',10=>'Amália',11=>'Nóra, Lili',12=>'Izabella, Dalma',13=>'Jenő',14=>'Örs, Stella',15=>'Henrik, Roland',16=>'Vali',17=>'Endre, Elek',18=>'Frigyes',19=>'Emília',20=>'Illés',21=>'Dániel, Daniella',22=>'Magdolna',23=>'Lenke',24=>'Kinga, Kincső',25=>'Kristóf, Jakab',26=>'Anna, Anikó',27=>'Olga, Liliána',28=>'Szabolcs',29=>'Márta, Flóra',30=>'Judit, Xénia',31=>'Oszkár'],8=>[1=>'Boglárka',2=>'Lehel',3=>'Hermina',4=>'Domonkos, Dominika',5=>'Krisztina',6=>'Berta, Bettina',7=>'Ibolya',8=>'László',9=>'Emőd',10=>'Lőrinc',11=>'Zsuzsanna, Tiborc',12=>'Klára',13=>'Ipoly',14=>'Marcell',15=>'Mária',16=>'Ábrahám',17=>'Jácint',18=>'Ilona',19=>'Huba',20=>'István',21=>'Sámuel, Hajna',22=>'Menyhért',23=>'Bence',24=>'Bertalan',25=>'Lajos, Patrícia',26=>'Izsó',27=>'Gáspár',28=>'Ágoston',29=>'Beatrix, Erna',30=>'Rózsa',31=>'Erika, Bella'],9=>[1=>'Egyed, Egon',2=>'Rezső',3=>'Hilda',4=>'Rozália',5=>'Viktor, Lőrinc',6=>'Zakariás',7=>'Regina',8=>'Mária, Adrienn',9=>'Ádám',10=>'Nikolett, Hunor',11=>'Teodóra',12=>'Mária',13=>'Kornél',14=>'Szeréna, Roxána',15=>'Enikő, Melitta',16=>'Edit',17=>'Zsófia',18=>'Diána',19=>'Vilhelmina',20=>'Friderika',21=>'Máté, Mirella',22=>'Mór, Gellért',23=>'Tekla, Líviusz',24=>'Gellért, Mercédesz',25=>'Eufrozina, Kende',26=>'Jusztina',27=>'Adalbert',28=>'Vencel',29=>'Mihály',30=>'Jeromos'],10=>[1=>'Malvin',2=>'Petra',3=>'Helga',4=>'Ferenc',5=>'Aurél',6=>'Brúnó, Renáta',7=>'Amália',8=>'Koppány',9=>'Dénes',10=>'Gedeon',11=>'Brigitta',12=>'Miksa',13=>'Kálmán, Ede',14=>'Helén',15=>'Teréz',16=>'Gál',17=>'Hedvig',18=>'Lukács',19=>'Nándor',20=>'Vendel',21=>'Orsolya',22=>'Előd',23=>'Gyöngyi',24=>'Salamon',25=>'Blanka, Bianca',26=>'Dömötör',27=>'Szabina',28=>'Simon, Szimonetta',29=>'Nárcisz',30=>'Alfonz',31=>'Farkas'],11=>[1=>'Marianna',2=>'Achilles',3=>'Győző',4=>'Károly',5=>'Imre',6=>'Lénárd',7=>'Rezső',8=>'Zsombor',9=>'Tivadar',10=>'Réka',11=>'Márton',12=>'Jónás, Renátó',13=>'Szilvia',14=>'Aliz',15=>'Albert, Lipót',16=>'Ödön',17=>'Hortenzia, Gergő',18=>'Jenő',19=>'Erzsébet',20=>'Jolán',21=>'Olivér',22=>'Cecília',23=>'Klementina',24=>'Emma',25=>'Katalin',26=>'Virág',27=>'Virgil',28=>'Stefánia',29=>'Taksony',30=>'András, Andor'],12=>[1=>'Elza',2=>'Melinda, Vivien',3=>'Ferenc, Olívia',4=>'Borbála, Barbara',5=>'Vilma',6=>'Miklós',7=>'Ambrus',8=>'Mária',9=>'Natália',10=>'Judit',11=>'Árpád',12=>'Gabriella',13=>'Luca, Otília',14=>'Szilárda',15=>'Valér',16=>'Etelka, Aletta',17=>'Lázár, Olimpia',18=>'Auguszta',19=>'Viola',20=>'Teofil',21=>'Tamás',22=>'Zénó',23=>'Viktória',24=>'Ádám, Éva',25=>'Eugénia',26=>'István',27=>'János',28=>'Kamilla',29=>'Tamás, Szeréna',30=>'Dávid',31=>'Szilveszter']];publicfunction__construct(){add_shortcode('nevnapok',[$this,'render_shortcode']);}/** * Névnap lekérése adott dátumra (kezeli a szökőéveket)*/privatefunctionget_nevnap_by_timestamp($timestamp){$month=(int)date('n',$timestamp);$day=(int)date('j',$timestamp);$is_leap_year=(date('L',$timestamp)==1);// Szökőév esetén február 24. után a névnapok 1 nappal eltolódnakif($is_leap_year&&$month==2){if($day==24){return'Szökőnap (Nincs külön névnap)';}elseif($day>24){$day--;// Február 25-29. a 24-28-ai névnapokat kapja}}returnisset(self::$nevnapok[$month][$day])?self::$nevnapok[$month][$day]:'Ismeretlen';}/** * Shortcode megjelenítése: [nevnapok]*/publicfunctionrender_shortcode($atts){// Alapértelmezett beállítások felülírhatósága$atts=shortcode_atts(['mai_label'=>'Mai névnap:','holnapi_label'=>'Holnapi névnap:','layout'=>'block'// 'block' vagy 'inline'],$atts,'nevnapok');// WordPress időzóna beállítása alapján kérjük le az időt$now=current_time('timestamp');$tomorrow=strtotime('+1 day',$now);$mai_nevnap=$this->get_nevnap_by_timestamp($now);$holnapi_nevnap=$this->get_nevnap_by_timestamp($tomorrow);// HTML kimenet előállításaob_start();?><divclass="magyar-nevnapok-container layout-<?php echo esc_attr($atts['layout']); ?>"><divclass="nevnap-item nevnap-mai"><spanclass="nevnap-label"><?phpechoesc_html($atts['mai_label']);?></span><spanclass="nevnap-name"><?phpechoesc_html($mai_nevnap);?></span></div><divclass="nevnap-item nevnap-holnapi"><spanclass="nevnap-label"><?phpechoesc_html($atts['holnapi_label']);?></span><spanclass="nevnap-name"><?phpechoesc_html($holnapi_nevnap);?></span></div></div><style>.magyar-nevnapok-container.layout-inline{display: flex;gap: 15px;align-items:center;}.magyar-nevnapok-container.nevnap-label{font-weight:bold;margin-right:4px;}</style><?phpreturnob_get_clean(); }}// Bővítmény inicializálásanewMagyar_Nevnapok_Plugin();
Használati útmutató
Telepítés:
Hozz létre egy magyar-nevnapok nevű mappát a weboldalad wp-content/plugins/ könyvtárában.
Mentsd el a fenti kódot magyar-nevnapok.php néven ebbe a mappába.
Lépj be a WordPress admin felületére, és kapcsold be a Magyar Névnapok (Mai és Holnapi) bővítményt.
Megjelenítés Shortcode-csal:Bármelyik oldalra, bejegyzésbe, widgetsávba vagy fejlécbe beillesztheted az alábbi shortcode-ok egyikét:
Alapértelmezett (blokk elrendezés):[ nevnapok ]
Egymás melletti (egysoros) elrendezés:[ nevnapok layout="inline" ]
Egyedi feliratok használata:[ nevnapok mai_label="Ma:" holnapi_label="Holnap:" layout="inline" ]
1.Fájl létrehozása:
Hozd létre a magyar-nevnapok.php fájlt a wp-content/plugins/magyar-nevnapok/ könyvtárban.
2.Aktiválás:
Lépj be a WordPress Adminba -> Bővítmények, majd aktiváld a „Magyar Névnapok” nevű bővítményt.
3.Shortcode elhelyezése:
Szúrd be a [ nevnapok ] shortcode-ot tetszőleges oldalba, blokkba vagy widgetbe.
Mivel napo óta ezzel szórakoztatom magam, gondoltam íratok erről pár sort az AI-val, mint emlékeztető, ha újra elő kell vennem a témát. Röviden: vannak esetek, amikor százalékos arányban kell hívásokat eszközölni a performancia mérésben. Ebben tud segíteni a Throughput Controller.
Nézzük, mint mond erről az AI:
A Throughput Controller az Apache JMeter egyik legfontosabb eleme, amikor a valós felhasználói viselkedést szeretnénk szimulálni. Neve ellenére nem a másodpercenkénti kérések számát (RPS) korlátozza (arra a Constant Throughput Timer való), hanem azt határozza meg, hogy a teszt lépései milyen arányban vagy rögzített alkalommal fussanak le.
Mire jó a Throughput Controller?
Egy webáruháznál a látogatók nem egyforma arányban böngésznek és vásárolnak:
80% csak böngészi a termékeket.
15% kosárba tesz valamit.
5% eljut a fizetésig.
A Throughput Controller segítségével pontosan ezt a megoszlást képezhetjük le egyetlen Thread Group-on belül.
A két fő működési mód (Based On)
Mód
Leírás
Mikor használd?
Percent Executions
A beállított százalékos arányban engedi lefutni a gyermek kéréseket a teszt során.
Valós felhasználói eloszlás szimulálásához (pl. 80-15-5% szabály).
Total Executions
Legfeljebb egy megadott fix alkalommal engedi lefutni a kérést, utána kihagyja.
Egyszeri beállításokhoz vagy korlátozott műveletekhez (pl. adatbázis-feltöltés).
Fontos beállítás (Per User): Ha be van pipálva, a számítás nem a teljes tesztre, hanem szálanként (felhasználónként) érvényesül.
Gyakorlati példa: Webáruház forgalomszimuláció
Tételezzük fel, hogy 100 szálat (felhasználót) indítunk egy hurokban (Loop Count: 100). A célunk a fent említett 80%-15%-5%-os megoszlás.
A 1000 összes lefutásból nagyjából 800 alkalommal a termékoldal kérés fog lefutni.
150 alkalommal a kosárba helyezés.
50 alkalommal pedig a fizetés lép fel.
Gyakori hibák és tippek
Ne keverd a Constant Throughput Timer-rel: Ha az a célod, hogy a szervert pontosan 100 req/sec terhelés alatt tartsd, használj Timert. A Throughput Controller az arányokról szól, nem a sebességről.
Keresztülfutás (Overhead): Ha a szabályok összege nem 100%, vagy egy szál egyik controllernek sem felel meg az adott iterációban, a szál kihagyja az adott részt és lép a következő hurokra.
Egymásba ágyazás: Összetettebb scenárióknál Simple Controller-rel vagy Transaction Controller-rel kombinálva egész folyamatokat is elhelyezhetsz egy-egy Throughput Controller alá.
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 ByclassLoginPage: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űveletekdefenter_username(self,username:str):self.driver.find_element(*self._username_input).send_keys(username)defenter_password(self,password:str):self.driver.find_element(*self._password_input).send_keys(password)defclick_login(self):self.driver.find_element(*self._login_button).click()# Összetett folyamat (Láncolt / Magasabb szintű akció)deflogin(self,username:str,password:str):self.enter_username(username)self.enter_password(password)self.click_login()defget_error_message(self)->str:returnself.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ó.
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';exportclassLoginPage{readonlypage:Page;readonlyusernameInput:Locator;readonlypasswordInput:Locator;readonlyloginButton:Locator;readonlyerrorMessage:Locator;constructor(page:Page){self.page=page;// A Playwright-ban a lokátorok deklaratívak, nem kérdezik le azonnal a DOM-otthis.usernameInput=page.locator('#username');this.passwordInput=page.locator('#password');this.loginButton=page.locator('button[type="submit"]');this.errorMessage=page.locator('.flash-error');}asyncgoto(){awaitthis.page.goto('https://example.com/login');}asynclogin(username:string,password:string){awaitthis.usernameInput.fill(username);awaitthis.passwordInput.fill(password);awaitthis.loginButton.click();}asyncgetErrorMessage():Promise<string>{returnawaitthis.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',()=>{letloginPage:LoginPage;test.beforeEach(async({page})=>{loginPage=newLoginPage(page);awaitloginPage.goto();});test('Sikeres bejelentkezés',async({page})=>{awaitloginPage.login('valid_user','correct_password');// Ellenőrzés Playwright assert-telawaitexpect(page).toHaveURL('https://example.com/dashboard');});test('Hibás bejelentkezés',async()=>{awaitloginPage.login('invalid_user','wrong_password');awaitexpect(loginPage.errorMessage).toBeVisible();awaitexpect(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 @FindBy elemek lekezeléséhez várakozás (WebDriverWait) kellhet
Párhuzamosítás
Alapból támogatott a tesztfutztatóban
TestNG vagy JUnit szálkezelést igényel
Inicializálás
Egyszerű objektumkonstruktor
PageFactory.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.tsimport {Page,Locator} from '@playwright/test';exportclassLoginPage{readonlypage:Page;readonlyusernameInput:Locator;constructor(page:Page){this.page=page;this.usernameInput=page.locator('#username');}asyncgoto(){awaitthis.page.goto('/login');}}// pages/DashboardPage.tsimport {Page,Locator} from '@playwright/test';exportclassDashboardPage{readonlypage:Page;readonlyuserMenu: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öztypeMyFixtures={loginPage:LoginPage;dashboardPage:DashboardPage;};// 2. A 'base.extend' használatával regisztráljuk a saját fixture-jeinketexportconsttest=base.extend<MyFixtures>({// Automatikusan példányosítja a LoginPage-t és igény esetén megnyitja az oldaltloginPage:async({page},use)=>{constloginPage=newLoginPage(page);awaitloginPage.goto();// Akár előkészítő lépéseket is tehetünk ideawaituse(loginPage);// Átadja az objektumot a tesztnek},// Példányosítja a DashboardPage-tdashboardPage:async({page},use)=>{constdashboardPage=newDashboardPage(page);awaituse(dashboardPage);},});// Az 'expect'-et is exportáljuk a kényelmes importálásértexport {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!awaitloginPage.usernameInput.fill('standard_user');// A dashboardPage is azonnal használható, nem kellett 'new'-val példányosítaniawaitexpect(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).
Sosem voltam egy nagy karakter húszár, így előnybe részesítettem a grafikus ezközöket. Mostanában viszont egyre gyakrabban kényszerűlők rá, hogy parancssorosan oldjak meg dolgok, mint pl a GIT-elést. Gondoltam AI-val összegyűjtetem a legáltalánosabb parancsokat.
A leggyakrabban használt Git parancsok kategóriák szerint csoportosítva:
Alapvető beállítások & Inicializálás
git config --global user.name "Neved" – Beállítja a felhasználóneved a commitokhoz.
git config --global user.email "email@cimed.hu" – Beállítja az e-mail-címedet.
git init – Új, üres Git repót hoz létre az aktuális mappában.
git clone <URL> – Letölt egy meglévő távoli tárolót (repository-t) a gépedre.
Változások nyomon követése & Commit
git status – Megmutatja a munkamenet állapotát (módosított, követetlen fájlok).
git add <fájlnév> – Hozzáadja a megadott fájlt a Staging Area-hoz.
git add . – Az összes módosított és új fájlt hozzáadja a Staging Area-hoz.
git commit -m "Üzenet" – Elmenti a Staging Area-ban lévő változtatásokat a megadott üzenettel.
git diff – Megmutatja a még el nem mentett (unstaged) módosításokat.
Nézet & Történet
git log – Megjeleníti a korábbi commitok történetét.
git log --oneline – Tömör, egysoros formátumban listázza a commitokat.
Ágak kezelése (Branching)
git branch – Listázza a helyi ágakat.
git branch <ág-név> – Létrehoz egy új ágat.
git checkout <ág-név> – Átvált a megadott ágra.
git checkout -b <ág-név> – Létrehoz egy új ágat és egyből át is vált rá.
git merge <ág-név> – A megadott ág tartalmát összefésüli az aktuális ággal.
Távoli tároló (Remote)
git fetch – Letölti az új információkat a távoli tárolóból, de nem egyesíti őket.
git pull – Letölti és azonnal összefésüli a távoli ág változásait.
git push origin <ág-név> – Feltölti a helyi commitokat a távoli tárolóba.
Módosítások visszavonása
git restore <fájlnév> – Visszaállítja a fájlt a legutóbbi commit állapotára (eldobja a nem elmentett módosításokat).
git reset HEAD~1 – Visszavonja a legutóbbi commitot, de a fájlokban lévő módosításokat megőrzi.
Ma ilyen AI-s napom van. Egyre jobban tör be a mindennapi munkámba, és úgy tűnik, hogy a hétvégeimet is ez teszi ki. Miért? Kérdezheted joggal. Megmondom. Az IT-ban, de gyanítom a többi szakmában is jobb, ha értünk hozzá, és megtanuljuk rutinosan használni, mintsem lemaradjunk róla, és nézzük bambán, ahogy az élet felsuhan előttünk.
Nézzük, mire is mentem elsőre.
Az alábbi PowerShell-script végigpásztázza a megadott mappát (és annak almappáit), a fájlok SHA256 hash értéke alapján azonosítja a duplikációkat, majd az eredményt kiírja a képernyőre és elmenti egy CSV-fájlba.
PowerShell duplikáció-kereső script
Hozz létre egy find-duplicates.ps1 fájlt, és másold bele az alábbi kódot:
PowerShell
# --- BEÁLLÍTÁSOK ---$TargetFolder="C:\Elérési\Út\A\Mappához"# Cseréld ki a vizsgálandó mappa útvonalára$OutputFile="C:\Elérési\Út\duplikatumok.csv"# Ide menti az eredménytWrite-Host"Fájlok indexelése és hash értékek számítása..."-ForegroundColor Cyan# 1. Összes fájl lekérése és méret szerinti csoportosítása (gyorsítási lépés)$fileGroups=Get-ChildItem-Path $TargetFolder-Recurse -File -ErrorAction SilentlyContinue |Group-Group-Object -Property Length |Where-Object{$_.Count-gt1}$duplicates=@()$totalGroups=$fileGroups.Count$counter=0# 2. Csak az azonos méretű fájlok SHA256 hash-ének ellenőrzéseforeach($groupin$fileGroups){$counter++Write-Progress-Activity "Duplikátumok keresése"-Status "Fájlcsoportok feldolgozása: $counter / $totalGroups"-PercentComplete (($counter/$totalGroups)*100)$hashTable=$group.Group|Get-FileHash-Algorithm SHA256 |Group-Object-Property Hash |Where-Object{$_.Count-gt1}foreach($hashGroupin$hashTable){foreach($filein$hashGroup.Group){$duplicates+=[PSCustomObject]@{Hash=$hashGroup.NamePath=$file.PathSizeMB=[math]::Round((Get-Item$file.Path).Length /1MB,2)}}}}# 3. Eredmények megjelenítése és mentéseif($duplicates.Count-gt0){Write-Host"`nTalált duplikátumok:"-ForegroundColor Green$duplicates|Format-Table-AutoSize -Property Hash, SizeMB, Path$duplicates|Export-Csv-Path $OutputFile-NoTypeInformation -Encoding UTF8Write-Host"Az eredmények elmentve ide: $OutputFile"-ForegroundColor Yellow}else{Write-Host"`nNem találhatók duplikált fájlok."-ForegroundColor Green}
Így használd:
Nyisd meg a PowerShell-t (akár Rendszergazdaként, ha védett mappákat is vizsgálsz).
Írd át a $TargetFolder változót a keresni kívánt mappára.
Futtasd a scriptet:PowerShell.\find-duplicates.ps1
Megjegyzés: Ha a PowerShell letiltja a scriptek futtatását, futtasd ezt a parancsot a munkamenetben:
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
Majd második próbálkozásra
Módosítottam a scriptet, hogy a célmappát (és opcióként a kimeneti CSV-fájl helyét is) paraméterként fogadja el.
A módosított script kódja:
PowerShell
<#.SYNOPSIS Fájl duplikációkat kereső és gyűjtő PowerShell script..DESCRIPTION A script végigpásztázza a paraméterként megadott mappát (és annak almappáit), és az SHA256 hash értékek alapján azonosítja a duplikátumokat. Az eredményt megjeleníti a konzolon és CSV-fájlba menti..PARAMETERTargetFolder A vizsgálandó mappa útvonala (kötelező paraméter)..PARAMETEROutputFile A kimeneti CSV fájl útvonala (opcionális, alapértelmezett: .\duplikatumok.csv).#>[CmdletBinding()]param([Parameter(Mandatory=$true,Position=0,HelpMessage="Kérjük, adja meg a vizsgálandó mappa útvonalát!")][ValidateScript({Test-Path$_-PathType Container })][string]$TargetFolder,[Parameter(Mandatory=$false,Position=1)][string]$OutputFile=".\duplikatumok.csv")# Abszolút útvonalak feloldása$TargetFolder=(Resolve-Path$TargetFolder).Path$OutputFile=$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputFile)Write-Host"Mappa elemzése: $TargetFolder"-ForegroundColor CyanWrite-Host"Fájlok indexelése és méret szerinti csoportosítása..."-ForegroundColor Cyan# 1. Összes fájl lekérése és méret szerinti csoportosítása (gyorsítási lépés)$fileGroups=Get-ChildItem-Path $TargetFolder-Recurse -File -ErrorAction SilentlyContinue |Group-Object-Property Length |Where-Object{$_.Count-gt1}$duplicates=@()$totalGroups=$fileGroups.Count$counter=0if($totalGroups-eq0){Write-Host"`nNem találhatók azonos méretű fájlok, nincsenek duplikátumok."-ForegroundColor Greenexit}# 2. Csak az azonos méretű fájlok SHA256 hash-ének ellenőrzéseforeach($groupin$fileGroups){$counter++Write-Progress-Activity "Duplikátumok keresése"-Status "Fájlcsoportok feldolgozása: $counter / $totalGroups"-PercentComplete (($counter/$totalGroups)*100)$hashTable=$group.Group|Get-FileHash-Algorithm SHA256 |Group-Object-Property Hash |Where-Object{$_.Count-gt1}foreach($hashGroupin$hashTable){foreach($filein$hashGroup.Group){$duplicates+=[PSCustomObject]@{Hash=$hashGroup.NamePath=$file.PathSizeMB=[math]::Round((Get-Item$file.Path).Length /1MB,2)}}}}# 3. Eredmények megjelenítése és mentéseif($duplicates.Count-gt0){Write-Host"`nTalált duplikátumok:"-ForegroundColor Green$duplicates|Format-Table-AutoSize -Property Hash, SizeMB, Path$duplicates|Export-Csv-Path $OutputFile-NoTypeInformation -Encoding UTF8Write-Host"Az eredmények elmentve ide: $OutputFile"-ForegroundColor Yellow}else{Write-Host"`nNem találhatók duplikált fájlok."-ForegroundColor Green}
Használati példák:
Alapértelmezett használat (a mappa elérést megadva, az eredmény a beállítások szerint a duplikatumok.csv-be kerül):PowerShell.\find-duplicates.ps1 -TargetFolder "C:\Users\Public\Documents"
Pozicionális paraméterként (nem kell kiírni a névadó kapcsolót):PowerShell.\find-duplicates.ps1 "D:\Képek"
Egyedi CSV kimeneti fájlnév megadásával:PowerShell.\find-duplicates.ps1 -TargetFolder "D:\Dokumentumok" -OutputFile "C:\Riportok\doksi_duplikatumok.csv"
Újdonságok a scriptben:
Automatikus mappa-ellenőrzés (ValidateScript): Ha nem létező vagy hibás mappa-útvonalat adsz meg, a script még a futás előtt jelez és leáll.
Mappa-kötelezőség (Mandatory = $true): Ha paraméter nélkül indítod el a scriptet, a PowerShell automatikusan megkérdezi tőled a célmappa útvonalát.
Nem vagyok teljes mértékben elragadtatva az eredménytől, de mára ez bőven elég volt, majd folytatjuk…