údržba
This commit is contained in:
4
Playwright základy na GitHub/.gitignore
vendored
Normal file
4
Playwright základy na GitHub/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
8
Playwright základy na GitHub/.idea/.gitignore
generated
vendored
Normal file
8
Playwright základy na GitHub/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
9
Playwright základy na GitHub/.idea/Playwright základy na GitHub.iml
generated
Normal file
9
Playwright základy na GitHub/.idea/Playwright základy na GitHub.iml
generated
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
Playwright základy na GitHub/.idea/misc.xml
generated
Normal file
6
Playwright základy na GitHub/.idea/misc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
Playwright základy na GitHub/.idea/modules.xml
generated
Normal file
8
Playwright základy na GitHub/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Playwright základy na GitHub.iml" filepath="$PROJECT_DIR$/.idea/Playwright základy na GitHub.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
Playwright základy na GitHub/.idea/vcs.xml
generated
Normal file
6
Playwright základy na GitHub/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -0,0 +1,7 @@
|
||||
O tom ako písať Xpathy a využívať ich v testovaní sa dočítaš napríklad tu: https://www.guru99.com/xpath-selenium.html alebo tu.
|
||||
|
||||
Viac o lokátoroch v Playwrighte nájdeš v dokumentácii tu.https://playwright.dev/docs/locators
|
||||
|
||||
Taktiež dobrý blog o lokalizovaní elementov v napísala ambasádorka Playwrightu, Debbie: https://debbie.codes/blog/how-to-locate-elements-in-playwright/
|
||||
|
||||
Skvelým rozšírením do Chrome prehliadača je [Selectors Hub](https://chrome.google.com/webstore/detail/selectorshub/ndgimibanhlabgdgjcpbbndiehljcpfh). Ako ho využívať uvidíš v [tomto](https://youtu.be/-GpTpwOLCUM) videu.
|
158
Playwright základy na GitHub/Async Await.md
Normal file
158
Playwright základy na GitHub/Async Await.md
Normal file
@ -0,0 +1,158 @@
|
||||
[Portfolio](https://www.kutac.cz#portfolio) [Blog](https://www.kutac.cz/blog) [Kontakt](https://www.kutac.cz#kontakt)
|
||||
|
||||
[Blog](https://www.kutac.cz/blog) [Weby a vše okolo](https://www.kutac.cz/weby-a-vse-okolo) Async / await
|
||||
|
||||
# Async / await
|
||||
|
||||
[Kategorie](#)
|
||||
|
||||
[Co na srdci, to na blogu](https://www.kutac.cz/co-na-srdci-to-na-blogu) [Weby a vše okolo](https://www.kutac.cz/weby-a-vse-okolo) [Počítače a internety](https://www.kutac.cz/pocitace-a-internety) [Erasmus a cestování](https://www.kutac.cz/erasmus-a-cestovani)
|
||||
|
||||
[Tagy](#)
|
||||
|
||||
[PHP](https://www.kutac.cz/php) [JavaScript](https://www.kutac.cz/javascript) [Laravel](https://www.kutac.cz/laravel) [Go](https://www.kutac.cz/golang) [Git](https://www.kutac.cz/git) [Kvalita kódu](https://www.kutac.cz/kvalita-kodu) [Bezpečnost](https://www.kutac.cz/bezpecnost) [Databáze](https://www.kutac.cz/databaze) [Windows](https://www.kutac.cz/windows) [Linux](https://www.kutac.cz/linux) [Google](https://www.kutac.cz/google) [HTML](https://www.kutac.cz/html) [CSS](https://www.kutac.cz/css) [htaccess](https://www.kutac.cz/htaccess) [Tipy & triky](https://www.kutac.cz/tiky-a-triky) [O mně](https://www.kutac.cz/o-mne)
|
||||
|
||||
[Rychlé odkazy](#)
|
||||
|
||||
[Seriály](https://www.kutac.cz/serialy) [Testovací data k článkům](https://testdata.kutac.cz/) [Čtenářský deník](https://www.kutac.cz/co-na-srdci-to-na-blogu/ctenarsky-denicek)
|
||||
|
||||
25.04.2018 22:52 Michael 1
|
||||
|
||||
[JavaScript](https://www.kutac.cz/javascript)
|
||||
|
||||
Asynchronní programování v Javascriptu bez callbacků a Promise nemusí být nutně sci-fi. Co všechno umí klíčová slova async / await?
|
||||
|
||||
[](https://www.kutac.cz/uploads/main-41375.jpg)
|
||||
|
||||
S příchodem [Promise](https://www.kutac.cz/weby-a-vse-okolo/promise-v-javascriptu) se změnil a podstatně zjednodušil způsob, jakým je možné pracovat s asynchroními voláními v Javascriptu. Špatně škálovatelné volání callback funkcí nahradilo zpracování, které je přehledné, řetězitelné a s jednoduchým zachytáváním chyb. Od uvedení [generátorů](https://www.kutac.cz/weby-a-vse-okolo/generatory-v-javascriptu) je také možné pomocí pozastavitelných funkcí zpracovávat Promise způsobem, který vypadá synchronně, ale na pozadí není (viz [příklad](https://www.kutac.cz/weby-a-vse-okolo/generatory-v-javascriptu#vyuziti-a-zaver) ve [článku o generátorech](https://www.kutac.cz/weby-a-vse-okolo/generatory-v-javascriptu)). Takový zápis může být mnohem čitelnější a čitelnější kód znamená snazší debugování. Až by mohlo někoho napadnout, proč něco takového není standardní součástí jazyka. A tak nám do Javascriptu přibyly slova async a await.
|
||||
|
||||
## [](#async-await)Async / Await
|
||||
|
||||
Klíčové slovo async je označením funkce, která je pozastavitelná, podobně jako generátory. V takto označené funkci pak lze použít klíčové slovo await. To automaticky vyřeší a přiřadí výsledek Promise do dané proměnné. Vezměme tento příklad, kdy na základě dat článku vypíšeme jméno jeho autora:
|
||||
|
||||
```javascript
|
||||
// Požadavek pomocí Promise
|
||||
function printAuthor(postId) {
|
||||
fetch(`api/posts/${postId}`)
|
||||
.then(res => res.json())
|
||||
.then(post => fetch(`api/users/${post.userId}`))
|
||||
.then(res => res.json())
|
||||
.then(user => console.log(user.name}))
|
||||
.catch(error => console.log(error))
|
||||
}
|
||||
|
||||
printAuthor(42) // 'Douglas Adams'
|
||||
```
|
||||
|
||||
Stejný příklad by při použití async / await vypadal takto:
|
||||
|
||||
```javascript
|
||||
// Požadavek pomocí async funkce
|
||||
async function printAuthorAsync(postId) {
|
||||
let res = await fetch(`api/posts/${postId}`)
|
||||
const post = await res.json()
|
||||
|
||||
res = await fetch(`api/users/${post.userId}`)
|
||||
const user = await res.json()
|
||||
|
||||
console.log(user.name)
|
||||
}
|
||||
|
||||
printAuthorAsync(42) // 'Douglas Adams'
|
||||
|
||||
|
||||
```
|
||||
|
||||
Příklad si můžete [vyzkoušet zde](https://jsfiddle.net/xs3yvp2d/13/).
|
||||
|
||||
Await prakticky říká "počkej, až se vyřeší tento Promise a pokračuj". To je důležitá vlastnost, protože await pracuje pouze s Promise. Pokud dostane cokoliv jiného, převede výsledek zase na Promise. Ten vždy vrací i samotná async funkce. Celý tento mechanismus je totiž postaven nad Promise a generátory. Async / await je ve skutečnosti jenom syntaktické pozlátko a využívá stávající funkce jazyka.
|
||||
|
||||
## [](#vyhody)Výhody
|
||||
|
||||
Proč jej vlastně používat? Tím, že se zapisuje v podstatě synchronně, je mnohem čitelnější a nastavení breakpointů při debugování je tak mnohem jednodušší.
|
||||
|
||||
Protože každé zpracování Promise nemá odlišný scope, všechny hodnoty mohou být k dispozici v celém scopu funkce:
|
||||
|
||||
```javascript
|
||||
// Všechny výsledky Promise mohou být k dispozici v jednom scopu
|
||||
async function foo() {
|
||||
const a = await promise1()
|
||||
const b = await promise2()
|
||||
|
||||
return {a, b}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Taky je možné používat klasické podmínky mnohem snáze:
|
||||
|
||||
```javascript
|
||||
// Funkci lze jednodušše větvit podmínkami
|
||||
async function foo() {
|
||||
const a = await promise1()
|
||||
const b = await promise2()
|
||||
|
||||
if (a > b) {
|
||||
return a
|
||||
}
|
||||
else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
A zachytávání výjimkek probíhá pomocí try/catch bloků:
|
||||
|
||||
```javascript
|
||||
// Chyby jsou zachytávány try/catch bloky
|
||||
async function foo() {
|
||||
try {
|
||||
const a = await promise1()
|
||||
const b = await promise2()
|
||||
|
||||
return {a, b}
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
## [](#zaver)Závěr
|
||||
|
||||
Async / await je velmi vítaným přínosem do Javascriptu. Pro asynchronní programování nabízí mnohdy čitelnější alternativu dnes rozšířeného Promise. Je podporován v NodeJS verze > 7.10 a větší částí posledních verzí moderních [prohlížečů](https://caniuse.com/#search=await). Přesto, pokud jej hodláte použít v prohlížeči, doporučoval bych nejdříve [transformaci Babelem](https://babeljs.io/docs/plugins/transform-async-to-generator/).
|
||||
|
||||
* * *
|
||||
|
||||
Napadá vás kdy je lepší použít Promise a naopak? Máte s async / await nějaké zkušenosti? Podělte se s ostatními v komentářích.
|
||||
|
||||
## Přidat komentář
|
||||
|
||||
Tvoje jméno *
|
||||
|
||||
<img width="28" height="28" src=":/3b9a1daff9a44f38a09e539024d45d03"/>
|
||||
|
||||
Tvůj email
|
||||
|
||||
Tvůj web
|
||||
|
||||
Tvůj komentář *
|
||||
|
||||
Položky označené * jsou povinné. Email nebude zveřejněn
|
||||
|
||||
* * *
|
||||
|
||||
## Komentáře
|
||||
|
||||
27.03.2021 22:13
|
||||
|
||||
**Milos Leng**
|
||||
|
||||
Super stranka, vysvetlenia lepsie ako v anglickych videach, ale stali mi je to malo :D
|
||||
|
||||
[Odpovědět](#comment-473)
|
||||
|
||||
© 2014 - 2023 All rights reserved, IČO: 01827219
|
44
Playwright základy na GitHub/README.MD
Normal file
44
Playwright základy na GitHub/README.MD
Normal file
@ -0,0 +1,44 @@
|
||||
Pozor TypeScript
|
||||
|
||||
|
||||
|
||||
súboj Playwrightu a Cypressu si pozrieš na týchto odkazoch:
|
||||
https://youtu.be/fncL63KRA-0
|
||||
https://www.youtube.com/live/bvvTzHmLWwY?feature=share
|
||||
https://youtu.be/RwNZTjwhgXc
|
||||
|
||||
|
||||
|
||||
Node.js si stiahneš na tomto odkaze: https://nodejs.org/en
|
||||
npm si inštalovať nemusíš. Node.js ho už obsahuje.
|
||||
|
||||
Visual Studio Code si stiahneš tu: https://code.visualstudio.com/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Viac o fixtures sa dozvieš v Playwright dokumentácii tu:
|
||||
https://playwright.dev/docs/api/class-fixtures
|
||||
|
||||
Všetky spôsoby spúšťania testov nájdeš tu.https://playwright.dev/docs/running-tests
|
||||
|
||||
|
||||
|
||||
Viac o async a await sa dočítaš tu: https://www.kutac.cz/weby-a-vse-okolo/async-await
|
||||
|
||||
|
||||
|
||||
Viac o configu nájdeš v dokumentácii tu.https://playwright.dev/docs/test-configuration
|
||||
|
||||
|
||||
O tom ako písať Xpathy a využívať ich v testovaní sa dočítaš napríklad tu: https://www.guru99.com/xpath-selenium.html alebo tu.
|
||||
|
||||
Viac o lokátoroch v Playwrighte nájdeš v dokumentácii tu.https://playwright.dev/docs/locators
|
||||
|
||||
Taktiež dobrý blog o lokalizovaní elementov v napísala ambasádorka Playwrightu, Debbie: https://debbie.codes/blog/how-to-locate-elements-in-playwright/
|
||||
|
||||
Skvelým rozšírením do Chrome prehliadača je [Selectors Hub](https://chrome.google.com/webstore/detail/selectorshub/ndgimibanhlabgdgjcpbbndiehljcpfh). Ako ho využívať uvidíš v [tomto](https://youtu.be/-GpTpwOLCUM) videu.
|
||||
|
||||
|
0
Playwright základy na GitHub/fixtures/basePages.ts
Normal file
0
Playwright základy na GitHub/fixtures/basePages.ts
Normal file
63
Playwright základy na GitHub/package-lock.json
generated
Normal file
63
Playwright základy na GitHub/package-lock.json
generated
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"name": "Playwright základy na GitHub",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.34.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.34.3",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.34.3.tgz",
|
||||
"integrity": "sha512-zPLef6w9P6T/iT6XDYG3mvGOqOyb6eHaV9XtkunYs0+OzxBtrPAAaHotc0X+PJ00WPPnLfFBTl7mf45Mn8DBmw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.34.3"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
|
||||
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.34.3",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.34.3.tgz",
|
||||
"integrity": "sha512-2pWd6G7OHKemc5x1r1rp8aQcpvDh7goMBZlJv6Co5vCNLVcQJdhxRL09SGaY6HcyHH9aT4tiynZabMofVasBYw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
Playwright základy na GitHub/package.json
Normal file
12
Playwright základy na GitHub/package.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "playwright_zaklady",
|
||||
"scripts": {
|
||||
"allTests": "playwright test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Kankys",
|
||||
"description": "",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.34.3"
|
||||
}
|
||||
}
|
45
Playwright základy na GitHub/page-objects copy/HomePage.ts
Normal file
45
Playwright základy na GitHub/page-objects copy/HomePage.ts
Normal file
@ -0,0 +1,45 @@
|
||||
// import třída modulů které budeme potřebovat
|
||||
import { Locator, Page
|
||||
} from "@playwright/test";
|
||||
|
||||
//definujeme třídy (class)
|
||||
export class HomePage{
|
||||
page: Page;
|
||||
menu: Locator;
|
||||
title: Locator;
|
||||
item: Locator;
|
||||
addToCart: Locator;
|
||||
cardBadge: Locator;
|
||||
|
||||
// vytvoříme konstruktor třídy definuje proměnou page
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.menu = page.locator('#react-burger-menu-btn');
|
||||
this.title = page.getByText('Swag Labs');
|
||||
this.item = page.locator('#item_4_title_link');
|
||||
this.addToCart = page.locator('#add-to-cart-sauce-labs-backpack');
|
||||
this.cardBadge = page.locator('//span[@class="shopping_cart_badge"]');
|
||||
}
|
||||
|
||||
// teď si definujeme metody na práci s elementy výše
|
||||
|
||||
async clickOnMenu() {
|
||||
await this.menu.click();
|
||||
}
|
||||
|
||||
async clickOnItem() {
|
||||
await this.item.click();
|
||||
}
|
||||
|
||||
|
||||
async clickOnAddToCart() {
|
||||
await this.addToCart.click();
|
||||
}
|
||||
|
||||
async clickOnCardBAdge() {
|
||||
await this.cardBadge.click();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
71
Playwright základy na GitHub/page-objects copy/LoginPage.ts
Normal file
71
Playwright základy na GitHub/page-objects copy/LoginPage.ts
Normal file
@ -0,0 +1,71 @@
|
||||
// import třída modulů které budeme potřebovat
|
||||
import { Locator, Page
|
||||
} from "@playwright/test";
|
||||
|
||||
//definujeme třídy (class)
|
||||
export class LoginPage{
|
||||
page: Page;
|
||||
userNameInput: Locator;
|
||||
passwordInput: Locator;
|
||||
loginButton: Locator;
|
||||
invalidCredentialsErrorMessage: Locator;
|
||||
requiredCredentialsErrorMassage: Locator;
|
||||
lockedOutErrorMassage: Locator;
|
||||
|
||||
// vytvoříme konstruktor třídy definuje proměnou page
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.userNameInput = page.locator('#user-name');
|
||||
this.passwordInput = page.locator('#password');
|
||||
this.loginButton = page.locator('#login-button');
|
||||
this.invalidCredentialsErrorMessage = page.getByText('Epic sadface: Username and password do not match any user in this service');
|
||||
this.requiredCredentialsErrorMassage = page.getByText('Epic sadface: Username is required');
|
||||
this.lockedOutErrorMassage = page.getByText('')
|
||||
this.lockedOutErrorMassage = page.getByText('Epic sadface: Sorry, this user has been locked out.');
|
||||
}
|
||||
|
||||
// teď si definujeme metody na práci s elementy výše this.userNameInput = page.locator('#user-name');
|
||||
// metoda na přejetí na stránku s Loginem
|
||||
async gotoLoginPage() {
|
||||
await this.page.goto('https://www.saucedemo.com/');
|
||||
}
|
||||
|
||||
// metoda přihlašovacího jména
|
||||
// protože chceme vepsat uživatelské jmáno použijeme metodu fill
|
||||
async enterValidUsername() {
|
||||
await this.userNameInput.fill('standard_user');
|
||||
}
|
||||
|
||||
async enterLockedOutUser() {
|
||||
await this.userNameInput.fill('locked_out_user');
|
||||
}
|
||||
|
||||
// alternativy k valid budou invalid
|
||||
async enterInvalidUsername() {
|
||||
await this.userNameInput.fill('jmeno');
|
||||
}
|
||||
|
||||
// zde zapíšeme heslo
|
||||
async enterValidPassword() {
|
||||
await this.passwordInput.fill('secret_sauce');
|
||||
}
|
||||
|
||||
async enterInvalidPassword() {
|
||||
await this.passwordInput.fill('heslo');
|
||||
}
|
||||
|
||||
// klik na login button
|
||||
async clickLoginButton() {
|
||||
await this.loginButton.click();
|
||||
}
|
||||
|
||||
|
||||
// valid metody na ´ůspěšné přihlášení zapozdříme tímto způsobem:
|
||||
async login() {
|
||||
await this.userNameInput.fill('standard_user');
|
||||
await this.passwordInput.fill('secret_sauce');
|
||||
await this.loginButton.click();
|
||||
}
|
||||
|
||||
}
|
||||
|
45
Playwright základy na GitHub/page-objects/HomePage.ts
Normal file
45
Playwright základy na GitHub/page-objects/HomePage.ts
Normal file
@ -0,0 +1,45 @@
|
||||
// import třída modulů které budeme potřebovat
|
||||
import { Locator, Page
|
||||
} from "@playwright/test";
|
||||
|
||||
//definujeme třídy (class)
|
||||
export class HomePage{
|
||||
page: Page;
|
||||
menu: Locator;
|
||||
title: Locator;
|
||||
item: Locator;
|
||||
addToCart: Locator;
|
||||
cardBadge: Locator;
|
||||
|
||||
// vytvoříme konstruktor třídy definuje proměnou page
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.menu = page.locator('#react-burger-menu-btn');
|
||||
this.title = page.getByText('Swag Labs');
|
||||
this.item = page.locator('#item_4_title_link');
|
||||
this.addToCart = page.locator('#add-to-cart-sauce-labs-backpack');
|
||||
this.cardBadge = page.locator('//span[@class="shopping_cart_badge"]');
|
||||
}
|
||||
|
||||
// teď si definujeme metody na práci s elementy výše
|
||||
|
||||
async clickOnMenu() {
|
||||
await this.menu.click();
|
||||
}
|
||||
|
||||
async clickOnItem() {
|
||||
await this.item.click();
|
||||
}
|
||||
|
||||
|
||||
async clickOnAddToCart() {
|
||||
await this.addToCart.click();
|
||||
}
|
||||
|
||||
async clickOnCardBAdge() {
|
||||
await this.cardBadge.click();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
72
Playwright základy na GitHub/page-objects/LoginPage.ts
Normal file
72
Playwright základy na GitHub/page-objects/LoginPage.ts
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
// import třída modulů které budeme potřebovat
|
||||
import { Locator, Page
|
||||
} from "@playwright/test";
|
||||
|
||||
//definujeme třídy (class)
|
||||
export class LoginPage{
|
||||
page: Page;
|
||||
userNameInput: Locator;
|
||||
passwordInput: Locator;
|
||||
loginButton: Locator;
|
||||
invalidCredentialsErrorMessage: Locator;
|
||||
requiredCredentialsErrorMassage: Locator;
|
||||
lockedOutErrorMassage: Locator;
|
||||
|
||||
// vytvoříme konstruktor třídy definuje proměnou page
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.userNameInput = page.locator('#user-name');
|
||||
this.passwordInput = page.locator('#password');
|
||||
this.loginButton = page.locator('#login-button');
|
||||
this.invalidCredentialsErrorMessage = page.getByText('Epic sadface: Username and password do not match any user in this service');
|
||||
this.requiredCredentialsErrorMassage = page.getByText('Epic sadface: Username is required');
|
||||
this.lockedOutErrorMassage = page.getByText('')
|
||||
this.lockedOutErrorMassage = page.getByText('Epic sadface: Sorry, this user has been locked out.');
|
||||
}
|
||||
|
||||
// teď si definujeme metody na práci s elementy výše this.userNameInput = page.locator('#user-name');
|
||||
// metoda na přejetí na stránku s Loginem
|
||||
async gotoLoginPage() {
|
||||
await this.page.goto('https://www.saucedemo.com/');
|
||||
}
|
||||
|
||||
// metoda přihlašovacího jména
|
||||
// protože chceme vepsat uživatelské jmáno použijeme metodu fill
|
||||
async enterValidUsername() {
|
||||
await this.userNameInput.fill('standard_user');
|
||||
}
|
||||
|
||||
async enterLockedOutUser() {
|
||||
await this.userNameInput.fill('locked_out_user');
|
||||
}
|
||||
|
||||
// alternativy k valid budou invalid
|
||||
async enterInvalidUsername() {
|
||||
await this.userNameInput.fill('jmeno');
|
||||
}
|
||||
|
||||
// zde zapíšeme heslo
|
||||
async enterValidPassword() {
|
||||
await this.passwordInput.fill('secret_sauce');
|
||||
}
|
||||
|
||||
async enterInvalidPassword() {
|
||||
await this.passwordInput.fill('heslo');
|
||||
}
|
||||
|
||||
// klik na login button
|
||||
async clickLoginButton() {
|
||||
await this.loginButton.click();
|
||||
}
|
||||
|
||||
|
||||
// valid metody na ´ůspěšné přihlášení zapozdříme tímto způsobem:
|
||||
async login() {
|
||||
await this.userNameInput.fill('standard_user');
|
||||
await this.passwordInput.fill('secret_sauce');
|
||||
await this.loginButton.click();
|
||||
}
|
||||
|
||||
}
|
||||
|
77
Playwright základy na GitHub/playwright.config.ts
Normal file
77
Playwright základy na GitHub/playwright.config.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// require('dotenv').config();
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: './tests',
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: 'html',
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
// baseURL: 'http://127.0.0.1:3000',
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
|
||||
{
|
||||
name: 'webkit',
|
||||
use: { ...devices['Desktop Safari'] },
|
||||
},
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: 'npm run start',
|
||||
// url: 'http://127.0.0.1:3000',
|
||||
// reuseExistingServer: !process.env.CI,
|
||||
// },
|
||||
});
|
@ -0,0 +1,437 @@
|
||||
import { test, expect, type Page } from '@playwright/test';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('https://demo.playwright.dev/todomvc');
|
||||
});
|
||||
|
||||
const TODO_ITEMS = [
|
||||
'buy some cheese',
|
||||
'feed the cat',
|
||||
'book a doctors appointment'
|
||||
];
|
||||
|
||||
test.describe('New Todo', () => {
|
||||
test('should allow me to add todo items', async ({ page }) => {
|
||||
// create a new todo locator
|
||||
const newTodo = page.getByPlaceholder('What needs to be done?');
|
||||
|
||||
// Create 1st todo.
|
||||
await newTodo.fill(TODO_ITEMS[0]);
|
||||
await newTodo.press('Enter');
|
||||
|
||||
// Make sure the list only has one todo item.
|
||||
await expect(page.getByTestId('todo-title')).toHaveText([
|
||||
TODO_ITEMS[0]
|
||||
]);
|
||||
|
||||
// Create 2nd todo.
|
||||
await newTodo.fill(TODO_ITEMS[1]);
|
||||
await newTodo.press('Enter');
|
||||
|
||||
// Make sure the list now has two todo items.
|
||||
await expect(page.getByTestId('todo-title')).toHaveText([
|
||||
TODO_ITEMS[0],
|
||||
TODO_ITEMS[1]
|
||||
]);
|
||||
|
||||
await checkNumberOfTodosInLocalStorage(page, 2);
|
||||
});
|
||||
|
||||
test('should clear text input field when an item is added', async ({ page }) => {
|
||||
// create a new todo locator
|
||||
const newTodo = page.getByPlaceholder('What needs to be done?');
|
||||
|
||||
// Create one todo item.
|
||||
await newTodo.fill(TODO_ITEMS[0]);
|
||||
await newTodo.press('Enter');
|
||||
|
||||
// Check that input is empty.
|
||||
await expect(newTodo).toBeEmpty();
|
||||
await checkNumberOfTodosInLocalStorage(page, 1);
|
||||
});
|
||||
|
||||
test('should append new items to the bottom of the list', async ({ page }) => {
|
||||
// Create 3 items.
|
||||
await createDefaultTodos(page);
|
||||
|
||||
// create a todo count locator
|
||||
const todoCount = page.getByTestId('todo-count')
|
||||
|
||||
// Check test using different methods.
|
||||
await expect(page.getByText('3 items left')).toBeVisible();
|
||||
await expect(todoCount).toHaveText('3 items left');
|
||||
await expect(todoCount).toContainText('3');
|
||||
await expect(todoCount).toHaveText(/3/);
|
||||
|
||||
// Check all items in one call.
|
||||
await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS);
|
||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Mark all as completed', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await createDefaultTodos(page);
|
||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ page }) => {
|
||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
||||
});
|
||||
|
||||
test('should allow me to mark all items as completed', async ({ page }) => {
|
||||
// Complete all todos.
|
||||
await page.getByLabel('Mark all as complete').check();
|
||||
|
||||
// Ensure all todos have 'completed' class.
|
||||
await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']);
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 3);
|
||||
});
|
||||
|
||||
test('should allow me to clear the complete state of all items', async ({ page }) => {
|
||||
const toggleAll = page.getByLabel('Mark all as complete');
|
||||
// Check and then immediately uncheck.
|
||||
await toggleAll.check();
|
||||
await toggleAll.uncheck();
|
||||
|
||||
// Should be no completed classes.
|
||||
await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']);
|
||||
});
|
||||
|
||||
test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => {
|
||||
const toggleAll = page.getByLabel('Mark all as complete');
|
||||
await toggleAll.check();
|
||||
await expect(toggleAll).toBeChecked();
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 3);
|
||||
|
||||
// Uncheck first todo.
|
||||
const firstTodo = page.getByTestId('todo-item').nth(0);
|
||||
await firstTodo.getByRole('checkbox').uncheck();
|
||||
|
||||
// Reuse toggleAll locator and make sure its not checked.
|
||||
await expect(toggleAll).not.toBeChecked();
|
||||
|
||||
await firstTodo.getByRole('checkbox').check();
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 3);
|
||||
|
||||
// Assert the toggle all is checked again.
|
||||
await expect(toggleAll).toBeChecked();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Item', () => {
|
||||
|
||||
test('should allow me to mark items as complete', async ({ page }) => {
|
||||
// create a new todo locator
|
||||
const newTodo = page.getByPlaceholder('What needs to be done?');
|
||||
|
||||
// Create two items.
|
||||
for (const item of TODO_ITEMS.slice(0, 2)) {
|
||||
await newTodo.fill(item);
|
||||
await newTodo.press('Enter');
|
||||
}
|
||||
|
||||
// Check first item.
|
||||
const firstTodo = page.getByTestId('todo-item').nth(0);
|
||||
await firstTodo.getByRole('checkbox').check();
|
||||
await expect(firstTodo).toHaveClass('completed');
|
||||
|
||||
// Check second item.
|
||||
const secondTodo = page.getByTestId('todo-item').nth(1);
|
||||
await expect(secondTodo).not.toHaveClass('completed');
|
||||
await secondTodo.getByRole('checkbox').check();
|
||||
|
||||
// Assert completed class.
|
||||
await expect(firstTodo).toHaveClass('completed');
|
||||
await expect(secondTodo).toHaveClass('completed');
|
||||
});
|
||||
|
||||
test('should allow me to un-mark items as complete', async ({ page }) => {
|
||||
// create a new todo locator
|
||||
const newTodo = page.getByPlaceholder('What needs to be done?');
|
||||
|
||||
// Create two items.
|
||||
for (const item of TODO_ITEMS.slice(0, 2)) {
|
||||
await newTodo.fill(item);
|
||||
await newTodo.press('Enter');
|
||||
}
|
||||
|
||||
const firstTodo = page.getByTestId('todo-item').nth(0);
|
||||
const secondTodo = page.getByTestId('todo-item').nth(1);
|
||||
const firstTodoCheckbox = firstTodo.getByRole('checkbox');
|
||||
|
||||
await firstTodoCheckbox.check();
|
||||
await expect(firstTodo).toHaveClass('completed');
|
||||
await expect(secondTodo).not.toHaveClass('completed');
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
||||
|
||||
await firstTodoCheckbox.uncheck();
|
||||
await expect(firstTodo).not.toHaveClass('completed');
|
||||
await expect(secondTodo).not.toHaveClass('completed');
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 0);
|
||||
});
|
||||
|
||||
test('should allow me to edit an item', async ({ page }) => {
|
||||
await createDefaultTodos(page);
|
||||
|
||||
const todoItems = page.getByTestId('todo-item');
|
||||
const secondTodo = todoItems.nth(1);
|
||||
await secondTodo.dblclick();
|
||||
await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]);
|
||||
await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages');
|
||||
await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter');
|
||||
|
||||
// Explicitly assert the new text value.
|
||||
await expect(todoItems).toHaveText([
|
||||
TODO_ITEMS[0],
|
||||
'buy some sausages',
|
||||
TODO_ITEMS[2]
|
||||
]);
|
||||
await checkTodosInLocalStorage(page, 'buy some sausages');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Editing', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await createDefaultTodos(page);
|
||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
||||
});
|
||||
|
||||
test('should hide other controls when editing', async ({ page }) => {
|
||||
const todoItem = page.getByTestId('todo-item').nth(1);
|
||||
await todoItem.dblclick();
|
||||
await expect(todoItem.getByRole('checkbox')).not.toBeVisible();
|
||||
await expect(todoItem.locator('label', {
|
||||
hasText: TODO_ITEMS[1],
|
||||
})).not.toBeVisible();
|
||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
||||
});
|
||||
|
||||
test('should save edits on blur', async ({ page }) => {
|
||||
const todoItems = page.getByTestId('todo-item');
|
||||
await todoItems.nth(1).dblclick();
|
||||
await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages');
|
||||
await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur');
|
||||
|
||||
await expect(todoItems).toHaveText([
|
||||
TODO_ITEMS[0],
|
||||
'buy some sausages',
|
||||
TODO_ITEMS[2],
|
||||
]);
|
||||
await checkTodosInLocalStorage(page, 'buy some sausages');
|
||||
});
|
||||
|
||||
test('should trim entered text', async ({ page }) => {
|
||||
const todoItems = page.getByTestId('todo-item');
|
||||
await todoItems.nth(1).dblclick();
|
||||
await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages ');
|
||||
await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter');
|
||||
|
||||
await expect(todoItems).toHaveText([
|
||||
TODO_ITEMS[0],
|
||||
'buy some sausages',
|
||||
TODO_ITEMS[2],
|
||||
]);
|
||||
await checkTodosInLocalStorage(page, 'buy some sausages');
|
||||
});
|
||||
|
||||
test('should remove the item if an empty text string was entered', async ({ page }) => {
|
||||
const todoItems = page.getByTestId('todo-item');
|
||||
await todoItems.nth(1).dblclick();
|
||||
await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('');
|
||||
await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter');
|
||||
|
||||
await expect(todoItems).toHaveText([
|
||||
TODO_ITEMS[0],
|
||||
TODO_ITEMS[2],
|
||||
]);
|
||||
});
|
||||
|
||||
test('should cancel edits on escape', async ({ page }) => {
|
||||
const todoItems = page.getByTestId('todo-item');
|
||||
await todoItems.nth(1).dblclick();
|
||||
await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages');
|
||||
await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape');
|
||||
await expect(todoItems).toHaveText(TODO_ITEMS);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Counter', () => {
|
||||
test('should display the current number of todo items', async ({ page }) => {
|
||||
// create a new todo locator
|
||||
const newTodo = page.getByPlaceholder('What needs to be done?');
|
||||
|
||||
// create a todo count locator
|
||||
const todoCount = page.getByTestId('todo-count')
|
||||
|
||||
await newTodo.fill(TODO_ITEMS[0]);
|
||||
await newTodo.press('Enter');
|
||||
|
||||
await expect(todoCount).toContainText('1');
|
||||
|
||||
await newTodo.fill(TODO_ITEMS[1]);
|
||||
await newTodo.press('Enter');
|
||||
await expect(todoCount).toContainText('2');
|
||||
|
||||
await checkNumberOfTodosInLocalStorage(page, 2);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Clear completed button', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await createDefaultTodos(page);
|
||||
});
|
||||
|
||||
test('should display the correct text', async ({ page }) => {
|
||||
await page.locator('.todo-list li .toggle').first().check();
|
||||
await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('should remove completed items when clicked', async ({ page }) => {
|
||||
const todoItems = page.getByTestId('todo-item');
|
||||
await todoItems.nth(1).getByRole('checkbox').check();
|
||||
await page.getByRole('button', { name: 'Clear completed' }).click();
|
||||
await expect(todoItems).toHaveCount(2);
|
||||
await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
|
||||
});
|
||||
|
||||
test('should be hidden when there are no items that are completed', async ({ page }) => {
|
||||
await page.locator('.todo-list li .toggle').first().check();
|
||||
await page.getByRole('button', { name: 'Clear completed' }).click();
|
||||
await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Persistence', () => {
|
||||
test('should persist its data', async ({ page }) => {
|
||||
// create a new todo locator
|
||||
const newTodo = page.getByPlaceholder('What needs to be done?');
|
||||
|
||||
for (const item of TODO_ITEMS.slice(0, 2)) {
|
||||
await newTodo.fill(item);
|
||||
await newTodo.press('Enter');
|
||||
}
|
||||
|
||||
const todoItems = page.getByTestId('todo-item');
|
||||
const firstTodoCheck = todoItems.nth(0).getByRole('checkbox');
|
||||
await firstTodoCheck.check();
|
||||
await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
|
||||
await expect(firstTodoCheck).toBeChecked();
|
||||
await expect(todoItems).toHaveClass(['completed', '']);
|
||||
|
||||
// Ensure there is 1 completed item.
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
||||
|
||||
// Now reload.
|
||||
await page.reload();
|
||||
await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
|
||||
await expect(firstTodoCheck).toBeChecked();
|
||||
await expect(todoItems).toHaveClass(['completed', '']);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Routing', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await createDefaultTodos(page);
|
||||
// make sure the app had a chance to save updated todos in storage
|
||||
// before navigating to a new view, otherwise the items can get lost :(
|
||||
// in some frameworks like Durandal
|
||||
await checkTodosInLocalStorage(page, TODO_ITEMS[0]);
|
||||
});
|
||||
|
||||
test('should allow me to display active items', async ({ page }) => {
|
||||
const todoItem = page.getByTestId('todo-item');
|
||||
await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check();
|
||||
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
||||
await page.getByRole('link', { name: 'Active' }).click();
|
||||
await expect(todoItem).toHaveCount(2);
|
||||
await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
|
||||
});
|
||||
|
||||
test('should respect the back button', async ({ page }) => {
|
||||
const todoItem = page.getByTestId('todo-item');
|
||||
await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check();
|
||||
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
||||
|
||||
await test.step('Showing all items', async () => {
|
||||
await page.getByRole('link', { name: 'All' }).click();
|
||||
await expect(todoItem).toHaveCount(3);
|
||||
});
|
||||
|
||||
await test.step('Showing active items', async () => {
|
||||
await page.getByRole('link', { name: 'Active' }).click();
|
||||
});
|
||||
|
||||
await test.step('Showing completed items', async () => {
|
||||
await page.getByRole('link', { name: 'Completed' }).click();
|
||||
});
|
||||
|
||||
await expect(todoItem).toHaveCount(1);
|
||||
await page.goBack();
|
||||
await expect(todoItem).toHaveCount(2);
|
||||
await page.goBack();
|
||||
await expect(todoItem).toHaveCount(3);
|
||||
});
|
||||
|
||||
test('should allow me to display completed items', async ({ page }) => {
|
||||
await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check();
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
||||
await page.getByRole('link', { name: 'Completed' }).click();
|
||||
await expect(page.getByTestId('todo-item')).toHaveCount(1);
|
||||
});
|
||||
|
||||
test('should allow me to display all items', async ({ page }) => {
|
||||
await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check();
|
||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
||||
await page.getByRole('link', { name: 'Active' }).click();
|
||||
await page.getByRole('link', { name: 'Completed' }).click();
|
||||
await page.getByRole('link', { name: 'All' }).click();
|
||||
await expect(page.getByTestId('todo-item')).toHaveCount(3);
|
||||
});
|
||||
|
||||
test('should highlight the currently applied filter', async ({ page }) => {
|
||||
await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected');
|
||||
|
||||
//create locators for active and completed links
|
||||
const activeLink = page.getByRole('link', { name: 'Active' });
|
||||
const completedLink = page.getByRole('link', { name: 'Completed' });
|
||||
await activeLink.click();
|
||||
|
||||
// Page change - active items.
|
||||
await expect(activeLink).toHaveClass('selected');
|
||||
await completedLink.click();
|
||||
|
||||
// Page change - completed items.
|
||||
await expect(completedLink).toHaveClass('selected');
|
||||
});
|
||||
});
|
||||
|
||||
async function createDefaultTodos(page: Page) {
|
||||
// create a new todo locator
|
||||
const newTodo = page.getByPlaceholder('What needs to be done?');
|
||||
|
||||
for (const item of TODO_ITEMS) {
|
||||
await newTodo.fill(item);
|
||||
await newTodo.press('Enter');
|
||||
}
|
||||
}
|
||||
|
||||
async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) {
|
||||
return await page.waitForFunction(e => {
|
||||
return JSON.parse(localStorage['react-todos']).length === e;
|
||||
}, expected);
|
||||
}
|
||||
|
||||
async function checkNumberOfCompletedTodosInLocalStorage(page: Page, expected: number) {
|
||||
return await page.waitForFunction(e => {
|
||||
return JSON.parse(localStorage['react-todos']).filter((todo: any) => todo.completed).length === e;
|
||||
}, expected);
|
||||
}
|
||||
|
||||
async function checkTodosInLocalStorage(page: Page, title: string) {
|
||||
return await page.waitForFunction(t => {
|
||||
return JSON.parse(localStorage['react-todos']).map((todo: any) => todo.title).includes(t);
|
||||
}, title);
|
||||
}
|
0
Playwright základy na GitHub/tests/alerts.spec.ts
Normal file
0
Playwright základy na GitHub/tests/alerts.spec.ts
Normal file
27
Playwright základy na GitHub/tests/assertions.spec.ts
Normal file
27
Playwright základy na GitHub/tests/assertions.spec.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
//pokud zapíšeme za test.only spustíme pouze jeden tento test
|
||||
test('Element state', async ({ page }) => {
|
||||
await page.goto('https://www.saucedemo.com');
|
||||
|
||||
//Vypíšeme zda stav elementu jestli je viditelný
|
||||
await expect(page.locator('#user-name')).toBeVisible();
|
||||
//await expect(page.locator('#user-name')).toContain;
|
||||
|
||||
//Vypíšeme zda stav elementu jestli je editovatelný
|
||||
await expect(page.locator('#password')).toBeEditable();
|
||||
|
||||
//Vypíšeme zda stav elementu jestli je na stránce jedenkrát (to je číslo 1 v závorce)
|
||||
await expect(page.locator('#login-button')).toHaveCount(1);
|
||||
|
||||
//Ověří že se některý element na stránce nenáchází. Přesný opak to.BeVisible. Na stránce by se neměl nacházet tento element
|
||||
await expect(page.locator('#skillmea')).not.toBeVisible();
|
||||
|
||||
});
|
||||
|
||||
// toto je idetifikovatelný element -- > await page.locator('#user-name')
|
||||
// Pokud nám test někde padá nebo chci případně přeskočit místo kde padl použiji .soft v tomto místě přeskočí chybu a pkračuje dál
|
||||
// await expect.soft(page.locator('#password'))not.toBeEditable();
|
||||
|
||||
// seznam všech asertů můžeš získat že za tešku vložím .toBeHave nebou .toBeContain
|
||||
//await expect(page.locator('#user-name')).toContain;
|
18
Playwright základy na GitHub/tests/elementState.spec.ts
Normal file
18
Playwright základy na GitHub/tests/elementState.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
//pokud zapíšeme za test.only spustíme pouze jeden tento test
|
||||
test('Element state', async ({ page }) => {
|
||||
await page.goto('https://www.saucedemo.com');
|
||||
|
||||
//Vypíšeme zda stav elementu jestli je editovatelný
|
||||
console.log(await page.locator('#user-name').isEditable());
|
||||
|
||||
//Vypíšeme zda stav elementu jestli je viditelný
|
||||
console.log(await page.locator('#password').isVisible());
|
||||
|
||||
//Vypíšeme zda stav elementu jestli je skrytý
|
||||
console.log(await page.locator('#login-button').isHidden());
|
||||
|
||||
|
||||
|
||||
});
|
18
Playwright základy na GitHub/tests/example.spec copy.ts
Normal file
18
Playwright základy na GitHub/tests/example.spec copy.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('has title', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev/');
|
||||
|
||||
// Expect a title "to contain" a substring.
|
||||
await expect(page).toHaveTitle(/Playwright/);
|
||||
});
|
||||
|
||||
test('get started link', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev/');
|
||||
|
||||
// Click the get started link.
|
||||
await page.getByRole('link', { name: 'Get started' }).click();
|
||||
|
||||
// Expects the URL to contain intro.
|
||||
await expect(page).toHaveURL(/.*intro/);
|
||||
});
|
18
Playwright základy na GitHub/tests/example.spec.ts
Normal file
18
Playwright základy na GitHub/tests/example.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('has title', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev/');
|
||||
|
||||
// Expect a title "to contain" a substring.
|
||||
await expect(page).toHaveTitle(/Playwright/);
|
||||
});
|
||||
|
||||
test('get started link', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev/');
|
||||
|
||||
// Click the get started link.
|
||||
await page.getByRole('link', { name: 'Get started' }).click();
|
||||
|
||||
// Expects the URL to contain intro.
|
||||
await expect(page).toHaveURL(/.*intro/);
|
||||
});
|
29
Playwright základy na GitHub/tests/home.spec.ts
Normal file
29
Playwright základy na GitHub/tests/home.spec.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { LoginPage } from '../page-objects/LoginPage';
|
||||
import { HomePage } from '../page-objects/HomePage';
|
||||
|
||||
// přihlášení na HomePage a ověření textu domovské stránky.
|
||||
test('Verify home title', async ({ page }) => {
|
||||
const loginPage = new LoginPage(page);
|
||||
const homePage = new HomePage(page);
|
||||
await loginPage.gotoLoginPage();
|
||||
await loginPage.login();
|
||||
await expect(homePage.title).toBeVisible();
|
||||
});
|
||||
|
||||
// test přidání produktu do košíku a kontrola že zobrazuje 1 položka v košíku
|
||||
test('Verify add to card functionality', async ({ page }) => {
|
||||
const loginPage = new LoginPage(page);
|
||||
const homePage = new HomePage(page);
|
||||
await loginPage.gotoLoginPage();
|
||||
await loginPage.login();
|
||||
await homePage.clickOnAddToCart();
|
||||
await expect(homePage.cardBadge).toHaveText("1");
|
||||
});
|
||||
|
||||
//Odstranit produkt z košíká zkontrolovat že v něm není
|
||||
|
||||
//vytvořit novou třídu pro produkt page, identifikovat elementy, napsat test na přidání do košíku product page, kliknutína tlačítko back ověřím že se dostanu zpět na homePage
|
||||
|
||||
|
||||
|
79
Playwright základy na GitHub/tests/login.spec.ts
Normal file
79
Playwright základy na GitHub/tests/login.spec.ts
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
Zápis pomocí Page_Objects --> je kratší, čitatelnější a přehlednější. Pokud se například změní lokátor id nemusím ho měnit ve všech testech
|
||||
ale, v daném page-objects
|
||||
ctrl + click mě přesune na zadanou metodu!!
|
||||
*/
|
||||
import { test, expect } from '@playwright/test';
|
||||
//Importujeme vytvořenou třídu z page-objects
|
||||
import { LoginPage } from '../page-objects/LoginPage';
|
||||
|
||||
test('Successful login', async ({ page }) => {
|
||||
// nová instance loginPage odkazuje na metody co jsme si vytvořili v LoginPage
|
||||
const loginPage = new LoginPage(page);
|
||||
// zadáme metody co jsme vytvořily v LoginPage
|
||||
await loginPage.gotoLoginPage();
|
||||
// místo tohoto použijeme námi vytvořenou metodu login z LoginPage
|
||||
//await loginPage.enterValidUsername();
|
||||
//await loginPage.enterValidPassword();
|
||||
//await loginPage.clickLoginButton();
|
||||
// metoda login
|
||||
await loginPage.login();
|
||||
// ověříme že jsme se úspěšně přihlásily
|
||||
await expect(page).toHaveURL('https://www.saucedemo.com/inventory.html');
|
||||
/*
|
||||
// způsob jeden test komplet v kódu bez odkazu na page-objects
|
||||
await page.goto('https://www.saucedemo.com/');
|
||||
await page.locator('[data-test="username"]').click();
|
||||
await page.locator('[data-test="username"]').fill('standard_user');
|
||||
await page.locator('[data-test="password"]').click();
|
||||
await page.locator('[data-test="password"]').fill('secret_sauce');
|
||||
await page.locator('[data-test="login-button"]').click();
|
||||
|
||||
// Zkontrolujeme jestli na stránce je viditelný Swag Labs
|
||||
await expect(page.getByText('Swag Labs')).toBeVisible();
|
||||
*/
|
||||
});
|
||||
|
||||
// test přihlášení s neplatným heslem
|
||||
test('Cannot login with valid username and invalid password', async ({ page }) => {
|
||||
// test reporty(video 23):
|
||||
|
||||
const loginPage = new LoginPage(page);
|
||||
await loginPage.gotoLoginPage();
|
||||
await loginPage.enterValidUsername();
|
||||
await loginPage.enterInvalidPassword();
|
||||
await loginPage.clickLoginButton();
|
||||
await expect(loginPage.invalidCredentialsErrorMessage).toBeVisible();
|
||||
});
|
||||
|
||||
|
||||
//test s neplatným přihlašovacím jménem
|
||||
test('Cannot login with invalid username and valid password', async ({ page }) => {
|
||||
const loginPage = new LoginPage(page);
|
||||
await loginPage.gotoLoginPage();
|
||||
await loginPage.enterInvalidUsername();
|
||||
await loginPage.enterValidPassword();
|
||||
await loginPage.clickLoginButton();
|
||||
await expect(loginPage.invalidCredentialsErrorMessage).toBeVisible();
|
||||
|
||||
});
|
||||
|
||||
//test pouze s kliknutím na login button
|
||||
test('Cannot login with blank fields', async ({ page }) => {
|
||||
const loginPage = new LoginPage(page);
|
||||
await loginPage.gotoLoginPage();
|
||||
await loginPage.clickLoginButton();
|
||||
await expect(loginPage.requiredCredentialsErrorMassage).toBeVisible();
|
||||
|
||||
});
|
||||
|
||||
// přihlášení s zablokovaným userem
|
||||
test('Cannot login with locked out user', async ({ page }) => {
|
||||
const loginPage = new LoginPage(page);
|
||||
await loginPage.gotoLoginPage();
|
||||
await loginPage.enterLockedOutUser();
|
||||
await loginPage.enterValidPassword();
|
||||
await loginPage.clickLoginButton();
|
||||
await expect(loginPage.lockedOutErrorMassage).toBeVisible();
|
||||
|
||||
});
|
0
Playwright základy na GitHub/tests/tabs.spec.ts
Normal file
0
Playwright základy na GitHub/tests/tabs.spec.ts
Normal file
0
Playwright základy na GitHub/tests/upload.spec.ts
Normal file
0
Playwright základy na GitHub/tests/upload.spec.ts
Normal file
13
Playwright základy na GitHub/Úkoly.md
Normal file
13
Playwright základy na GitHub/Úkoly.md
Normal file
@ -0,0 +1,13 @@
|
||||
1. vytvořit novou třídu pro produkt page, identifikovat elementy, napsat test na přidání do košíku product page, kliknutína tlačítko back ověřím že se dostanu zpět na homePage
|
||||
|
||||
2. product page --> //vytvořit novou třídu pro produkt page, identifikovat elementy, napsat test na přidání do košíku product page, kliknutína tlačítko back ověřím že se dostanu zpět na homePage
|
||||
|
||||
3. fixtures dodělat video 21!!
|
||||
|
||||
4. report test --> test stepy
|
||||
|
||||
5. video 26 alerty udělat
|
||||
|
||||
6. Od 21 vše dodělat!!
|
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
Page Object Model (POM) je návrhový vzor v test automatizácii, ktorý slúži na organizáciu a správu automatizovaných testov v testovacej sade. Tento vzor zabezpečuje oddelenie testovacieho kódu od samotnej implementácie testovaných stránok.
|
||||
|
||||
|
||||
Konkrétne, POM rozdeľuje testovanie webovej aplikácie na dva oddelené kódy:
|
||||
|
||||
Testovací kód: tento kód zahŕňa logiku testovania, ako sú interakcie s webovými stránkami, overenie správnosti vykonania akcií a overenie výsledkov testovania.
|
||||
Kód objektov stránky (Page Objects): tento kód zahŕňa definície objektov, ktoré predstavujú prvky na webovej stránke (napr. tlačidlá, polia na vstupe, odkazy atď.) a ich správanie. Každý objekt stránky má svoju vlastnú triedu, ktorá implementuje metódy pre interakciu s príslušnými prvky na stránke.
|
||||
|
||||
Výhodou použitia POM je to, že testovací kód sa stáva jednoduchším a ľahšie udržiavateľným, pretože neobsahuje žiadne informácie o interakcii s prvkami na webovej stránke. Kód objektov stránky poskytuje abstraktnú reprezentáciu prvkov na webovej stránke, ktorá je potom využívaná testovacím kódom. Tento prístup umožňuje jednoduchšiu údržbu automatizovaných testov v prípade zmien na webovej stránke, pretože zmeny sa robia len v kóde objektov stránky.
|
Reference in New Issue
Block a user