diff --git a/playwright/PageObjects/ChatsElements/GifPicker.ts b/playwright/PageObjects/ChatsElements/GifPicker.ts index f22ecc0..1074758 100644 --- a/playwright/PageObjects/ChatsElements/GifPicker.ts +++ b/playwright/PageObjects/ChatsElements/GifPicker.ts @@ -1,11 +1,77 @@ -import MainPage from "../MainPage"; -import { type Locator, type Page } from "@playwright/test"; +import { type Locator, type Page, expect } from "@playwright/test"; +import { CombinedSelector } from "./CombinedSelector"; -export class GifPicker extends MainPage { - readonly combinedSelector: Locator; +export class GifPicker extends CombinedSelector { + readonly allFavoritesButton: Locator; + readonly allGifs: Locator; + readonly favoriteGifs: Locator; + readonly gifContainer: Locator; + readonly gifFavoriteButton: Locator; + readonly gifImage: Locator; + readonly gifsSizeLabel: Locator; + readonly gifsSizeRangeSelector: Locator; + readonly gifsSizeRangeSelectorInput: Locator; + readonly searchInput: Locator; + readonly textNoFavoritesYet: Locator; constructor(public readonly page: Page) { super(page); - this.combinedSelector = this.page.getByTestId("combined-selector"); + this.allFavoritesButton = this.page.getByTestId( + "giphy-selector-favorites-button", + ); + this.allGifs = this.page.getByTestId("giphy-selector-gifs"); + this.favoriteGifs = this.page.getByTestId("giphy-selector-favorites"); + this.gifContainer = this.page.getByTestId("gif-container"); + this.gifFavoriteButton = this.gifContainer.getByTestId( + "gif-container-favorite-button", + ); + this.gifImage = this.gifContainer.locator("img"); + this.gifsSizeLabel = this.page.getByTestId("giphy-selector-label-size"); + this.gifsSizeRangeSelector = this.page.getByTestId("range-selector"); + this.gifsSizeRangeSelectorInput = this.page.getByTestId( + "range-selector-input", + ); + this.searchInput = this.page.getByTestId("giphy-selector-search-bar"); + this.textNoFavoritesYet = this.page.getByTestId("text-no-favorites-yet"); + } + + async changeGifSizeView(size: string) { + await this.gifsSizeRangeSelectorInput.fill(size); + } + + async getGifAltText(index: number) { + const textOfGif = await this.gifContainer + .nth(index) + .locator("img") + .getAttribute("alt"); + return textOfGif; + } + + async searchGif(gifText: string) { + await this.searchInput.focus(); + await this.page.keyboard.type(gifText); + await this.page.waitForTimeout(1000); + } + + async selectGif(gifText: string) { + await this.page + .getByTestId("gif-container") + .filter({ + has: this.page.getByAltText(gifText), + }) + .first() + .click(); + await this.page.waitForTimeout(2000); + } + + async validateSingleGifSize(gifText: string, expectedSize: string) { + const gifLocator = this.page.getByTestId("gif-container").filter({ + has: this.page.getByAltText(gifText), + }); + await expect(gifLocator).toHaveCSS("font-size", expectedSize); + } + + async waitForGifsToLoad() { + await this.page.waitForTimeout(2000); } } diff --git a/playwright/PageObjects/ChatsElements/StickerPicker.ts b/playwright/PageObjects/ChatsElements/StickerPicker.ts index c578a12..add1676 100644 --- a/playwright/PageObjects/ChatsElements/StickerPicker.ts +++ b/playwright/PageObjects/ChatsElements/StickerPicker.ts @@ -1,11 +1,104 @@ -import MainPage from "../MainPage"; -import { type Locator, type Page } from "@playwright/test"; +import { type Locator, type Page, expect } from "@playwright/test"; +import { CombinedSelector } from "./CombinedSelector"; -export class StickerPicker extends MainPage { - readonly combinedSelector: Locator; +export class StickerPicker extends CombinedSelector { + readonly allStickers: Locator; + readonly stickerCollection: Locator; + readonly stickerCollectionItem: Locator; + readonly stickerCollectionItemImage: Locator; + readonly stickerCollectionItemName: Locator; + readonly stickerCollectionLabel: Locator; + readonly stickerSearchInput: Locator; + readonly stickerSelectorSidebar: Locator; + readonly stickerSidebarCollection: Locator; + readonly stickerSelectorSidebarLabel: Locator; constructor(public readonly page: Page) { super(page); - this.combinedSelector = this.page.getByTestId("combined-selector"); + this.allStickers = this.page.getByTestId("sticker-contents"); + this.stickerCollection = this.page.getByTestId("sticker-collection"); + this.stickerCollectionItem = this.page.getByTestId( + "sticker-collection-item", + ); + this.stickerCollectionItemImage = this.stickerCollectionItem.locator("img"); + this.stickerCollectionItemName = this.stickerCollectionItem.getByTestId( + "sticker-collection-item-name", + ); + this.stickerCollectionLabel = this.page.getByTestId( + "sticker-collection-label", + ); + this.stickerSelectorSidebar = this.page.getByTestId( + "sticker-selector-sidebar", + ); + this.stickerSidebarCollection = this.page.getByTestId( + "sticker-sidebar-collection", + ); + this.stickerSelectorSidebarLabel = this.page.getByTestId( + "sticker-selector-sidebar-label", + ); + } + + async navigateThroughStickerCategories(collectionName: string) { + await this.page.getByLabel("Jump to " + collectionName).click(); + await this.page + .locator('[id="' + collectionName + '"]') + .waitFor({ state: "visible" }); + } + + async selectSticker(collectionName: string, stickerName: string) { + const stickerCollection = this.page.locator( + '[id="' + collectionName + '"]', + ); + const stickerCollectionItem = stickerCollection + .getByTestId("sticker-collection-item") + .filter({ + has: this.page.getByAltText(stickerName), + }); + await stickerCollectionItem.click(); + await this.page.waitForTimeout(2000); + } + + async searchSticker(stickerText: string) { + await this.stickerSearchInput.focus(); + await this.page.keyboard.type(stickerText); + await this.page.waitForTimeout(1000); + } + + async validateStickerCategories(expectedCategories: string[]) { + // Define an array to store section names + const sectionNames = []; + + // Select all section elements (assuming they have a data-cy attribute ending with '-section') + const sections = await this.page.$$( + `section[data-cy$="sticker-collection"]`, + ); + + // Loop through each section and find its corresponding label + for (const section of sections) { + // Find the label within the current section that ends with '-label' + const label = await section.$( + `label[data-cy$="sticker-collection-label"]`, + ); + if (label) { + const sectionName = await label.textContent(); + sectionNames.push(sectionName.trim()); + } + } + expect(sectionNames).toEqual(expectedCategories); + } + + async validateNumberOfStickersPerSection( + collectionName: string, + expectedNumber: number, + ) { + const stickerCount = await this.page + .locator('[id="' + collectionName + '"]') + .getByTestId("sticker-collection-item") + .count(); + expect(stickerCount).toEqual(expectedNumber); + } + + async waitForStickersToLoad() { + await this.page.waitForTimeout(2000); } } diff --git a/playwright/PageObjects/MainPage.ts b/playwright/PageObjects/MainPage.ts index e5be75b..cdbf23d 100644 --- a/playwright/PageObjects/MainPage.ts +++ b/playwright/PageObjects/MainPage.ts @@ -12,8 +12,10 @@ export default class MainPage { readonly buttonWallet: Locator; readonly chatPreview: Locator; readonly chatPreviewLastMessage: Locator; + readonly chatPreviewLastMessageImage: Locator; readonly chatPreviewName: Locator; readonly chatPreviewPicture: Locator; + readonly chatPreviewPictureIdenticon: Locator; readonly chatPreviewPictureImage: Locator; readonly chatPreviewStatusIndicator: Locator; readonly chatPreviewTimestamp: Locator; @@ -47,8 +49,12 @@ export default class MainPage { this.chatPreviewLastMessage = this.page.getByTestId( "chat-preview-last-message", ); + this.chatPreviewLastMessageImage = + this.chatPreviewLastMessage.locator("img"); this.chatPreviewName = this.page.getByTestId("chat-preview-name"); this.chatPreviewPicture = this.page.getByTestId("chat-preview-picture"); + this.chatPreviewPictureIdenticon = + this.chatPreviewPicture.locator(".identicon img"); this.chatPreviewPictureImage = this.chatPreviewPicture.locator("img"); this.chatPreviewStatusIndicator = this.chatPreview.getByTestId("status-indicator"); @@ -156,13 +162,6 @@ export default class MainPage { return svgString.replace(/(width|height)="\d+"/g, ""); } - async openContextMenuOnChatPreview(chatName: string) { - await this.page - .getByTestId("chat-preview-name") - .filter({ hasText: chatName }) - .click({ button: "right" }); - } - async visitOtherSite(url: string) { await this.page.goto(url); } @@ -224,4 +223,51 @@ export default class MainPage { async waitForToastNotificationToDisappear() { await this.toastNotification.waitFor({ state: "detached" }); } + + // Chat Preview Methods + async openContextMenuOnChatPreview(chatName: string) { + await this.page + .getByTestId("chat-preview-name") + .filter({ hasText: chatName }) + .click({ button: "right" }); + } + + async validateChatPreviewMessageImage( + chatName: string, + expectedAltText: string, + ) { + const chatPreviewLocator = this.page + .getByTestId("chat-preview-name") + .filter({ hasText: chatName }) + .locator("xpath=../../.."); + const imagePreview = chatPreviewLocator + .getByTestId("chat-preview-last-message") + .locator("img"); + const altText = await imagePreview.getAttribute("alt"); + const timestamp = await chatPreviewLocator + .getByTestId("chat-preview-timestamp") + .textContent(); + const statusIndicator = chatPreviewLocator.getByTestId("status-indicator"); + await expect(imagePreview).toBeVisible(); + expect(altText).toEqual(expectedAltText); + expect(timestamp).toEqual("just now"); + expect(statusIndicator).toHaveClass(/.*\bonline\b.*/); + } + + async validateChatPreviewMessageText(chatName: string, expectedText: string) { + const chatPreviewLocator = this.page + .getByTestId("chat-preview-name") + .filter({ hasText: chatName }) + .locator("xpath=../../.."); + const text = await chatPreviewLocator + .getByTestId("chat-preview-last-message") + .textContent(); + const timestamp = await chatPreviewLocator + .getByTestId("chat-preview-timestamp") + .textContent(); + const statusIndicator = chatPreviewLocator.getByTestId("status-indicator"); + expect(text).toEqual(expectedText); + expect(timestamp).toEqual("just now"); + expect(statusIndicator).toHaveClass(/.*\bonline\b.*/); + } } diff --git a/playwright/specs/03-friends-two-instances.spec.ts b/playwright/specs/03-friends-two-instances.spec.ts index de69d82..ff54de4 100644 --- a/playwright/specs/03-friends-two-instances.spec.ts +++ b/playwright/specs/03-friends-two-instances.spec.ts @@ -8,6 +8,8 @@ import { faker } from "@faker-js/faker"; import { SettingsProfile } from "playwright/PageObjects/Settings/SettingsProfile"; import { SettingsMessages } from "playwright/PageObjects/Settings/SettingsMessages"; import { EmojiPicker } from "playwright/PageObjects/ChatsElements/EmojiPicker"; +import { GifPicker } from "playwright/PageObjects/ChatsElements/GifPicker"; +import { StickerPicker } from "playwright/PageObjects/ChatsElements/StickerPicker"; const username = "ChatUserA"; const usernameTwo = "ChatUserB"; @@ -499,9 +501,17 @@ test.describe("Two instances tests - Friends and Chats", () => { await expect(chatsMainPageFirst.chatPreviewLastMessage).toHaveText( "Hello from the second user", ); + await chatsMainPageFirst.validateChatPreviewMessageText( + usernameTwo, + "Hello from the second user", + ); await expect(chatsMainPageSecond.chatPreviewLastMessage).toHaveText( "Hello from the second user", ); + await chatsMainPageSecond.validateChatPreviewMessageText( + username, + "Hello from the second user", + ); // C15 - Right clicking a chat in sidebar should open context menu // C16 - Context menu should display: Favorite, Hide, Mark as read @@ -1639,6 +1649,176 @@ test.describe("Two instances tests - Friends and Chats", () => { // Search for emojis in emoji picker await emojiPickerSecond.searchEmoji("mexico"); }); + + test("B67 - Sending and receiving GIFs and gif picker tests", async ({ + firstUserContext, + secondUserContext, + }) => { + // Declare constants required from the fixtures + const context1 = firstUserContext.context; + const page1 = firstUserContext.page; + const page2 = secondUserContext.page; + const friendsScreenFirst = new FriendsScreen(page1); + const friendsScreenSecond = new FriendsScreen(page2); + const chatsMainPageFirst = new ChatsMainPage(page1); + const chatsMainPageSecond = new ChatsMainPage(page2); + + // Setup accounts for testing + await setupChats( + chatsMainPageFirst, + chatsMainPageSecond, + context1, + friendsScreenFirst, + friendsScreenSecond, + page1, + ); + + // Change GIF size in gifs container view + await chatsMainPageSecond.openGifPicker(); + const gifPickerSecond = new GifPicker(page2); + await gifPickerSecond.waitForGifsToLoad(); + await gifPickerSecond.changeGifSizeView("100"); + await gifPickerSecond.changeGifSizeView("200"); + await gifPickerSecond.changeGifSizeView("150"); + + // Send a Gif to the other user + const gifToSelect = await gifPickerSecond.getGifAltText(0); + await gifPickerSecond.selectGif(gifToSelect); + + // Validate GIF sent is displayed on local and remote sides + const imageSent = chatsMainPageSecond.messageBubbleContent + .last() + .locator("img"); + const imageReceived = chatsMainPageFirst.messageBubbleContent + .last() + .locator("img"); + await expect(imageSent).toHaveAttribute("alt", gifToSelect); + await expect(imageSent).toBeVisible(); + await expect(imageReceived).toHaveAttribute("alt", gifToSelect); + await expect(imageReceived).toBeVisible(); + + // Validate GIF sent is displayed in chat preview from sidebar as last message sent + await chatsMainPageSecond.validateChatPreviewMessageImage( + username, + gifToSelect, + ); + await chatsMainPageFirst.validateChatPreviewMessageImage( + usernameTwo, + gifToSelect, + ); + + // Validate user can navigate through tabs in Gif picker + await chatsMainPageSecond.openGifPicker(); + await gifPickerSecond.goToStickersTab(); + await gifPickerSecond.goToEmojisTab(); + await gifPickerSecond.goToGifsTab(); + }); + + test("B68 - Sending and receiving stickers and sticker picker tests", async ({ + firstUserContext, + secondUserContext, + }) => { + // Declare constants required from the fixtures + const context1 = firstUserContext.context; + const page1 = firstUserContext.page; + const page2 = secondUserContext.page; + const friendsScreenFirst = new FriendsScreen(page1); + const friendsScreenSecond = new FriendsScreen(page2); + const chatsMainPageFirst = new ChatsMainPage(page1); + const chatsMainPageSecond = new ChatsMainPage(page2); + + // Setup accounts for testing + await setupChats( + chatsMainPageFirst, + chatsMainPageSecond, + context1, + friendsScreenFirst, + friendsScreenSecond, + page1, + ); + + await chatsMainPageSecond.openStickerPicker(); + const stickerPickerSecond = new StickerPicker(page2); + await stickerPickerSecond.waitForStickersToLoad(); + + // Send a Sticker to the other user + await stickerPickerSecond.selectSticker("Space Cat", "Power Up"); + + // Validate Sticker sent is displayed on local and remote sides + const imageSent = chatsMainPageSecond.messageBubbleContent + .last() + .locator("img"); + const imageReceived = chatsMainPageFirst.messageBubbleContent + .last() + .locator("img"); + await expect(imageSent).toHaveAttribute("alt", "Power Up"); + await expect(imageSent).toBeVisible(); + await expect(imageReceived).toHaveAttribute("alt", "Power Up"); + await expect(imageReceived).toBeVisible(); + + // Validate Sticker sent is displayed in chat preview from sidebar as last message sent + await chatsMainPageSecond.validateChatPreviewMessageImage( + username, + "Power Up", + ); + await chatsMainPageFirst.validateChatPreviewMessageImage( + usernameTwo, + "Power Up", + ); + + // Validate user can navigate through tabs in sticker picker + await chatsMainPageSecond.openStickerPicker(); + await stickerPickerSecond.goToEmojisTab(); + await stickerPickerSecond.goToGifsTab(); + await stickerPickerSecond.goToStickersTab(); + + // Validate sticker categories displayed in sticker container + const stickerCategories = [ + "Space Cat (Team Satellite)", + "Bad Animals (Team Satellite)", + "Anime (Team Satellite)", + "Words (Team Satellite)", + "Fishy Business (Team Satellite)", + "The Garden (Team Satellite)", + "Sassy Toons (Team Satellite)", + ]; + await stickerPickerSecond.validateStickerCategories(stickerCategories); + + // Validate number of stickers per category + await stickerPickerSecond.validateNumberOfStickersPerSection( + "Space Cat", + 16, + ); + await stickerPickerSecond.validateNumberOfStickersPerSection( + "Bad Animals", + 18, + ); + await stickerPickerSecond.validateNumberOfStickersPerSection("Anime", 13); + await stickerPickerSecond.validateNumberOfStickersPerSection("Words", 9); + await stickerPickerSecond.validateNumberOfStickersPerSection( + "Fishy Business", + 9, + ); + await stickerPickerSecond.validateNumberOfStickersPerSection( + "The Garden", + 9, + ); + await stickerPickerSecond.validateNumberOfStickersPerSection( + "Sassy Toons", + 5, + ); + + // Validate user can navigate through all categories of stickers + await stickerPickerSecond.navigateThroughStickerCategories("Space Cat"); + await stickerPickerSecond.navigateThroughStickerCategories("Bad Animals"); + await stickerPickerSecond.navigateThroughStickerCategories("Anime"); + await stickerPickerSecond.navigateThroughStickerCategories("Words"); + await stickerPickerSecond.navigateThroughStickerCategories( + "Fishy Business", + ); + await stickerPickerSecond.navigateThroughStickerCategories("The Garden"); + await stickerPickerSecond.navigateThroughStickerCategories("Sassy Toons"); + }); }); async function setupChats(