mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-21 20:06:06 +00:00
183 lines
5.5 KiB
TypeScript
183 lines
5.5 KiB
TypeScript
import { expect, test } from '@playwright/test';
|
|
|
|
import { installLangBotApiMocks } from './fixtures/langbot-api';
|
|
|
|
test('terminal invitation errors refresh on a new fragment and allow account switching', async ({
|
|
page,
|
|
}) => {
|
|
await installLangBotApiMocks(page, {
|
|
storage: {
|
|
token: 'playwright-token',
|
|
userEmail: 'another-account@example.com',
|
|
},
|
|
});
|
|
await page.route('**/api/v1/invitations/inspect', async (route) => {
|
|
const body = JSON.parse(route.request().postData() || '{}') as {
|
|
token?: string;
|
|
};
|
|
const code =
|
|
body.token === 'revoked-invitation'
|
|
? 'invitation_revoked'
|
|
: 'invitation_used';
|
|
await route.fulfill({
|
|
status: 410,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ code, msg: code }),
|
|
});
|
|
});
|
|
|
|
await page.goto('/invitations/accept#token=used-invitation');
|
|
await expect(
|
|
page.getByText('This invitation was already used.'),
|
|
).toBeVisible();
|
|
await expect
|
|
.poll(() =>
|
|
page.evaluate(() =>
|
|
sessionStorage.getItem('langbot_pending_invitation_token'),
|
|
),
|
|
)
|
|
.toBeNull();
|
|
|
|
await page.evaluate(() => {
|
|
window.location.hash = 'token=revoked-invitation';
|
|
});
|
|
await expect(page.getByText('This invitation was revoked.')).toBeVisible();
|
|
|
|
await page.getByRole('button', { name: 'Back to sign in' }).click();
|
|
await expect(page).toHaveURL(/\/login$/);
|
|
await expect(page.getByText('Welcome')).toBeVisible();
|
|
expect(
|
|
await page.evaluate(() => ({
|
|
token: localStorage.getItem('token'),
|
|
userEmail: localStorage.getItem('userEmail'),
|
|
})),
|
|
).toEqual({ token: null, userEmail: null });
|
|
});
|
|
|
|
test('login preserves an explicit invitation email mismatch error', async ({
|
|
page,
|
|
}) => {
|
|
await installLangBotApiMocks(page, { authenticated: false });
|
|
await page.route('**/api/v1/invitations/inspect', async (route) => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
code: 0,
|
|
data: {
|
|
invitation: {
|
|
uuid: 'mismatch-invitation',
|
|
workspace_uuid: 'workspace-playwright',
|
|
normalized_email: 'invited@example.com',
|
|
role: 'viewer',
|
|
status: 'pending',
|
|
},
|
|
workspace: {
|
|
uuid: 'workspace-playwright',
|
|
name: 'Playwright Workspace',
|
|
},
|
|
},
|
|
msg: 'ok',
|
|
}),
|
|
});
|
|
});
|
|
await page.route('**/api/v1/invitations/accept', async (route) => {
|
|
await route.fulfill({
|
|
status: 400,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
code: 'invitation_email_mismatch',
|
|
msg: 'Invitation email does not match the Account',
|
|
}),
|
|
});
|
|
});
|
|
|
|
await page.goto('/invitations/accept#token=mismatch-invitation');
|
|
await page.getByRole('button', { name: 'I already have an account' }).click();
|
|
await page.getByPlaceholder('Enter email address').fill('other@example.com');
|
|
await page.getByPlaceholder('Enter password').fill('password');
|
|
await page.getByRole('button', { name: 'Login with password' }).click();
|
|
|
|
await expect(page).toHaveURL(
|
|
/\/invitations\/accept\?error=invitation_email_mismatch$/,
|
|
);
|
|
await expect(
|
|
page.getByText('This invitation belongs to a different email address.'),
|
|
).toBeVisible();
|
|
await expect(page.getByText('Login successful')).toHaveCount(0);
|
|
});
|
|
|
|
test('a temporary accept failure keeps the authenticated invitation retryable', async ({
|
|
page,
|
|
}) => {
|
|
await installLangBotApiMocks(page, { authenticated: false });
|
|
await page.route('**/api/v1/invitations/inspect', async (route) => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
code: 0,
|
|
data: {
|
|
invitation: {
|
|
uuid: 'retryable-invitation',
|
|
workspace_uuid: 'workspace-playwright',
|
|
normalized_email: 'invited@example.com',
|
|
role: 'viewer',
|
|
status: 'pending',
|
|
},
|
|
workspace: {
|
|
uuid: 'workspace-playwright',
|
|
name: 'Playwright Workspace',
|
|
},
|
|
},
|
|
msg: 'ok',
|
|
}),
|
|
});
|
|
});
|
|
let acceptAttempts = 0;
|
|
await page.route('**/api/v1/invitations/accept', async (route) => {
|
|
acceptAttempts += 1;
|
|
if (acceptAttempts === 1) {
|
|
await route.fulfill({
|
|
status: 503,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
code: 'temporary_failure',
|
|
msg: 'Please retry',
|
|
}),
|
|
});
|
|
return;
|
|
}
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({
|
|
code: 0,
|
|
data: {
|
|
token: 'accepted-token',
|
|
workspace_uuid: 'workspace-playwright',
|
|
},
|
|
msg: 'ok',
|
|
}),
|
|
});
|
|
});
|
|
|
|
await page.goto('/invitations/accept#token=retryable-invitation');
|
|
await page.getByRole('button', { name: 'I already have an account' }).click();
|
|
await page
|
|
.getByPlaceholder('Enter email address')
|
|
.fill('invited@example.com');
|
|
await page.getByPlaceholder('Enter password').fill('password');
|
|
await page.getByRole('button', { name: 'Login with password' }).click();
|
|
|
|
await expect(page).toHaveURL(/\/invitations\/accept$/);
|
|
await expect(
|
|
page.getByRole('button', { name: 'Accept with current account' }),
|
|
).toBeVisible();
|
|
await page
|
|
.getByRole('button', { name: 'Accept with current account' })
|
|
.click();
|
|
await expect(page).toHaveURL(/\/home(?:\/monitoring)?$/);
|
|
expect(acceptAttempts).toBe(2);
|
|
});
|