mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-27 11:56:42 +08:00
fix(web): stabilize invitation error assertions
The invitation error copy also renders as a transient sonner toast, so the plain text locator resolved to two elements and tripped Playwright strict mode while the toast was on screen. Tag the inline error region with data-testid="invitation-error" and assert against it, keeping the check deterministic under CI parallelism.
This commit is contained in:
@@ -296,7 +296,7 @@ export default function AcceptInvitationPage() {
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-start gap-2 rounded-lg border border-destructive/20 bg-destructive/5 p-3 text-sm text-destructive">
|
<div className="flex items-start gap-2 rounded-lg border border-destructive/20 bg-destructive/5 p-3 text-sm text-destructive">
|
||||||
<AlertCircle className="mt-0.5 size-4 shrink-0" />
|
<AlertCircle className="mt-0.5 size-4 shrink-0" />
|
||||||
<span>{errorMessage}</span>
|
<span data-testid="invitation-error">{errorMessage}</span>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -313,7 +313,7 @@ export default function AcceptInvitationPage() {
|
|||||||
{errorMessage && (
|
{errorMessage && (
|
||||||
<div className="flex items-start gap-2 rounded-lg border border-destructive/20 bg-destructive/5 p-3 text-sm text-destructive">
|
<div className="flex items-start gap-2 rounded-lg border border-destructive/20 bg-destructive/5 p-3 text-sm text-destructive">
|
||||||
<AlertCircle className="mt-0.5 size-4 shrink-0" />
|
<AlertCircle className="mt-0.5 size-4 shrink-0" />
|
||||||
<span>{errorMessage}</span>
|
<span data-testid="invitation-error">{errorMessage}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ test('terminal invitation errors refresh on a new fragment and allow account swi
|
|||||||
});
|
});
|
||||||
|
|
||||||
await page.goto('/invitations/accept#token=used-invitation');
|
await page.goto('/invitations/accept#token=used-invitation');
|
||||||
await expect(
|
await expect(page.getByTestId('invitation-error')).toContainText(
|
||||||
page.getByText('This invitation was already used.'),
|
'This invitation was already used.',
|
||||||
).toBeVisible();
|
);
|
||||||
await expect
|
await expect
|
||||||
.poll(() =>
|
.poll(() =>
|
||||||
page.evaluate(() =>
|
page.evaluate(() =>
|
||||||
@@ -41,7 +41,9 @@ test('terminal invitation errors refresh on a new fragment and allow account swi
|
|||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
window.location.hash = 'token=revoked-invitation';
|
window.location.hash = 'token=revoked-invitation';
|
||||||
});
|
});
|
||||||
await expect(page.getByText('This invitation was revoked.')).toBeVisible();
|
await expect(page.getByTestId('invitation-error')).toContainText(
|
||||||
|
'This invitation was revoked.',
|
||||||
|
);
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Back to sign in' }).click();
|
await page.getByRole('button', { name: 'Back to sign in' }).click();
|
||||||
await expect(page).toHaveURL(/\/login$/);
|
await expect(page).toHaveURL(/\/login$/);
|
||||||
@@ -101,9 +103,11 @@ test('login preserves an explicit invitation email mismatch error', async ({
|
|||||||
await expect(page).toHaveURL(
|
await expect(page).toHaveURL(
|
||||||
/\/invitations\/accept\?error=invitation_email_mismatch$/,
|
/\/invitations\/accept\?error=invitation_email_mismatch$/,
|
||||||
);
|
);
|
||||||
await expect(
|
// The same copy is also shown as a transient toast, so target the page's
|
||||||
page.getByText('This invitation belongs to a different email address.'),
|
// inline error region to keep the assertion deterministic.
|
||||||
).toBeVisible();
|
await expect(page.getByTestId('invitation-error')).toContainText(
|
||||||
|
'This invitation belongs to a different email address.',
|
||||||
|
);
|
||||||
await expect(page.getByText('Login successful')).toHaveCount(0);
|
await expect(page.getByText('Login successful')).toHaveCount(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user