This commit is contained in:
Lukáš Kaňka 2023-08-15 18:27:27 +02:00
commit a117466599
116 changed files with 6597 additions and 0 deletions

4
PWLukTS/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/

8
PWLukTS/.idea/.gitignore vendored Normal file
View 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

View 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
PWLukTS/.idea/misc.xml Normal file
View 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>

View 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/PWLukTS.iml" filepath="$PROJECT_DIR$/.idea/PWLukTS.iml" />
</modules>
</component>
</project>

7
PWLukTS/.idea/vcs.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

Binary file not shown.

View File

@ -0,0 +1,8 @@
{
"ExpandedNodes": [
"",
"\\tests"
],
"SelectedNode": "\\tests\\cookies.test.spec.ts",
"PreviewInSolutionExplorer": false
}

BIN
PWLukTS/.vs/slnx.sqlite Normal file

Binary file not shown.

46
PWLukTS/README.md Normal file
View File

@ -0,0 +1,46 @@
Vítám tě na mém účtu GitHub.
Teď jsi na mám hřišti Playwright kde objevuji jeho funkce a další možnosti. Postupně to tu pomalu rozšiřuji.
Můžeš se podívat i na mé další projekty, poznáš je, že jsou Public. Vše co je Private jsou mé placené kurzy (které jsem koupil a nesmí se šířit) nebo projekty od jiných skvělých programátorů co většinou dělají tutoriály na YouTube.
Krátký popis kde co je:
PWlkTS - testování v Playwright na mém druhém blogu lukaskanka.cz : https://github.com/LukasKanka/PWlkTS
CY_Auta_TS - testování Cypress v TS na stránkách jednoho bazaru (ať je vše pestřejší): https://github.com/LukasKanka/CY_Auta_TS
PLaywright_GH_TS - nekolik menších testíku v Playwright: https://github.com/LukasKanka/Playwright_GH_TS
PWlkPY - Playwright v Pythonu: https://github.com/LukasKanka/PWlkPY
CyLukTS - zde zkouším Cypress s Playwright na svém blogu:https://github.com/LukasKanka/CyLukTs
Tutorials - místo kde jsem si sepsal několik základů, hlavně kolem testingu. Delší dobu neaktualizované: https://github.com/LukasKanka/Tutorials
MSTest_Win - testování na webu zive.cz v MSTest + C#: https://github.com/LukasKanka/MSTest_Win
Testing_Win - testování v Frameworcích MSTest, Nunit, xUnit: https://github.com/LukasKanka/Testing_Win
Testing_Ubuntu - testování v .Net, pokus testování jak to jde v Ubuntu: https://github.com/LukasKanka/Testing_Ubuntu
Nunit_Win - testování v Nunit a C#: https://github.com/LukasKanka/Nunit_Win
xUnit.NET - testování v xUnit a C#: https://github.com/LukasKanka/xUnit.NET
MSTest_VSCode - testování v MSTest a C#: https://github.com/LukasKanka/MSTest_VSCode
html_hints - můj pomocník s HTML: https://github.com/LukasKanka/html_hints

8
PWLukTS/helpers.ts Normal file
View File

@ -0,0 +1,8 @@
export async function loadHomepage ( page ) {
await page.goto('https://Lukan.cz');
await page.getByText('Accept').click();
};
export async function cokieeAccept ( page ) {
await page.getByText('Accept').click();
};

67
PWLukTS/package-lock.json generated Normal file
View File

@ -0,0 +1,67 @@
{
"name": "lukan",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lukan",
"version": "1.0.0",
"license": "ISC",
"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"
}
}
}
}

13
PWLukTS/package.json Normal file
View File

@ -0,0 +1,13 @@
{
"name": "lukan",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.34.3"
}
}

View File

