# Test info

- Name: Feature case for request-listing >> REQ_048 - Verify mail when comment in post
- Location: /root/code/portal-automation-test/tests/request/function.spec.ts:1601:9

# Error details

```
Error: locator.waitFor: Test timeout of 80000ms exceeded.
Call log:
  - waiting for locator('//p[text()=\'Added New Successfully!\']') to be visible

    at RequestPage.addCommentToNewestPost (/root/code/portal-automation-test/pom/dashboard.page.ts:634:61)
    at /root/code/portal-automation-test/tests/request/function.spec.ts:1608:13
    at /root/code/portal-automation-test/tests/request/function.spec.ts:1606:9
```

# Page snapshot

```yaml
- complementary:
  - img
  - link "WellCare Pharmacy12321@@@@ Portal QA":
    - /url: /
    - paragraph: WellCare Pharmacy12321@@@@
    - paragraph: Portal QA
  - list:
    - listitem:
      - link "Home":
        - /url: https://qa.loprx.com
        - img
        - text: Home
    - listitem:
      - link "Case":
        - /url: https://qa.loprx.com/cases
        - img
        - text: Case
    - listitem:
      - link "Request":
        - /url: https://qa.loprx.com/requests
        - img
        - text: Request
    - listitem:
      - link "Patient":
        - /url: https://qa.loprx.com/clients
        - img
        - text: Patient
    - listitem:
      - button "Business/Contact":
        - img
        - text: Business/Contact
    - listitem:
      - button "Inbox/Sent":
        - img
        - text: Inbox/Sent
    - listitem:
      - button "Settings":
        - img
        - text: Settings
  - list:
    - listitem:
      - link "Shared with me":
        - /url: https://qa.loprx.com/shared/requests
        - img
        - text: Shared with me
- banner:
  - button:
    - img
  - button [disabled]:
    - img
  - img
  - text: Minh Phong shared details regarding New Case 123 Letter of Protection. See the information now. 3 days ago
  - img
  - text: "Get the details: Lawyer Phan's response to the Letter of Protection Test Request is now available. 3 days ago"
  - img
  - text: Son HaiBon Phan assigned a request to you 21 minutes ago
  - img
  - text: Son HaiBon Phan assigned a case to you 2 hours ago
  - img
  - text: Tri01 Duc shared some information about New Guy 123 Letter of Protection. Find out what it says. 1 week ago
  - img
  - text: "Get the details: Lawyer Phan's response to the Letter of Protection Test Request is now available. 3 days ago"
  - img
  - text: Son HaiBon Phan assigned a request to you 21 minutes ago
  - img
  - text: Son HaiBon Phan assigned a case to you 2 hours ago
  - img
  - img
  - textbox "Search..."
  - img
  - img
  - paragraph: No notifications yet
  - paragraph: When you get notifications, they'll show up here
  - button "Refresh"
  - list:
    - listitem:
      - img
      - paragraph: Pause notifications...
      - list:
        - listitem: For 30 minutes
        - listitem: For 1 hour
        - listitem: For 2 hours
        - listitem: Until tomorrow
    - listitem:
      - img
    - listitem:
      - img
    - listitem:
      - img
    - listitem:
      - img
    - listitem:
      - img
    - listitem:
      - img
  - img
  - button "0 Cart":
    - img
    - text: 0 Cart
  - text: Feedback
  - img
  - link "Open user menu":
    - /url: "#"
    - text: Minh
- img
- text: "#527231 Letter of Protection"
- img
- img
- img
- link "Test Request":
  - /url: /clients/801a8b15-a5c5-4282-aacd-6a9b2e6ae3b3
- text: "-"
- 'link "DOB: 03/01/1999"':
  - /url: /clients/801a8b15-a5c5-4282-aacd-6a9b2e6ae3b3
- 'link "Case: #538240"':
  - /url: /cases/538240
- text: "-"
- 'link "DOI: 01/05/2026"':
  - /url: /cases/538240
- 'link "Category: Unspecified Accident"':
  - /url: /cases/538240
- text: Tag
- img
- 'button "Status: Open"'
- button "Status Details:":
  - text: "Status Details:"
  - listbox:
    - listitem:
      - text: Awaiting
      - img
  - img
- 'button "Assignee: --"':
  - text: "Assignee: --"
  - img
- button:
  - img
- button:
  - img
- button "Activity":
  - img
  - text: Activity
- button "Share":
  - img
  - text: Share
- paragraph: Minh Phong
- text: Posted
- paragraph: 08/25/2025
- img
- list:
  - listitem
- text: Read more comment Minh Phong 23 hours ago Please check this comment 6158247734
- img
- text: Minh Phong 12 hours ago Please check this comment 8589813584
- img
- textbox "Message"
- button [disabled]:
  - img
- text: Comments here are public to anyone with access to this request, unlike the members-only private discussion room.
- heading "Snapshot" [level=2]
- list:
  - listitem: Minh Phong 08/25/2025 Submitted a request Respond
- heading "Discussion" [level=2]
- text: Start a discussion
- img
- heading "Newest Discusssion" [level=4]
- text: Please check this discusssion 0182011390 27 seconds ago
- img
- heading "Secret Room" [level=4]
- text: Please check this discusssion 0103927663 01/06/2026
- img
- heading "Minh Phong (You)" [level=4]
- img
- text: See all rooms
- heading "Discussion" [level=2]
- text: Start a discussion
- img
- heading "Newest Discusssion" [level=4]
- text: Please check this discusssion 0182011390 27 seconds ago
- img
- heading "Secret Room" [level=4]
- text: Please check this discusssion 0103927663 01/06/2026
- img
- heading "Minh Phong (You)" [level=4]
- img
- heading "Team Discussion" [level=4]
- img
- img "image-share-this-request"
- paragraph: Share this request using the Share button.
- text: Share
```

