Skip to content

Comments

test: implement regression tests for in conversation search [WPB-19955]#20492

Draft
JacquelineLehner wants to merge 3 commits intodevfrom
19955-in-conversation-search
Draft

test: implement regression tests for in conversation search [WPB-19955]#20492
JacquelineLehner wants to merge 3 commits intodevfrom
19955-in-conversation-search

Conversation

@JacquelineLehner
Copy link
Collaborator

@JacquelineLehner JacquelineLehner commented Feb 23, 2026

TaskWPB-19955 [Web/QA] Write the In Conversation Search regression tests in Playwright

Pull Request

Summary

  • add regression tests for in conversation search

Security Checklist (required)

  • External inputs are validated & sanitized on client and/or server where applicable.
  • API responses are validated; unexpected shapes are handled safely (fallbacks or errors).
  • No unsafe HTML is rendered; if unavoidable, sanitization is applied and documented where it happens.
  • Injection risks (XSS/SQL/command) are prevented via safe APIs and/or escaping.

Accessibility (required)

Standards Acknowledgement (required)


Screenshots or demo (if the user interface changed)

Notes for reviewers

  • Trade-offs:
  • Follow-ups (linked issues):
  • Linked PRs (e.g. web-packages):

…ia collection

This commit introduces a new test suite to verify the in-conversation
search and media collection functionality.

Implemented scenarios include:
- Verifying the media overview for images, audio, and files
  (@TC-352, @TC-356, @TC-357, @TC-359).
- Searching for specific messages, links, and special characters,
  as well as testing search string trimming (@TC-385, @TC-391,
  @TC-398, @TC-403, @TC-405).
- Verifying that clicking a search result scrolls the relevant message
  into view (@TC-408).
- Ensuring deleted messages and media do not appear in search results
  or the media collection (@TC-360, @TC-392).

Note: Tests @TC-358 (overview of all links) and @TC-388 (text mixed
with link preview) are currently skipped due to the known bug
[WPB-22484].

Refs: WPB-19955
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
35.5% Duplication on New Code (required ≤ 5%)

See analysis details on SonarQube Cloud

@codecov
Copy link

codecov bot commented Feb 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 45.38%. Comparing base (68e19ae) to head (b21d4b1).

Additional details and impacted files
@@            Coverage Diff             @@
##              dev   #20492      +/-   ##
==========================================
- Coverage   45.38%   45.38%   -0.01%     
==========================================
  Files        1637     1637              
  Lines       40370    40370              
  Branches     8337     8337              
==========================================
- Hits        18323    18322       -1     
  Misses      20112    20112              
- Partials     1935     1936       +1     
Flag Coverage Δ
app_webapp 43.56% <ø> (-0.01%) ⬇️
lib_api_client 50.50% <ø> (ø)
lib_core 58.86% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.
see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 23, 2026

🔗 Download Full Report Artifact

🧪 Playwright Test Summary

  • Passed: 199
  • Failed: 1
  • Skipped: 16
  • 🔁 Flaky: 9
  • 📊 Total: 225
  • Total Runtime: 4156.9s (~ 69 min 17 sec)
specs/Accessibility/Accessibility.spec.ts (❌ 0 failed, ⚠️ 1 flaky)
  • ⚠️ In collapsed view > I want to see collapsed view when app is narrow (tags: TC-48, regression)
specs/ArchiveSpecs/archive.spec.ts (❌ 0 failed, ⚠️ 1 flaky)
  • ⚠️ Accessibility > I want to archive the 1on1 conversation from conversation details (tags: TC-105, regression)
specs/ClearConversationContent/clearConversationContent.spec.ts (❌ 0 failed, ⚠️ 1 flaky)
  • ⚠️ Clear Conversation Content > I want to see incoming picture, ping and call after I clear content of a 1:1 conversation via conversation list (tags: TC-8779, regression)
specs/Drive/editMultipartMessage-TC-8786.spec.ts (❌ 0 failed, ⚠️ 1 flaky)
  • ⚠️ Edit multipart message in a group conversation (tags: crit-flow-cells, regression, TC-8786)
specs/InConversationSearch/inConversationSearch.spec.ts (❌ 0 failed, ⚠️ 1 flaky)
  • ⚠️ In Conversation Search > Verify I can not search for a deleted message (tags: TC-392, regression)
specs/Notifications/notifications.spec.ts (❌ 0 failed, ⚠️ 2 flaky)
  • ⚠️ Notifications > I should not receive notifications for muted 1:1 conversations (tags: TC-1444, regression)
  • ⚠️ Notifications > Verify I see notification when someone creates a group (tags: TC-1459, regression)
specs/ParticipantProfile/participantProfile.spec.ts (❌ 0 failed, ⚠️ 1 flaky)
  • ⚠️ Participant Profile > Verify you can access profile information for the other participant in a 1to1 conversation (tags: TC-1474, regression)
specs/Reactions/reactions.spec.ts (❌ 0 failed, ⚠️ 1 flaky)
  • ⚠️ Reactions > Verify likes are reset if you edited message (tags: TC-1538, regression)
specs/SelfDeletingMessages/selfDeletingMessages.spec.ts (❌ 1 failed, ⚠️ 0 flaky)
  • ❌ Self Deleting Messages > Verify that message with previous timer are deleted on start-up when the timeout passed in 1:1 (tags: TC-664, regression)

Comment on lines +114 to +115
await userAPages.collection().page.getByRole('presentation').click();
await expect(userAPages.collection().page.getByRole('presentation')).toBeVisible();
Copy link
Collaborator

Choose a reason for hiding this comment

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

This locator looks for an item with the role "presentation" on the whole page, this will fail due to strict mode as there are multiple such items on the page. Please limit the area you're searching and don't use the whole page. E.g.: userAPages.collection().imagesSection.getByRole('presentation').first()

You're also just clicking the image and checking that it's visible. I don't think this check is sufficient to verify the image was opened in the full screen detail view.

Comment on lines +337 to +339
for (let i = 0; i < 20; i++) {
await userAPages.conversation().sendMessage(`Message from User A: ${i}`);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Tipp: Instead of sending multiple messages you could also just send one very long message containing line breaks ;)

Suggested change
for (let i = 0; i < 20; i++) {
await userAPages.conversation().sendMessage(`Message from User A: ${i}`);
}
await pages.conversation().sendMessage('Empty\n'.repeat(20));

await userAPages.conversation().sendMessage(`Message from User A: ${i}`);
}

await expect(userAPages.conversation().getMessage({content: 'Message from User A: 19'})).toBeVisible();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of asserting the last message is visible I'd suggest to rather check the first message is not visible as that's the state you're trying to reach here.

Comment on lines +44 to +62
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});
}
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 ;)

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

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"?

* 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants