commit a11746659935e5c6f51d076924adbd7e7489d499
Author: Lukáš Kaňka <124378142+LukasKanka@users.noreply.github.com>
Date: Tue Aug 15 18:27:27 2023 +0200
údržba
diff --git a/PWLukTS/.gitignore b/PWLukTS/.gitignore
new file mode 100644
index 0000000..75e854d
--- /dev/null
+++ b/PWLukTS/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/PWLukTS/.idea/.gitignore b/PWLukTS/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/PWLukTS/.idea/.gitignore
@@ -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
diff --git a/PWLukTS/.idea/PWLukTS.iml b/PWLukTS/.idea/PWLukTS.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/PWLukTS/.idea/PWLukTS.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PWLukTS/.idea/misc.xml b/PWLukTS/.idea/misc.xml
new file mode 100644
index 0000000..639900d
--- /dev/null
+++ b/PWLukTS/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PWLukTS/.idea/modules.xml b/PWLukTS/.idea/modules.xml
new file mode 100644
index 0000000..b46564a
--- /dev/null
+++ b/PWLukTS/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PWLukTS/.idea/vcs.xml b/PWLukTS/.idea/vcs.xml
new file mode 100644
index 0000000..62bd7a0
--- /dev/null
+++ b/PWLukTS/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PWLukTS/.vs/PWLukTS/FileContentIndex/d716de9a-2387-475d-b8ff-c8380967c4a3.vsidx b/PWLukTS/.vs/PWLukTS/FileContentIndex/d716de9a-2387-475d-b8ff-c8380967c4a3.vsidx
new file mode 100644
index 0000000..c0fa9b2
Binary files /dev/null and b/PWLukTS/.vs/PWLukTS/FileContentIndex/d716de9a-2387-475d-b8ff-c8380967c4a3.vsidx differ
diff --git a/PWLukTS/.vs/PWLukTS/v17/.wsuo b/PWLukTS/.vs/PWLukTS/v17/.wsuo
new file mode 100644
index 0000000..2929932
Binary files /dev/null and b/PWLukTS/.vs/PWLukTS/v17/.wsuo differ
diff --git a/PWLukTS/.vs/VSWorkspaceState.json b/PWLukTS/.vs/VSWorkspaceState.json
new file mode 100644
index 0000000..0745879
--- /dev/null
+++ b/PWLukTS/.vs/VSWorkspaceState.json
@@ -0,0 +1,8 @@
+{
+ "ExpandedNodes": [
+ "",
+ "\\tests"
+ ],
+ "SelectedNode": "\\tests\\cookies.test.spec.ts",
+ "PreviewInSolutionExplorer": false
+}
\ No newline at end of file
diff --git a/PWLukTS/.vs/slnx.sqlite b/PWLukTS/.vs/slnx.sqlite
new file mode 100644
index 0000000..96a7ac4
Binary files /dev/null and b/PWLukTS/.vs/slnx.sqlite differ
diff --git a/PWLukTS/README.md b/PWLukTS/README.md
new file mode 100644
index 0000000..480d197
--- /dev/null
+++ b/PWLukTS/README.md
@@ -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
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PWLukTS/helpers.ts b/PWLukTS/helpers.ts
new file mode 100644
index 0000000..9301513
--- /dev/null
+++ b/PWLukTS/helpers.ts
@@ -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();
+};
\ No newline at end of file
diff --git a/PWLukTS/package-lock.json b/PWLukTS/package-lock.json
new file mode 100644
index 0000000..8011d7c
--- /dev/null
+++ b/PWLukTS/package-lock.json
@@ -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"
+ }
+ }
+ }
+}
diff --git a/PWLukTS/package.json b/PWLukTS/package.json
new file mode 100644
index 0000000..9c8322e
--- /dev/null
+++ b/PWLukTS/package.json
@@ -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"
+ }
+}
diff --git a/PWLukTS/page-objects/HomePage.ts b/PWLukTS/page-objects/HomePage.ts
new file mode 100644
index 0000000..0e5ee9a
--- /dev/null
+++ b/PWLukTS/page-objects/HomePage.ts
@@ -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;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/PWLukTS/page-objects/LoginPage.ts b/PWLukTS/page-objects/LoginPage.ts
new file mode 100644
index 0000000..304c184
--- /dev/null
+++ b/PWLukTS/page-objects/LoginPage.ts
@@ -0,0 +1,7 @@
+import { Locator, Page
+} from "@playwright/test";
+export class LoginPage{
+ page: Page;
+
+
+}
\ No newline at end of file
diff --git a/PWLukTS/playwright.config.ts b/PWLukTS/playwright.config.ts
new file mode 100644
index 0000000..54fc979
--- /dev/null
+++ b/PWLukTS/playwright.config.ts
@@ -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,
+ // },
+});
diff --git a/PWLukTS/tests-examples/demo-todo-app.spec.ts b/PWLukTS/tests-examples/demo-todo-app.spec.ts
new file mode 100644
index 0000000..2fd6016
--- /dev/null
+++ b/PWLukTS/tests-examples/demo-todo-app.spec.ts
@@ -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);
+}
diff --git a/PWLukTS/tests/cookies.test.spec.ts b/PWLukTS/tests/cookies.test.spec.ts
new file mode 100644
index 0000000..97a5d00
--- /dev/null
+++ b/PWLukTS/tests/cookies.test.spec.ts
@@ -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();
+});
\ No newline at end of file
diff --git a/PWLukTS/tests/example.spec.ts b/PWLukTS/tests/example.spec.ts
new file mode 100644
index 0000000..c511525
--- /dev/null
+++ b/PWLukTS/tests/example.spec.ts
@@ -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/);
+});
diff --git a/PWLukTS/tests/help.spec.ts b/PWLukTS/tests/help.spec.ts
new file mode 100644
index 0000000..501f8e4
--- /dev/null
+++ b/PWLukTS/tests/help.spec.ts
@@ -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);
+
+
+ });
\ No newline at end of file
diff --git a/PWLukTS/tests/login.spec.ts b/PWLukTS/tests/login.spec.ts
new file mode 100644
index 0000000..bd0afac
--- /dev/null
+++ b/PWLukTS/tests/login.spec.ts
@@ -0,0 +1 @@
+// login deaktivován
\ No newline at end of file
diff --git a/PWLukTS/tests/menuButton.test.spec.ts b/PWLukTS/tests/menuButton.test.spec.ts
new file mode 100644
index 0000000..37ca867
--- /dev/null
+++ b/PWLukTS/tests/menuButton.test.spec.ts
@@ -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();
+});
\ No newline at end of file
diff --git a/PWLukTS/tests/primary.menu.spec.ts b/PWLukTS/tests/primary.menu.spec.ts
new file mode 100644
index 0000000..6fe9b29
--- /dev/null
+++ b/PWLukTS/tests/primary.menu.spec.ts
@@ -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);
+
+
+ });
\ No newline at end of file
diff --git a/PWLukTS/tests/search.spec.ts b/PWLukTS/tests/search.spec.ts
new file mode 100644
index 0000000..0f781be
--- /dev/null
+++ b/PWLukTS/tests/search.spec.ts
@@ -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();
+
+});
\ No newline at end of file
diff --git a/PWLukTS/tests/social.test.spec.ts b/PWLukTS/tests/social.test.spec.ts
new file mode 100644
index 0000000..09bd351
--- /dev/null
+++ b/PWLukTS/tests/social.test.spec.ts
@@ -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);
+})
\ No newline at end of file
diff --git a/PWLukTS/tests/test-1.spec.ts b/PWLukTS/tests/test-1.spec.ts
new file mode 100644
index 0000000..29fdff8
--- /dev/null
+++ b/PWLukTS/tests/test-1.spec.ts
@@ -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();
+});
\ No newline at end of file
diff --git a/PWLukTS/tests/tittle.spec.ts b/PWLukTS/tests/tittle.spec.ts
new file mode 100644
index 0000000..7f14f65
--- /dev/null
+++ b/PWLukTS/tests/tittle.spec.ts
@@ -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');
+
+});
\ No newline at end of file
diff --git a/PWLukTS/tests/vsechny.spec.ts b/PWLukTS/tests/vsechny.spec.ts
new file mode 100644
index 0000000..7353c4b
--- /dev/null
+++ b/PWLukTS/tests/vsechny.spec.ts
@@ -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);
+
+
+ });
+
+
+
+
+
+
+});
+
diff --git a/PW_ZiveTS/.gitignore b/PW_ZiveTS/.gitignore
new file mode 100644
index 0000000..706b4ea
--- /dev/null
+++ b/PW_ZiveTS/.gitignore
@@ -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/
diff --git a/PW_ZiveTS/.idea/PW_ZiveTS.iml b/PW_ZiveTS/.idea/PW_ZiveTS.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/PW_ZiveTS/.idea/PW_ZiveTS.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PW_ZiveTS/.idea/misc.xml b/PW_ZiveTS/.idea/misc.xml
new file mode 100644
index 0000000..639900d
--- /dev/null
+++ b/PW_ZiveTS/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PW_ZiveTS/.idea/modules.xml b/PW_ZiveTS/.idea/modules.xml
new file mode 100644
index 0000000..2b302f1
--- /dev/null
+++ b/PW_ZiveTS/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PW_ZiveTS/.idea/vcs.xml b/PW_ZiveTS/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/PW_ZiveTS/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PW_ZiveTS/.idea/workspace.xml b/PW_ZiveTS/.idea/workspace.xml
new file mode 100644
index 0000000..6689e56
--- /dev/null
+++ b/PW_ZiveTS/.idea/workspace.xml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1692115830712
+
+
+ 1692115830712
+
+
+
+
+
+
+
+
+
+
+
+ file://$PROJECT_DIR$/test/aaa.spec.ts
+ 5
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PW_ZiveTS/e2e/example.spec.ts b/PW_ZiveTS/e2e/example.spec.ts
new file mode 100644
index 0000000..54a906a
--- /dev/null
+++ b/PW_ZiveTS/e2e/example.spec.ts
@@ -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();
+});
diff --git a/PW_ZiveTS/package-lock.json b/PW_ZiveTS/package-lock.json
new file mode 100644
index 0000000..5cc717c
--- /dev/null
+++ b/PW_ZiveTS/package-lock.json
@@ -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"
+ }
+ }
+ }
+}
diff --git a/PW_ZiveTS/package.json b/PW_ZiveTS/package.json
new file mode 100644
index 0000000..48f1c5b
--- /dev/null
+++ b/PW_ZiveTS/package.json
@@ -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"
+ }
+}
diff --git a/PW_ZiveTS/playwright.config.ts b/PW_ZiveTS/playwright.config.ts
new file mode 100644
index 0000000..f389f33
--- /dev/null
+++ b/PW_ZiveTS/playwright.config.ts
@@ -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,
+ // },
+});
diff --git a/PW_ZiveTS/test/aa.spec.ts b/PW_ZiveTS/test/aa.spec.ts
new file mode 100644
index 0000000..66af5d1
--- /dev/null
+++ b/PW_ZiveTS/test/aa.spec.ts
@@ -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();
+})();
\ No newline at end of file
diff --git a/PW_ZiveTS/test/aaa.spec.ts b/PW_ZiveTS/test/aaa.spec.ts
new file mode 100644
index 0000000..0ac2afc
--- /dev/null
+++ b/PW_ZiveTS/test/aaa.spec.ts
@@ -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();
+});
\ No newline at end of file
diff --git a/PW_ZiveTS/test/example.spec.ts b/PW_ZiveTS/test/example.spec.ts
new file mode 100644
index 0000000..3914e7f
--- /dev/null
+++ b/PW_ZiveTS/test/example.spec.ts
@@ -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');
+
+
+
+
+
+
+ });
diff --git a/PW_ZiveTS/tests-examples/demo-todo-app.spec.ts b/PW_ZiveTS/tests-examples/demo-todo-app.spec.ts
new file mode 100644
index 0000000..2fd6016
--- /dev/null
+++ b/PW_ZiveTS/tests-examples/demo-todo-app.spec.ts
@@ -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);
+}
diff --git a/Playwright základy na GitHub/.gitignore b/Playwright základy na GitHub/.gitignore
new file mode 100644
index 0000000..75e854d
--- /dev/null
+++ b/Playwright základy na GitHub/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/Playwright základy na GitHub/.idea/.gitignore b/Playwright základy na GitHub/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/Playwright základy na GitHub/.idea/.gitignore
@@ -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
diff --git a/Playwright základy na GitHub/.idea/Playwright základy na GitHub.iml b/Playwright základy na GitHub/.idea/Playwright základy na GitHub.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/Playwright základy na GitHub/.idea/Playwright základy na GitHub.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Playwright základy na GitHub/.idea/misc.xml b/Playwright základy na GitHub/.idea/misc.xml
new file mode 100644
index 0000000..639900d
--- /dev/null
+++ b/Playwright základy na GitHub/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Playwright základy na GitHub/.idea/modules.xml b/Playwright základy na GitHub/.idea/modules.xml
new file mode 100644
index 0000000..57ecd1d
--- /dev/null
+++ b/Playwright základy na GitHub/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Playwright základy na GitHub/.idea/vcs.xml b/Playwright základy na GitHub/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/Playwright základy na GitHub/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Playwright základy na GitHub/11 Identifikácia elementov a akcie s nimi.md b/Playwright základy na GitHub/11 Identifikácia elementov a akcie s nimi.md
new file mode 100644
index 0000000..b6c7035
--- /dev/null
+++ b/Playwright základy na GitHub/11 Identifikácia elementov a akcie s nimi.md
@@ -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.
\ No newline at end of file
diff --git a/Playwright základy na GitHub/Async Await.md b/Playwright základy na GitHub/Async Await.md
new file mode 100644
index 0000000..fe27756
--- /dev/null
+++ b/Playwright základy na GitHub/Async Await.md
@@ -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 *
+
+
+
+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
\ No newline at end of file
diff --git a/Playwright základy na GitHub/README.MD b/Playwright základy na GitHub/README.MD
new file mode 100644
index 0000000..a67c9cc
--- /dev/null
+++ b/Playwright základy na GitHub/README.MD
@@ -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.
+
+
diff --git a/Playwright základy na GitHub/fixtures/basePages.ts b/Playwright základy na GitHub/fixtures/basePages.ts
new file mode 100644
index 0000000..e69de29
diff --git a/Playwright základy na GitHub/package-lock.json b/Playwright základy na GitHub/package-lock.json
new file mode 100644
index 0000000..ad04375
--- /dev/null
+++ b/Playwright základy na GitHub/package-lock.json
@@ -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"
+ }
+ }
+ }
+}
diff --git a/Playwright základy na GitHub/package.json b/Playwright základy na GitHub/package.json
new file mode 100644
index 0000000..824e4f4
--- /dev/null
+++ b/Playwright základy na GitHub/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "playwright_zaklady",
+ "scripts": {
+ "allTests": "playwright test"
+ },
+ "keywords": [],
+ "author": "Kankys",
+ "description": "",
+ "devDependencies": {
+ "@playwright/test": "^1.34.3"
+ }
+}
\ No newline at end of file
diff --git a/Playwright základy na GitHub/page-objects copy/HomePage.ts b/Playwright základy na GitHub/page-objects copy/HomePage.ts
new file mode 100644
index 0000000..b1e2494
--- /dev/null
+++ b/Playwright základy na GitHub/page-objects copy/HomePage.ts
@@ -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();
+}
+
+
+}
+
diff --git a/Playwright základy na GitHub/page-objects copy/LoginPage.ts b/Playwright základy na GitHub/page-objects copy/LoginPage.ts
new file mode 100644
index 0000000..8005fa6
--- /dev/null
+++ b/Playwright základy na GitHub/page-objects copy/LoginPage.ts
@@ -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();
+ }
+
+}
+
diff --git a/Playwright základy na GitHub/page-objects/HomePage.ts b/Playwright základy na GitHub/page-objects/HomePage.ts
new file mode 100644
index 0000000..b1e2494
--- /dev/null
+++ b/Playwright základy na GitHub/page-objects/HomePage.ts
@@ -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();
+}
+
+
+}
+
diff --git a/Playwright základy na GitHub/page-objects/LoginPage.ts b/Playwright základy na GitHub/page-objects/LoginPage.ts
new file mode 100644
index 0000000..9720203
--- /dev/null
+++ b/Playwright základy na GitHub/page-objects/LoginPage.ts
@@ -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();
+ }
+
+}
+
diff --git a/Playwright základy na GitHub/playwright.config.ts b/Playwright základy na GitHub/playwright.config.ts
new file mode 100644
index 0000000..cdcccfe
--- /dev/null
+++ b/Playwright základy na GitHub/playwright.config.ts
@@ -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,
+ // },
+});
diff --git a/Playwright základy na GitHub/tests-examples/demo-todo-app.spec.ts b/Playwright základy na GitHub/tests-examples/demo-todo-app.spec.ts
new file mode 100644
index 0000000..2fd6016
--- /dev/null
+++ b/Playwright základy na GitHub/tests-examples/demo-todo-app.spec.ts
@@ -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);
+}
diff --git a/Playwright základy na GitHub/tests/alerts.spec.ts b/Playwright základy na GitHub/tests/alerts.spec.ts
new file mode 100644
index 0000000..e69de29
diff --git a/Playwright základy na GitHub/tests/assertions.spec.ts b/Playwright základy na GitHub/tests/assertions.spec.ts
new file mode 100644
index 0000000..15d7058
--- /dev/null
+++ b/Playwright základy na GitHub/tests/assertions.spec.ts
@@ -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;
\ No newline at end of file
diff --git a/Playwright základy na GitHub/tests/elementState.spec.ts b/Playwright základy na GitHub/tests/elementState.spec.ts
new file mode 100644
index 0000000..385e360
--- /dev/null
+++ b/Playwright základy na GitHub/tests/elementState.spec.ts
@@ -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());
+
+
+
+});
\ No newline at end of file
diff --git a/Playwright základy na GitHub/tests/example.spec copy.ts b/Playwright základy na GitHub/tests/example.spec copy.ts
new file mode 100644
index 0000000..c511525
--- /dev/null
+++ b/Playwright základy na GitHub/tests/example.spec copy.ts
@@ -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/);
+});
diff --git a/Playwright základy na GitHub/tests/example.spec.ts b/Playwright základy na GitHub/tests/example.spec.ts
new file mode 100644
index 0000000..c511525
--- /dev/null
+++ b/Playwright základy na GitHub/tests/example.spec.ts
@@ -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/);
+});
diff --git a/Playwright základy na GitHub/tests/home.spec.ts b/Playwright základy na GitHub/tests/home.spec.ts
new file mode 100644
index 0000000..b3521f2
--- /dev/null
+++ b/Playwright základy na GitHub/tests/home.spec.ts
@@ -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
+
+
+
diff --git a/Playwright základy na GitHub/tests/login.spec.ts b/Playwright základy na GitHub/tests/login.spec.ts
new file mode 100644
index 0000000..aa80cba
--- /dev/null
+++ b/Playwright základy na GitHub/tests/login.spec.ts
@@ -0,0 +1,79 @@
+/*
+ Zápis pomocí Page_Objects --> je kratší, čitatelnější a přehlednější. Pokud se například změní lokátor id nemusím ho měnit ve všech testech
+ale, v daném page-objects
+ctrl + click mě přesune na zadanou metodu!!
+ */
+import { test, expect } from '@playwright/test';
+//Importujeme vytvořenou třídu z page-objects
+import { LoginPage } from '../page-objects/LoginPage';
+
+test('Successful login', async ({ page }) => {
+ // nová instance loginPage odkazuje na metody co jsme si vytvořili v LoginPage
+ const loginPage = new LoginPage(page);
+ // zadáme metody co jsme vytvořily v LoginPage
+ await loginPage.gotoLoginPage();
+ // místo tohoto použijeme námi vytvořenou metodu login z LoginPage
+ //await loginPage.enterValidUsername();
+ //await loginPage.enterValidPassword();
+ //await loginPage.clickLoginButton();
+ // metoda login
+ await loginPage.login();
+ // ověříme že jsme se úspěšně přihlásily
+ await expect(page).toHaveURL('https://www.saucedemo.com/inventory.html');
+ /*
+ // způsob jeden test komplet v kódu bez odkazu na page-objects
+ await page.goto('https://www.saucedemo.com/');
+ await page.locator('[data-test="username"]').click();
+ await page.locator('[data-test="username"]').fill('standard_user');
+ await page.locator('[data-test="password"]').click();
+ await page.locator('[data-test="password"]').fill('secret_sauce');
+ await page.locator('[data-test="login-button"]').click();
+
+ // Zkontrolujeme jestli na stránce je viditelný Swag Labs
+ await expect(page.getByText('Swag Labs')).toBeVisible();
+ */
+});
+
+// test přihlášení s neplatným heslem
+test('Cannot login with valid username and invalid password', async ({ page }) => {
+ // test reporty(video 23):
+
+ const loginPage = new LoginPage(page);
+ await loginPage.gotoLoginPage();
+ await loginPage.enterValidUsername();
+ await loginPage.enterInvalidPassword();
+ await loginPage.clickLoginButton();
+ await expect(loginPage.invalidCredentialsErrorMessage).toBeVisible();
+});
+
+
+ //test s neplatným přihlašovacím jménem
+ test('Cannot login with invalid username and valid password', async ({ page }) => {
+ const loginPage = new LoginPage(page);
+ await loginPage.gotoLoginPage();
+ await loginPage.enterInvalidUsername();
+ await loginPage.enterValidPassword();
+ await loginPage.clickLoginButton();
+ await expect(loginPage.invalidCredentialsErrorMessage).toBeVisible();
+
+});
+
+//test pouze s kliknutím na login button
+test('Cannot login with blank fields', async ({ page }) => {
+ const loginPage = new LoginPage(page);
+ await loginPage.gotoLoginPage();
+ await loginPage.clickLoginButton();
+ await expect(loginPage.requiredCredentialsErrorMassage).toBeVisible();
+
+});
+
+// přihlášení s zablokovaným userem
+test('Cannot login with locked out user', async ({ page }) => {
+ const loginPage = new LoginPage(page);
+ await loginPage.gotoLoginPage();
+ await loginPage.enterLockedOutUser();
+ await loginPage.enterValidPassword();
+ await loginPage.clickLoginButton();
+ await expect(loginPage.lockedOutErrorMassage).toBeVisible();
+
+});
diff --git a/Playwright základy na GitHub/tests/screenshots.spec.ts b/Playwright základy na GitHub/tests/screenshots.spec.ts
new file mode 100644
index 0000000..e69de29
diff --git a/Playwright základy na GitHub/tests/tabs.spec.ts b/Playwright základy na GitHub/tests/tabs.spec.ts
new file mode 100644
index 0000000..e69de29
diff --git a/Playwright základy na GitHub/tests/upload.spec.ts b/Playwright základy na GitHub/tests/upload.spec.ts
new file mode 100644
index 0000000..e69de29
diff --git a/Playwright základy na GitHub/Úkoly.md b/Playwright základy na GitHub/Úkoly.md
new file mode 100644
index 0000000..7235adb
--- /dev/null
+++ b/Playwright základy na GitHub/Úkoly.md
@@ -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!!
+
+
diff --git a/Playwright základy na GitHub/Čo je Page Object Model (POM).md b/Playwright základy na GitHub/Čo je Page Object Model (POM).md
new file mode 100644
index 0000000..695731e
--- /dev/null
+++ b/Playwright základy na GitHub/Čo je Page Object Model (POM).md
@@ -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.
\ No newline at end of file
diff --git a/Playwright_GH_TS/...github/workflows/search_google.yml b/Playwright_GH_TS/...github/workflows/search_google.yml
new file mode 100644
index 0000000..7ab226a
--- /dev/null
+++ b/Playwright_GH_TS/...github/workflows/search_google.yml
@@ -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
+
diff --git a/Playwright_GH_TS/...github/workflows/zive.yml b/Playwright_GH_TS/...github/workflows/zive.yml
new file mode 100644
index 0000000..66aef33
--- /dev/null
+++ b/Playwright_GH_TS/...github/workflows/zive.yml
@@ -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
+
diff --git a/Playwright_GH_TS/aaa/.gitignore b/Playwright_GH_TS/aaa/.gitignore
new file mode 100644
index 0000000..75e854d
--- /dev/null
+++ b/Playwright_GH_TS/aaa/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/Playwright_GH_TS/aaa/package-lock.json b/Playwright_GH_TS/aaa/package-lock.json
new file mode 100644
index 0000000..a9226bc
--- /dev/null
+++ b/Playwright_GH_TS/aaa/package-lock.json
@@ -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"
+ }
+ }
+ }
+}
diff --git a/Playwright_GH_TS/aaa/package.json b/Playwright_GH_TS/aaa/package.json
new file mode 100644
index 0000000..efdc99d
--- /dev/null
+++ b/Playwright_GH_TS/aaa/package.json
@@ -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"
+ }
+}
diff --git a/Playwright_GH_TS/aaa/playwright.config.ts b/Playwright_GH_TS/aaa/playwright.config.ts
new file mode 100644
index 0000000..301801e
--- /dev/null
+++ b/Playwright_GH_TS/aaa/playwright.config.ts
@@ -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,
+ // },
+});
diff --git a/Playwright_GH_TS/aaa/tests-examples/demo-todo-app.spec.ts b/Playwright_GH_TS/aaa/tests-examples/demo-todo-app.spec.ts
new file mode 100644
index 0000000..2fd6016
--- /dev/null
+++ b/Playwright_GH_TS/aaa/tests-examples/demo-todo-app.spec.ts
@@ -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);
+}
diff --git a/Playwright_GH_TS/aaa/tests/aa.spec.ts b/Playwright_GH_TS/aaa/tests/aa.spec.ts
new file mode 100644
index 0000000..66af5d1
--- /dev/null
+++ b/Playwright_GH_TS/aaa/tests/aa.spec.ts
@@ -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();
+})();
\ No newline at end of file
diff --git a/Playwright_GH_TS/aaa/tests/aaa.spec.ts b/Playwright_GH_TS/aaa/tests/aaa.spec.ts
new file mode 100644
index 0000000..0ac2afc
--- /dev/null
+++ b/Playwright_GH_TS/aaa/tests/aaa.spec.ts
@@ -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();
+});
\ No newline at end of file
diff --git a/Playwright_GH_TS/aaa/tests/example.spec.ts b/Playwright_GH_TS/aaa/tests/example.spec.ts
new file mode 100644
index 0000000..c511525
--- /dev/null
+++ b/Playwright_GH_TS/aaa/tests/example.spec.ts
@@ -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/);
+});
diff --git a/Playwright_GH_TS/lukan/.gitignore b/Playwright_GH_TS/lukan/.gitignore
new file mode 100644
index 0000000..6d284fa
--- /dev/null
+++ b/Playwright_GH_TS/lukan/.gitignore
@@ -0,0 +1,7 @@
+node_modules/
+/test-results/
+/playwright-report/
+/playwright/.cache/
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/Playwright_GH_TS/lukan/e2e/example.spec.ts b/Playwright_GH_TS/lukan/e2e/example.spec.ts
new file mode 100644
index 0000000..c511525
--- /dev/null
+++ b/Playwright_GH_TS/lukan/e2e/example.spec.ts
@@ -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/);
+});
diff --git a/Playwright_GH_TS/lukan/package-lock.json b/Playwright_GH_TS/lukan/package-lock.json
new file mode 100644
index 0000000..c41e1fc
--- /dev/null
+++ b/Playwright_GH_TS/lukan/package-lock.json
@@ -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"
+ }
+ }
+ }
+}
diff --git a/Playwright_GH_TS/lukan/package.json b/Playwright_GH_TS/lukan/package.json
new file mode 100644
index 0000000..4fe98a6
--- /dev/null
+++ b/Playwright_GH_TS/lukan/package.json
@@ -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"
+ }
+}
diff --git a/Playwright_GH_TS/lukan/page-objects/HomePage.ts b/Playwright_GH_TS/lukan/page-objects/HomePage.ts
new file mode 100644
index 0000000..5799dc5
--- /dev/null
+++ b/Playwright_GH_TS/lukan/page-objects/HomePage.ts
@@ -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();
+ }
+
+
+};
\ No newline at end of file
diff --git a/Playwright_GH_TS/lukan/page-objects/LoginPage.ts b/Playwright_GH_TS/lukan/page-objects/LoginPage.ts
new file mode 100644
index 0000000..d4711a7
--- /dev/null
+++ b/Playwright_GH_TS/lukan/page-objects/LoginPage.ts
@@ -0,0 +1,5 @@
+import { Locator, Page
+} from "@playwright/test";
+export class LoginPage{
+
+}
\ No newline at end of file
diff --git a/Playwright_GH_TS/lukan/playwright.config.ts b/Playwright_GH_TS/lukan/playwright.config.ts
new file mode 100644
index 0000000..34956d0
--- /dev/null
+++ b/Playwright_GH_TS/lukan/playwright.config.ts
@@ -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,
+ // },
+});
diff --git a/Playwright_GH_TS/lukan/tests-examples/demo-todo-app.spec.ts b/Playwright_GH_TS/lukan/tests-examples/demo-todo-app.spec.ts
new file mode 100644
index 0000000..2fd6016
--- /dev/null
+++ b/Playwright_GH_TS/lukan/tests-examples/demo-todo-app.spec.ts
@@ -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);
+}
diff --git a/Playwright_GH_TS/lukan/tests/cookies.test.spec.ts b/Playwright_GH_TS/lukan/tests/cookies.test.spec.ts
new file mode 100644
index 0000000..aaf84da
--- /dev/null
+++ b/Playwright_GH_TS/lukan/tests/cookies.test.spec.ts
@@ -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();
+})
\ No newline at end of file
diff --git a/Playwright_GH_TS/lukan/tests/example.spec.ts b/Playwright_GH_TS/lukan/tests/example.spec.ts
new file mode 100644
index 0000000..c511525
--- /dev/null
+++ b/Playwright_GH_TS/lukan/tests/example.spec.ts
@@ -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/);
+});
diff --git a/Playwright_GH_TS/lukan/tests/login.spec.ts b/Playwright_GH_TS/lukan/tests/login.spec.ts
new file mode 100644
index 0000000..e69de29
diff --git a/Playwright_GH_TS/lukan/tests/menuButton.test.spec.ts b/Playwright_GH_TS/lukan/tests/menuButton.test.spec.ts
new file mode 100644
index 0000000..d4cb240
--- /dev/null
+++ b/Playwright_GH_TS/lukan/tests/menuButton.test.spec.ts
@@ -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();
+});
\ No newline at end of file
diff --git a/Playwright_GH_TS/lukan/tests/search.spec.ts b/Playwright_GH_TS/lukan/tests/search.spec.ts
new file mode 100644
index 0000000..0f781be
--- /dev/null
+++ b/Playwright_GH_TS/lukan/tests/search.spec.ts
@@ -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();
+
+});
\ No newline at end of file
diff --git a/Playwright_GH_TS/lukan/tests/test-1.spec.ts b/Playwright_GH_TS/lukan/tests/test-1.spec.ts
new file mode 100644
index 0000000..29fdff8
--- /dev/null
+++ b/Playwright_GH_TS/lukan/tests/test-1.spec.ts
@@ -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();
+});
\ No newline at end of file
diff --git a/Playwright_GH_TS/search_google/.gitignore b/Playwright_GH_TS/search_google/.gitignore
new file mode 100644
index 0000000..40a2227
--- /dev/null
+++ b/Playwright_GH_TS/search_google/.gitignore
@@ -0,0 +1,10 @@
+node_modules/
+/test-results/
+/playwright-report/
+/playwright/.cache/
+/test-results/
+/playwright-report/
+/playwright/.cache/
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/Playwright_GH_TS/search_google/package-lock.json b/Playwright_GH_TS/search_google/package-lock.json
new file mode 100644
index 0000000..f8e68b1
--- /dev/null
+++ b/Playwright_GH_TS/search_google/package-lock.json
@@ -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"
+ }
+ }
+ }
+}
diff --git a/Playwright_GH_TS/search_google/package.json b/Playwright_GH_TS/search_google/package.json
new file mode 100644
index 0000000..7240edc
--- /dev/null
+++ b/Playwright_GH_TS/search_google/package.json
@@ -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"
+ }
+}
diff --git a/Playwright_GH_TS/search_google/playwright.config.ts b/Playwright_GH_TS/search_google/playwright.config.ts
new file mode 100644
index 0000000..213b45f
--- /dev/null
+++ b/Playwright_GH_TS/search_google/playwright.config.ts
@@ -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: './tests',
+ /* 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,
+ // },
+});
diff --git a/Playwright_GH_TS/search_google/tests-examples/demo-todo-app.spec.ts b/Playwright_GH_TS/search_google/tests-examples/demo-todo-app.spec.ts
new file mode 100644
index 0000000..2fd6016
--- /dev/null
+++ b/Playwright_GH_TS/search_google/tests-examples/demo-todo-app.spec.ts
@@ -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);
+}
diff --git a/Playwright_GH_TS/search_google/tests/example.spec.ts b/Playwright_GH_TS/search_google/tests/example.spec.ts
new file mode 100644
index 0000000..bd681a2
--- /dev/null
+++ b/Playwright_GH_TS/search_google/tests/example.spec.ts
@@ -0,0 +1,33 @@
+//****Tento projekt je TypeScript****//
+
+import { test, expect } from '@playwright/test';
+import { chromium } from '@playwright/test';
+
+test('has title', async ({ page }) => {
+ // const browser = await chromium.launch();
+ // const context = await browser.newContext();
+ await page.goto('https://www.google.com');
+
+ // Odsouhlasí cookies
+ await page.click("#W0wltc > div");
+
+ // Najdeme pole vyhledávání a napíšeme do něj slovo "test"
+ const searchInput = await page.$('[name="q"]');
+ await searchInput?.type('test');
+
+ // Potvrdíme vyhledávání stisknutím klávesy Enter
+ await searchInput?.press('Enter');
+
+ // Nebo můžeme kliknout na tlačítko pro vyhledávání
+ // const searchButton = await page.$('[name="btnK"]');
+ // await searchButton?.click();
+
+ // Vypíše název stránky do konzole
+ const title = await page.title();
+ console.log(title);
+
+ //await page.waitForNavigation();
+ // console.log('Search results page title:', await page.title());
+
+ // await browser.close();
+});
diff --git a/Playwright_GH_TS/zive.ts/.gitignore b/Playwright_GH_TS/zive.ts/.gitignore
new file mode 100644
index 0000000..75e854d
--- /dev/null
+++ b/Playwright_GH_TS/zive.ts/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/Playwright_GH_TS/zive.ts/package-lock.json b/Playwright_GH_TS/zive.ts/package-lock.json
new file mode 100644
index 0000000..dc57de5
--- /dev/null
+++ b/Playwright_GH_TS/zive.ts/package-lock.json
@@ -0,0 +1,67 @@
+{
+ "name": "zive.ts",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "zive.ts",
+ "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.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.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"
+ }
+ }
+ }
+}
diff --git a/Playwright_GH_TS/zive.ts/package.json b/Playwright_GH_TS/zive.ts/package.json
new file mode 100644
index 0000000..82cccf6
--- /dev/null
+++ b/Playwright_GH_TS/zive.ts/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "zive.ts",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {},
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "@playwright/test": "^1.31.2"
+ }
+}
diff --git a/Playwright_GH_TS/zive.ts/playwright.config.ts b/Playwright_GH_TS/zive.ts/playwright.config.ts
new file mode 100644
index 0000000..5e5154b
--- /dev/null
+++ b/Playwright_GH_TS/zive.ts/playwright.config.ts
@@ -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: './tests',
+ /* 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,
+ // },
+});
diff --git a/Playwright_GH_TS/zive.ts/tests-examples/demo-todo-app.spec.ts b/Playwright_GH_TS/zive.ts/tests-examples/demo-todo-app.spec.ts
new file mode 100644
index 0000000..2fd6016
--- /dev/null
+++ b/Playwright_GH_TS/zive.ts/tests-examples/demo-todo-app.spec.ts
@@ -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);
+}
diff --git a/Playwright_GH_TS/zive.ts/tests/example.spec.ts b/Playwright_GH_TS/zive.ts/tests/example.spec.ts
new file mode 100644
index 0000000..ecbe392
--- /dev/null
+++ b/Playwright_GH_TS/zive.ts/tests/example.spec.ts
@@ -0,0 +1,11 @@
+import { test, expect } from '@playwright/test';
+
+test('test', async ({ page }) => {
+ await page.goto('https://www.zive.cz/');
+ await page.getByRole('button', { name: 'Souhlasit a zavřít: Souhlasit s naším zpracováním údajů a zavřít' }).click();
+ await page.getByRole('link', { name: 'Menu' }).click();
+ await page.getByPlaceholder('Hledat na Živě').click();
+ await page.getByPlaceholder('Hledat na Živě').fill('zive');
+ await page.goto('https://www.zive.cz/vysledky-vyhledavani/sc-236/?q=zive');
+ await page.getByRole('link', { name: 'O počítačích, IT a internetu - Živě.cz' }).click();
+});
\ No newline at end of file
diff --git a/Playwright_GH_TS/zive/.gitignore b/Playwright_GH_TS/zive/.gitignore
new file mode 100644
index 0000000..6d284fa
--- /dev/null
+++ b/Playwright_GH_TS/zive/.gitignore
@@ -0,0 +1,7 @@
+node_modules/
+/test-results/
+/playwright-report/
+/playwright/.cache/
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/Playwright_GH_TS/zive/e2e/example.spec.ts b/Playwright_GH_TS/zive/e2e/example.spec.ts
new file mode 100644
index 0000000..c511525
--- /dev/null
+++ b/Playwright_GH_TS/zive/e2e/example.spec.ts
@@ -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/);
+});
diff --git a/Playwright_GH_TS/zive/package-lock.json b/Playwright_GH_TS/zive/package-lock.json
new file mode 100644
index 0000000..df8ded4
--- /dev/null
+++ b/Playwright_GH_TS/zive/package-lock.json
@@ -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.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.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.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"
+ }
+ }
+ }
+}
diff --git a/Playwright_GH_TS/zive/package.json b/Playwright_GH_TS/zive/package.json
new file mode 100644
index 0000000..caf7bbc
--- /dev/null
+++ b/Playwright_GH_TS/zive/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "zive",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "directories": {
+ "test": "tests"
+ },
+ "scripts": {},
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "devDependencies": {
+ "@playwright/test": "^1.31.2"
+ }
+}
diff --git a/Playwright_GH_TS/zive/playwright.config.ts b/Playwright_GH_TS/zive/playwright.config.ts
new file mode 100644
index 0000000..fbf188a
--- /dev/null
+++ b/Playwright_GH_TS/zive/playwright.config.ts
@@ -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: './e2e',
+ /* 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,
+ // },
+});
diff --git a/Playwright_GH_TS/zive/tests-examples/demo-todo-app.spec.ts b/Playwright_GH_TS/zive/tests-examples/demo-todo-app.spec.ts
new file mode 100644
index 0000000..2fd6016
--- /dev/null
+++ b/Playwright_GH_TS/zive/tests-examples/demo-todo-app.spec.ts
@@ -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);
+}
diff --git a/Playwright_GH_TS/zive/tests/example.spec.ts b/Playwright_GH_TS/zive/tests/example.spec.ts
new file mode 100644
index 0000000..3914e7f
--- /dev/null
+++ b/Playwright_GH_TS/zive/tests/example.spec.ts
@@ -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');
+
+
+
+
+
+
+ });