Skip to content

Commit

Permalink
Remove unused imports and fix files naming
Browse files Browse the repository at this point in the history
  • Loading branch information
Taras Yatsynych authored and Yatsynych-T committed Dec 4, 2023
1 parent 84de993 commit 9e8ba95
Show file tree
Hide file tree
Showing 5 changed files with 687 additions and 0 deletions.
131 changes: 131 additions & 0 deletions src/test/playwright/PO/BasePage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { expect } from "@playwright/test";

class BasePage {
constructor(page) {
this.page = page;
this.navBarCityDropdown = page.locator("header > div.right-side-menu div.city");
this.navBarCityDropdownList = page.locator("body > div:last-child ul");
this.paginationNextPageButton = page.locator('ul > li[title="Next Page"]');
this.paginationFirstPage = page.locator('li[title="1"]');
}

async expectElementToHaveText(element, text) {
await expect(element).toHaveText(text);
}

async expectElementToContainText(element, text) {
await expect(element).toContainText(text);
}

async expectElementToNotContainText(element, text) {
await expect(element).not.toContainText(text);
}

async assertTextContains(text, searchText) {
const doesContain = text.includes(searchText);
expect(doesContain).toBe(true);
}

async verifyElementVisibility(element, isVisible = true) {
if (!(typeof isVisible === "boolean")) {
throw new Error("Second paramenter should be boolean");
}
isVisible
? await expect(element, ' should be visible').toBeVisible()
: await expect(element, 'should NOT be visible').not.toBeVisible();
}

async isElementWithNamePresent(allElements, name){
const elementsTextContents = await allElements.allTextContents();
if (await elementsTextContents.includes(name)) {
return true;
} else if (await this.isNextPageAvailable()) {
// If the element is not found on this page, check if there's a next page and recursively search
await this.goToNextPage();
return await this.isElementWithNamePresent(allElements, name);
} else {
// If the element is not found and there are no more pages, return false
return false;
}
}

//use the method above to make assertion
async verifyElementExistance(allElements, name, doesExist = true) {
if (await this.isItFirstPage()) {
await this.paginationFirstPage.click();
}
const isElementPresent = await this.isElementWithNamePresent(allElements, name);
doesExist ? expect(isElementPresent).toBe(true) : expect(isElementPresent).toBe(false);
}

async verifyUrl(expectedUrl) {
const currentUrl = await this.page.url();
expect(currentUrl).toBe(expectedUrl);
}

async isNextPageAvailable() {
return (
(await this.paginationNextPageButton.isVisible()) &&
(await this.paginationNextPageButton.getAttribute("aria-disabled")) !== "true"
);
}

async isItFirstPage() {
return (
(await this.paginationFirstPage.isVisible()) &&
!(await this.paginationFirstPage.getAttribute("ant-pagination-item-active"))
);
}

async goToNextPage() {
await this.paginationNextPageButton.click();
}

async goToNextPageIfAvailabe(actionsOnThePage = async () => {}) {
if (await this.isNextPageAvailable()) {
await this.goToNextPage();
await actionsOnThePage();
}
}

/*
*This method can be used to check whether the element is present and, if visible,
*has the required text.
*It combines both checks to reduce code duplication when
*verifying error messages' presence or absence.
*/
async verifyElementVisibilityAndText(element, isVisible = true, text) {
await this.verifyElementVisibility(element, isVisible);
if (isVisible === true) {
await this.expectElementToHaveText(element, text);
}
}

async fillInputField(element, value) {
await element.waitFor({ timeout: 5000 });
await element.click();
await element.clear();
await element.fill(value);
}

async selectCityInNavBar(city) {
await this.navBarCityDropdown.click();
await (await this.navBarCityDropdownList.getByText(city)).click();
}

async sortElementsAsc([...elements]) {
return elements.sort();
}

async sortElementsDesc([...elements]) {
return elements.sort((a, b) => b - a);
}

async verifyTooltipAppearsOnHover(selector, message) {
await selector.hover();
const tooltip = this.page.locator("div.ant-tooltip-inner").filter({ hasText: `${message}` });
await this.verifyElementVisibility(tooltip, true);
}
}

module.exports = BasePage;
149 changes: 149 additions & 0 deletions src/test/playwright/PO/ClubsPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { expect} from "@playwright/test";
import {CLUBS_URL} from "../constants/api.constants";
import BasePage from "./BasePage";

