{"id":46373,"date":"2023-08-17T19:02:19","date_gmt":"2023-08-17T17:02:19","guid":{"rendered":"https:\/\/qualityminds.com\/?p=46373"},"modified":"2024-09-30T15:32:00","modified_gmt":"2024-09-30T13:32:00","slug":"framework-testow-w-selenium-z-paralelizacja-obsluga-wielu-przegladarek-i-internacjonalizacja-czesc-2","status":"publish","type":"post","link":"https:\/\/qualityminds.com\/pl\/framework-testow-w-selenium-z-paralelizacja-obsluga-wielu-przegladarek-i-internacjonalizacja-czesc-2\/","title":{"rendered":"Framework test\u00f3w w Selenium z paralelizacj\u0105, obs\u0142ug\u0105 wielu przegl\u0105darek i internacjonalizacj\u0105 &#8211; cz\u0119\u015b\u0107 2"},"content":{"rendered":"\n<section id=\"block-6679260c26026\"  class=\"hero-section template11\">\n\t<div class=\"bg\">\n\t\t\t<\/div>\n\t<div class=\"container\">\n\t\t<div class=\"hero-section__wrapper flex flex-wrap justify-between\">\n\t\t\t<div class=\"hero-section__description\">\n\t\t\t\t<div class=\"text-element-wrapper\">\n\t\t\t\t\t<div class=\"text-element\">\n\n<h1 class=\"wp-block-heading has-text-align-left\"><strong>Framework test\u00f3w w Selenium z paralelizacj\u0105, obs\u0142ug\u0105 wielu przegl\u0105darek i internacjonalizacj\u0105 &#8211; cz\u0119\u015b\u0107 2<\/strong><\/h1>\n\n<\/div>\n\t\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<\/div>\n\n\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t<div class=\"hero-section__img\">\n\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"2560\" height=\"1829\" src=\"https:\/\/qualityminds.com\/wp-content\/uploads\/2023\/08\/framework-testow-scaled.jpg\" class=\"attachment-full size-full\" alt=\"\" loading=\"eager\" srcset=\"https:\/\/qualityminds.com\/wp-content\/uploads\/2023\/08\/framework-testow-scaled.jpg 2560w, https:\/\/qualityminds.com\/wp-content\/uploads\/2023\/08\/framework-testow-300x214.jpg 300w, https:\/\/qualityminds.com\/wp-content\/uploads\/2023\/08\/framework-testow-1024x731.jpg 1024w, https:\/\/qualityminds.com\/wp-content\/uploads\/2023\/08\/framework-testow-768x549.jpg 768w, https:\/\/qualityminds.com\/wp-content\/uploads\/2023\/08\/framework-testow-1536x1097.jpg 1536w, https:\/\/qualityminds.com\/wp-content\/uploads\/2023\/08\/framework-testow-2048x1463.jpg 2048w\" sizes=\"(max-width: 2560px) 100vw, 2560px\" \/>\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\n\t\t\t\n\t\t\t\t\t<\/div>\n\t<\/div>\n\n\t<div class=\"social\">\n\t\t<div class=\"container\">\n\t\t\t<div class=\"social-wrapper flex items-center\">\n\t\t\t\t\u015aled\u017a nas\t\t\t\t\t<ul class=\"no-list no-margin social-list\">\n\t\t\t\t\t<li>\n\t\t\t\t<a href=\"https:\/\/www.linkedin.com\/company\/qualityminds-gmbh\/\" target=\"_blank\" aria-label=\"share on social media\" rel=\"noopener\">\n\t\t\t\t\t<img decoding=\"async\" width=\"29\" height=\"29\" src=\"https:\/\/qualityminds.com\/wp-content\/uploads\/2024\/06\/linkedin.svg\" class=\"attachment-full size-full\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t<\/a>\n\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t<a href=\"https:\/\/de-de.facebook.com\/QualityMindsGmbH\/\" target=\"_blank\" aria-label=\"share on social media\" rel=\"noopener\">\n\t\t\t\t\t<img decoding=\"async\" width=\"29\" height=\"29\" src=\"https:\/\/qualityminds.com\/wp-content\/uploads\/2024\/06\/facebook.svg\" class=\"attachment-full size-full\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t<\/a>\n\t\t\t<\/li>\n\t\t\t\t\t<li>\n\t\t\t\t<a href=\"https:\/\/www.xing.com\/pages\/qualitymindsgmbh\" target=\"_blank\" aria-label=\"share on social media\" rel=\"noopener\">\n\t\t\t\t\t<img decoding=\"async\" width=\"29\" height=\"29\" src=\"https:\/\/qualityminds.com\/wp-content\/uploads\/2024\/09\/xing_icon.svg\" class=\"attachment-full size-full\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t<\/a>\n\t\t\t<\/li>\n\t\t\t<\/ul>\n\t\t\t<\/div>\n\t\t<\/div>\n\t<\/div>\n<\/section>\n\n\n\t<section id=\"block-6679260c2607a\"  class=\"single-post-section\">\n\t\t<div class=\"container\">\n\t\t\t<div class=\"content\">\n\t\t\t\t<div class=\"single-post-main\">\n\t\t\t\t\t<div class=\"text-element\">\n\n<h2 class=\"wp-block-heading\">W <a href=\"https:\/\/qualityminds.com\/pl\/framework-testow-w-selenium-z-paralelizacja-obsluga-wielu-przegladarek-i-internacjonalizacja\/\" target=\"_blank\" rel=\"noopener\"><strong>poprzednim artykule<\/strong><\/a> pokazali\u015bmy Wam pierwsze etapy pisania frameworku z niezale\u017cnymi testami: konfiguracj\u0119 zale\u017cno\u015bci i tworzenie podstawowych klas. Nast\u0119pny etap pracy to logowanie:<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Krok 3: logowanie<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Je\u015bli wszystko posz\u0142o zgodnie z planem, powinni\u015bmy mie\u0107 uruchomione testy, kt\u00f3re generuj\u0105 du\u017co niepotrzebnego ha\u0142asu w konsoli. Dodatkowo, logi nie s\u0105 zapisywane, co utrudnia proces debugowania.\n<br><br>\nAby rozwi\u0105za\u0107 ten problem, mo\u017cemy doda\u0107 konfiguracj\u0119 logowania i zapisywanie log\u00f3w do pliku. U\u017cyjemy w tym celu <span style=\"font-family: courier;\">Logback<\/span>. Nale\u017cy doda\u0107 odpowiednie pliki konfiguracyjne dla <span style=\"font-family: courier;\">Logback<\/span> (np. <span style=\"font-family: courier;\">logback-test.xml<\/span>), gdzie zdefiniujemy regu\u0142y dotycz\u0105ce poziom\u00f3w logowania, docelowych plik\u00f3w log\u00f3w, itp. \n<br><br>\nPoni\u017cej znajduje si\u0119 przyk\u0142adowa konfiguracja <span style=\"font-family: courier;\">Logbacka<\/span>, do umieszczenia w <span style=\"font-family: courier;\">resources<\/span>\n<br><br>\n<script src=\"https:\/\/gist.github.com\/rafalmich\/e53e911489d79d2528bb9790a86371e0.js\"><\/script>\n<br><br>\nTo jak konfigurowa\u0107 <span style=\"font-family: courier;\">Logback<\/span>, to temat na oddzielny artyku\u0142. Powy\u017csz\u0105 konfiguracj\u0119 skopiujmy do <span style=\"font-family: courier;\">resources<\/span>, a poni\u017cszy plik do package <span style=\"font-family: courier;\">utils<\/span>.  \n<script src=\"https:\/\/gist.github.com\/rafalmich\/208f93a700b77b7f5d02dbd357edf67f.js\"><\/script>\n<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Krok 4: parametryzacja<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Teraz czas na zmodyfikowanie pliku <span style=\"font-family: courier;\">BaseTest<\/span>, tak by przyjmowa\u0142 parametry z r\u00f3\u017cnych \u017ar\u00f3de\u0142. Napiszemy kod, kt\u00f3ry pozwala czyta\u0107 parametry z pliku <span style=\"font-family: courier;\">XML<\/span>, jednak mo\u017cna je nadpisa\u0107 podaj\u0105c <span style=\"font-family: courier;\">JVM Options<\/span>, a najwy\u017cszy priorytet przyjmuj\u0105 parametry wprowadzane z <span style=\"font-family: courier;\">CLI<\/span>\n<br><br>\nZatem &lt;<span style=\"font-family: courier;\">parameter name=browser value=chrome<\/span>&gt; ma by\u0107 nadpisywany przez polecenie z CLI &#8211; <span style=\"font-family: courier;\">Dbrowser=EDGE<\/span>. \n<br><br>\nZmodyfikujmy wi\u0119c klas\u0119 <span style=\"font-family: courier;\">BaseTest<\/span>, tak by obs\u0142ugiwa\u0142a powy\u017csze za\u0142o\u017cenia: \n<script src=\"https:\/\/gist.github.com\/rafalmich\/61af0daf7413c36e3fb95be9bef764ab.js\"><\/script>\nW 1 kolejno\u015bci dodajemy 2 pola <span style=\"font-family: courier;\">BrowserType DEAFULT_BROWSER = BrowserType.CHROME i boolean DEFAULT_HEADLESS = TRUE<\/span>. \n<br><br>\nNast\u0119pnie modyfikujemy metod\u0119 <span style=\"font-family: courier;\">before<\/span>, tak by w przypadku podania zbyt ma\u0142ej b\u0105d\u017a zbyt du\u017cej liczby argument\u00f3w, wybra\u0142a wynikaj\u0105cy z precedencji, b\u0105d\u017a domy\u015blny. \n<br><br>\nNajpierw potrzebna b\u0119dzie nam metoda <span style=\"font-family: courier;\">boolean isNullOrBlank(String)<\/span>, kt\u00f3ra sprawdza, czy argument nie jest <span style=\"font-family: courier;\">null<\/span> b\u0105d\u017a pusty. \n<br><br>\nW 32 linijce mamy funkcje <span style=\"font-family: courier;\">T resolve(String String T)<\/span>, kt\u00f3ra odpowiada za precedencje parametr\u00f3w.\n<br><br>\nJak wida\u0107 cia\u0142o metody <span style=\"font-family: courier;\">before<\/span> zosta\u0142o zmodyfikowane tak by zwraca\u0107 w\u0142a\u015bciwy driver na podstawie wy\u017cej wymienionych zmiennych, kt\u00f3re definiuj\u0105 instancje Drivera. \n<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Krok 5: Page Object Model<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Przestrzegamy bran\u017cowych zasad i oczywi\u015bcie tworzymy framework korzystaj\u0105c z page object model. Po wej\u015bciu na stron\u0119 <a href=\"https:\/\/qualityminds.com\" target=\"_blank\" rel=\"noopener\">qualityminds.com<\/a> widzimy, \u017ce sk\u0142ada si\u0119 ona z podstron i wsp\u00f3lnego g\u00f3rnego paska nawigacyjnego (TopBar). Podczas naszych test\u00f3w b\u0119dziemy musieli otworzy\u0107 stron\u0119 g\u0142\u00f3wn\u0105 (index) oraz podstron\u0119 automatyzacji. Wi\u0119c b\u0119dziemy mieli do wykonania 3 PO \u2013 <span style=\"font-family: courier;\">HomePagePO<\/span>, <span style=\"font-family: courier;\">AutoTestPO<\/span>, <span style=\"font-family: courier;\">TopBarPO<\/span> \u2013 ten ostatni umie\u015bcimy jako pole (field) w poprzednich Page Objectach, korzystaj\u0105c z kompozycji. \n<br><br>\nDodatkowo, ka\u017cdy Page Object (ale nie <span style=\"font-family: courier;\">TopBarPO<\/span>) zawiera metody <span style=\"font-family: courier;\">load()<\/span> i <span style=\"font-family: courier;\">waitForPageToLoad()<\/span>, takie, \u017ce <span style=\"font-family: courier;\">load()<\/span> wywo\u0142uje <span style=\"font-family: courier;\">waitForPageToLoad()<\/span>. W przypadku internacjonalizacji, metody te musz\u0105 przyjmowa\u0107 <span style=\"font-family: courier;\">I18n<\/span> jako parametr, by wiedzie\u0107 z jakim j\u0119zykiem por\u00f3wnywa\u0107 widoczne tre\u015bci. \n<script src=\"https:\/\/gist.github.com\/rafalmich\/54e3f89e28bcdcd07899a5efc42c49cc.js\"><\/script>\nTe dwa interfejsy zawieraj\u0105 te metody, a interfejs <span style=\"font-family: courier;\">Loadable<\/span> \u015bwietnie pasuje do stron, kt\u00f3re wygl\u0105daj\u0105 tak samo w ka\u017cdym j\u0119zyku lub w przypadku, gdy elementy lokalizacji nie s\u0105 istotne z punktu widzenia automatycznego testu. Umie\u015b\u0107my je w pakiecie <span style=\"font-family: courier;\">pages<\/span>.\n<br><br>\nDesignu samej klasy <span style=\"font-family: courier;\">BasePage<\/span> nie b\u0119d\u0119 t\u0142umaczy\u0142 szczeg\u00f3\u0142owo, kod dost\u0119pny jest poni\u017cej \n<script src=\"https:\/\/gist.github.com\/rafalmich\/097ca65d9f9220905f0f60e0c5fde3bf.js\"><\/script>\n<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Krok 6: lokalizacja<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Zanim rozszerzymy klas\u0119 <span style=\"font-family: courier;\">BasePage<\/span> na konkretne podklasy, potrzebujemy narz\u0119dzia, kt\u00f3re umo\u017cliwi nam por\u00f3wnywanie znalezionego tekstu na stronie z oczekiwanym. Mo\u017cemy oczywi\u015bcie zdefiniowa\u0107 18 prywatnych statycznych zmiennych typu <span style=\"font-family: courier;\">String<\/span>, ale w rzeczywistych frameworkach wykonujemy du\u017co wi\u0119cej asercji, a ka\u017cda zmiana tekstu na stronie wymaga\u0142aby modyfikacji kodu. Dlatego znacznie \u0142atwiej i bezpieczniej jest przechowywa\u0107 kod w zewn\u0119trznym pliku, na przyk\u0142ad w formacie <span style=\"font-family: courier;\">JSON<\/span>, i odczytywa\u0107 stamt\u0105d oczekiwane warto\u015bci tekstowe. \n<br><br>\nOkre\u015blmy, jakie stringi b\u0119d\u0105 nam potrzebne do asercji i zapiszmy je w pliku <span style=\"font-family: courier;\">json<\/span>:\n<script src=\"https:\/\/gist.github.com\/rafalmich\/235e8f3dccebda2392dbbf3929bc01ac.js\"><\/script>\nTeraz napiszemy kod, kt\u00f3ry pomo\u017ce nam czyta\u0107 z pliku <span style=\"font-family: courier;\">json<\/span>, potrzebne b\u0119d\u0105 do tego 2 klasy \u2013 <span style=\"font-family: courier;\">StringLoader<\/span> \u2013 b\u0119dzie to singleton \u0142aduj\u0105cy plik <span style=\"font-family: courier;\">json<\/span> do pami\u0119ci oraz <span style=\"font-family: courier;\">Parser<\/span> \u2013 klasa, kt\u00f3ra plik <span style=\"font-family: courier;\">json<\/span> zamieni na obiekt <span style=\"font-family: courier;\">JsonNode<\/span>. \n<br><br>\nZacznijmy od klasy <span style=\"font-family: courier;\">Parser<\/span>, umie\u015b\u0107my j\u0105 w package <span style=\"font-family: courier;\">utils<\/span> razem z <span style=\"font-family: courier;\">ThreadIdConverter<\/span>, b\u0119dzie to prosta implementacja <span style=\"font-family: courier;\">ObjectMapper<\/span> z <span style=\"font-family: courier;\">Jacksona<\/span>. \n<script src=\"https:\/\/gist.github.com\/rafalmich\/a341eae0223d69f2d038d2d5828b4229.js\"><\/script>\nZawiera ona tylko jedn\u0105 metod\u0119 publiczn\u0105, kt\u00f3ra ma zamieni\u0107 plik w <span style=\"font-family: courier;\">JsonNode<\/span>. W argumencie przyjmuje jego lokalizacje w <span style=\"font-family: courier;\">classpath<\/span>. \n<br><br>\nTeraz napiszmy klas\u0119 <span style=\"font-family: courier;\">StringLoader<\/span> r\u00f3wnie\u017c w <span style=\"font-family: courier;\">utils<\/span>. \n<script src=\"https:\/\/gist.github.com\/rafalmich\/d93e4d9b521d29422f48683e989971b0.js\"><\/script>\nKlasa jest <span style=\"font-family: courier;\">lazy loaded singletonem<\/span>, korzystaj\u0105cym z <span style=\"font-family: courier;\">Initialization-on-demand holder idiom<\/span>. \n<br><br>\nKonstruktor singletona \u0142aduje plik <span style=\"font-family: courier;\">strings.json<\/span> do pami\u0119ci, a metoda <span style=\"font-family: courier;\">JsonNode strings(I18n)<\/span> pozwala na otrzymanie obiektu z pliku <span style=\"font-family: courier;\">json<\/span> zawieraj\u0105cego dane dla konkretnej internacjonalizacji.\n<br><br>\nTakie rozwi\u0105zanie dzia\u0142a, jest jednak bardzo niewygodne w u\u017cyciu, za ka\u017cdym razem, gdy chcieliby\u015bmy np. przywo\u0142a\u0107 konkretny string musieliby\u015bmy pisa\u0107:  \n<br><br>\n<span style=\"font-family: courier;\">StringLoader.getInstance().strings(i18n).get(key).asText();<\/span>\n<br><br>\nWobec tego zr\u00f3bmy interfejs z jedn\u0105 metod\u0105 <span style=\"font-family: courier;\">default<\/span>, zawieraj\u0105c\u0105 w\u0142a\u015bnie powy\u017cszy sparametryzowany kod. Ka\u017cda klasa, kt\u00f3ra zaimplementuje ten interfejs nie b\u0119dzie mia\u0142a problem\u00f3w z wyci\u0105ganiem string\u00f3w z <span style=\"font-family: courier;\">json<\/span>. \n<br><br>\nA oto implementacja Interfejsu <span style=\"font-family: courier;\">Localizable<\/span> (zapiszmy go w package <span style=\"font-family: courier;\">pages<\/span>): \n<script src=\"https:\/\/gist.github.com\/rafalmich\/7460cc02315f511d2245bcf75854002a.js\"><\/script>\nZauwa\u017cmy, \u017ce zdefiniowa\u0142em ju\u017c 6 kluczy string\u00f3w jako sta\u0142e, wi\u0119c u\u017cywanie ich nie powinno by\u0107 problemem. Ten interfejs b\u0119dzie zaimplementowany przez ka\u017cdy PO, w kt\u00f3rym s\u0105 elementy, kt\u00f3rych tekst nale\u017cy sprawdzi\u0107 asercj\u0105, czyli <span style=\"font-family: courier;\">HomePagePO<\/span> i <span style=\"font-family: courier;\">AutoTestPO<\/span>, kt\u00f3re zaimplementujemy w nast\u0119pnym korku:\n<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Krok 7: konfiguracja PO<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Teraz rozszerzymy klas\u0119 <span style=\"font-family: courier;\">BasePage<\/span> na poszczeg\u00f3lne Page Objecty. Ten krok nie zawiera nic skomplikowanego, dlatego te\u017c ogranicz\u0119 si\u0119 do kr\u00f3tkiego opisu i podania gotowego kodu. Tworz\u0105c metody w Page Objectach polecam korzysta\u0107 z tzw. <span style=\"font-family: courier;\">Fluent API<\/span>, czyli kaza\u0107 metodom zwraca\u0107 <span style=\"font-family: courier;\">this<\/span>, b\u0105d\u017a, gdy metoda powoduje zmian\u0119 strony (np. klikni\u0119cie w menu), now\u0105 instancj\u0119 tego Page Objectu, kt\u00f3ry reprezentuje abstrakcj\u0119 strony, na kt\u00f3r\u0105 przechodzimy.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Zanim jednak ruszymy jakiekolwiek PO, szybko wr\u00f3\u0107my do dawno stworzonego enuma, <span style=\"font-family: courier;\">I18n<\/span>. \n<script src=\"https:\/\/gist.github.com\/rafalmich\/9f92364775690c71dcbfa25896c690c2.js\"><\/script>\nDodajmy sta\u0142e <span style=\"font-family: courier;\">abbr<\/span>, <span style=\"font-family: courier;\">url<\/span><span style=\"font-family: courier;\"> i <span style=\"font-family: courier;\">href<\/span>, co u\u0142atwi pisanie metod, kt\u00f3re przyjmuj\u0105 <span style=\"font-family: courier;\">I18n<\/span> jako parametr.<br><br><\/span><\/li>\n\n\n\n<li><span style=\"font-family: courier;\">HomePagePO<\/span> \u2013 implementuje <span style=\"font-family: courier;\">Loadable<homepagepo><\/homepagepo><\/span>, <span style=\"font-family: courier;\">LocaleLoadable<homepagepo><\/homepagepo><\/span> oraz <span style=\"font-family: courier;\">Localizable<\/span>: \n<script src=\"https:\/\/gist.github.com\/rafalmich\/88af2777e6a87353fddacf3654706c5f.js\"><\/script>\nMetody <span style=\"font-family: courier;\">load()<\/span> i <span style=\"font-family: courier;\">waitForPageToLoad()<\/span> (wywo\u0142ywana przez <span style=\"font-family: courier;\">load()<\/span>) s\u0105 przydatne do otwierania strony bez okre\u015blania j\u0119zyka &#8211; w takim przypadku strona jest \u0142adowana domy\u015blnie. Mamy r\u00f3wnie\u017c te same dwie metody z parametrem typu <span style=\"font-family: courier;\">I18n<\/span>, kt\u00f3re u\u017cywamy, gdy zmieniamy j\u0119zyk, poniewa\u017c wtedy \u0142adowany jest inny adres, a metoda <span style=\"font-family: courier;\">waitForPageToLoad(I18n)<\/span> sprawdza, czy strona zosta\u0142a poprawnie za\u0142adowana w r\u00f3\u017cnych j\u0119zykach, zale\u017cnie od parametru <span style=\"font-family: courier;\">I18n<\/span>.\n<br><br>\n\u0141atwo zauwa\u017cy\u0107, \u017ce metoda <span style=\"font-family: courier;\">waitForPageToLoad()<\/span> korzysta z metody <span style=\"font-family: courier;\">default<\/span> z interfejsu <span style=\"font-family: courier;\">Localizable<\/span>, aby por\u00f3wnywa\u0107 tekst ze strony z oczekiwanym tekstem z pliku <span style=\"font-family: courier;\">json<\/span>.\n<br><br>\nDodatkowo jako pole klasy, mamy instancj\u0119 <span style=\"font-family: courier;\">TopBarPO<\/span>, kt\u00f3ra umo\u017cliwia dost\u0119p do g\u00f3rnego paska w dowolnym momencie korzystania z <span style=\"font-family: courier;\">HomePagePO<\/span>, co wykorzystamy w testach.<br><br><\/li>\n\n\n\n<li><span style=\"font-family: courier;\">AutoTestPO<\/span> &#8211; implementuje <span style=\"font-family: courier;\">LocaleLoadable<homepagepo><\/homepagepo><\/span> oraz Localizable: \n<script src=\"https:\/\/gist.github.com\/rafalmich\/ab8a7785e70a901fb48529f6ee30425e.js\"><\/script>\nPodobnie jak w <span style=\"font-family: courier;\">HomePagePO<\/span>, komponentem klasy jest r\u00f3wnie\u017c <span style=\"font-family: courier;\">TopBarPO<\/span>.<br><br><\/li>\n\n\n\n<li><span style=\"font-family: courier;\">TopBarPO<\/span> \u2013 jedyny PO, kt\u00f3ry nie jest abstrakcj\u0105 nad danym widokiem strony, a komponentem widocznym z ka\u017cdego widoku, dlatego te\u017c jest wkomponowany w poprzednie PO. <br><script><\/script><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Mamy ju\u017c wszystkie metody niezb\u0119dne do nawigowania po stronie, jedyne co nam pozosta\u0142o, to wywo\u0142a\u0107 je i mamy gotowy test automatyczny. \n<script src=\"https:\/\/gist.github.com\/rafalmich\/f78ad390d6b653c12e7439af49e21cc0.js\"><\/script>\nW package <span style=\"font-family: courier;\">test<\/span> zr\u00f3bmy klas\u0119 <span style=\"font-family: courier;\">LocalisationTest<\/span> z metod\u0105 <span style=\"font-family: courier;\">void verifyTestAutomationPageTranslation(I18n)<\/span>, poniewa\u017c taki sam test musi by\u0107 wykonany trzykrotnie dla ka\u017cdego z j\u0119zyk\u00f3w. W tym celu skorzystamy z <span style=\"font-family: courier;\">DataProvidera<\/span>, kt\u00f3remu ka\u017cmy zwr\u00f3ci\u0107 <span style=\"font-family: courier;\">I18n[]<\/span> czyli <span style=\"font-family: courier;\">I18n.values()<\/span>. Ustawmy adnotacje <span style=\"font-family: courier;\">@DataProvider(parallel = true)<\/span>, dzi\u0119ki czemu, p\u00f3ki starczy w\u0105tk\u00f3w, metody mog\u0105 by\u0107 uruchamiane r\u00f3wnolegle.\n<br><br>\nSam test jest bardzo prosty, dzi\u0119ki <span style=\"font-family: courier;\">fluent API<\/span> raz wywo\u0142ujemy <span style=\"font-family: courier;\">new HomePagePO(driver())<\/span>, a potem ju\u017c do ko\u0144ca testu chainujemy metody w tej kolejno\u015bci (poni\u017cej opis krok po kroku). Dzi\u0119ki u\u017cyciu <span style=\"font-family: courier;\">DataProvidera<\/span>, wykonaj\u0105 si\u0119 one 3 razy, za ka\u017cdym razem z innym parametrem <span style=\"font-family: courier;\">i18n<\/span>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Za\u0142aduj stron\u0119 g\u0142\u00f3wn\u0105 <\/li>\n\n\n\n<li>Zamknij popup z Cookies. <\/li>\n\n\n\n<li>Zwr\u00f3\u0107 instancje <span style=\"font-family: courier;\">TopBarPO<\/span><\/li>\n\n\n\n<li>Sprawd\u017a, \u017ce obecny j\u0119zyk to angielski <\/li>\n\n\n\n<li>Najed\u017a mysz\u0105 na menu j\u0119zyka<\/li>\n\n\n\n<li>Zmie\u0144 j\u0119zyk na <span style=\"font-family: courier;\">i18n<\/span> (ta metoda nie robi nic, je\u015bli <span style=\"font-family: courier;\">i18n == I18n.ENGLISH<\/span>).<\/li>\n\n\n\n<li>Sprawd\u017a czy obecna ikonka j\u0119zyka odpowiada <span style=\"font-family: courier;\">i18n<\/span><\/li>\n\n\n\n<li>Najed\u017a mysz\u0105 na menu Portfolio <\/li>\n\n\n\n<li>Kliknij na podmenu automation tests <\/li>\n\n\n\n<li>Poczekaj, a\u017c strona si\u0119 za\u0142aduje w j\u0119zyku <span style=\"font-family: courier;\">i18n<\/span><\/li>\n\n\n\n<li>Sprawd\u017a przycisk contact us dla j\u0119zyka <span style=\"font-family: courier;\">i18n<\/span><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">I tyle. \n<br><br>\nZmodyfikujmy jeszcze plik testng.xml \n<script src=\"https:\/\/gist.github.com\/rafalmich\/884c1c12e762d929e0f5ca33e198dbce.js\"><\/script>\nI uruchamiamy testy \u2013 wszystko powinno dzia\u0142a\u0107. \n<br><br>\nJak zwykle zach\u0119cam do pobawienia si\u0119 plikiem konfiguracyjnym, dopisania w\u0142asnych test\u00f3w (kt\u00f3re chocia\u017cby tylko mia\u0142y pisa\u0107 wiadomo\u015b\u0107 na konsoli) i posprawdzania r\u00f3\u017cnych wariant\u00f3w paralelizacji. \n<br><br>\nCzytelniczka lub czytelnik na pewno zauwa\u017c\u0105, \u017ce g\u0142\u0119boko\u015b\u0107, na kt\u00f3rej chcemy dokonywa\u0107 paralelizacji, wymaga od nas coraz wi\u0119kszej dyscypliny w budowaniu frameworku. Uruchamianie test\u00f3w na poziomie poszczeg\u00f3lnych metod wymaga najwi\u0119kszej dyscypliny w pisaniu kodu. \n<br><br>\nNa stronie repozytorium, na ga\u0142\u0119zi <span style=\"font-family: courier;\">main<\/span> jest jeszcze dost\u0119pny workflow dla GitHuba oraz plik <span style=\"font-family: courier;\">bat<\/span> uruchamiaj\u0105cy skrypt PowerShell, kt\u00f3ry natychmiast wy\u0142\u0105cza wszystkie sesje Chrome, Edge, Firefoxa i ich driver\u00f3w \u2013 przydatne, gdy podczas debugowania zostaje nam mn\u00f3stwo niedomkni\u0119tych okienek.<\/p>\n\n<\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"single-post-aside\">\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"post-author-wr\">\n\t\t\t\t\t\t\t<div class=\"author-img\">\n\t\t\t\t\t\t\t\t<img alt='' src='https:\/\/secure.gravatar.com\/avatar\/be24f7a5f0d4999b17910d6208d7a4e726fc3e94e1131257b63d9069f8b5926f?s=96&#038;d=mm&#038;r=g' srcset='https:\/\/secure.gravatar.com\/avatar\/be24f7a5f0d4999b17910d6208d7a4e726fc3e94e1131257b63d9069f8b5926f?s=192&#038;d=mm&#038;r=g 2x' class='avatar avatar-96 photo' height='96' width='96' \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"author-info text-element\">\n\t\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\t\tGeschrieben von:\t\t\t\t\t\t\t\t\t<\/p>\n\t\t\t\t\t\t\t\t\t<p class=\"author-name\">\n\t\t\t\t\t\t\t\t\t\tAdministrator QualityMinds\t\t\t\t\t\t\t\t\t<\/p>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"aside-cta\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"icon-wr\">\n\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"76\" height=\"76\" src=\"https:\/\/qualityminds.com\/wp-content\/uploads\/2024\/05\/Capa_1.svg\" class=\"attachment-full size-full\" alt=\"\" loading=\"lazy\" \/>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"text-element\">\n\t\t\t\t\t\t\t\t\t<p>Chcesz om\u00f3wi\u0107 swoje osobiste obawy dotycz\u0105ce transformacji cyfrowej?<\/p>\n<p>Skontaktuj si\u0119 z nami w celu uzyskania bezp\u0142atnej i niewi\u0105\u017c\u0105cej konsultacji:<\/p>\n<p><a href=\"mailto:hello@qualityminds.de\">hello@qualityminds.de<\/a><\/p>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"similar-posts\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"heading\">\n\t\t\t\t\t\t\t\t\tDalszy wk\u0142ad\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<ul class=\"no-list no-margin\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/qualityminds.com\/pl\/ai-navigator-2024-jestesmy-jego-czescia\/\">AI Navigator 2024 &#8211; Jeste\u015bmy jego cz\u0119\u015bci\u0105\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/qualityminds.com\/pl\/thoughts-on-using-chatgpt-as-a-software-developer\/\">Thoughts on using ChatGPT as a software developer\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/qualityminds.com\/pl\/nie-mam-czasu-na-nauke-w-godzinach-pracy-wlasciwie-dlaczego-nie\/\">Nie mam czasu na nauk\u0119 w godzinach pracy! &#8211; w\u0142a\u015bciwie dlaczego nie?\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\n\t\t\t\t\t\t\t<div class=\"social-sharing\">\n\t\t\t\t\t<p class=\"no-margin\">Udzia\u0142\t\t\t\t\t<\/p>\n\t\t\t\t\t\n<ul class=\"no-list no-margin\">\n\t<li>\n\t\t<a href=\"https:\/\/www.linkedin.com\/feed\/?shareActive=true&#038;text=https:\/\/qualityminds.com\/pl\/nie-mam-czasu-na-nauke-w-godzinach-pracy-wlasciwie-dlaczego-nie\/\" class=\"linkedin\" target=\"_blank\" aria-label=\"Udost\u0119pnij na LinkedIn\"><\/a>\n\t<\/li>\n\t<li>\n\t\t<a href=\"https:\/\/www.facebook.com\/sharer\/sharer.php?u=https:\/\/qualityminds.com\/pl\/nie-mam-czasu-na-nauke-w-godzinach-pracy-wlasciwie-dlaczego-nie\/\" class=\"facebook\" target=\"_blank\" aria-label=\"Udost\u0119pnij na Facebooku\"><\/a>\n\t<\/li>\n\t<li>\n\t\t<a href=\"https:\/\/www.xing.com\/spi\/shares\/new?url=https:\/\/qualityminds.com\/pl\/nie-mam-czasu-na-nauke-w-godzinach-pracy-wlasciwie-dlaczego-nie\/\" class=\"xing\" target=\"_blank\" aria-label=\"Udost\u0119pnij na Xing\"><\/a>\n\t<\/li>\n<\/ul>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t<\/section>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":67,"featured_media":46380,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[26,489,491,493],"tags":[],"class_list":["post-46373","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","category-news-pl","category-qm-stories-pl","category-testing-qa-pl"],"acf":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/qualityminds.com\/wp-content\/uploads\/2023\/08\/framework-testow-scaled.jpg","_links":{"self":[{"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/posts\/46373","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/users\/67"}],"replies":[{"embeddable":true,"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/comments?post=46373"}],"version-history":[{"count":11,"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/posts\/46373\/revisions"}],"predecessor-version":[{"id":59661,"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/posts\/46373\/revisions\/59661"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/media\/46380"}],"wp:attachment":[{"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/media?parent=46373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/categories?post=46373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qualityminds.com\/pl\/wp-json\/wp\/v2\/tags?post=46373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}