-
-
Notifications
You must be signed in to change notification settings - Fork 9
[User functionality] Small PR focused on tests for user functionality #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
58dfabf
11f8477
dd01e0b
d6e31ba
eb7825c
56b4a9b
4e6d4f3
17072c9
5129e8e
224f0c8
0016c69
7bb8eea
89efb0f
ef63832
e0561b5
9571d9b
42d28da
ca42cfc
27ef668
b3e3413
6e7cd77
7daf458
1d898f3
ce0c7cd
fae4fd7
6e1b846
90c3f22
3918830
d6c2b03
19e65cb
ede380a
9bf34a5
c1dacbd
492ee7a
8a4aafb
ab72f17
00a9a85
b32f468
178dfdc
585f9f2
4c2bd90
00e7662
23eedd0
21a720f
f490548
8f0910d
eaa0b4c
75a21b2
c74c36a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import {Browser} from '@playwright/test' | ||
|
|
||
| import {App} from '../web/pages/app' | ||
|
|
||
| export class ContextManager { | ||
| private contexts: Map<string, App> = new Map() | ||
|
|
||
| constructor(private browser: Browser) {} | ||
|
|
||
| async createContext(customName?: string): Promise<App> { | ||
| const name = customName ?? crypto.randomUUID().slice(0, 6) | ||
| const existing = this.contexts.get(name) | ||
| // Return the existing one instead of closing it? | ||
| if (existing) await existing.page.context().close() | ||
|
|
||
| const context = await this.browser.newContext() | ||
| const page = await context.newPage() | ||
| const app = new App(page) | ||
| this.contexts.set(name, app) | ||
| return app | ||
| } | ||
|
|
||
| getContext(name: string): App | undefined { | ||
| return this.contexts.get(name) | ||
| } | ||
|
|
||
| async closeAll(): Promise<void> { | ||
| for (const app of this.contexts.values()) { | ||
| await app.page.context().close() | ||
| } | ||
| this.contexts.clear() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,108 @@ | ||||||||||
| import {expect, Locator, Page} from '@playwright/test' | ||||||||||
| import {sleep} from 'common/util/time' | ||||||||||
|
|
||||||||||
| 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 sleep(1000) | ||||||||||
| await expect(this.newMessageSearchResults).toBeVisible() | ||||||||||
| const results = await this.newMessageSearchResults | ||||||||||
| .getByTestId('search-results-username') | ||||||||||
| .all() | ||||||||||
| const targetUser = username[i].toLowerCase() | ||||||||||
| for (let j = 0; j < results.length; j++) { | ||||||||||
| const usernameResults = (await results[j].textContent())?.toLowerCase() | ||||||||||
| if (usernameResults === targetUser) { | ||||||||||
| await results[j].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() | ||||||||||
| const verified = await this.verifyMessage(message) | ||||||||||
| if (!verified) | ||||||||||
| throw new Error(`Message "${message}" was not found in conversation after sending`) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| async findMessageConversation(displayName: string) { | ||||||||||
| await expect(this.messagesTable).toBeVisible() | ||||||||||
| await this.page.waitForTimeout(1000) | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove This violates the explicit guideline: "Never use Fixed timeouts introduce flakiness and are discouraged as "sleep hacks for eventual consistency." Playwright's 🔧 Proposed fix to remove the timeout async findMessageConversation(displayName: string) {
await expect(this.messagesTable).toBeVisible()
- await this.page.waitForTimeout(1000)
const doMessagesExist = (await this.messagesRow.count()) > 0If additional synchronization is needed, use: await expect(this.messagesRow.first()).toBeVisible({timeout: 5000})As per coding guidelines: Never use 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| 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() | ||||||||||
| await sleep(1000) | ||||||||||
| 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') | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
Uh oh!
There was an error while loading. Please reload this page.