# Test source

```ts
  534 |             await closeButton.click();
  535 |         } catch (error) {
  536 |             console.log('No notification popup appeared');
  537 |         }
  538 |
  539 |         await this.dashboardLoc.notification.btnNotification.waitFor({ state: 'visible' });
  540 |         await this.dashboardLoc.notification.btnNotification.click({ force: true });
  541 |         await this.dashboardLoc.notification.notificationType(type).click();
  542 |         if (gotoFirstNoti) {
  543 |             await this.dashboardLoc.notification.listNotiReminder.first().click();
  544 |         }
  545 |     }
  546 |
  547 |     async addMultipleTags(tagCount: number, tagPrefix: string = "test"): Promise<void> {
  548 |         await this.dashboardLoc.tag.divTag.click();
  549 |         await this.dashboardLoc.tag.inputTag.first().waitFor({ state: 'visible' });
  550 |         for (let i = 0; i < tagCount; i++) {
  551 |             await this.dashboardLoc.tag.inputTag.first().fill(`${tagPrefix}${i}`);
  552 |             await this.dashboardLoc.tag.inputTag.first().press("Enter");
  553 |         }
  554 |     }
  555 |
  556 |     async saveTags(): Promise<void> {
  557 |         await this.dashboardLoc.tag.btnSaveTag.click();
  558 |         await this.waitForSecond(1);
  559 |     }
  560 |
  561 |     async getTagCount(): Promise<number> {
  562 |         return (await this.dashboardLoc.tag.listTagDetail.all()).length;
  563 |     }
  564 |
  565 |     async removeOneTag(): Promise<void> {
  566 |         await this.dashboardLoc.tag.listRemoveTag.first().click();
  567 |     }
  568 |
  569 |     async clearAllTags(): Promise<void> {
  570 |         await this.dashboardLoc.tag.listTagDetail.first().click();
  571 |         await this.dashboardLoc.tag.btnClearAllTag.waitFor({ state: 'visible' });
  572 |         await this.waitForSecond(1);
  573 |         await this.dashboardLoc.tag.btnClearAllTag.click({ force: true });
  574 |     }
  575 |
  576 |     async showEntries(entries: Number) {
  577 |         const inputShowSelector = `//input[@id='input_per_page']`;
  578 |         await this.page.locator(inputShowSelector).click();
  579 |         await this.page.locator(inputShowSelector).fill(entries.toString());
  580 |         await this.page.waitForLoadState("domcontentloaded");
  581 |     }
  582 |
  583 |     /**
  584 |      * Universal bulk edit verification function with dynamic parameters
  585 |      * Optimized for reuse across multiple test cases and page types
  586 |      * @param tabName - The tab name to click and verify ("Contacts", "Cases", "Request", etc.)
  587 |      * @param entryCount - Number of entries to show in the table
  588 |      * @param detailPageName - Name of the detail page for back navigation verification
  589 |      * @param shouldNavigateBack - Whether to navigate back after verification (default: true)
  590 |      */
  591 |     async verifyBulkEditForTab(
  592 |         tabName: string,
  593 |         entryCount: number,
  594 |         detailPageName: string,
  595 |         shouldNavigateBack: boolean = true
  596 |     ): Promise<void> {
  597 |         // Navigate to tab and show entries
  598 |         await this.dashboardLoc.detail.tabName(tabName).waitFor({ state: 'visible' });
  599 |         await this.waitForSecond(1.5);
  600 |         await this.dashboardLoc.detail.tabName(tabName).click({ force: true });
  601 |         await this.showEntries(entryCount);
  602 |         await this.waitForSecond(2);
  603 |
  604 |         // Get original table data
  605 |         const originalData = await this.getTableData(0);
  606 |
  607 |         // Click Bulk Edit and verify
  608 |         await this.dashboardLoc.buttonByText("Bulk Edit").click();
  609 |         await this.dashboardLoc.common.spanText("Bulk Edit").first().waitFor({ state: 'visible' });
  610 |         await this.waitForSecond(2);
  611 |
  612 |         // Get bulk edit table data and compare
  613 |         const bulkEditData = await this.getTableData(1, false, true);
  614 |
  615 |         // Data validation (without expect as requested)
  616 |         if (JSON.stringify(originalData) !== JSON.stringify(bulkEditData)) {
  617 |             throw new Error(`Bulk edit data mismatch in ${tabName} tab: Original ${JSON.stringify(originalData)} vs Bulk Edit ${JSON.stringify(bulkEditData)}`);
  618 |         }
  619 |
  620 |         // Navigate back if required
  621 |         if (shouldNavigateBack) {
  622 |             await this.dashboardLoc.buttonByText("Back").first().click();
  623 |             await this.dashboardLoc.common.spanText(detailPageName).waitFor({ state: 'visible' });
  624 |         }
  625 |     }
  626 |
  627 |     // Add a comment to the newest post
  628 |     async addCommentToNewestPost(content: string): Promise<void> {
  629 |         await this.dashboardLoc.comment.cmtInPost.first().waitFor({ state: 'visible' });
  630 |         await this.dashboardLoc.comment.cmtInPost.first().click();
  631 |         await this.dashboardLoc.comment.inputComment.first().fill(content);
  632 |         await this.waitForSecond(1);
  633 |         await this.dashboardLoc.comment.btnSubmitComment.first().click({ force: true });
> 634 |         await this.dashboardLoc.comment.msgCreateCmtSuccess.waitFor({ state: 'visible' })
      |                                                             ^ Error: locator.waitFor: Test timeout of 80000ms exceeded.
  635 |     }
  636 |
  637 |     async createDiscussion(title: string, memberName: string, message: string): Promise<void> {
  638 |         await this.dashboardLoc.discussion.btnCreateDiscussion.click();
  639 |         await this.dashboardLoc.modal.headerModal("Start a discussion").waitFor({ state: 'visible' });
  640 |         await this.dashboardLoc.discussion.inputTitle.fill(title);
  641 |         await this.dashboardLoc.modal.inputByPlaceHolder("Type or select an email address").nth(1).fill(memberName);
  642 |         await this.dashboardLoc.discussion.dropdownMemberShare(memberName).waitFor({ state: "visible", timeout: 15_000 });
  643 |         await this.waitForSecond(2);
  644 |         await this.dashboardLoc.discussion.dropdownMemberShare(memberName).click();
  645 |         await this.dashboardLoc.modal.headerModal("Start a discussion").click();
  646 |         await this.dashboardLoc.discussion.msgFirstDis.fill(message);
  647 |         await this.dashboardLoc.modal.headerModal("Start a discussion").click();
  648 |         await this.dashboardLoc.buttonByText("Start").click({ force: true });
  649 |         await this.dashboardLoc.modal.headerModal("Start a discussion").waitFor({ state: 'hidden' });
  650 |         await this.dashboardLoc.msgCreateSuccess.waitFor({ state: 'visible' });
  651 |     }
  652 |
  653 |     async addMessageToDiscussion(message: string): Promise<void> {
  654 |         await this.dashboardLoc.discussion.inputMessage.fill(message);
  655 |         await this.waitForSecond(1);
  656 |         await this.dashboardLoc.discussion.btnSendMsg.click();
  657 |         await this.waitForSecond(2);
  658 |     }
  659 |
  660 |     async getNewestRequestHistory(): Promise<string> {
  661 |         await this.dashboardLoc.buttonByText("Activity").click();
  662 |         const textActivity = await this.dashboardLoc.modalActivity.listActivity.first().innerText();
  663 |         await this.dashboardLoc.modalActivity.btnClose.click();
  664 |         return textActivity.replace(/\s+/g, ' ').trim();
  665 |     }
  666 |
  667 |     async getRowCount(): Promise<number> {
  668 |         return this.dashboardLoc.table.rowsInTable.count();
  669 |     }
  670 |
  671 |     async openGlobalSearch() {
  672 |         await expect(this.dashboardLoc.iconSearchGlobal).toBeVisible();
  673 |         await this.dashboardLoc.iconSearchGlobal.click();
  674 |     }
  675 |
  676 |     async switchTab(targetTab: 'My' | 'All'): Promise<void> {
  677 |         if (targetTab === 'My') {
  678 |             await this.dashboardLoc.tabMyRequest.click();
  679 |         } else {
  680 |             await this.dashboardLoc.tabAllRequest.click();
  681 |         }
  682 |     }
  683 |
  684 |     async getExpectedResultText(count: number): Promise<string> {
  685 |         return count > 1
  686 |             ? `There are ${count} results found.`
  687 |             : `There are ${count} result found.`;
  688 |     }
  689 | }
```