Wait on the composer rather than the send button in e2e specs (#434)

This commit is contained in:
Coracle-Bot 2026-09-08 18:17:30 +00:00 committed by hodlbod
parent 90ba6cff4c
commit 2d92c21490
2 changed files with 19 additions and 8 deletions

View file

@ -95,6 +95,11 @@ const composer = (page: Page) => page.locator(".chat-editor [contenteditable=tru
// The send button carries the shortcut it advertises, which differs by platform. // The send button carries the shortcut it advertises, which differs by platform.
const sendButton = (page: Page) => page.locator("button[data-tip$='enter to send']") const sendButton = (page: Page) => page.locator("button[data-tip$='enter to send']")
// The editor is where the composer says whether it is ready. The send button is not there to
// ask while the composer is empty, since a dictation button stands in its place.
const composerEnabled = (page: Page) =>
expect(page.locator(".room__compose .chat-editor")).toHaveAttribute("aria-disabled", "false")
const suggestions = (page: Page) => page.locator(".tiptap-suggestions__item") const suggestions = (page: Page) => page.locator(".tiptap-suggestions__item")
const timeline = (page: Page) => page.locator(".room__content") const timeline = (page: Page) => page.locator(".room__content")
@ -316,11 +321,11 @@ test("US-057 attach and send an image", async ({seed, as}) => {
await expect(composer(alice).locator(".tiptap-uploading")).toHaveCount(0) await expect(composer(alice).locator(".tiptap-uploading")).toHaveCount(0)
// The same thing in a conversation. Its composer stays disabled until the recipient's messaging // The same thing in a conversation. Its composer stays disabled until the recipient's messaging
// relays have been read, which is what waiting on the send button waits out. // relays have been read, which is what waiting on the composer waits out.
await alice.goto(chatPath(users.bob.pubkey)) await alice.goto(chatPath(users.bob.pubkey))
await bob.goto(chatPath(users.alice.pubkey)) await bob.goto(chatPath(users.alice.pubkey))
await expect(sendButton(alice)).toBeEnabled() await composerEnabled(alice)
await chooseFile(alice, chatUploadButton(alice), gifFile("selfie.gif")) await chooseFile(alice, chatUploadButton(alice), gifFile("selfie.gif"))
@ -379,7 +384,7 @@ test("US-058 drafts survive navigating away", async ({seed, as}) => {
const editor = composer(page) const editor = composer(page)
const rooms = page.locator(".secondary-nav") const rooms = page.locator(".secondary-nav")
await expect(sendButton(page)).toBeEnabled() await composerEnabled(page)
await editor.click() await editor.click()
await editor.pressSequentially("still thinking about this") await editor.pressSequentially("still thinking about this")

View file

@ -48,6 +48,12 @@ const composer = (page: Page) => page.locator(".chat-editor [contenteditable=tru
// The send button carries the shortcut it advertises, which differs by platform. // The send button carries the shortcut it advertises, which differs by platform.
const sendButton = (page: Page) => page.locator("button[data-tip$='enter to send']") const sendButton = (page: Page) => page.locator("button[data-tip$='enter to send']")
// The editor is where the composer says whether it is ready. The send button is not there to
// ask while the composer is empty, since a dictation button stands in its place. Only the
// conversation composer has a disabled state; a room's is usable as soon as it renders.
const composerEnabled = (page: Page) =>
expect(page.locator(".room__compose .chat-editor")).toHaveAttribute("aria-disabled", "false")
const timeline = (page: Page) => page.locator(".room__content") const timeline = (page: Page) => page.locator(".room__content")
const message = (page: Page, text: string) => page.locator(".room__item").filter({hasText: text}) const message = (page: Page, text: string) => page.locator(".room__item").filter({hasText: text})
@ -76,10 +82,10 @@ const modal = (page: Page, title: string) =>
const editorOf = (scope: Locator) => scope.locator(".note-editor [contenteditable=true]") const editorOf = (scope: Locator) => scope.locator(".note-editor [contenteditable=true]")
// The composer stays disabled until every recipient's messaging relays have been read, so waiting // Every caller of this sends to a room, whose composer gates on nothing, so the wait is for the
// on the send button is part of sending rather than a wait for a wait's sake. // room to have rendered one.
const send = async (page: Page, content: string) => { const send = async (page: Page, content: string) => {
await expect(sendButton(page)).toBeEnabled() await expect(composer(page)).toBeVisible()
await composer(page).click() await composer(page).click()
await composer(page).pressSequentially(content) await composer(page).pressSequentially(content)
await composer(page).press("Enter") await composer(page).press("Enter")
@ -561,7 +567,7 @@ test("US-073 a multi-part message reports one status", async ({seed, as}) => {
await mockBlossom(alice.context(), {server: BLOSSOM_ORIGIN}) await mockBlossom(alice.context(), {server: BLOSSOM_ORIGIN})
await mockBlossom(bob.context(), {server: BLOSSOM_ORIGIN}) await mockBlossom(bob.context(), {server: BLOSSOM_ORIGIN})
await expect(sendButton(alice)).toBeEnabled() await composerEnabled(alice)
await composer(alice).click() await composer(alice).click()
await composer(alice).pressSequentially("here is the harbour") await composer(alice).pressSequentially("here is the harbour")
@ -590,7 +596,7 @@ test("US-073 a multi-part message reports one status", async ({seed, as}) => {
// The same message to someone one of whose relays refuses it: each part says so for itself. // The same message to someone one of whose relays refuses it: each part says so for itself.
await alice.goto(chatPath(users.carol.pubkey)) await alice.goto(chatPath(users.carol.pubkey))
await expect(sendButton(alice)).toBeEnabled() await composerEnabled(alice)
await composer(alice).click() await composer(alice).click()
await composer(alice).pressSequentially("and one for you") await composer(alice).pressSequentially("and one for you")