117 lines
8.9 KiB
TypeScript
117 lines
8.9 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
||
|
||
test('未应用 URL 自动参与测试和保存,关闭结果清理状态且参数可回读', async ({page}) => {
|
||
await page.goto('/');
|
||
const session = await (await page.request.get('/api/v1/session')).json();
|
||
const headers = {'X-CSRF-Token':session.csrfToken};
|
||
let id = '';
|
||
try {
|
||
await page.getByRole('navigation',{name:'工作空间菜单'}).getByRole('button',{name:'目标服务',exact:true}).click();
|
||
await page.getByRole('button',{name:'+ 新建目标',exact:true}).click();
|
||
const editor = page.getByRole('dialog',{name:'新建目标服务',exact:true});
|
||
await editor.locator('[data-field="name"] input').fill('参数与标识回归');
|
||
await editor.getByLabel('连接 URL',{exact:true}).fill('mysql://reader:isolated-secret@fixture.invalid/app?charset=latin1&tls=false');
|
||
await page.route('**/api/v1/targets/test',async route => {
|
||
const body = route.request().postDataJSON();
|
||
expect(body.config).toMatchObject({targetHost:'fixture.invalid',database:'app',connectionOptions:{charset:'latin1'}});
|
||
expect(body.config.accounts[0].password).toBe('isolated-secret');
|
||
await route.fulfill({json:{version:'fixture',tls:false}});
|
||
});
|
||
await editor.getByRole('button',{name:'测试连接',exact:true}).click();
|
||
const details = page.getByRole('dialog',{name:'连接测试',exact:true});
|
||
await expect(details).toContainText('fixture');
|
||
await details.locator('.workspace-page__footer').getByRole('button',{name:'关闭',exact:true}).click();
|
||
await expect(details).not.toBeVisible();
|
||
await expect(editor.locator('.test-summary')).toHaveCount(0);
|
||
await expect(editor.getByTestId('connection-stages')).toHaveCount(0);
|
||
await editor.getByLabel('URL 参数',{exact:true}).fill('charset=utf8mb4&tls=false&database=next');
|
||
await expect(editor.locator('.test-summary')).toHaveCount(0);
|
||
await editor.getByLabel('连接备注',{exact:true}).fill('回归测试用途');
|
||
await editor.locator('label.el-checkbox').filter({hasText:'在资源列表和侧栏显示备注'}).click();
|
||
await expect(editor.getByRole('checkbox',{name:'在资源列表和侧栏显示备注'})).toBeChecked();
|
||
await editor.getByRole('tab',{name:'高级',exact:true}).click();
|
||
await editor.getByLabel('网络连接超时',{exact:true}).fill('8');
|
||
await expect(editor.getByLabel('查询超时',{exact:true})).toBeDisabled();
|
||
const saving = page.waitForResponse(response => response.url().endsWith('/api/v1/targets') && response.request().method() === 'POST');
|
||
await editor.getByRole('button',{name:'保存配置',exact:true}).click();
|
||
const response = await saving;
|
||
expect(response.ok()).toBeTruthy(); id = (await response.json()).config.id;
|
||
const row = page.locator('.target-card').filter({hasText:'参数与标识回归'});
|
||
await expect(row).toContainText('回归测试用途');
|
||
await row.getByRole('button',{name:'配置目标',exact:true}).click();
|
||
const edit = page.getByRole('dialog',{name:'编辑目标服务',exact:true});
|
||
await expect(edit.getByLabel('URL 参数',{exact:true})).toHaveValue(/charset=utf8mb4/);
|
||
const saved = await (await page.request.get(`/api/v1/targets/${id}`)).json();
|
||
expect(saved.config).toMatchObject({database:'next',remark:'回归测试用途',showRemark:true,connectionOptions:{charset:'utf8mb4',connectTimeoutSeconds:8}});
|
||
expect(JSON.stringify(await page.evaluate(() => ({...localStorage})))).not.toContain('isolated-secret');
|
||
} finally { await page.unrouteAll({behavior:'ignoreErrors'}).catch(()=>{}); if (id) await page.request.delete(`/api/v1/targets/${id}`,{headers}).catch(()=>{}); }
|
||
});
|
||
|
||
test('搜索和树导航复用资源标签,切换保护草稿且最近记录仅存标识', async ({page}) => {
|
||
await page.goto('/');
|
||
const session = await (await page.request.get('/api/v1/session')).json();
|
||
const headers = {'X-CSRF-Token':session.csrfToken};
|
||
const response = await page.request.post('/api/v1/targets',{headers,data:{name:'工作区导航回归',project:'导航回归项目',environment:'test',type:'mysql',targetHost:'fixture.invalid',targetPort:3306,color:'#22c55e',accounts:[{id:'account',remark:'account',username:'reader',password:'navigation-fixture-secret'}]}});
|
||
expect(response.ok()).toBeTruthy(); const id = (await response.json()).config.id;
|
||
try {
|
||
await page.reload();
|
||
await expect(page.getByRole('button',{name:'搜索全部资源',exact:true})).toBeVisible();
|
||
await page.keyboard.press('Control+k');
|
||
const search = page.getByRole('dialog',{name:'搜索资源 · 当前项目与环境'});
|
||
await search.getByRole('combobox',{name:'搜索资源关键词'}).fill('工作区导航回归');
|
||
await search.getByRole('combobox',{name:'搜索资源关键词'}).press('Enter');
|
||
const editor = page.getByRole('dialog',{name:'编辑目标服务',exact:true});
|
||
await expect(editor).toBeVisible();
|
||
await editor.getByLabel('连接备注',{exact:true}).fill('unsaved');
|
||
await editor.getByRole('button',{name:'关闭当前标签',exact:true}).click();
|
||
await expect(page.getByRole('dialog',{name:'未保存的更改',exact:true})).toBeVisible();
|
||
await page.getByRole('button',{name:'继续编辑',exact:true}).click();
|
||
await expect(editor.getByLabel('连接备注',{exact:true})).toHaveValue('unsaved');
|
||
await editor.getByRole('button',{name:'关闭当前标签',exact:true}).click();
|
||
await page.getByRole('button',{name:'放弃更改',exact:true}).click();
|
||
await expect(editor).not.toBeVisible();
|
||
await page.getByRole('navigation',{name:'工作空间菜单'}).getByRole('button',{name:'运行概览',exact:true}).click();
|
||
await expect(page.locator('.workspace-home')).toContainText('工作区导航回归');
|
||
const history = JSON.parse(await page.evaluate(() => localStorage.getItem('linkport.recent.v1')) || '[]');
|
||
expect(history.find((item:any) => item.id === id)).toMatchObject({kind:'targets',id});
|
||
expect(Object.keys(history.find((item:any) => item.id === id)).sort()).toEqual(['at','id','kind']);
|
||
await page.setViewportSize({width:390,height:844});
|
||
await page.getByRole('tab', {name:'资源',exact:true}).click();
|
||
await page.getByRole('button',{name:'展开资源树',exact:true}).click();
|
||
const tree = page.getByRole('dialog',{name:'资源树',exact:true});
|
||
await expect(tree).toContainText('导航回归项目');
|
||
await expect.poll(() => page.evaluate(() => document.documentElement.scrollWidth-innerWidth)).toBeLessThanOrEqual(1);
|
||
} finally { await page.request.delete(`/api/v1/targets/${id}`,{headers}).catch(()=>{}); }
|
||
});
|
||
|
||
test('表格列显隐、排序和宽度偏好可恢复,右键菜单有键盘入口', async ({page}) => {
|
||
await page.goto('/');
|
||
await page.getByRole('button',{name:'表格列设置',exact:true}).click();
|
||
const picker = page.getByLabel('表格列设置面板',{exact:true});
|
||
await picker.locator('label.el-checkbox').filter({has:page.getByRole('checkbox',{name:'目标服务',exact:true})}).click();
|
||
await expect(picker.getByRole('checkbox',{name:'目标服务',exact:true})).not.toBeChecked();
|
||
await picker.getByRole('button',{name:'上移状态列',exact:true}).click();
|
||
await picker.getByRole('spinbutton',{name:'状态列宽',exact:true}).fill('160');
|
||
await page.getByRole('heading',{name:'网关服务',exact:true}).click();
|
||
await page.reload();
|
||
await expect(page.locator('.proxy-table .el-table__header th').filter({hasText:'目标服务'})).toHaveCount(0);
|
||
await page.getByRole('button',{name:'表格列设置',exact:true}).click();
|
||
await picker.getByRole('button',{name:'恢复默认列',exact:true}).click();
|
||
await page.getByRole('heading',{name:'网关服务',exact:true}).click();
|
||
await expect(page.locator('.proxy-table .el-table__header th').filter({hasText:'目标服务'})).toBeVisible();
|
||
const session = await (await page.request.get('/api/v1/session')).json();
|
||
const headers = {'X-CSRF-Token':session.csrfToken};
|
||
const response = await page.request.post('/api/v1/targets',{headers,data:{name:'菜单回归目标',type:'mysql',targetHost:'fixture.invalid',targetPort:3306,accounts:[{id:'account',remark:'account',username:'reader',password:'fixture-secret'}]}});
|
||
expect(response.ok()).toBeTruthy(); const id = (await response.json()).config.id;
|
||
try {
|
||
await page.reload();
|
||
await page.getByRole('navigation',{name:'工作空间菜单'}).getByRole('button',{name:'目标服务',exact:true}).click();
|
||
await page.locator('.target-card').filter({hasText:'菜单回归目标'}).click({button:'right'});
|
||
const menu = page.getByRole('menu',{name:'资源操作',exact:true});
|
||
await expect(menu.getByRole('menuitem',{name:'编辑配置',exact:true})).toBeFocused();
|
||
await page.keyboard.press('End');
|
||
await expect(menu.getByRole('menuitem',{name:'删除目标',exact:true})).toBeFocused();
|
||
await page.keyboard.press('Escape'); await expect(menu).not.toBeVisible();
|
||
} finally { await page.request.delete(`/api/v1/targets/${id}`,{headers}); }
|
||
});
|