Преглед изворни кода

refactor(tests): use expect.element for DOM assertions

Replace sync expect on locators with await expect.element across
browser integration tests. Scope config drawer checks to the theme
settings dialog and disambiguate the Sidebar label.
satnaing пре 2 месеци
родитељ
комит
75a1999786

+ 23 - 14
src/components/config-drawer.test.tsx

@@ -31,9 +31,9 @@ async function openDrawer(screen: RenderResult) {
   await userEvent.click(
     screen.getByRole('button', { name: /^Open theme settings$/i })
   )
-  await vi.waitFor(() =>
-    expect(screen.getByText(/^Theme Settings$/i)).toBeInTheDocument()
-  )
+  await expect
+    .element(screen.getByText(/^Theme Settings$/i))
+    .toBeInTheDocument()
 }
 
 describe('ConfigDrawer (integration)', () => {
@@ -51,14 +51,23 @@ describe('ConfigDrawer (integration)', () => {
 
     await openDrawer(screen)
 
-    expect(screen.getByText(/^Theme$/i)).toBeInTheDocument()
-    expect(screen.getByText(/^Layout$/i)).toBeInTheDocument()
-    expect(screen.getByText(/^Direction$/i)).toBeInTheDocument()
-    expect(
-      screen.getByRole('button', {
-        name: /reset all settings to default values/i,
-      })
-    ).toBeInTheDocument()
+    const drawer = screen.getByRole('dialog', { name: /theme settings/i })
+
+    await expect.element(drawer).toBeInTheDocument()
+
+    await expect.element(drawer.getByText(/^Theme$/i)).toBeInTheDocument()
+    await expect.element(drawer.getByText(/^Layout$/i)).toBeInTheDocument()
+    await expect
+      .element(drawer.getByText(/^Sidebar$/i).first())
+      .toBeInTheDocument()
+    await expect.element(drawer.getByText(/^Direction$/i)).toBeInTheDocument()
+    await expect
+      .element(
+        screen.getByRole('button', {
+          name: /reset all settings to default values/i,
+        })
+      )
+      .toBeInTheDocument()
   })
 
   describe('theme preference', () => {
@@ -257,9 +266,9 @@ describe('ConfigDrawer (integration)', () => {
 
     await openDrawer(screen)
 
-    expect(
-      screen.getByRole('radio', { name: /select default/i })
-    ).toHaveAttribute('data-state', 'checked')
+    await expect
+      .element(screen.getByRole('radio', { name: /select default/i }))
+      .toHaveAttribute('data-state', 'checked')
 
     await userEvent.click(
       screen.getByRole('radio', { name: /select compact/i })

+ 22 - 12
src/components/confirm-dialog.test.tsx

@@ -16,10 +16,16 @@ describe('ConfirmDialog', () => {
       />
     )
 
-    expect(getByRole('heading', { name: 'Delete item' })).toBeInTheDocument()
-    expect(getByText('This action cannot be undone.')).toBeInTheDocument()
-    expect(getByRole('button', { name: 'Cancel' })).toBeInTheDocument()
-    expect(getByRole('button', { name: 'Continue' })).toBeInTheDocument()
+    await expect
+      .element(getByRole('heading', { name: 'Delete item' }))
+      .toBeInTheDocument()
+    await expect
+      .element(getByText('This action cannot be undone.'))
+      .toBeInTheDocument()
+    await expect.element(getByRole('button', { name: 'Cancel' })).toBeInTheDocument()
+    await expect
+      .element(getByRole('button', { name: 'Continue' }))
+      .toBeInTheDocument()
   })
 
   it('calls handleConfirm when the confirm button is clicked', async () => {
@@ -53,7 +59,7 @@ describe('ConfirmDialog', () => {
     )
 
     const confirm = getByRole('button', { name: 'Continue' })
-    expect(confirm).toBeDisabled()
+    await expect.element(confirm).toBeDisabled()
     expect(handleConfirm).not.toHaveBeenCalled()
   })
 
@@ -70,8 +76,10 @@ describe('ConfirmDialog', () => {
       />
     )
 
-    expect(getByRole('button', { name: 'Cancel' })).toBeDisabled()
-    expect(getByRole('button', { name: 'Continue' })).toBeDisabled()
+    await expect.element(getByRole('button', { name: 'Cancel' })).toBeDisabled()
+    await expect
+      .element(getByRole('button', { name: 'Continue' }))
+      .toBeDisabled()
   })
 
   it('supports custom button texts', async () => {
@@ -87,8 +95,8 @@ describe('ConfirmDialog', () => {
       />
     )
 
-    expect(getByRole('button', { name: 'No' })).toBeInTheDocument()
-    expect(getByRole('button', { name: 'Yes' })).toBeInTheDocument()
+    await expect.element(getByRole('button', { name: 'No' })).toBeInTheDocument()
+    await expect.element(getByRole('button', { name: 'Yes' })).toBeInTheDocument()
   })
 
   it('renders confirm as submit button linked to desc form when `form` is set', async () => {
@@ -109,8 +117,10 @@ describe('ConfirmDialog', () => {
     )
 
     const deleteBtn = getByRole('button', { name: 'Delete' })
-    expect(deleteBtn).toHaveAttribute('type', 'submit')
-    expect(deleteBtn).toHaveAttribute('form', 'tasks-multi-delete-form')
+    await expect.element(deleteBtn).toHaveAttribute('type', 'submit')
+    await expect
+      .element(deleteBtn)
+      .toHaveAttribute('form', 'tasks-multi-delete-form')
   })
 
   it('submits the desc form when confirm is clicked (form prop, no handleConfirm)', async () => {
@@ -196,7 +206,7 @@ describe('ConfirmDialog', () => {
     )
 
     const deleteBtn = getByRole('button', { name: 'Delete' })
-    expect(deleteBtn).toBeDisabled()
+    await expect.element(deleteBtn).toBeDisabled()
     expect(handleFormSubmit).not.toHaveBeenCalled()
   })
 })

+ 15 - 13
src/components/password-input.test.tsx

@@ -20,9 +20,9 @@ describe('PasswordInput', () => {
     const passwordInput = getByPlaceholder('password')
     const showPasswordButton = getByRole('button', { name: /show password/i })
 
-    expect(passwordInput).toBeInTheDocument()
-    expect(passwordInput).toHaveAttribute('type', 'password')
-    expect(showPasswordButton).toBeVisible()
+    await expect.element(passwordInput).toBeInTheDocument()
+    await expect.element(passwordInput).toHaveAttribute('type', 'password')
+    await expect.element(showPasswordButton).toBeVisible()
   })
 
   it('toggles the password visibility when the show password button is clicked', async () => {
@@ -33,19 +33,21 @@ describe('PasswordInput', () => {
     const passwordInput = getByPlaceholder('password')
     const showPasswordButton = getByRole('button', { name: /show password/i })
 
-    expect(passwordInput).toHaveAttribute('type', 'password')
-    expect(showPasswordButton).toBeInTheDocument()
+    await expect.element(passwordInput).toHaveAttribute('type', 'password')
+    await expect.element(showPasswordButton).toBeInTheDocument()
 
     await userEvent.click(showPasswordButton)
 
-    expect(passwordInput).toHaveAttribute('type', 'text')
+    await expect.element(passwordInput).toHaveAttribute('type', 'text')
     const hidePasswordButton = getByRole('button', { name: /hide password/i })
-    expect(hidePasswordButton).toBeInTheDocument()
+    await expect.element(hidePasswordButton).toBeInTheDocument()
 
     await userEvent.click(hidePasswordButton)
 
-    expect(passwordInput).toHaveAttribute('type', 'password')
-    expect(getByRole('button', { name: /show password/i })).toBeInTheDocument()
+    await expect.element(passwordInput).toHaveAttribute('type', 'password')
+    await expect
+      .element(getByRole('button', { name: /show password/i }))
+      .toBeInTheDocument()
   })
 
   it('disables the show password button when the password input is disabled', async () => {
@@ -55,8 +57,8 @@ describe('PasswordInput', () => {
 
     const passwordInput = getByPlaceholder('password')
     const showPasswordButton = getByRole('button', { name: /show password/i })
-    expect(showPasswordButton).toBeDisabled()
-    expect(passwordInput).toBeDisabled()
+    await expect.element(showPasswordButton).toBeDisabled()
+    await expect.element(passwordInput).toBeDisabled()
   })
 
   it('works with FormLabel and react-hook-form field spread', async () => {
@@ -88,10 +90,10 @@ describe('PasswordInput', () => {
     const { getByLabelText } = await render(<PasswordInLabeledForm />)
 
     const password = getByLabelText(/^Password$/i)
-    expect(password).toHaveAttribute('type', 'password')
+    await expect.element(password).toHaveAttribute('type', 'password')
 
     await userEvent.type(password, 'secret-value')
 
-    expect(password).toHaveValue('secret-value')
+    await expect.element(password).toHaveValue('secret-value')
   })
 })

+ 32 - 24
src/context/search-provider.test.tsx

@@ -47,9 +47,9 @@ async function openCommandPalette(
         await userEvent.keyboard(`{${modifier}>}k{/${modifier}}`)
       }
 
-      expect(
-        screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
-      ).toBeInTheDocument()
+      await expect
+        .element(screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER))
+        .toBeInTheDocument()
     },
     { interval: 50, timeout: 5000 }
   )
@@ -66,18 +66,22 @@ describe('SearchProvider and CommandMenu', () => {
 
     await openCommandPalette(screen)
 
-    expect(getByPlaceholder(COMMAND_MENU_PLACEHOLDER)).toBeInTheDocument()
-    expect(getByText('Theme')).toBeInTheDocument()
-    expect(getByText('Light')).toBeInTheDocument()
-    expect(getByText('Dark')).toBeInTheDocument()
-    expect(getByText('System')).toBeInTheDocument()
-    expect(getByText('Dashboard')).toBeInTheDocument()
+    await expect
+      .element(getByPlaceholder(COMMAND_MENU_PLACEHOLDER))
+      .toBeInTheDocument()
+    await expect.element(getByText('Theme')).toBeInTheDocument()
+    await expect.element(getByText('Light')).toBeInTheDocument()
+    await expect.element(getByText('Dark')).toBeInTheDocument()
+    await expect.element(getByText('System')).toBeInTheDocument()
+    await expect.element(getByText('Dashboard')).toBeInTheDocument()
   })
 
   it('does not show the dialog content when search is closed', async () => {
     const { getByPlaceholder } = await renderWithSearchProvider()
 
-    expect(getByPlaceholder(COMMAND_MENU_PLACEHOLDER)).not.toBeInTheDocument()
+    await expect
+      .element(getByPlaceholder(COMMAND_MENU_PLACEHOLDER))
+      .not.toBeInTheDocument()
   })
 
   it.each([
@@ -88,15 +92,15 @@ describe('SearchProvider and CommandMenu', () => {
     async (_label, modifier) => {
       const screen = await renderWithSearchProvider()
 
-      expect(
-        screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
-      ).not.toBeInTheDocument()
+      await expect
+        .element(screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER))
+        .not.toBeInTheDocument()
 
       await openCommandPalette(screen, modifier)
 
-      expect(
-        screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
-      ).toBeInTheDocument()
+      await expect
+        .element(screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER))
+        .toBeInTheDocument()
     }
   )
 
@@ -108,9 +112,9 @@ describe('SearchProvider and CommandMenu', () => {
     await userEvent.click(screen.getByText('Tasks'))
 
     expect(mocks.navigate).toHaveBeenCalledWith({ to: '/tasks' })
-    expect(
-      screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
-    ).not.toBeInTheDocument()
+    await expect
+      .element(screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER))
+      .not.toBeInTheDocument()
   })
 
   it('navigates for nested sidebar items (group with sub-items)', async () => {
@@ -122,7 +126,9 @@ describe('SearchProvider and CommandMenu', () => {
     await userEvent.click(getByRole('option', { name: 'Settings Account' }))
 
     expect(mocks.navigate).toHaveBeenCalledWith({ to: '/settings/account' })
-    expect(getByPlaceholder(COMMAND_MENU_PLACEHOLDER)).not.toBeInTheDocument()
+    await expect
+      .element(getByPlaceholder(COMMAND_MENU_PLACEHOLDER))
+      .not.toBeInTheDocument()
   })
 
   it('applies theme and closes the palette when a theme command is chosen', async () => {
@@ -133,9 +139,9 @@ describe('SearchProvider and CommandMenu', () => {
     await userEvent.click(screen.getByText('Dark'))
 
     expect(mocks.setTheme).toHaveBeenCalledWith('dark')
-    expect(
-      screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER)
-    ).not.toBeInTheDocument()
+    await expect
+      .element(screen.getByPlaceholder(COMMAND_MENU_PLACEHOLDER))
+      .not.toBeInTheDocument()
   })
 
   it('shows empty state when the filter matches nothing', async () => {
@@ -148,6 +154,8 @@ describe('SearchProvider and CommandMenu', () => {
       'zzzz-no-match-xxxx'
     )
 
-    expect(screen.getByText('No results found.')).toBeInTheDocument()
+    await expect
+      .element(screen.getByText('No results found.'))
+      .toBeInTheDocument()
   })
 })

+ 6 - 4
src/features/auth/forgot-password/components/forgot-password-form.test.tsx

@@ -29,13 +29,15 @@ describe('ForgotPasswordForm', () => {
   })
 
   it('renders email field and continue button', async () => {
-    expect(emailInput).toBeInTheDocument()
-    expect(continueButton).toBeInTheDocument()
+    await expect.element(emailInput).toBeInTheDocument()
+    await expect.element(continueButton).toBeInTheDocument()
   })
 
   it('shows validation when submitting empty form', async () => {
     await userEvent.click(continueButton)
-    expect(screen.getByText(/^Please enter your email\.$/i)).toBeInTheDocument()
+    await expect
+      .element(screen.getByText(/^Please enter your email\.$/i))
+      .toBeInTheDocument()
   })
 
   it('resets the form and navigates to /otp on success', async () => {
@@ -47,6 +49,6 @@ describe('ForgotPasswordForm', () => {
     )
 
     // Form should reset on success
-    expect(emailInput).toHaveValue('')
+    await expect.element(emailInput).toHaveValue('')
   })
 })

+ 3 - 3
src/features/auth/otp/components/otp-form.test.tsx

@@ -31,13 +31,13 @@ describe('OtpForm', () => {
   })
 
   it('disables Verify until 6 digits are entered', async () => {
-    expect(verifyButton).toBeDisabled()
+    await expect.element(verifyButton).toBeDisabled()
 
     await userEvent.fill(otpInput, '12345')
-    expect(verifyButton).toBeDisabled()
+    await expect.element(verifyButton).toBeDisabled()
 
     await userEvent.fill(otpInput, '123456')
-    expect(verifyButton).toBeEnabled()
+    await expect.element(verifyButton).toBeEnabled()
   })
 
   it('submits the OTP and navigates after timeout', async () => {

+ 10 - 6
src/features/auth/sign-in/components/user-auth-form.test.tsx

@@ -67,17 +67,21 @@ describe('UserAuthForm', () => {
     })
 
     it('renders fields, submit button, and forgot password link', async () => {
-      expect(emailInput).toBeInTheDocument()
-      expect(passwordInput).toBeInTheDocument()
-      expect(signInButton).toBeInTheDocument()
-      expect(forgotPasswordLink).toBeInTheDocument()
+      await expect.element(emailInput).toBeInTheDocument()
+      await expect.element(passwordInput).toBeInTheDocument()
+      await expect.element(signInButton).toBeInTheDocument()
+      await expect.element(forgotPasswordLink).toBeInTheDocument()
     })
 
     it('shows validation messages when submitting empty form', async () => {
       await userEvent.click(signInButton)
 
-      expect(screen.getByText(FORM_MESSAGES.emailEmpty)).toBeInTheDocument()
-      expect(screen.getByText(FORM_MESSAGES.passwordEmpty)).toBeInTheDocument()
+      await expect
+        .element(screen.getByText(FORM_MESSAGES.emailEmpty))
+        .toBeInTheDocument()
+      await expect
+        .element(screen.getByText(FORM_MESSAGES.passwordEmpty))
+        .toBeInTheDocument()
     })
 
     it('authenticates and navigates to default route on success', async () => {

+ 18 - 12
src/features/auth/sign-up/components/sign-up-form.test.tsx

@@ -40,20 +40,24 @@ describe('SignUpForm', () => {
   })
 
   it('renders fields and submit button', async () => {
-    expect(emailInput).toBeInTheDocument()
-    expect(passwordInput).toBeInTheDocument()
-    expect(confirmPasswordInput).toBeInTheDocument()
-    expect(submitButton).toBeInTheDocument()
+    await expect.element(emailInput).toBeInTheDocument()
+    await expect.element(passwordInput).toBeInTheDocument()
+    await expect.element(confirmPasswordInput).toBeInTheDocument()
+    await expect.element(submitButton).toBeInTheDocument()
   })
 
   it('shows validation messages when submitting empty form', async () => {
     await userEvent.click(submitButton)
 
-    expect(screen.getByText(FORM_MESSAGES.emailEmpty)).toBeInTheDocument()
-    expect(screen.getByText(FORM_MESSAGES.passwordEmpty)).toBeInTheDocument()
-    expect(
-      screen.getByText(FORM_MESSAGES.confirmPasswordEmpty)
-    ).toBeInTheDocument()
+    await expect
+      .element(screen.getByText(FORM_MESSAGES.emailEmpty))
+      .toBeInTheDocument()
+    await expect
+      .element(screen.getByText(FORM_MESSAGES.passwordEmpty))
+      .toBeInTheDocument()
+    await expect
+      .element(screen.getByText(FORM_MESSAGES.confirmPasswordEmpty))
+      .toBeInTheDocument()
   })
 
   it('shows a mismatch error when passwords do not match', async () => {
@@ -62,7 +66,9 @@ describe('SignUpForm', () => {
     await userEvent.fill(confirmPasswordInput, '7654321')
 
     await userEvent.click(submitButton)
-    expect(screen.getByText(FORM_MESSAGES.passwordMismatch)).toBeInTheDocument()
+    await expect
+      .element(screen.getByText(FORM_MESSAGES.passwordMismatch))
+      .toBeInTheDocument()
   })
 
   it('disables submit while submitting and re-enables after timeout', async () => {
@@ -73,10 +79,10 @@ describe('SignUpForm', () => {
     await userEvent.fill(confirmPasswordInput, '1234567')
 
     await userEvent.click(submitButton)
-    expect(submitButton).toBeDisabled()
+    await expect.element(submitButton).toBeDisabled()
 
     await vi.advanceTimersByTimeAsync(2000)
-    await vi.waitFor(() => expect(submitButton).toBeEnabled())
+    await expect.element(submitButton).toBeEnabled()
     expect(toastPromise).toHaveBeenCalledOnce()
   })
 })

+ 7 - 5
src/features/tasks/components/tasks-import-dialog.test.tsx

@@ -28,11 +28,11 @@ describe('TasksImportDialog', () => {
 
     const importButton = getByRole('button', { name: /^Import$/i })
 
-    expect(title).toBeInTheDocument()
-    expect(desc).toBeInTheDocument()
-    expect(fileInput).toBeInTheDocument()
+    await expect.element(title).toBeInTheDocument()
+    await expect.element(desc).toBeInTheDocument()
+    await expect.element(fileInput).toBeInTheDocument()
     expect(closeButtons).toHaveLength(2)
-    expect(importButton).toBeInTheDocument()
+    await expect.element(importButton).toBeInTheDocument()
   })
 
   it('shows validation when submitting without a file', async () => {
@@ -44,7 +44,9 @@ describe('TasksImportDialog', () => {
     const importButton = getByRole('button', { name: /^Import$/i })
     await userEvent.click(importButton)
 
-    expect(getByText('Please upload a file.')).toBeInTheDocument()
+    await expect
+      .element(getByText('Please upload a file.'))
+      .toBeInTheDocument()
     expect(onOpenChange).not.toHaveBeenCalled()
     expect(showSubmittedData).not.toHaveBeenCalled()
   })

+ 15 - 15
src/features/tasks/components/tasks-multi-delete-dialog.test.tsx

@@ -43,12 +43,12 @@ describe('TasksMultiDeleteDialog', () => {
     const cancelButton = getByRole('button', { name: /Cancel/i })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(title).toBeInTheDocument()
-    expect(desc).toBeInTheDocument()
-    expect(confirmDeleteInput).toBeInTheDocument()
-    expect(cancelButton).toBeInTheDocument()
-    expect(deleteButton).toBeInTheDocument()
-    expect(deleteButton).toBeDisabled()
+    await expect.element(title).toBeInTheDocument()
+    await expect.element(desc).toBeInTheDocument()
+    await expect.element(confirmDeleteInput).toBeInTheDocument()
+    await expect.element(cancelButton).toBeInTheDocument()
+    await expect.element(deleteButton).toBeInTheDocument()
+    await expect.element(deleteButton).toBeDisabled()
   })
 
   it('keeps the delete button disabled until the confirm delete input is filled correctly', async () => {
@@ -62,13 +62,13 @@ describe('TasksMultiDeleteDialog', () => {
     })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(confirmDeleteInput, 'wrong-input')
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(confirmDeleteInput, 'DELETE')
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
   })
 
   it('closes the dialog when the cancel button is clicked', async () => {
@@ -112,14 +112,14 @@ describe('TasksMultiDeleteDialog', () => {
       name: /Confirm by typing "DELETE"/i,
     })
     await userEvent.fill(confirmDeleteInput, 'DELETE')
-    expect(confirmDeleteInput).toHaveValue('DELETE')
+    await expect.element(confirmDeleteInput).toHaveValue('DELETE')
 
     const cancelButton = getByRole('button', { name: /Cancel/i })
     await userEvent.click(cancelButton)
 
     const reopenButton = getByRole('button', { name: /Reopen/i })
     await userEvent.click(reopenButton)
-    expect(confirmDeleteInput).toHaveValue('')
+    await expect.element(confirmDeleteInput).toHaveValue('')
   })
 
   it('shows the submitted data when deleted successfully', async () => {
@@ -134,10 +134,10 @@ describe('TasksMultiDeleteDialog', () => {
     })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(confirmDeleteInput, 'DELETE')
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
 
     await userEvent.click(deleteButton)
 
@@ -159,10 +159,10 @@ describe('TasksMultiDeleteDialog', () => {
     })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(confirmDeleteInput, 'DELETE')
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
 
     await userEvent.keyboard('{Enter}')
     expect(onOpenChange).toHaveBeenCalledOnce()

+ 30 - 20
src/features/tasks/components/tasks-mutate-drawer.test.tsx

@@ -30,8 +30,8 @@ describe('TasksMutateDrawer', () => {
     })
     const desc = getByText(/Add a new task/i)
 
-    expect(title).toBeInTheDocument()
-    expect(desc).toBeInTheDocument()
+    await expect.element(title).toBeInTheDocument()
+    await expect.element(desc).toBeInTheDocument()
   })
 
   it('renders edit title, description, and prefilled title', async () => {
@@ -50,12 +50,14 @@ describe('TasksMutateDrawer', () => {
     const labelRadio = getByRole('radio', { name: MOCK_TASK.label })
     const priorityRadio = getByRole('radio', { name: MOCK_TASK.priority })
 
-    expect(title).toBeInTheDocument()
-    expect(desc).toBeInTheDocument()
-    expect(titleInput).toHaveValue(MOCK_TASK.title)
-    expect(statusSelect).toHaveTextContent(new RegExp(MOCK_TASK.status, 'i'))
-    expect(labelRadio).toBeChecked()
-    expect(priorityRadio).toBeChecked()
+    await expect.element(title).toBeInTheDocument()
+    await expect.element(desc).toBeInTheDocument()
+    await expect.element(titleInput).toHaveValue(MOCK_TASK.title)
+    await expect
+      .element(statusSelect)
+      .toHaveTextContent(new RegExp(MOCK_TASK.status, 'i'))
+    await expect.element(labelRadio).toBeChecked()
+    await expect.element(priorityRadio).toBeChecked()
   })
 
   it('shows validation messages when submitting an empty form', async () => {
@@ -66,10 +68,18 @@ describe('TasksMutateDrawer', () => {
     const saveButton = getByRole('button', { name: /Save changes/i })
     await userEvent.click(saveButton)
 
-    expect(getByText(/Title is required.$/i)).toBeInTheDocument()
-    expect(getByText(/Please select a status.$/i)).toBeInTheDocument()
-    expect(getByText(/Please select a label.$/i)).toBeInTheDocument()
-    expect(getByText(/Please choose a priority.$/i)).toBeInTheDocument()
+    await expect
+      .element(getByText(/Title is required.$/i))
+      .toBeInTheDocument()
+    await expect
+      .element(getByText(/Please select a status.$/i))
+      .toBeInTheDocument()
+    await expect
+      .element(getByText(/Please select a label.$/i))
+      .toBeInTheDocument()
+    await expect
+      .element(getByText(/Please choose a priority.$/i))
+      .toBeInTheDocument()
   })
 
   it('submits create form and shows submitted data', async () => {
@@ -138,20 +148,20 @@ describe('TasksMutateDrawer', () => {
 
     const titleInput = getByRole('textbox', { name: /Title/i })
     await userEvent.fill(titleInput, 'Draft title')
-    expect(titleInput).toHaveValue('Draft title')
+    await expect.element(titleInput).toHaveValue('Draft title')
 
     const statusSelect = getByRole('combobox', { name: /Status/i })
     await userEvent.click(statusSelect)
     await userEvent.click(getByRole('option', { name: /Todo/i }))
-    expect(statusSelect).toHaveTextContent(/Todo/i)
+    await expect.element(statusSelect).toHaveTextContent(/Todo/i)
 
     const labelRadio = getByRole('radio', { name: /^Documentation$/i })
     await userEvent.click(labelRadio)
-    expect(labelRadio).toBeChecked()
+    await expect.element(labelRadio).toBeChecked()
 
     const priorityRadio = getByRole('radio', { name: /^High$/i })
     await userEvent.click(priorityRadio)
-    expect(priorityRadio).toBeChecked()
+    await expect.element(priorityRadio).toBeChecked()
 
     const closeButtons = getByRole('dialog')
       .getByRole('button', {
@@ -163,9 +173,9 @@ describe('TasksMutateDrawer', () => {
     const reopenButton = getByRole('button', { name: /Reopen/i })
     await userEvent.click(reopenButton)
 
-    expect(titleInput).toHaveValue('')
-    expect(statusSelect).not.toHaveTextContent(/Todo/i)
-    expect(labelRadio).not.toBeChecked()
-    expect(priorityRadio).not.toBeChecked()
+    await expect.element(titleInput).toHaveValue('')
+    await expect.element(statusSelect).not.toHaveTextContent(/Todo/i)
+    await expect.element(labelRadio).not.toBeChecked()
+    await expect.element(priorityRadio).not.toBeChecked()
   })
 })

+ 53 - 35
src/features/users/components/users-action-dialog.test.tsx

@@ -51,8 +51,8 @@ describe('UsersActionDialog', () => {
         /Create new user here. Click save when you're done./i
       )
 
-      expect(title).toBeInTheDocument()
-      expect(description).toBeInTheDocument()
+      await expect.element(title).toBeInTheDocument()
+      await expect.element(description).toBeInTheDocument()
     })
 
     it('shows validation messages when the form is submitted with empty fields', async () => {
@@ -63,13 +63,27 @@ describe('UsersActionDialog', () => {
       const submitButton = getByRole('button', { name: /Save Changes/i })
       await userEvent.click(submitButton)
 
-      expect(getByText(VALIDATION_MESSAGES.firstName)).toBeInTheDocument()
-      expect(getByText(VALIDATION_MESSAGES.lastName)).toBeInTheDocument()
-      expect(getByText(VALIDATION_MESSAGES.username)).toBeInTheDocument()
-      expect(getByText(VALIDATION_MESSAGES.phoneNumber)).toBeInTheDocument()
-      expect(getByText(VALIDATION_MESSAGES.email)).toBeInTheDocument()
-      expect(getByText(VALIDATION_MESSAGES.role)).toBeInTheDocument()
-      expect(getByText(VALIDATION_MESSAGES.password)).toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.firstName))
+        .toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.lastName))
+        .toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.username))
+        .toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.phoneNumber))
+        .toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.email))
+        .toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.role))
+        .toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.password))
+        .toBeInTheDocument()
     })
 
     it('keeps confirm password disabled until password field is touched', async () => {
@@ -81,10 +95,10 @@ describe('UsersActionDialog', () => {
       const confirmPassword = getByRole('textbox', {
         name: /Confirm Password/i,
       })
-      expect(confirmPassword).toBeDisabled()
+      await expect.element(confirmPassword).toBeDisabled()
 
       await userEvent.type(password, 'a')
-      expect(confirmPassword).toBeEnabled()
+      await expect.element(confirmPassword).toBeEnabled()
     })
 
     it('shows password validation messages when password is invalid', async () => {
@@ -102,36 +116,40 @@ describe('UsersActionDialog', () => {
 
       await userEvent.click(submitButton)
 
-      expect(
-        getByText(VALIDATION_MESSAGES.passwordMismatch)
-      ).toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.passwordMismatch))
+        .toBeInTheDocument()
 
       await userEvent.fill(password, 'short')
 
-      expect(getByText(VALIDATION_MESSAGES.passwordLength)).toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.passwordLength))
+        .toBeInTheDocument()
 
       await userEvent.fill(password, 'ONLYUPPERCASE')
 
-      expect(
-        getByText(VALIDATION_MESSAGES.passwordLowercase)
-      ).toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.passwordLowercase))
+        .toBeInTheDocument()
 
       await userEvent.fill(password, 'onlylowercase')
 
-      expect(getByText(VALIDATION_MESSAGES.passwordNumber)).toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.passwordNumber))
+        .toBeInTheDocument()
 
       await userEvent.fill(password, 'S3cur3P@ssw0rd')
       await userEvent.fill(confirmPassword, 'S3cur3P@ssw0rd')
 
-      expect(
-        getByText(VALIDATION_MESSAGES.passwordMismatch)
-      ).not.toBeInTheDocument()
-      expect(
-        getByText(VALIDATION_MESSAGES.passwordLength)
-      ).not.toBeInTheDocument()
-      expect(
-        getByText(VALIDATION_MESSAGES.passwordNumber)
-      ).not.toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.passwordMismatch))
+        .not.toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.passwordLength))
+        .not.toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.passwordNumber))
+        .not.toBeInTheDocument()
     })
 
     it('shows the submitted data when the form is submitted successfully', async () => {
@@ -180,8 +198,8 @@ describe('UsersActionDialog', () => {
         /Update the user here\. Click save when you're done\./i
       )
 
-      expect(title).toBeInTheDocument()
-      expect(description).toBeInTheDocument()
+      await expect.element(title).toBeInTheDocument()
+      await expect.element(description).toBeInTheDocument()
     })
 
     it('submits without password changes', async () => {
@@ -225,14 +243,14 @@ describe('UsersActionDialog', () => {
       })
 
       await userEvent.fill(password, 'S3cur3P@ssw0rd')
-      expect(confirmPassword).toBeEnabled()
+      await expect.element(confirmPassword).toBeEnabled()
 
       const submitButton = getByRole('button', { name: /Save Changes/i })
       await userEvent.click(submitButton)
 
-      expect(
-        getByText(VALIDATION_MESSAGES.passwordMismatch)
-      ).toBeInTheDocument()
+      await expect
+        .element(getByText(VALIDATION_MESSAGES.passwordMismatch))
+        .toBeInTheDocument()
     })
 
     it('shows the submitted data when the form is submitted successfully', async () => {
@@ -303,7 +321,7 @@ async function fillRequiredProfileFields(
 
   for (const [label, value] of entries) {
     const el = screen.getByLabelText(label)
-    expect(el).toBeInTheDocument()
+    await expect.element(el).toBeInTheDocument()
     await user.type(el, value)
   }
 

+ 15 - 15
src/features/users/components/users-delete-dialog.test.tsx

@@ -40,12 +40,12 @@ describe('UsersDeleteDialog', () => {
     const cancelButton = getByRole('button', { name: /Cancel/i })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(title).toBeInTheDocument()
-    expect(desc).toBeInTheDocument()
-    expect(usernameInput).toBeInTheDocument()
-    expect(cancelButton).toBeInTheDocument()
-    expect(deleteButton).toBeInTheDocument()
-    expect(deleteButton).toBeDisabled()
+    await expect.element(title).toBeInTheDocument()
+    await expect.element(desc).toBeInTheDocument()
+    await expect.element(usernameInput).toBeInTheDocument()
+    await expect.element(cancelButton).toBeInTheDocument()
+    await expect.element(deleteButton).toBeInTheDocument()
+    await expect.element(deleteButton).toBeDisabled()
   })
 
   it('keeps the delete button disabled until the username input is filled correctly', async () => {
@@ -56,13 +56,13 @@ describe('UsersDeleteDialog', () => {
     const usernameInput = getByRole('textbox', { name: /Username/i })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(usernameInput, 'wrong-username')
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(usernameInput, MOCK_USER.username)
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
   })
 
   it('closes the dialog when the cancel button is clicked', async () => {
@@ -105,14 +105,14 @@ describe('UsersDeleteDialog', () => {
 
     const usernameInput = getByRole('textbox', { name: /Username/i })
     await userEvent.fill(usernameInput, MOCK_USER.username)
-    expect(usernameInput).toHaveValue(MOCK_USER.username)
+    await expect.element(usernameInput).toHaveValue(MOCK_USER.username)
 
     const closeButton = getByRole('button', { name: /Cancel/i })
     await userEvent.click(closeButton)
 
     const reopenButton = getByRole('button', { name: /Reopen/i })
     await userEvent.click(reopenButton)
-    expect(usernameInput).toHaveValue('')
+    await expect.element(usernameInput).toHaveValue('')
   })
 
   it('shows the submitted data when deleted successfully', async () => {
@@ -128,11 +128,11 @@ describe('UsersDeleteDialog', () => {
     const usernameInput = getByRole('textbox', { name: /Username/i })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(usernameInput, MOCK_USER.username)
 
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
 
     await userEvent.click(deleteButton)
 
@@ -159,10 +159,10 @@ describe('UsersDeleteDialog', () => {
     const usernameInput = getByRole('textbox', { name: /Username/i })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(usernameInput, MOCK_USER.username)
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
 
     await userEvent.keyboard('{Enter}')
 

+ 10 - 10
src/features/users/components/users-invite-dialog.test.tsx

@@ -61,8 +61,8 @@ describe('UsersInviteDialog', () => {
     const submitButton = getByRole('button', { name: /Invite/i })
     await userEvent.click(submitButton)
 
-    expect(emailErrorMessage).toBeInTheDocument()
-    expect(roleErrorMessage).toBeInTheDocument()
+    await expect.element(emailErrorMessage).toBeInTheDocument()
+    await expect.element(roleErrorMessage).toBeInTheDocument()
 
     const emailInput = getByRole('textbox', { name: /Email/i })
     await userEvent.fill(emailInput, 'test@example.com')
@@ -71,8 +71,8 @@ describe('UsersInviteDialog', () => {
     await userEvent.click(roleSelect)
     await userEvent.click(getByRole('option', { name: /Superadmin/i }))
 
-    expect(emailErrorMessage).not.toBeInTheDocument()
-    expect(roleErrorMessage).not.toBeInTheDocument()
+    await expect.element(emailErrorMessage).not.toBeInTheDocument()
+    await expect.element(roleErrorMessage).not.toBeInTheDocument()
   })
 
   it('resets entered values when the dialog is closed and reopened', async () => {
@@ -104,9 +104,9 @@ describe('UsersInviteDialog', () => {
     const descInput = getByRole('textbox', { name: /Description/i })
     await userEvent.fill(descInput, DESC_VALUE)
 
-    expect(emailInput).toHaveValue(EMAIL_VALUE)
-    expect(roleSelect).toHaveTextContent(ROLE_VALUE)
-    expect(descInput).toHaveValue(DESC_VALUE)
+    await expect.element(emailInput).toHaveValue(EMAIL_VALUE)
+    await expect.element(roleSelect).toHaveTextContent(ROLE_VALUE)
+    await expect.element(descInput).toHaveValue(DESC_VALUE)
 
     const cancelButton = getByRole('button', { name: /Cancel/i })
     await userEvent.click(cancelButton)
@@ -114,9 +114,9 @@ describe('UsersInviteDialog', () => {
     const reopenButton = getByRole('button', { name: /Reopen/i })
     await userEvent.click(reopenButton)
 
-    expect(emailInput).toHaveValue('')
-    expect(roleSelect).toHaveTextContent('Select a role')
-    expect(descInput).toHaveValue('')
+    await expect.element(emailInput).toHaveValue('')
+    await expect.element(roleSelect).toHaveTextContent('Select a role')
+    await expect.element(descInput).toHaveValue('')
   })
 
   it('shows submitted data when the form is submitted successfully', async () => {

+ 14 - 14
src/features/users/components/users-multi-delete-dialog.test.tsx

@@ -42,11 +42,11 @@ describe('UsersMultiDeleteDialog', () => {
     })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(title).toBeInTheDocument()
-    expect(desc).toBeInTheDocument()
-    expect(confirmDeleteInput).toBeInTheDocument()
-    expect(deleteButton).toBeInTheDocument()
-    expect(deleteButton).toBeDisabled()
+    await expect.element(title).toBeInTheDocument()
+    await expect.element(desc).toBeInTheDocument()
+    await expect.element(confirmDeleteInput).toBeInTheDocument()
+    await expect.element(deleteButton).toBeInTheDocument()
+    await expect.element(deleteButton).toBeDisabled()
   })
 
   it('keeps the delete button disabled until the confirm delete input is filled correctly', async () => {
@@ -60,13 +60,13 @@ describe('UsersMultiDeleteDialog', () => {
     })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(confirmDeleteInput, 'wrong-input')
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(confirmDeleteInput, 'DELETE')
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
   })
 
   it('closes the dialog when the cancel button is clicked', async () => {
@@ -110,14 +110,14 @@ describe('UsersMultiDeleteDialog', () => {
       name: /Confirm by typing "DELETE"/i,
     })
     await userEvent.fill(confirmDeleteInput, 'DELETE')
-    expect(confirmDeleteInput).toHaveValue('DELETE')
+    await expect.element(confirmDeleteInput).toHaveValue('DELETE')
 
     const cancelButton = getByRole('button', { name: /Cancel/i })
     await userEvent.click(cancelButton)
 
     const reopenButton = getByRole('button', { name: /Reopen/i })
     await userEvent.click(reopenButton)
-    expect(confirmDeleteInput).toHaveValue('')
+    await expect.element(confirmDeleteInput).toHaveValue('')
   })
 
   it('shows the submitted data when deleted successfully', async () => {
@@ -132,10 +132,10 @@ describe('UsersMultiDeleteDialog', () => {
     })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(confirmDeleteInput, 'DELETE')
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
 
     await userEvent.click(deleteButton)
 
@@ -157,10 +157,10 @@ describe('UsersMultiDeleteDialog', () => {
     })
     const deleteButton = getByRole('button', { name: /Delete/i })
 
-    expect(deleteButton).toBeDisabled()
+    await expect.element(deleteButton).toBeDisabled()
 
     await userEvent.fill(confirmDeleteInput, 'DELETE')
-    expect(deleteButton).toBeEnabled()
+    await expect.element(deleteButton).toBeEnabled()
 
     await userEvent.keyboard('{Enter}')
     expect(onOpenChange).toHaveBeenCalledOnce()