Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,69 @@ import {Locator, Page} from '@playwright/test';

/** POM for the "collection". This page is accessible by searching for a message within a conversation. */
export class CollectionPage {
readonly page: Locator;
readonly page: Page;
readonly component: Locator;

constructor(page: Page) {
this.page = page.locator('#collection');
this.page = page;
this.component = page.locator('#collection');
}

get searchInput() {
return this.page.getByRole('textbox', {name: 'Search text messages'});
return this.component.getByRole('textbox', {name: 'Search text messages'});
}

get searchItems() {
return this.page.getByTestId('full-search-item');
return this.component.getByTestId('full-search-item');
}

async searchForMessages(search: string) {
await this.searchInput.fill(search);
}

get imagesSection() {
return this.component.locator('section').filter({has: this.page.locator('header', {hasText: 'Images'})});
}

get audioSection() {
return this.component.locator('section').filter({has: this.page.locator('header', {hasText: 'Audio'})});
}

get filesSection() {
return this.component.locator('section').filter({has: this.page.locator('header', {hasText: 'Files'})});
}

get overviewImagesButton() {
return this.imagesSection.getByRole('button', {name: /Show all/i});
}

get overviewFilesButton() {
return this.filesSection.getByRole('button', {name: /Show all/i});
}
Comment on lines +44 to +62
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if there's a new type of section, e.g. the one for the links? -> You'd have to add two new functions, one to get the section and one for the show all button. This is just code duplication and not very scaleable.

Here's a trick how you can combine all of this into one small package, by leveraging Object.assign:

Suggested change
get imagesSection() {
return this.component.locator('section').filter({has: this.page.locator('header', {hasText: 'Images'})});
}
get audioSection() {
return this.component.locator('section').filter({has: this.page.locator('header', {hasText: 'Audio'})});
}
get filesSection() {
return this.component.locator('section').filter({has: this.page.locator('header', {hasText: 'Files'})});
}
get overviewImagesButton() {
return this.imagesSection.getByRole('button', {name: /Show all/i});
}
get overviewFilesButton() {
return this.filesSection.getByRole('button', {name: /Show all/i});
}
getSection(type: 'Images' | 'Audio' | 'Files') {
const section = this.component.locator('section').filter({has: this.page.locator('header', {hasText: type})});
return Object.assign(section, {
showAllButton: section.getByRole('button', {name: 'Show all'}),
});
}

Instead of returning only the locator for the wanted section, we add a new property showAllButton to it and then return it. This way the returned locator can still be used like any other e.g. inside an expect or to chain off other locators from it. But we can also access the showAllButton using getSection('Images').showAllButton on it. A neat trick for when you want to add util to something returned by an other util but it's not worth creating a whole new POM for it ;)


get fullSearchBar() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ Why "fullSearchBar" and not just "searchBar"?

return this.component.getByRole('textbox', {name: 'Search text messages'});
}

get noResultsMessage() {
return this.component.getByText('No results.', {exact: true});
}

/**
* Returns a locator for the highlighted (marked) text within the search results.
* @param searchTerm The text you expect to be highlighted.
*/
getMarkedSearchResult(searchTerm: string): Locator {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes a util useless if you need to pass in what you're searching for. Maybe a locator for all searchResults in general could be more useful. Then we could assert on the number of results, or filter them or find the marked texts inside. :)

This would also replace the resultTexts() util below as we could just assert on the text in the results in general instead of having a util for it.

return this.component.locator('mark').filter({hasText: searchTerm});
}

/** Locates the text content of every search result item */
get resultTexts() {
return this.component.locator('[data-uie-name="full-search-item-text"]');
}

/** Gets all result texts as an array of strings */
async getAllResultTexts(): Promise<string[]> {
return await this.resultTexts.allInnerTexts();
}
}
Loading