class ClubsPage extends BasePage {
constructor(page) {
super(page);
this.clubsPageTitle = page.locator(".city-name");
this.searchField = page.locator('div.search-container input[type="search"]');
this.searchButton = page.locator('span[aria-label="search"]');
this.cards = page.locator("div.ant-card");
this.clubsNames = page.locator("div.title");
this.clubsCategories = page.locator("div.club-tags-box span.name");
this.clubsDescriptions = page.locator("p.description");
this.clubsANDcategories = page.locator("span.and");
this.clubDetailsCategories = page.locator("div.tags.categories span.name");
this.clubDetailsCloseButton = page.locator('button[aria-label="Close"]');
this.paginationNextPageButton = page.locator('ul > li[title="Next Page"]');
this.paginationFirstPageButton = page.locator('ul > li[title="1"]');
this.advancedSearchButton = page.locator('span[title="Розширений пошук"]');
this.firstCardTitle = page.locator("div.content-clubs-list > div:first-child div.name");

this.noResultsMessage = page.locator('div.clubs-not-found');
}

async gotoClubsPage() {
await this.page.goto(CLUBS_URL);
}

// Click the advanced search button and wait for a short timeout for clubs to update
async toggleAdvancedSearch() {
await this.advancedSearchButton.click();
await this.page.waitForTimeout(500);
}

/*
* Method to accumulate titles of all club cards
* Iterates through pages of club cards, accumulating their titles
* Uses the firstTitleLocator to ensure that previous clubs have disappeared
* from the page before adding new titles to the array
*/
async getAllClubsTitles() {
let allClubsTitles = [];
while (true) {
try {
const firstTitle = await this.firstCardTitle.textContent();
const firstTitleLocator = await this.page.getByRole("div", { name: firstTitle });
const pageTitlesText = await this.clubsNames.allTextContents();
allClubsTitles = allClubsTitles.concat(pageTitlesText);
console.log(pageTitlesText);
if (await this.isNextPageAvailable()) {
await this.goToNextPage();
await firstTitleLocator.waitFor({ state: "hidden", timeout: 10000 });
} else {
break;
}
} catch (e) {
console.error("Error " + e);
break;
}
}
return allClubsTitles;
}

/*
* Asserts that accumulated club titles are sorted in ascending order
*/
async verifyClubsSortedByTitlesAsc() {
const originalClubsTitles = await this.getAllClubsTitles();
const sortedClubsTitles = await this.sortElementsAsc(originalClubsTitles);
expect(originalClubsTitles).toMatchObject(sortedClubsTitles);
}

// Check if the next page button is visible and enabled
async isNextPageAvailable() {
return (
(await this.paginationNextPageButton.isVisible()) &&
(await this.paginationNextPageButton.getAttribute("aria-disabled")) !== "true"
);
}

async goToNextPage() {
await this.paginationNextPageButton.click();
}

async simpleSearchByQuery(query) {
const firstTitle = await this.firstCardTitle.textContent();
const firstTitleLocator = await this.page.getByRole("div", { name: firstTitle });
await this.searchField.clear();
await this.searchField.fill(query);
await this.searchButton.click();
await firstTitleLocator.waitFor({ state: "detached", timeout: 10000 });
}

/*
* Navigates to the next page if available and executes additional actions on the page.
* @param {Function} actionsOnThePage - Optional function to perform additional actions on the page.
* Defaults to an empty async function.
*/
async goToNextPageIfAvailabe(actionsOnThePage = async () => {}) {
if (await this.isNextPageAvailable()) {
await this.goToNextPage();
await actionsOnThePage();
}
}

async openCardDetailsPopUp(card) {
await card.locator(this.clubsNames).click();
}

async closeCardDetailsPopUp() {
await this.clubDetailsCloseButton.click();
}

async goToFirstPage() {
await this.paginationFirstPageButton.click();
}

/*
* Method to verify that club cards contain the specified text
* Iterates through club cards, comparing their text with the search query
* Opens card details to check for additional categories, if any
* Utilizes recursion to iterate through all pages
*/
async verifyClubCardsContainText(text) {
text = text.toLowerCase();
const cards = await this.cards.all();
if (await cards.length === 0) {
throw new Error("There are no result for this search query!");
}
for (let card of cards) {
const cardANDcategory = await card.locator(this.clubsANDcategories).textContent();
if (cardANDcategory.length > 0) {
await this.openCardDetailsPopUp(card);
const cardCategories = (await this.clubDetailsCategories.allTextContents()).join("; ").toLowerCase();
await this.closeCardDetailsPopUp();
card = ((await card.textContent()) + cardCategories).toLowerCase();
} else {
card = (await card.textContent()).toLowerCase();
}
await this.assertTextContains(card, text);
}
await this.goToNextPageIfAvailabe(async () => {
await this.verifyClubCardsContainText(text);
});
}
}

module.exports = ClubsPage;
50 changes: 50 additions & 0 deletions src/test/playwright/PO/HomePage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ADMIN_EMAIL, ADMIN_PASSWORD, USER_EMAIL, USER_PASSWORD } from "../constants/general.constants";
import {API_URL} from "../constants/api.constants";
import {ADD_CLUB_PAGE} from "../constants/locatorsText.constants";
import { SUCCESS_LOGIN_MESSAGE } from "../constants/messages.constants";
import BasePage from "./BasePage";

class HomePage extends BasePage{
constructor(page){
super(page);
this.citiesDropdown = page.locator('.ant-dropdown-trigger.city');
this.userDropdown = page.locator('.ant-dropdown-trigger.user-profile');
this.registerButton = page.getByRole('menuitem', { name: 'Увійти' });
this.emailField = page.locator('input#basic_email');
this.passwordField = page.locator('input#basic_password');
this.loginButton = page.locator('button.login-button');
this.loginSuccessMessage = page.locator('div.ant-message-success span:nth-child(2)');
this.addClubButton = this.page.getByRole("button", { name: ADD_CLUB_PAGE.addClub });
this.harkivItem = page.getByRole('menuitem', { name: 'Харків' })
}

async gotoHomepage(){
await this.page.goto(API_URL)
}

async openAddClubPage() {
await this.page.goto(API_URL);
await this.addClubButton.click();
}

async uiLoginAs(userType){
const userData = {
admin: { email: ADMIN_EMAIL, password: ADMIN_PASSWORD },
user: { email: USER_EMAIL, password: USER_PASSWORD },
};
await this.userDropdown.click();
await this.registerButton.click();

if (!userData[userType]) {
throw new Error("Invalid user type: " + userType);
}

await this.emailField.fill(userData[userType].email);
await this.passwordField.fill(userData[userType].password);

await this.loginButton.click();
await this.expectElementToHaveText(this.loginSuccessMessage, SUCCESS_LOGIN_MESSAGE);
}
}

module.exports = HomePage;
Loading

0 comments on commit 9e8ba95

Please sign in to comment.