diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ActivityFeed.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ActivityFeed.spec.ts index 8b94c0766dd..88d7bc10251 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ActivityFeed.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ActivityFeed.spec.ts @@ -21,13 +21,18 @@ import { TableClass } from '../../support/entity/TableClass'; import { TeamClass } from '../../support/team/TeamClass'; import { UserClass } from '../../support/user/UserClass'; import { + addMentionCommentInFeed, checkDescriptionInEditModal, deleteFeedComments, + FIRST_FEED_SELECTOR, + REACTION_EMOJIS, + reactOnFeed, } from '../../utils/activityFeed'; import { performAdminLogin } from '../../utils/admin'; import { descriptionBox, redirectToHomePage, + removeLandingBanner, toastNotification, uuid, visitOwnProfilePage, @@ -90,6 +95,51 @@ test.describe('Activity feed', () => { await afterAction(); }); + test('Feed widget should be visible', async ({ page }) => { + await removeLandingBanner(page); + // Locate the feed widget + const feedWidget = page.locator('[data-testid="activity-feed-widget"]'); + + // Check if the feed widget is visible + await expect(feedWidget).toBeVisible(); + + // Check if the feed widget contains specific text + await expect(feedWidget).toContainText('All'); + await expect(feedWidget).toContainText('@Mentions'); + await expect(feedWidget).toContainText('Tasks'); + }); + + test('Emoji reaction on feed should be working fine', async ({ page }) => { + await removeLandingBanner(page); + + await test.step('Add Emoji reaction', async () => { + // Assign reaction for latest feed + await reactOnFeed(page); + + // Verify if reaction is working or not + for (const emoji of REACTION_EMOJIS) { + await expect( + page.locator( + '[data-testid="activity-feed-widget"] [data-testid="message-container"]:first-child [data-testid="feed-reaction-container"]' + ) + ).toContainText(emoji); + } + }); + + await test.step('Remove Emoji reaction from feed', async () => { + // Remove reaction for latest feed + await reactOnFeed(page); + + // Verify if reaction is removed or not + const feedReactionContainer = page + .locator('[data-testid="message-container"]') + .nth(1) + .locator('[data-testid="feed-reaction-container"]'); + + await expect(feedReactionContainer).toHaveCount(1); + }); + }); + test('Assigned task should appear to task tab', async ({ page }) => { const value: TaskDetails = { term: entity.entity.name, @@ -483,6 +533,54 @@ test.describe('Activity feed', () => { // create description task await createDescriptionTask(page, value); }); + + test('Mention should work for the feed reply', async ({ page }) => { + await addMentionCommentInFeed(page, adminUser.responseData.name); + + // Close drawer + await page.locator('[data-testid="closeDrawer"]').click(); + + // Get the feed text + const feedText = await page + .locator(`${FIRST_FEED_SELECTOR} [data-testid="headerText"]`) + .innerText(); + + // Click on @Mentions tab + const fetchMentionsFeedResponse = page.waitForResponse( + '/api/v1/feed?filterType=MENTIONS&userId=*' + ); + await page + .locator('[data-testid="activity-feed-widget"]') + .locator('text=@Mentions') + .click(); + + await fetchMentionsFeedResponse; + + const mentionedText = await page + .locator(`${FIRST_FEED_SELECTOR} [data-testid="headerText"]`) + .innerText(); + + expect(mentionedText).toContain(feedText); + }); + + test('Mention should work for the feed reply in case of users having dot in their name', async ({ + page, + }) => { + await addMentionCommentInFeed(page, 'aaron.warren5'); + + await expect( + page.locator( + `#feed-panel [data-testid="message-container"] [data-testid="feed-replies"] [data-testid="viewer-container"] [data-testid="markdown-parser"]` + ) + ).toContainText('Can you resolve this thread for me? @aaron.warren5'); + + // Close drawer + await page.locator('[data-testid="closeDrawer"]').click(); + + expect( + page.locator(`${FIRST_FEED_SELECTOR} [data-testid="reply-count"]`) + ).toContainText('01 Reply'); + }); }); base.describe('Activity feed with Data Consumer User', () => { diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/activityFeed.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/activityFeed.ts index 1ac04e2f39c..59d4372e7b2 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/activityFeed.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/activityFeed.ts @@ -11,9 +11,24 @@ * limitations under the License. */ import { expect, Locator, Page } from '@playwright/test'; -import { descriptionBox } from './common'; +import { descriptionBox, removeLandingBanner } from './common'; import { TaskDetails } from './task'; +export const REACTION_EMOJIS = ['🚀', '😕', '👀', '❤️', '🎉', '😄', '👎', '👍']; + +export const FEED_REACTIONS = [ + 'thumbsUp', + 'thumbsDown', + 'laugh', + 'hooray', + 'confused', + 'heart', + 'eyes', + 'rocket', +]; +export const FIRST_FEED_SELECTOR = + '[data-testid="activity-feed-widget"] [data-testid="message-container"]:first-child'; + export const checkDescriptionInEditModal = async ( page: Page, taskValue: TaskDetails @@ -59,3 +74,67 @@ export const deleteFeedComments = async (page: Page, feed: Locator) => { await deleteResponse; }; + +export const reactOnFeed = async (page: Page) => { + for (const reaction of FEED_REACTIONS) { + await page + .locator( + '[data-testid="activity-feed-widget"] [data-testid="message-container"]:first-child' + ) + .locator('[data-testid="feed-reaction-container"]') + .locator('[data-testid="add-reactions"]') + .click(); + + await page + .locator('.ant-popover-feed-reactions .ant-popover-inner-content') + .waitFor({ state: 'visible' }); + await page + .locator(`[data-testid="reaction-button"][title="${reaction}"]`) + .click(); + } +}; + +export const addMentionCommentInFeed = async (page: Page, user: string) => { + await removeLandingBanner(page); + + // Click on add reply + const feedResponse = page.waitForResponse('/api/v1/feed/*'); + await page + .locator(FIRST_FEED_SELECTOR) + .locator('[data-testid="thread-count"]') + .click(); + + await feedResponse; + + await page.waitForSelector('.ant-drawer-content', { + state: 'visible', + }); + + // Type reply with mention + await page + .locator( + '[data-testid="editor-wrapper"] [contenteditable="true"].ql-editor' + ) + .click(); + + const userSuggestionsResponse = page.waitForResponse( + `/api/v1/search/query?q=*${user}***` + ); + + await page + .locator( + '[data-testid="editor-wrapper"] [contenteditable="true"].ql-editor' + ) + .type(`Can you resolve this thread for me? @${user}`); + await userSuggestionsResponse; + + await page.locator(`[data-value="@${user}"]`).click(); + + // Send reply + await expect(page.locator('[data-testid="send-button"]')).toBeVisible(); + await expect(page.locator('[data-testid="send-button"]')).not.toBeDisabled(); + + const postReplyResponse = page.waitForResponse('/api/v1/feed/*/posts'); + await page.locator('[data-testid="send-button"]').click(); + await postReplyResponse; +};