@ -0,0 +1,83 @@
import { Locator, Page, expect
} from "@playwright/test";
export class HomePage{
page: Page;
cookiesButtonAccept: Locator;
cookiesButtonDecline: Locator;
menuButtonUvodniStrana: Locator;
menuButtonOMne: Locator;
menuButtonZasadyOchranyOsobnichUdaju: Locator;
menuButtonPodporovatele: Locator;
searchButton: Locator;
searchFieldInput: Locator;
// verifyTitleHomePage: Locator;
XsocialButton: Locator;
constructor(page: Page){
this.page = page;
this.cookiesButtonAccept = page.getByText('Accept');
this.cookiesButtonDecline = page.getByText('Decline');
this.menuButtonUvodniStrana = page.getByRole('link', { name: 'Úvodní stránka' });
this.menuButtonOMne = page.getByRole('link' , { name: 'O Mně' });
this.menuButtonZasadyOchranyOsobnichUdaju = page.getByRole('link' , { name: 'Zásady ochrany osobních údajů' });
this.menuButtonPodporovatele = page.getByRole('link' , { name: 'Podporovatelé' });
this.searchFieldInput = page.locator('//*[@id="search-7"]/form/label/input');
this.searchButton = page.locator('#search-7 > form > button > svg > use');
// this.verifyTitleHomePage = expect.toHaveTitle('Lukáš bloguje - Blog o všem možném i nemožném');
this.XsocialButton = page.locator('#block-54 > ul > li.wp-social-link.wp-social-link-twitter.wp-block-social-link > a > svg > path');
}
async gotoHome() {
await this.page.goto('https://www.lukan.cz/');
return this;
}
async clickCookiesButtonAccept() {
await this.cookiesButtonAccept.click();
return this;
}
async clickCookiesButtonDecline() {
await this.cookiesButtonDecline.click();
return this;
}
async clickUvodniStranaButton() {
await this.menuButtonUvodniStrana.click();
return this;
}
async clickOMneButton() {
await this.menuButtonOMne.click();
return this;
}
async clickZOOUButton() {
await this.menuButtonZasadyOchranyOsobnichUdaju.click();
return this;
}
async clickPodporovateleButton() {
await this.menuButtonPodporovatele.click();
return this;
}
async enterTextSearchFields() {
await this.searchFieldInput.fill('Test');
return this;
}
async clickSearchButton() {
await this.searchButton.click();
return this;
}
async clickXsocialButton() {
await this.XsocialButton.click();
return this;
}
}

View File

@ -0,0 +1,7 @@
import { Locator, Page
} from "@playwright/test";
export class LoginPage{
page: Page;
}

View File

