108 lines
5.3 KiB
TypeScript
108 lines
5.3 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
|
|
const username = 'admin'
|
|
const password = process.env.MEMRELAY_E2E_PASSWORD || '242520'
|
|
|
|
async function authenticate(page: import('@playwright/test').Page): Promise<void> {
|
|
await page.goto('/auth')
|
|
await page.getByLabel('用户名').fill(username)
|
|
await page.getByLabel('密码', { exact: true }).fill(password)
|
|
const initialize = page.getByRole('button', { name: '完成初始化' })
|
|
if (await initialize.isVisible()) {
|
|
await page.getByLabel('确认密码').fill(password)
|
|
await initialize.click()
|
|
} else {
|
|
await page.getByRole('button', { name: '登录' }).click()
|
|
}
|
|
await expect(page.getByRole('heading', { name: '仪表盘' })).toBeVisible()
|
|
}
|
|
|
|
test('desktop workflow uses real memory, token, and file services', async ({ page }) => {
|
|
const suffix = Date.now().toString()
|
|
const projectName = `E2E Project ${suffix}`
|
|
const memoryTitle = `E2E Memory ${suffix}`
|
|
const marker = `relay-e2e-${suffix}`
|
|
const tokenName = `E2E Token ${suffix}`
|
|
const fileName = `artifact-${suffix}.txt`
|
|
const directoryName = `e2e-${suffix}`
|
|
const filePath = `${directoryName}/${fileName}`
|
|
const fileBody = Buffer.from(`MemRelay range download ${marker}`, 'utf8')
|
|
|
|
await authenticate(page)
|
|
|
|
await page.getByRole('button', { name: '界面语言' }).click()
|
|
await page.getByRole('menuitem', { name: 'English' }).click()
|
|
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()
|
|
await expect(
|
|
page.getByLabel('Current status of the shared workspace and dependencies'),
|
|
).toBeVisible()
|
|
await page.getByRole('button', { name: 'Language' }).click()
|
|
await page.getByRole('menuitem', { name: '简体中文' }).click()
|
|
await expect(page.getByRole('heading', { name: '仪表盘' })).toBeVisible()
|
|
|
|
await page.getByRole('link', { name: '项目', exact: true }).click()
|
|
await page.getByRole('button', { name: '新建项目' }).click()
|
|
const projectDialog = page.getByRole('dialog', { name: '新建项目' })
|
|
await projectDialog.getByLabel('名称').fill(projectName)
|
|
await projectDialog.getByLabel('Git remote').fill(`https://example.test/team/${suffix}.git`)
|
|
await projectDialog.getByRole('button', { name: '创建' }).click()
|
|
await expect(page.getByText('项目已创建')).toBeVisible()
|
|
|
|
await page.getByRole('button', { name: new RegExp(projectName) }).click()
|
|
await page.getByRole('button', { name: '新建记忆' }).click()
|
|
const memoryDrawer = page.getByRole('dialog', { name: '新建记忆' })
|
|
await memoryDrawer.getByLabel('标题').fill(memoryTitle)
|
|
await memoryDrawer.getByLabel('标签').fill('e2e, playwright')
|
|
await memoryDrawer.getByLabel('Markdown 内容').fill(`# ${memoryTitle}\n\n${marker}`)
|
|
await memoryDrawer.getByRole('button', { name: '保存' }).click()
|
|
await expect(page.getByText('记忆已保存')).toBeVisible()
|
|
await expect(page.getByRole('cell', { name: memoryTitle, exact: true })).toBeVisible()
|
|
|
|
await page.getByRole('link', { name: '搜索与编辑' }).click()
|
|
await page.getByPlaceholder('搜索记忆').fill(marker)
|
|
await page.getByRole('button', { name: '搜索', exact: true }).click()
|
|
await expect(page.getByRole('cell', { name: memoryTitle, exact: true })).toBeVisible()
|
|
|
|
await page.getByRole('link', { name: 'MCP Token' }).click()
|
|
await page.getByRole('button', { name: '创建 Token' }).click()
|
|
const tokenDialog = page.getByRole('dialog', { name: '创建 MCP Token' })
|
|
await tokenDialog.getByLabel('名称').fill(tokenName)
|
|
await tokenDialog.getByRole('button', { name: '创建' }).click()
|
|
await expect(page.getByRole('cell', { name: tokenName })).toBeVisible()
|
|
|
|
await page.getByRole('link', { name: '客户端配置' }).click()
|
|
await expect(page.locator('.code-box')).toContainText('/mcp')
|
|
await expect(page.locator('.code-box')).toContainText('bearer_token_env_var')
|
|
|
|
await page.getByRole('link', { name: '文件仓储' }).click()
|
|
await page.getByRole('button', { name: '上传' }).click()
|
|
const uploadDialog = page.getByRole('dialog', { name: '上传文件' })
|
|
await uploadDialog.locator('input[type="file"]').setInputFiles({
|
|
name: fileName,
|
|
mimeType: 'text/plain',
|
|
buffer: fileBody,
|
|
})
|
|
await uploadDialog.getByLabel('仓储路径').fill(filePath)
|
|
await uploadDialog.getByLabel('版本').fill('1.0.0')
|
|
await uploadDialog.getByLabel('用途').fill('E2E validation')
|
|
await uploadDialog.getByLabel('说明').fill(marker)
|
|
await uploadDialog.getByRole('button', { name: '上传', exact: true }).click()
|
|
await expect(page.getByText('上传完成')).toBeVisible()
|
|
await page.getByRole('button', { name: `进入目录:${directoryName}` }).click()
|
|
await expect(page.getByRole('cell', { name: fileName })).toBeVisible()
|
|
|
|
const files = await page.request.get(`/api/v1/files?query=${encodeURIComponent(marker)}`)
|
|
expect(files.ok()).toBeTruthy()
|
|
const [file] = (await files.json()) as Array<{ id: string }>
|
|
expect(file).toBeTruthy()
|
|
const download = await page.request.get(`/api/v1/files/${file.id}/download`)
|
|
const { url } = (await download.json()) as { url: string }
|
|
const range = await page.request.get(url, { headers: { Range: 'bytes=0-7' } })
|
|
expect(range.status()).toBe(206)
|
|
expect(await range.body()).toEqual(fileBody.subarray(0, 8))
|
|
|
|
if (process.env.MEMRELAY_E2E_SCREENSHOT) {
|
|
await page.screenshot({ path: process.env.MEMRELAY_E2E_SCREENSHOT, fullPage: true })
|
|
}
|
|
})
|