From 2ffb7d31a7dfd1fb24df99e1700dea1d7d33512d Mon Sep 17 00:00:00 2001 From: Iryna Herashchenko Date: Sat, 12 Apr 2025 20:27:09 +0200 Subject: [PATCH 1/4] Homework234 --- pages/base.page.js | 33 ++ pages/registration.page.js | 70 ++++ playwright.config.js | 19 +- tests-examples/demo-todo-app.spec.js | 449 ------------------------ tests/example.spec.js | 19 - tests/registration/registration.spec.js | 106 ++++++ 6 files changed, 219 insertions(+), 477 deletions(-) create mode 100644 pages/base.page.js create mode 100644 pages/registration.page.js delete mode 100644 tests-examples/demo-todo-app.spec.js delete mode 100644 tests/example.spec.js create mode 100644 tests/registration/registration.spec.js diff --git a/pages/base.page.js b/pages/base.page.js new file mode 100644 index 0000000..bcc0fea --- /dev/null +++ b/pages/base.page.js @@ -0,0 +1,33 @@ +export class BasePage { + constructor(page) { + this.page = page; + } + + async navigate(url) { + await this.page.goto(url); + } + + async click(locator) { + await locator.click(); + } + + async fill(locator, text) { + await locator.fill(text); + } + + async type(locator, text) { + await locator.type(text); + } + + async getText(locator) { + return await locator.innerText(); + } + + async isVisible(locator) { + return await locator.isVisible(); + } + + async isEnabled(locator) { + return await locator.isEnabled(); + } + } \ No newline at end of file diff --git a/pages/registration.page.js b/pages/registration.page.js new file mode 100644 index 0000000..173d524 --- /dev/null +++ b/pages/registration.page.js @@ -0,0 +1,70 @@ +import { BasePage } from './base.page'; +import { expect } from '@playwright/test'; + +class RegistrationPage extends BasePage { + constructor(page) { + super(page); + + // Локатори + this.signUpButton = page.locator('button:has-text("Sign up")'); + this.nameInput = page.locator('#signupName'); + this.lastNameInput = page.locator('#signupLastName'); + this.emailInput = page.locator('#signupEmail'); + this.passwordInput = page.locator('#signupPassword'); + this.repeatPasswordInput = page.locator('#signupRepeatPassword'); + this.registerButton = page.locator('button:text("Register")'); + + // Помилки валідації + this.nameError = page.locator('#signupName + .invalid-feedback'); + this.lastNameError = page.locator('#signupLastName + .invalid-feedback'); + this.emailError = page.locator('#signupEmail + .invalid-feedback'); + this.passwordError = page.locator('#signupPassword + .invalid-feedback'); + this.repeatPasswordError = page.locator('#signupRepeatPassword + .invalid-feedback'); + } + + async navigateToRegistration() { + await this.navigate('https://guest:welcome2qauto@qauto.forstudy.space/'); + await this.click(this.signUpButton); + } + + async fillRegistrationForm(name, lastName, email, password, repeatPassword) { + await this.fill(this.nameInput, name); + await this.fill(this.lastNameInput, lastName); + await this.fill(this.emailInput, email); + await this.fill(this.passwordInput, password); + await this.fill(this.repeatPasswordInput, repeatPassword); + } + + async submitRegistration() { + await this.click(this.registerButton); + } + + async expectSuccessfulRegistration() { + await expect(this.page).toHaveURL(/panel\/garage/); + } + + async expectNameError(message) { + await expect(this.nameError).toHaveText(message); + await expect(this.nameInput).toHaveCSS('border-color', 'rgb(220, 53, 69)'); + } + + async expectEmailError(message) { + await expect(this.emailError).toHaveText(message); + await expect(this.emailInput).toHaveCSS('border-color', 'rgb(220, 53, 69)'); + } + + async expectPasswordError(message) { + await expect(this.passwordError).toHaveText(message); + await expect(this.passwordInput).toHaveCSS('border-color', 'rgb(220, 53, 69)'); + } + + async expectRepeatPasswordError(message) { + await expect(this.repeatPasswordError).toHaveText(message); + await expect(this.repeatPasswordInput).toHaveCSS('border-color', 'rgb(220, 53, 69)'); + } + + async expectRegisterButtonDisabled() { + await expect(this.registerButton).toBeDisabled(); + } +} +export {RegistrationPage}; \ No newline at end of file diff --git a/playwright.config.js b/playwright.config.js index eefe573..0c5d1c2 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -38,17 +38,18 @@ export default defineConfig({ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, - }, + } + //, - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, + // { + // name: 'firefox', + // use: { ...devices['Desktop Firefox'] }, + // }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, /* Test against mobile viewports. */ // { diff --git a/tests-examples/demo-todo-app.spec.js b/tests-examples/demo-todo-app.spec.js deleted file mode 100644 index 4449561..0000000 --- a/tests-examples/demo-todo-app.spec.js +++ /dev/null @@ -1,449 +0,0 @@ -// @ts-check -import { test, expect } 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) { - // 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'); - } -} - -/** - * @param {import('@playwright/test').Page} page - * @param {number} expected - */ - async function checkNumberOfTodosInLocalStorage(page, expected) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).length === e; - }, expected); -} - -/** - * @param {import('@playwright/test').Page} page - * @param {number} expected - */ - async function checkNumberOfCompletedTodosInLocalStorage(page, expected) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).filter(i => i.completed).length === e; - }, expected); -} - -/** - * @param {import('@playwright/test').Page} page - * @param {string} title - */ -async function checkTodosInLocalStorage(page, title) { - return await page.waitForFunction(t => { - return JSON.parse(localStorage['react-todos']).map(i => i.title).includes(t); - }, title); -} diff --git a/tests/example.spec.js b/tests/example.spec.js deleted file mode 100644 index 26ed206..0000000 --- a/tests/example.spec.js +++ /dev/null @@ -1,19 +0,0 @@ -// @ts-check -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/tests/registration/registration.spec.js b/tests/registration/registration.spec.js new file mode 100644 index 0000000..4cb2d93 --- /dev/null +++ b/tests/registration/registration.spec.js @@ -0,0 +1,106 @@ +import { test, expect } from '@playwright/test'; +import { RegistrationPage } from '/Users/ira/Desktop/PlaywrightTest/pages/registration.page.js'; + +test.describe('User Registration Tests', () => { + let registrationPage; + const timestamp = Date.now(); + const email = `aqa-${timestamp}@test.com`; + + const testData = { + name: 'Ira', + invalidName: 'I', + lastName: 'Herashchenko', + correctPassword: 'Password123', + incorrectPassword: 'short', + differentPassword: 'Different456', + invalidEmail: 'invalid-email' + }; + + test.beforeEach(async ({ page }) => { + registrationPage = new RegistrationPage(page); + await registrationPage.navigateToRegistration(); + }); + + test('Successful user registration', async () => { + await registrationPage.fillRegistrationForm( + testData.name, + testData.lastName, + email, + testData.correctPassword, + testData.correctPassword + ); + + await registrationPage.submitRegistration(); + await registrationPage.expectSuccessfulRegistration(); + }); + + test('Empty Name field validation', async () => { + await registrationPage.nameInput.focus(); + await registrationPage.fillRegistrationForm( + '', + testData.lastName, + email, + testData.correctPassword, + testData.correctPassword + ); + + await registrationPage.expectNameError('Name required'); + await registrationPage.expectRegisterButtonDisabled(); + }); + + test('Invalid Email validation', async () => { + await registrationPage.fillRegistrationForm( + testData.name, + testData.lastName, + testData.invalidEmail, + testData.correctPassword, + testData.correctPassword + ); + + await registrationPage.expectEmailError('Email is incorrect'); + await registrationPage.expectRegisterButtonDisabled(); + }); + + test('Password requirements validation', async () => { + await registrationPage.fillRegistrationForm( + testData.name, + testData.lastName, + email, + testData.incorrectPassword, + testData.incorrectPassword + ); + + await registrationPage.expectPasswordError( + 'Password has to be from 8 to 15 characters long and contain at least one integer, one capital, and one small letter' + ); + await registrationPage.expectRegisterButtonDisabled(); + }); + + test('Password mismatch validation', async () => { + await registrationPage.fillRegistrationForm( + testData.name, + testData.lastName, + email, + testData.correctPassword, + testData.differentPassword + ); + + await registrationPage.nameInput.focus(); // Trigger validation + + await registrationPage.expectRepeatPasswordError('Passwords do not match'); + await registrationPage.expectRegisterButtonDisabled(); + }); + + test('Name length validation', async () => { + await registrationPage.fillRegistrationForm( + testData.invalidName, + testData.lastName, + email, + testData.correctPassword, + testData.correctPassword + ); + + await registrationPage.expectNameError('Name has to be from 2 to 20 characters long'); + await registrationPage.expectRegisterButtonDisabled(); + }); +}); \ No newline at end of file From eea7304985b25be2f510a6bbf9ce265184aaa9bf Mon Sep 17 00:00:00 2001 From: Iryna Herashchenko Date: Sun, 13 Apr 2025 02:05:50 +0200 Subject: [PATCH 2/4] Homework25 --- .env | 3 +++ package-lock.json | 15 +++++++++++++++ package.json | 3 +++ pages/registration.page.js | 2 +- playwright.config.js | 6 +++++- 5 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..2137afe --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +BASE_URL=https://qauto.forstudy.space +HTTP_CREDENTIALS_USERNAME=guest +HTTP_CREDENTIALS_PASSWORD=welcome2qauto \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index eaa933a..db99c31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "playwrighttest", "version": "1.0.0", "license": "ISC", + "dependencies": { + "dotenv": "^16.5.0" + }, "devDependencies": { "@playwright/test": "^1.51.1", "@types/node": "^22.14.0" @@ -39,6 +42,18 @@ "undici-types": "~6.21.0" } }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", diff --git a/package.json b/package.json index 8b93b57..6e63a68 100644 --- a/package.json +++ b/package.json @@ -10,5 +10,8 @@ "devDependencies": { "@playwright/test": "^1.51.1", "@types/node": "^22.14.0" + }, + "dependencies": { + "dotenv": "^16.5.0" } } diff --git a/pages/registration.page.js b/pages/registration.page.js index 173d524..46d17f3 100644 --- a/pages/registration.page.js +++ b/pages/registration.page.js @@ -23,7 +23,7 @@ class RegistrationPage extends BasePage { } async navigateToRegistration() { - await this.navigate('https://guest:welcome2qauto@qauto.forstudy.space/'); + await this.navigate(`https://${process.env.HTTP_CREDENTIALS_USERNAME}:${process.env.HTTP_CREDENTIALS_PASSWORD}@${process.env.BASE_URL}`); await this.click(this.signUpButton); } diff --git a/playwright.config.js b/playwright.config.js index 0c5d1c2..15fd05a 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -27,7 +27,11 @@ export default defineConfig({ /* 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', + baseURL: process.env.BASE_URL, + httpCredentials: { + username: process.env.HTTP_CREDENTIALS_USERNAME, + password: process.env.HTTP_CREDENTIALS_PASSWORD, + }, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', From 9958afa2eaa344a32a36535d3b9217638df8283d Mon Sep 17 00:00:00 2001 From: Iryna Herashchenko Date: Tue, 15 Apr 2025 10:11:21 +0200 Subject: [PATCH 3/4] homework25 --- .env | 6 +++--- package-lock.json | 7 +++---- package.json | 4 +--- pages/base.page.js | 9 ++++++--- pages/registration.page.js | 9 ++++++++- playwright.config.js | 31 ++++++++++++++----------------- 6 files changed, 35 insertions(+), 31 deletions(-) diff --git a/.env b/.env index 2137afe..4d280cb 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -BASE_URL=https://qauto.forstudy.space -HTTP_CREDENTIALS_USERNAME=guest -HTTP_CREDENTIALS_PASSWORD=welcome2qauto \ No newline at end of file +BASE_URL=qauto.forstudy.space +HTTP_USERNAME=guest +HTTP_PASSWORD=welcome2qauto \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index db99c31..54d73a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,10 @@ "name": "playwrighttest", "version": "1.0.0", "license": "ISC", - "dependencies": { - "dotenv": "^16.5.0" - }, "devDependencies": { "@playwright/test": "^1.51.1", - "@types/node": "^22.14.0" + "@types/node": "^22.14.0", + "dotenv": "^16.5.0" } }, "node_modules/@playwright/test": { @@ -46,6 +44,7 @@ "version": "16.5.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" diff --git a/package.json b/package.json index 6e63a68..4d856a7 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,7 @@ "description": "", "devDependencies": { "@playwright/test": "^1.51.1", - "@types/node": "^22.14.0" - }, - "dependencies": { + "@types/node": "^22.14.0", "dotenv": "^16.5.0" } } diff --git a/pages/base.page.js b/pages/base.page.js index bcc0fea..88ec5f6 100644 --- a/pages/base.page.js +++ b/pages/base.page.js @@ -2,9 +2,12 @@ export class BasePage { constructor(page) { this.page = page; } - - async navigate(url) { - await this.page.goto(url); + + async logNavigationDetails(url) { + console.log('--- NAVIGATION DEBUG ---'); + console.log('Constructed URL:', url); + console.log('Environment BASE_URL:', process.env.BASE_URL); + console.log('Current page URL (before):', await this.page.url()); } async click(locator) { diff --git a/pages/registration.page.js b/pages/registration.page.js index 46d17f3..9410e64 100644 --- a/pages/registration.page.js +++ b/pages/registration.page.js @@ -23,7 +23,14 @@ class RegistrationPage extends BasePage { } async navigateToRegistration() { - await this.navigate(`https://${process.env.HTTP_CREDENTIALS_USERNAME}:${process.env.HTTP_CREDENTIALS_PASSWORD}@${process.env.BASE_URL}`); + const config = this.page.context()._options; + + // Debug logging (optional) + console.log('Base URL:', config.baseURL); + console.log('Using login:', config.httpCredentials?.username); + console.log('Using password:', config.httpCredentials?.password); + this.logNavigationDetails(config.baseURL); + await this.page.goto('/'); await this.click(this.signUpButton); } diff --git a/playwright.config.js b/playwright.config.js index 15fd05a..cc96fdb 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -1,37 +1,34 @@ -// @ts-check +// @ts-nocheck + import { defineConfig, devices } from '@playwright/test'; -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// import dotenv from 'dotenv'; -// import path from 'path'; -// dotenv.config({ path: path.resolve(__dirname, '.env') }); +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: process.env.BASE_URL, httpCredentials: { - username: process.env.HTTP_CREDENTIALS_USERNAME, - password: process.env.HTTP_CREDENTIALS_PASSWORD, + username: process.env.HTTP_USERNAME, + password: process.env.HTTP_PASSWORD }, + // use: { + // baseURL: 'https://qauto.forstudy.space/', + // httpCredentials: { + // username: 'guest', + // password: 'welcome2qauto', + // }, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', From 5475126fe798b9e40fe1b682c49cd637d1dd5317 Mon Sep 17 00:00:00 2001 From: Iryna Herashchenko Date: Tue, 15 Apr 2025 11:58:05 +0200 Subject: [PATCH 4/4] fix url --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 4d280cb..52d736c 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -BASE_URL=qauto.forstudy.space +BASE_URL=https://qauto.forstudy.space/ HTTP_USERNAME=guest HTTP_PASSWORD=welcome2qauto \ No newline at end of file