mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-05-29 19:31:19 -04:00
Added Tests for sending/recieving messages
Added tests for staring/favoriting profiles Added testIds where necessary Added messagesPage.ts Updated peoplePage.ts
This commit is contained in:
@@ -13,6 +13,8 @@ import {SignUpPage} from './signUpPage'
|
||||
import {SocialPage} from './socialPage'
|
||||
import {PeoplePage} from './peoplePage'
|
||||
import {NotificationPage} from './notificationsPage'
|
||||
import { MessagesPage } from './messagesPage'
|
||||
|
||||
|
||||
export class App {
|
||||
readonly auth: AuthPage
|
||||
@@ -26,6 +28,7 @@ export class App {
|
||||
readonly social: SocialPage
|
||||
readonly people: PeoplePage
|
||||
readonly notifs: NotificationPage
|
||||
readonly messages: MessagesPage
|
||||
readonly contextManager: ContextManager
|
||||
readonly context: BrowserContext
|
||||
|
||||
@@ -41,6 +44,7 @@ export class App {
|
||||
this.social = new SocialPage(page)
|
||||
this.people = new PeoplePage(page)
|
||||
this.notifs = new NotificationPage(page)
|
||||
this.messages = new MessagesPage(page)
|
||||
this.context = page.context()
|
||||
|
||||
const browser = page.context().browser()
|
||||
|
||||
97
tests/e2e/web/pages/messagesPage.ts
Normal file
97
tests/e2e/web/pages/messagesPage.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import {expect, Locator, Page} from '@playwright/test'
|
||||
|
||||
export class MessagesPage {
|
||||
private readonly messagesPageHeader: Locator
|
||||
private readonly messagesTable: Locator
|
||||
private readonly messagesRow: Locator
|
||||
private readonly messagesUsername: Locator
|
||||
private readonly messagesTimestamp: Locator
|
||||
private readonly newMessageButton: Locator
|
||||
private readonly newMessageSearchUsers: Locator
|
||||
private readonly newMessageSearchResults: Locator
|
||||
private readonly newMessageSearchCreateButton: Locator
|
||||
private readonly newMessageStart: Locator
|
||||
private readonly messageInput: Locator
|
||||
private readonly messageSubmit: Locator
|
||||
private readonly conversation: Locator
|
||||
private readonly conversationMessage: Locator
|
||||
|
||||
constructor(public readonly page: Page) {
|
||||
this.messagesPageHeader = page.getByRole('heading', { name: 'Messages' })
|
||||
this.messagesTable = page.getByTestId('messages-table')
|
||||
this.messagesRow = page.getByTestId('messages-row')
|
||||
this.messagesUsername = page.getByTestId('messages-username')
|
||||
this.messagesTimestamp = page.getByTestId('messages-timestamp')
|
||||
this.newMessageButton = page.getByRole('button', { name: 'New Message' })
|
||||
this.newMessageSearchUsers = page.getByRole('textbox', { name: 'Search users...' })
|
||||
this.newMessageSearchResults = page.getByTestId('search-results')
|
||||
this.newMessageSearchCreateButton = page.getByRole('button', { name: 'Create' })
|
||||
this.newMessageStart = page.getByText('No messages yet.', { exact: true })
|
||||
this.messageInput = page.locator('.tiptap')
|
||||
this.messageSubmit = page.getByTestId('conversation-message-submit')
|
||||
this.conversation = page.getByTestId('conversation')
|
||||
this.conversationMessage = page.getByTestId('conversation-message')
|
||||
}
|
||||
|
||||
async verifyMessagesPage() {
|
||||
await expect(this.messagesPageHeader).toBeVisible()
|
||||
}
|
||||
|
||||
async createNewMessage(username: string []) {
|
||||
await expect(this.newMessageButton).toBeVisible()
|
||||
await this.newMessageButton.click()
|
||||
await expect(this.newMessageSearchUsers).toBeVisible()
|
||||
for (let i = 0; i < username.length; i++) {
|
||||
await this.newMessageSearchUsers.fill(username[i])
|
||||
await expect(this.newMessageSearchResults).toBeVisible()
|
||||
const results = await this.newMessageSearchResults.getByTestId('search-results-username').all()
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
const usernameResults = await results[i].textContent()
|
||||
if (usernameResults?.toLowerCase() === username[i].toLowerCase()) await results[i].click()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
await expect(this.newMessageSearchCreateButton).toBeVisible()
|
||||
await this.newMessageSearchCreateButton.click()
|
||||
}
|
||||
|
||||
async sendMessage(message: string) {
|
||||
await expect(this.messageInput).toBeVisible()
|
||||
await this.messageInput.fill(message)
|
||||
await expect(this.messageSubmit).toBeVisible()
|
||||
await this.messageSubmit.click()
|
||||
}
|
||||
|
||||
async findMessageConversation(displayName: string) {
|
||||
await expect(this.messagesTable).toBeVisible()
|
||||
const doMessagesExist = await this.messagesRow.count() > 0
|
||||
if (doMessagesExist) {
|
||||
const messages = await this.messagesRow.getByTestId('messages-username').all()
|
||||
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
await expect(messages[i]).toBeVisible()
|
||||
const messageFromUser = await messages[i].textContent()
|
||||
if (messageFromUser?.toLowerCase() === displayName.toLowerCase()) await messages[i].click()
|
||||
}
|
||||
} else {
|
||||
throw new Error('There are no messages on this account')
|
||||
}
|
||||
}
|
||||
|
||||
async verifyMessage(messageContent: string) {
|
||||
await expect(this.conversation).toBeVisible()
|
||||
const messageCount = await this.conversationMessage.count() > 0
|
||||
if (messageCount) {
|
||||
const messages = await this.conversationMessage.all()
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
const message = await messages[i].textContent()
|
||||
if (message?.toLowerCase() === messageContent.toLowerCase()) return true
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
throw new Error('There are no messages in this conversation')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,10 @@ export type PeoplePageFilter = {
|
||||
|
||||
export class PeoplePage {
|
||||
private readonly peopleHeading: Locator
|
||||
private readonly savedPeopleHeading: Locator
|
||||
private readonly savedPeopleList: Locator
|
||||
private readonly searchBox: Locator
|
||||
private readonly savedPeopleButton: Locator
|
||||
private readonly profileCount: Locator
|
||||
private readonly resetFilters: Locator
|
||||
private readonly yourFiltersCheckbox: Locator
|
||||
@@ -122,13 +125,20 @@ export class PeoplePage {
|
||||
private readonly displayDropdown: Locator
|
||||
private readonly profileGrid: Locator
|
||||
private readonly profileResults: Locator
|
||||
private readonly profileHide: Locator
|
||||
private readonly profileStar: Locator
|
||||
private readonly profileMessage: Locator
|
||||
private readonly messageInput: Locator
|
||||
private readonly profileName: Locator
|
||||
private readonly profileAgeGender: Locator
|
||||
private readonly profileSeeking: Locator
|
||||
|
||||
constructor(public readonly page: Page) {
|
||||
this.peopleHeading = page.getByRole('heading', {name: 'People'})
|
||||
this.savedPeopleHeading = page.getByRole('heading', { name: 'Saved People' })
|
||||
this.savedPeopleList = page.getByTestId('saved-person')
|
||||
this.searchBox = page.getByRole('textbox', {name: 'Search anything...'})
|
||||
this.savedPeopleButton = page.getByRole('button', { name: 'Saved People' })
|
||||
this.profileCount = page.getByTestId('people-profile-count')
|
||||
this.resetFilters = page.getByRole('button', {name: 'Reset filters'})
|
||||
this.yourFiltersCheckbox = page.getByText('Your filters', {exact: true})
|
||||
@@ -162,6 +172,10 @@ export class PeoplePage {
|
||||
this.displayDropdown = page.getByRole('button', {name: 'Display'})
|
||||
this.profileGrid = page.getByTestId('people-profile-grid')
|
||||
this.profileResults = page.getByTestId('people-profile-results')
|
||||
this.profileHide = page.getByTestId('hide-profile-button')
|
||||
this.profileStar = page.getByTestId('star-profile-button')
|
||||
this.profileMessage = page.getByTestId('message-profile-button')
|
||||
this.messageInput = page.locator('.tiptap')
|
||||
this.profileName = page.getByTestId('people-profile-name')
|
||||
this.profileAgeGender = page.getByTestId('people-profile-age-gender')
|
||||
this.profileSeeking = page.getByTestId('people-profile-seeking')
|
||||
@@ -247,12 +261,16 @@ export class PeoplePage {
|
||||
await expect(this.peopleHeading).toBeVisible()
|
||||
}
|
||||
|
||||
//Doesn't actually work, need to find out why
|
||||
async clickSavedPeopleButton() {
|
||||
await expect(this.savedPeopleButton).toBeVisible()
|
||||
await this.savedPeopleButton.click()
|
||||
}
|
||||
|
||||
async useSearch(item: string) {
|
||||
await expect(this.searchBox).toBeVisible()
|
||||
await this.searchBox.click()
|
||||
await this.searchBox.fill(item)
|
||||
await this.page.keyboard.press('Enter')
|
||||
await this.page.waitForTimeout(1000)
|
||||
}
|
||||
|
||||
async resetFilter() {
|
||||
@@ -443,12 +461,18 @@ export class PeoplePage {
|
||||
const profileName = await chosenProfile.getByTestId('people-profile-name').textContent()
|
||||
const ageGender = await chosenProfile.getByTestId('people-profile-age-gender').textContent()
|
||||
const seekingInfo = await chosenProfile.getByTestId('people-profile-seeking').textContent()
|
||||
const hideProfile = await chosenProfile.getByTestId('hide-profile-button')
|
||||
const starProfile = await chosenProfile.getByTestId('star-profile-button')
|
||||
const messageProfile = await chosenProfile.getByTestId('message-profile-button')
|
||||
|
||||
return {
|
||||
profile: chosenProfile ?? '',
|
||||
name: profileName ?? '',
|
||||
ageGender: ageGender ?? '',
|
||||
seeking: seekingInfo ?? '',
|
||||
hide: hideProfile ?? '',
|
||||
star: starProfile ?? '',
|
||||
message: messageProfile ?? '',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,4 +489,41 @@ export class PeoplePage {
|
||||
await expect(noProfilesFound).toBeVisible()
|
||||
}
|
||||
}
|
||||
|
||||
async selectProfile(displayName: string) {
|
||||
await expect(this.profileGrid).toBeVisible()
|
||||
await this.profileName.getByText(displayName).click()
|
||||
}
|
||||
|
||||
async messageProfile(displayName: string, message: string) {
|
||||
await expect(this.profileGrid).toBeVisible()
|
||||
const profiles = await this.profileResults.all()
|
||||
|
||||
for (let i = 0; i < profiles.length; i++) {
|
||||
const profileName = await profiles[i].getByTestId('people-profile-name').textContent();
|
||||
if (profileName?.toLowerCase() === displayName.toLowerCase()) {
|
||||
await profiles[i].getByTestId('message-profile-button').click()
|
||||
await expect(this.messageInput).toBeVisible()
|
||||
await this.messageInput.fill(message)
|
||||
await this.page.getByTestId('conversation-message-submit').click()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async verifySavedPerson(displayName: string) {
|
||||
await expect(this.savedPeopleHeading).toBeVisible()
|
||||
const isThereSavedPeople = await this.savedPeopleList.count() > 0
|
||||
|
||||
if (isThereSavedPeople) {
|
||||
const listOfPeople = await this.savedPeopleList.all()
|
||||
for (let i = 0; i < listOfPeople.length; i++) {
|
||||
await expect(listOfPeople[i]).toBeVisible()
|
||||
const profileName = await listOfPeople[i].textContent()
|
||||
if (profileName?.toLowerCase() === displayName.toLowerCase()) return true
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
throw new Error('There are no profiles in the saved people list')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {expect, test} from '../fixtures/signInFixture'
|
||||
import {ContextManager} from '../../utils/contextManager'
|
||||
|
||||
test.describe('when given valid input', () => {
|
||||
test('should be able to sign in to an available account', async ({
|
||||
@@ -11,6 +10,19 @@ test.describe('when given valid input', () => {
|
||||
await app.home.verifySignedInHomePage(account.display_name)
|
||||
})
|
||||
|
||||
test('should be able to save/favorite people', async ({
|
||||
app,
|
||||
signedOutAccount: account,
|
||||
}) => {
|
||||
await app.signinWithEmail(account)
|
||||
await app.home.clickPeopleLink()
|
||||
const profile = await app.people.getProfileInfo()
|
||||
await expect(profile.star).toBeVisible()
|
||||
await profile.star.click()
|
||||
await app.people.clickSavedPeopleButton()
|
||||
await app.people.verifySavedPerson(profile.name)
|
||||
})
|
||||
|
||||
test.describe('the applied filter should', () => {
|
||||
test('update the profile count', async ({app, signedOutAccount: account}) => {
|
||||
await app.signinWithEmail(account)
|
||||
@@ -226,14 +238,39 @@ test.describe('when given valid input', () => {
|
||||
})
|
||||
|
||||
test.describe('a verified account should', () => {
|
||||
test('be able to send a message', async ({app, devOneAccount, devTwoAccount}) => {
|
||||
test('be able to send a message from the messages page', async ({app, devOneAccount, devTwoAccount}) => {
|
||||
const devOne = await app.contextManager.createContext('devOne')
|
||||
const devTwo = await app.contextManager.createContext('devTwo')
|
||||
await devOne.signinWithEmail(devOneAccount)
|
||||
await devOne.home.clickPeopleLink()
|
||||
await devTwo.signinWithEmail(devTwoAccount)
|
||||
await devTwo.home.clickPeopleLink()
|
||||
|
||||
await devOne.home.clickMessagesLink()
|
||||
await devOne.messages.createNewMessage([devTwoAccount.display_name])
|
||||
await devOne.messages.sendMessage('This is a message')
|
||||
|
||||
await devTwo.home.clickMessagesLink()
|
||||
await devTwo.messages.findMessageConversation(devOneAccount.display_name)
|
||||
await devTwo.messages.verifyMessage('This is a message')
|
||||
})
|
||||
|
||||
test('be able to send a message from the people page', async ({app, devOneAccount, devTwoAccount}) => {
|
||||
const devOne = await app.contextManager.createContext('devOne')
|
||||
const devTwo = await app.contextManager.createContext('devTwo')
|
||||
await devOne.signinWithEmail(devOneAccount)
|
||||
await devTwo.signinWithEmail(devTwoAccount)
|
||||
|
||||
await devOne.home.clickPeopleLink()
|
||||
await devOne.people.useSearch(devTwoAccount.display_name)
|
||||
const message = "This is a message".repeat(20)
|
||||
await devOne.people.messageProfile(devTwoAccount.display_name, message)
|
||||
await devOne.messages.verifyMessage(message)
|
||||
|
||||
await devTwo.home.clickMessagesLink()
|
||||
await devTwo.messages.findMessageConversation(devOneAccount.display_name)
|
||||
await devTwo.messages.verifyMessage(message)
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ export function ChatMessageItem(props: {
|
||||
isMe && 'flex-row-reverse',
|
||||
firstOfUser ? 'mt-2' : 'mt-1',
|
||||
)}
|
||||
data-testid="conversation-message"
|
||||
>
|
||||
{!isMe && !hideAvatar && (
|
||||
<MessageAvatar
|
||||
|
||||
@@ -227,6 +227,7 @@ export function CommentInputTextArea(props: {
|
||||
)}
|
||||
{!isSubmitting && !isDisabled && submit && commentTypes.includes('comment') && (
|
||||
<button
|
||||
data-testid="conversation-message-submit"
|
||||
className="text-ink-500 hover:text-ink-700 active:bg-ink-300 disabled:text-ink-300 px-4 transition-colors"
|
||||
disabled={isDisabled || !editor || editor.isEmpty}
|
||||
onClick={() => submit('comment')}
|
||||
|
||||
@@ -431,7 +431,10 @@ function ProfilePreview(props: {
|
||||
/>
|
||||
)}
|
||||
{user && (
|
||||
<div className={clsx(cardSize !== 'large' && 'hidden sm:flex')}>
|
||||
<div
|
||||
className={clsx(cardSize !== 'large' && 'hidden sm:flex')}
|
||||
data-testid="message-profile-button"
|
||||
>
|
||||
<SendMessageButton
|
||||
toUser={user}
|
||||
profile={profile}
|
||||
|
||||
@@ -230,7 +230,7 @@ function StarModal(props: {
|
||||
</p>
|
||||
<Col className={clsx('divide-y divide-canvas-200 w-full pr-2', SCROLLABLE_MODAL_CLASS)}>
|
||||
{visibleUsers.map((u) => (
|
||||
<div key={u.id} className="py-3 first:pt-0 last:pb-0">
|
||||
<div key={u.id} className="py-3 first:pt-0 last:pb-0" data-testid="saved-person">
|
||||
<div className="bg-canvas-0 border border-canvas-200 rounded-xl p-3 transition-all hover:border-primary-300 hover:shadow-sm">
|
||||
<Row className="items-center justify-between gap-3">
|
||||
<Link className="flex-1 group" href={'/' + u.username}>
|
||||
@@ -243,7 +243,10 @@ function StarModal(props: {
|
||||
/>
|
||||
</div>
|
||||
<Col className="flex-1">
|
||||
<div className="font-medium text-ink-900 group-hover:text-primary-600 transition-colors">
|
||||
<div
|
||||
className="font-medium text-ink-900 group-hover:text-primary-600 transition-colors"
|
||||
data-testid="saved-person-display-name"
|
||||
>
|
||||
{u.name}
|
||||
</div>
|
||||
<div className="text-ink-500 text-sm">@{u.username}</div>
|
||||
@@ -251,6 +254,7 @@ function StarModal(props: {
|
||||
</Row>
|
||||
</Link>
|
||||
<button
|
||||
data-testid="remove-saved-person"
|
||||
onClick={() => {
|
||||
// Optimistically remove the user from the list
|
||||
setRemovingIds((prev) => new Set(prev).add(u.id))
|
||||
|
||||
@@ -94,6 +94,7 @@ export function SelectUsers(props: {
|
||||
'relative inline-block w-full overflow-y-scroll text-right',
|
||||
queryReady && 'h-56',
|
||||
)}
|
||||
data-testid="search-results"
|
||||
>
|
||||
{() => (
|
||||
<Transition
|
||||
@@ -112,7 +113,7 @@ export function SelectUsers(props: {
|
||||
>
|
||||
<div className="py-1">
|
||||
{filteredUsers.map((user) => (
|
||||
<Menu.Item key={user.id}>
|
||||
<Menu.Item key={user.id} data-testid="search-results-username">
|
||||
{({active}) => (
|
||||
<button
|
||||
className={clsx(
|
||||
|
||||
@@ -76,6 +76,7 @@ export function HideProfileButton(props: HideProfileButtonProps) {
|
||||
noTap
|
||||
>
|
||||
<button
|
||||
data-testid="hide-profile-button"
|
||||
className={clsx(
|
||||
'relative inline-flex items-center justify-center border bg-canvas-50 border-canvas-300 text-ink-300 hover:border-primary-400 hover:bg-primary-50 rounded-lg h-7 w-7',
|
||||
className,
|
||||
|
||||
@@ -43,6 +43,7 @@ export const StarButton = (props: {
|
||||
|
||||
const button = (
|
||||
<button
|
||||
data-testid="star-profile-button"
|
||||
className={clsx(
|
||||
'border border-canvas-200',
|
||||
buttonClass('xs', 'none'),
|
||||
|
||||
@@ -388,6 +388,7 @@ export const PrivateChat = (props: {
|
||||
style={{
|
||||
transform: isSafari ? 'translate3d(0, 0, 0)' : 'none',
|
||||
}}
|
||||
data-testid="conversation"
|
||||
>
|
||||
<div
|
||||
className="relative px-1 pb-4 pt-1 transition-all duration-100"
|
||||
|
||||
@@ -64,7 +64,7 @@ export function MessagesContent(props: {currentUser: User}) {
|
||||
</h1>
|
||||
<NewMessageButton />
|
||||
</Row>
|
||||
<Col className={'w-full overflow-hidden gap-2'}>
|
||||
<Col className={'w-full overflow-hidden gap-2'} data-testid="messages-table">
|
||||
{channels && channels.length === 0 && (
|
||||
<div className="bg-canvas-50 border border-canvas-200 rounded-xl p-8 text-center mt-4">
|
||||
<p className="text-ink-500 text-sm mb-1">
|
||||
@@ -116,6 +116,7 @@ export const MessageChannelRow = (props: {
|
||||
className={
|
||||
'items-center gap-3 bg-canvas-50 border border-canvas-200 rounded-xl p-3 transition-all hover:border-primary-300 hover:shadow-sm hover:bg-canvas-100'
|
||||
}
|
||||
data-testid="messages-row"
|
||||
>
|
||||
{otherUsers && otherUsers.length > 0 ? (
|
||||
<MultipleOrSingleAvatars
|
||||
@@ -135,6 +136,7 @@ export const MessageChannelRow = (props: {
|
||||
className={
|
||||
'font-medium text-ink-900 text-sm group-hover:text-primary-600 transition-colors'
|
||||
}
|
||||
data-testid="messages-username"
|
||||
>
|
||||
{otherUsers && otherUsers.length > 0 ? (
|
||||
<span>
|
||||
@@ -162,7 +164,7 @@ export const MessageChannelRow = (props: {
|
||||
)}
|
||||
{isBanned && <BannedBadge />}
|
||||
</span>
|
||||
<span className={'text-ink-300 text-xs'}>
|
||||
<span className={'text-ink-300 text-xs'} data-testid="messages-timestamp">
|
||||
{lastMessage && <RelativeTimestamp time={lastMessage.createdTime} />}
|
||||
</span>
|
||||
</Row>
|
||||
|
||||
Reference in New Issue
Block a user