@ -0,0 +1,78 @@
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: {
headless: false,
/* 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,
// },
});

View File

@ -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);
}

View File

@ -0,0 +1,19 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
// test odsouhlasení cookies
test('HomePage click Accept cookies', async ({ page }) => {
const homePage = new HomePage(page);
await (await homePage.gotoHome())
.clickCookiesButtonAccept();
});
// test zamítnutí cookies
test('HomaPage click Decline cookies' , async ({page}) => {
const homePage = new HomePage(page);
await (await homePage.gotoHome())
.clickCookiesButtonDecline();
});

View 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/);
});

View File

@ -0,0 +1,10 @@
import { test, expect } from '@playwright/test';
import { loadHomepage, cokieeAccept
} from "../helpers";
test('1' , async ({ page }) => {
await loadHomepage(page);
await cokieeAccept(page);
});

View File

@ -0,0 +1 @@
// login deaktivován

View File

@ -0,0 +1,12 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
test('Click menu button with HomePage' , async ({ page }) => {
const homePage = new HomePage(page);
await (await (await (await (await (await homePage.gotoHome())
.clickCookiesButtonAccept())
.clickUvodniStranaButton())
.clickOMneButton())
.clickZOOUButton())
.clickPodporovateleButton();
});

View File

@ -0,0 +1,29 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
// test Textů v menu
test('Otestování textů v menu', async ({ page }) => {
const verifyTextMenu = [
"Úvodní stránka",
"O mně",
"Zásady ochrany osobních údajů",
"Podporovatelé"
];
const homepage = new HomePage(page);
await homepage.gotoHome();
const navLinks = page.locator('#menu-menu-1 li[id*=menu]');
for (const el of await navLinks.elementHandles()) {
console.log(await el.textContent());
}
expect(await navLinks.allTextContents()).toEqual(verifyTextMenu);
});

View File

@ -0,0 +1,10 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
test('Search web' , async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.enterTextSearchFields();
await homePage.clickSearchButton();
});

View File

@ -0,0 +1,26 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
test('Sociální sítě X- kliknutí na Homepage' , async ({page}) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
// Klikne na ikonu Twitter a přesměrujeme se na web Twitter
await homePage.clickXsocialButton();
const expectedUrl = 'https://twitter.com/KankysCZ';
// Kontrola odkazu z prokliku že jsem na správné stránce, než nám Musk změní adresu
const currentUrl = await page.url();
if (currentUrl === expectedUrl) {
console.log('Super jsi na správné stránce!');
} else {
console.log(`Průser jsi nejsi na správné stránce. Jsi tu ${currentUrl}`);
}
});
test('Sociální sítě LinkId - kliknutí na Hompage', ({page}) => {
const homePage = new HomePage(page);
})

View File

@ -0,0 +1,6 @@
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://lukan.cz/');
await page.getByRole('link', { name: 'Úvodní stránka' }).click();
});

View File

@ -0,0 +1,9 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
test('Kontrola titulku', async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await expect(page).toHaveTitle('Lukáš bloguje - Blog o všem možném i nemožném');
});

View File

@ -0,0 +1,89 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
test.describe('Kolekce testů', () => {
test('Kontrola titulku', async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await expect(page).toHaveTitle('Lukáš bloguje - Blog o všem možném i nemožném');
});
test('Kontrola textu na stránce', async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
const headingText = await page.locator('text=Lukáš bloguje Blog o všem možném i nemožném ');
await expect(headingText).toBeVisible();
await expect(page).toHaveURL(/./);
});
test('HomePage click Accept cookies', async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.clickCookiesButtonAccept();
});
// test zamítnutí cookies
test('HomaPage click Decline cookies' , async ({page}) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.clickCookiesButtonDecline();
})
test('Click menu button with HomePage' , async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.clickUvodniStranaButton();
await homePage.clickOMneButton();
await homePage.clickZOOUButton();
await homePage.clickPodporovateleButton();
});
test('Search web' , async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.enterTextSearchFields();
await homePage.clickSearchButton();
});
test('test', async ({ page }) => {
await page.goto('https://lukan.cz/');
await page.getByRole('link', { name: 'Úvodní stránka' }).click();
});
test('Otestování textů v menu', async ({ page }) => {
const verifyTextMenu = [
"Úvodní stránka",
"O mně",
"Zásady ochrany osobních údajů",
"Podporovatelé"
];
await page.goto('https://lukan.cz/')
const navLinks = page.locator('#menu-menu-1 li[id*=menu]');
for (const el of await navLinks.elementHandles()) {
console.log(await el.textContent());
}
expect(await navLinks.allTextContents()).toEqual(verifyTextMenu);
});
});

16
PW_ZiveTS/.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
/test-results/
/playwright-report/
/playwright/.cache/
/test-results/
/playwright-report/
/playwright/.cache/
/test-results/
/playwright-report/
/playwright/.cache/
/test-results/
/playwright-report/
/playwright/.cache/

View 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
PW_ZiveTS/.idea/misc.xml Normal file
View 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>

View 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/PW_ZiveTS.iml" filepath="$PROJECT_DIR$/.idea/PW_ZiveTS.iml" />
</modules>
</component>
</project>

6
PW_ZiveTS/.idea/vcs.xml Normal file
View 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>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="2ad508fa-1af8-47a1-bdab-47b1a2e633f2" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component>
<component name="ProjectColorInfo"><![CDATA[{
"associatedIndex": 5
}]]></component>
<component name="ProjectId" id="2U1nD0crHhOfToVjmQQqiHNlSGh" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"WebServerToolWindowFactoryState": "false",
"git-widget-placeholder": "main",
"last_opened_file_path": "C:/Users/lukas/Nextcloud/GitHub/Vse PlaywrightTypeScript/Playwright_TS/PW_ZiveTS",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"ts.external.directory.path": "C:\\Program Files\\JetBrains\\Aqua 232.8660.199\\plugins\\javascript-impl\\jsLanguageServicesImpl\\external",
"vue.rearranger.settings.migration": "true"
}
}]]></component>
<component name="RunManager" selected="Playwright.test (1)">
<configuration name="test (1)" type="JavaScriptTestRunnerPlaywright" temporary="true" nameIsGenerated="true">
<node-interpreter value="project" />
<playwright-package value="$PROJECT_DIR$/node_modules/@playwright/test" />
<working-dir value="$PROJECT_DIR$" />
<envs />
<scope-kind value="TEST" />
<test-file value="$PROJECT_DIR$/test/aaa.spec.ts" />
<test-names>
<test-name value="test" />
</test-names>
<method v="2" />
</configuration>
<configuration name="test" type="JavaScriptTestRunnerPlaywright" temporary="true" nameIsGenerated="true">
<node-interpreter value="project" />
<playwright-package value="$PROJECT_DIR$/node_modules/@playwright/test" />
<working-dir value="$PROJECT_DIR$" />
<envs />
<scope-kind value="TEST" />
<test-file value="$PROJECT_DIR$/tests/aaa.spec.ts" />
<test-names>
<test-name value="test" />
</test-names>
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Playwright.test (1)" />
<item itemvalue="Playwright.test" />
</list>
</recent_temporary>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="2ad508fa-1af8-47a1-bdab-47b1a2e633f2" name="Changes" comment="" />
<created>1692115830712</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1692115830712</updated>
<workItem from="1692115832470" duration="696000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="javascript">
<url>file://$PROJECT_DIR$/test/aaa.spec.ts</url>
<line>5</line>
<properties lambdaOrdinal="-1" />
<option name="timeStamp" value="1" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
</project>

View 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 page to have a heading with the name of Installation.
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
});

67
PW_ZiveTS/package-lock.json generated Normal file
View File

@ -0,0 +1,67 @@
{
"name": "zive",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "zive",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.37.0"
}
},
"node_modules/@playwright/test": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.0.tgz",
"integrity": "sha512-181WBLk4SRUyH1Q96VZl7BP6HcK0b7lbdeKisn3N/vnjitk+9HbdlFz/L5fey05vxaAhldIDnzo8KUoy8S3mmQ==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.37.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=16"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/@types/node": {
"version": "18.15.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz",
"integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==",
"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.37.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.0.tgz",
"integrity": "sha512-1c46jhTH/myQw6sesrcuHVtLoSNfJv8Pfy9t3rs6subY7kARv0HRw5PpyfPYPpPtQvBOmgbE6K+qgYUpj81LAA==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=16"
}
}
}
}

16
PW_ZiveTS/package.json Normal file
View File

@ -0,0 +1,16 @@
{
"name": "zive",
"version": "1.0.0",
"description": "",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.37.0"
}
}

View File

@ -0,0 +1,90 @@
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: './test',
/* Maximum time one test can run for. */
timeout: 30 * 1000,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
* For example in `await expect(locator).toHaveText();`
*/
timeout: 5000
},
/* 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: {
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
actionTimeout: 0,
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://localhost: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: { channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { channel: 'chrome' },
// },
],
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
// outputDir: 'test-results/',
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// port: 3000,
// },
});

26
PW_ZiveTS/test/aa.spec.ts Normal file
View File

@ -0,0 +1,26 @@
const { chrome } = require('playwright');
(async () => {
const browser = await chrome.launch({
headless: false
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://www.aaaauto.cz/');
await page.getByRole('button', { name: 'Přijmout vše' }).click();
await page.getByRole('button', { name: 'Značka Vyberte značku' }).click();
await page.getByText('Škoda (2793)').first().click();
await page.getByRole('button', { name: 'Model Vyberte model' }).click();
await page.getByText('Citigo(40)').click();
await page.getByRole('button', { name: 'Rok Vyberte stáří vozu' }).click();
await page.getByText('Do 10 let').click();
await page.getByRole('button', { name: 'Cena Vyberte cenu' }).click();
await page.getByText('Do 200 000 Kč', { exact: true }).click();
await page.getByRole('button', { name: 'Kategorie Vyberte kategorii' }).click();
await page.getByText('Úsporné vozy (31)').click();
await page.getByRole('button', { name: 'Hledat' }).click();
// ---------------------
await context.close();
await browser.close();
})();

View File

@ -0,0 +1,17 @@
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://www.aaaauto.cz/');
await page.getByRole('button', { name: 'Přijmout vše' }).click();
await page.getByRole('button', { name: 'Značka Vyberte značku' }).click();
await page.getByText('Škoda', { exact: true }).first().click();
await page.getByRole('button', { name: 'Model Vyberte model' }).click();
await page.getByText('Citigo(40)').click();
await page.getByRole('button', { name: 'Rok Vyberte stáří vozu' }).click();
await page.getByText('Do 10 let').click();
await page.getByRole('button', { name: 'Cena Vyberte cenu' }).click();
await page.getByText('Do 200 000 Kč', { exact: true }).click();
await page.getByRole('button', { name: 'Kategorie Vyberte kategorii' }).click();
await page.locator('#hpFilterNG').getByText('Úsporné vozy').click();
await page.getByRole('button', { name: 'Hledat' }).click();
});

View File

@ -0,0 +1,44 @@
import { test, expect } from '@playwright/test';
import { chromium } from '@playwright/test';
test('has title', async ({ page }) => {
await page.goto('https://zive.cz');
// Odsouhlasí cookies
await page.click("//button[@id='didomi-notice-agree-button']/span");
// takto
//const button = await page.locator("//button[@id='didomi-notice-agree-button']");
//await button.click();
// Klikne na menu
await page.click("//a[contains(text(),'Menu')]");
// vrátí se na hlavní stranu
await page.click("#mainFORM > nav > div > div.header > a.mn-logo");
// klikne do vyhledávání
await page.click("//a[@onclick='layout.menu.toggle(true)']");
// klikne do vyhledávacího pole
const searchInput = await page.$("#mainFORM > nav > div > div.header > div");
await searchInput?.type('test');
// Potvrdíme vyhledávání stisknutím klávesy Enter
await searchInput?.press('Enter');
// vrátíme se na hlavní stránku
await page.click('//*[@id="mainFORM"]/div[3]/header/div[2]/div/a');
// Zkontrolujeme, že stránka má správný název
const pageTitle = await page.title();
expect(pageTitle).toBe('Živě.cz O počítačích, internetu, vědě a technice');
});

View File

@ -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);
}

View File

@ -0,0 +1,4 @@
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/

View 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

View 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>

View 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>

View 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>

View 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>

View File

@ -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.

View 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?
[![Async / await v Javascriptu](:/6ce0f100ec5a4fefb8cd737380630c3e "Async / await v Javascriptu")](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

View 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.

View 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"
}
}
}
}

View File

@ -0,0 +1,12 @@
{
"name": "playwright_zaklady",
"scripts": {
"allTests": "playwright test"
},
"keywords": [],
"author": "Kankys",
"description": "",
"devDependencies": {
"@playwright/test": "^1.34.3"
}
}

View 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();
}
}

View 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();
}
}

View 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();
}
}

View 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();
}
}

View 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,
// },
});

View File

@ -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);
}

View 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;

View 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());
});

View 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/);
});

View 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/);
});

View 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

View 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 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();
});

View 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!!

View File

@ -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.

View File

@ -0,0 +1,37 @@
name: Search Google Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
path: 'Playwright_GH_TS'
- uses: actions/setup-node@v2
with:
node-version: 16
- name: Install dependencies
run: |
cd Playwright_GH_TS/search_google
npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: |
cd Playwright_GH_TS/search_google
npx playwright test
- uses: actions/upload-artifact@v2
if: always()
with:
name: playwright-report
path: cd Playwright_GH_TS/search_google/playwright-report/
retention-days: 90

View File

@ -0,0 +1,37 @@
name: Zive Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
path: 'Playwright_GH_TS'
- uses: actions/setup-node@v2
with:
node-version: 16
- name: Install dependencies
run: |
cd Playwright_GH_TS/zive
npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: |
cd Playwright_GH_TS/zive
npx playwright test
- uses: actions/upload-artifact@v2
if: always()
with:
name: playwright-report
path: cd Playwright_GH_TS/zive/playwright-report/
retention-days: 90

4
Playwright_GH_TS/aaa/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/

67
Playwright_GH_TS/aaa/package-lock.json generated Normal file
View File

@ -0,0 +1,67 @@
{
"name": "aaa",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "aaa",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.36.2"
}
},
"node_modules/@playwright/test": {
"version": "1.36.2",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.2.tgz",
"integrity": "sha512-2rVZeyPRjxfPH6J0oGJqE8YxiM1IBRyM8hyrXYK7eSiAqmbNhxwcLa7dZ7fy9Kj26V7FYia5fh9XJRq4Dqme+g==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.36.2"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=16"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/@types/node": {
"version": "20.4.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz",
"integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==",
"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.36.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.2.tgz",
"integrity": "sha512-sQYZt31dwkqxOrP7xy2ggDfEzUxM1lodjhsQ3NMMv5uGTRDsLxU0e4xf4wwMkF2gplIxf17QMBCodSFgm6bFVQ==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=16"
}
}
}
}

View File

@ -0,0 +1,13 @@
{
"name": "aaa",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.36.2"
}
}

View 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,
// },
});

View File

@ -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);
}

View File

@ -0,0 +1,26 @@
const { chrome } = require('playwright');
(async () => {
const browser = await chrome.launch({
headless: false
});
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://www.aaaauto.cz/');
await page.getByRole('button', { name: 'Přijmout vše' }).click();
await page.getByRole('button', { name: 'Značka Vyberte značku' }).click();
await page.getByText('Škoda (2793)').first().click();
await page.getByRole('button', { name: 'Model Vyberte model' }).click();
await page.getByText('Citigo(40)').click();
await page.getByRole('button', { name: 'Rok Vyberte stáří vozu' }).click();
await page.getByText('Do 10 let').click();
await page.getByRole('button', { name: 'Cena Vyberte cenu' }).click();
await page.getByText('Do 200 000 Kč', { exact: true }).click();
await page.getByRole('button', { name: 'Kategorie Vyberte kategorii' }).click();
await page.getByText('Úsporné vozy (31)').click();
await page.getByRole('button', { name: 'Hledat' }).click();
// ---------------------
await context.close();
await browser.close();
})();

View File

@ -0,0 +1,17 @@
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://www.aaaauto.cz/');
await page.getByRole('button', { name: 'Přijmout vše' }).click();
await page.getByRole('button', { name: 'Značka Vyberte značku' }).click();
await page.getByText('Škoda', { exact: true }).first().click();
await page.getByRole('button', { name: 'Model Vyberte model' }).click();
await page.getByText('Citigo(40)').click();
await page.getByRole('button', { name: 'Rok Vyberte stáří vozu' }).click();
await page.getByText('Do 10 let').click();
await page.getByRole('button', { name: 'Cena Vyberte cenu' }).click();
await page.getByText('Do 200 000 Kč', { exact: true }).click();
await page.getByRole('button', { name: 'Kategorie Vyberte kategorii' }).click();
await page.locator('#hpFilterNG').getByText('Úsporné vozy').click();
await page.getByRole('button', { name: 'Hledat' }).click();
});

View 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/);
});

7
Playwright_GH_TS/lukan/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
/test-results/
/playwright-report/
/playwright/.cache/

View 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/);
});

67
Playwright_GH_TS/lukan/package-lock.json generated Normal file
View File

@ -0,0 +1,67 @@
{
"name": "lukan",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lukan",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.36.2"
}
},
"node_modules/@playwright/test": {
"version": "1.36.2",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.2.tgz",
"integrity": "sha512-2rVZeyPRjxfPH6J0oGJqE8YxiM1IBRyM8hyrXYK7eSiAqmbNhxwcLa7dZ7fy9Kj26V7FYia5fh9XJRq4Dqme+g==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.36.2"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=16"
},
"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.36.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.2.tgz",
"integrity": "sha512-sQYZt31dwkqxOrP7xy2ggDfEzUxM1lodjhsQ3NMMv5uGTRDsLxU0e4xf4wwMkF2gplIxf17QMBCodSFgm6bFVQ==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=16"
}
}
}
}

View File

@ -0,0 +1,13 @@
{
"name": "lukan",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.36.2"
}
}

View File

@ -0,0 +1,62 @@
import { Locator, Page
} from "@playwright/test";
export class HomePage{
page: Page;
cookiesButtonAccept: Locator;
cookiesButtonDecline: Locator;
menuButtonUvodniStrana: Locator;
menuButtonOMne: Locator;
menuButtonZasadyOchranyOsobnichUdaju: Locator;
menuButtonPodporovatele: Locator;
searchButton: Locator;
searchFieldInput: Locator;
constructor(page: Page){
this.page = page;
this.cookiesButtonAccept = page.getByText('Accept');
this.cookiesButtonDecline = page.getByText('Decline');
this.menuButtonUvodniStrana = page.getByRole('link', { name: 'Úvodní stránka' });
this.menuButtonOMne = page.getByRole('link' , { name: 'O Mně' });
this.menuButtonZasadyOchranyOsobnichUdaju = page.getByRole('link' , { name: 'Zásady ochrany osobních údajů' });
this.menuButtonPodporovatele = page.getByRole('link' , { name: 'Podporovatelé' });
this.searchFieldInput = page.locator('//*[@id="search-7"]/form/label/input');
this.searchButton = page.locator('#search-7 > form > button > svg > use');
}
async gotoHome() {
await this.page.goto('https://www.lukan.cz/');
}
async clickCookiesButtonAccept() {
await this.cookiesButtonAccept.click();
}
async clickCookiesButtonDecline() {
await this.cookiesButtonDecline.click();
}
async clickUvodniStranaButton() {
await this.menuButtonUvodniStrana.click();
}
async clickOMneButton() {
await this.menuButtonOMne.click();
}
async clickZOOUButton() {
await this.menuButtonZasadyOchranyOsobnichUdaju.click();
}
async clickPodporovateleButton() {
await this.menuButtonPodporovatele.click();
}
async enterTextSearchFields() {
await this.searchFieldInput.fill('Test');
}
async clickSearchButton() {
await this.searchButton.click();
}
};

View File

@ -0,0 +1,5 @@
import { Locator, Page
} from "@playwright/test";
export class LoginPage{
}

View 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,
// },
});

View File

@ -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);
}

View File

@ -0,0 +1,19 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
// test odsouhlasení cookies
test('HomePage click Accept cookies', async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.clickCookiesButtonAccept();
});
// test zamítnutí cookies
test('HomaPage click Decline cookies' , async ({page}) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.clickCookiesButtonDecline();
})

View 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/);
});

View File

@ -0,0 +1,14 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
test('Click menu button with HomePage' , async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.clickUvodniStranaButton();
await homePage.clickOMneButton();
await homePage.clickZOOUButton();
await homePage.clickPodporovateleButton();
//await context.close();
//await browser.close();
});

View File

@ -0,0 +1,10 @@
import { test, expect } from '@playwright/test';
import { HomePage } from '../page-objects/HomePage';
test('Search web' , async ({ page }) => {
const homePage = new HomePage(page);
await homePage.gotoHome();
await homePage.enterTextSearchFields();
await homePage.clickSearchButton();
});

View File

@ -0,0 +1,6 @@
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://lukan.cz/');
await page.getByRole('link', { name: 'Úvodní stránka' }).click();
});

View File

@ -0,0 +1,10 @@
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
/test-results/
/playwright-report/
/playwright/.cache/
/test-results/
/playwright-report/
/playwright/.cache/

View File

@ -0,0 +1,67 @@
{
"name": "search_google",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "search_google",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.31.2"
}
},
"node_modules/@playwright/test": {
"version": "1.31.2",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.31.2.tgz",
"integrity": "sha512-BYVutxDI4JeZKV1+ups6dt5WiqKhjBtIYowyZIJ3kBDmJgsuPKsqqKNIMFbUePLSCmp2cZu+BDL427RcNKTRYw==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.31.2"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=14"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/@types/node": {
"version": "18.13.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz",
"integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==",
"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.31.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.31.2.tgz",
"integrity": "sha512-a1dFgCNQw4vCsG7bnojZjDnPewZcw7tZUNFN0ZkcLYKj+mPmXvg4MpaaKZ5SgqPsOmqIf2YsVRkgqiRDxD+fDQ==",
"dev": true,
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=14"
}
}
}
}

View File

@ -0,0 +1,13 @@
{
"name": "search_google",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.31.2"
}
}

Some files were not shown because too many files have changed in this diff Show More