Files
LinkPort/web/tests/account-editor.spec.ts

156 lines
9.0 KiB
TypeScript

import { test, expect } from '@playwright/test';
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: '目标账号下拉编辑', type: 'mysql', targetHost: 'fixture.invalid', targetPort: 3306,
accounts: [
{ id: 'reader', remark: '读取账号', username: 'reader', password: 'fixture-reader' },
{ id: 'writer', remark: '写入账号', username: 'writer', password: 'fixture-writer' },
],
} });
expect(response.ok()).toBeTruthy();
const id = (await response.json()).config.id;
try {
await page.reload();
await page.getByRole('navigation').getByRole('button', { name: /目标服务/ }).click();
const drawer = page.getByRole('dialog', { name: '编辑目标服务', exact: true });
const open = async () => {
await page.locator('.target-card').filter({ hasText: '目标账号下拉编辑' }).getByRole('button', { name: '配置目标', exact: true }).click();
await drawer.getByRole('tab', { name: '账号', exact: true }).click();
};
const editor = drawer.locator('.target-accounts');
const remark = editor.getByRole('textbox', { name: '账号备注', exact: true });
const username = editor.getByRole('textbox', { name: '登录用户名', exact: true });
const password = editor.getByLabel('账号密码', { exact: true });
const add = editor.getByRole('button', { name: '添加账号', exact: true });
const remove = editor.getByRole('button', { name: '删除账号', exact: true });
const select = async (label: string) => {
await editor.locator('.el-select').filter({ has: page.getByRole('combobox', { name: '编辑目标账号', exact: true }) }).click();
await page.getByRole('option', { name: label, exact: true }).click();
};
await open();
await expect(editor.locator('.account-fields')).toHaveCount(1);
await expect(username).toHaveValue('reader');
await select('2. 写入账号 · writer');
await remark.fill('修改写入账号');
await username.fill('updated-writer');
await password.fill('updated-fixture-writer');
await add.click();
await expect(remark).toBeFocused();
await expect(remark).toHaveValue('');
await expect(editor.locator('.account-fields')).toHaveCount(1);
await remark.fill('新增账号');
await username.fill('new-user');
await password.fill('fixture-new');
await select('1. 读取账号 · reader');
await username.fill('');
await select('2. 修改写入账号 · updated-writer');
await expect(password).toHaveValue('updated-fixture-writer');
await select('3. 新增账号 · new-user');
await expect(password).toHaveValue('fixture-new');
await drawer.getByRole('button', { name: '保存配置', exact: true }).click();
await expect(username).toBeFocused();
await expect(remark).toHaveValue('读取账号');
await expect(username).toHaveValue('');
await username.fill('reader');
await drawer.getByRole('button', { name: '保存配置', exact: true }).click();
await expect(drawer).not.toBeVisible();
const saved = await (await page.request.get(`/api/v1/targets/${id}`)).json();
expect(saved.config.accounts).toHaveLength(3);
expect(saved.config.accounts[1]).toMatchObject({ id: 'writer', remark: '修改写入账号', username: 'updated-writer' });
expect(saved.config.accounts[2]).toMatchObject({ remark: '新增账号', username: 'new-user' });
for (const account of saved.config.accounts) expect(saved.secretStatus[`account:${account.id}:password`]).toBe(true);
await open();
for (const viewport of [{ width: 1440, height: 900 }, { width: 375, height: 812 }, { width: 320, height: 568 }]) {
await page.setViewportSize(viewport);
await expect(add).toBeInViewport();
await expect(remove).toBeInViewport();
await expect.poll(() => drawer.evaluate(el => el.scrollWidth <= el.clientWidth + 1)).toBe(true);
}
await select('2. 修改写入账号 · updated-writer');
await remove.click();
await expect(remark).toHaveValue('新增账号');
await remove.click();
await expect(remark).toHaveValue('读取账号');
await remove.click();
await expect(editor.locator('.account-fields')).toHaveCount(0);
await expect(editor.getByRole('combobox', { name: '编辑目标账号', exact: true })).toBeDisabled();
await expect(remove).toBeDisabled();
await expect(editor.getByText('点击「添加账号」开始配置。', { exact: true })).toBeVisible();
await add.click();
await expect(remark).toBeFocused();
await expect(remark).toHaveValue('');
await expect(editor.locator('.account-fields')).toHaveCount(1);
await remark.fill('重建账号');
await username.fill('replacement');
await password.fill('fixture-replacement');
await drawer.getByRole('button', { name: '保存配置', exact: true }).click();
await expect(drawer).not.toBeVisible();
const replaced = await (await page.request.get(`/api/v1/targets/${id}`)).json();
expect(replaced.config.accounts).toHaveLength(1);
expect(replaced.config.accounts[0]).toMatchObject({ remark: '重建账号', username: 'replacement' });
} finally { 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/proxies', {headers,data:{
name:'页面账号编辑',type:'mysql',listenHost:'127.0.0.1',listenPort:24923,
gatewayAccounts:Array.from({length:12},(_,i)=>({id:`account-${i}`,username:`client-${i}`,password:`fixture-${i}`,accessMode:'readonly'})),
}});
expect(response.ok()).toBeTruthy();
const id = (await response.json()).config.id;
try {
await page.reload();
await page.getByRole('row').filter({hasText:'页面账号编辑'}).getByRole('button',{name:'配置',exact:true}).click();
const workspacePage = page.getByRole('dialog',{name:'编辑网关服务',exact:true});
await workspacePage.getByRole('tab',{name:'账号',exact:true}).click();
const editor = workspacePage.locator('.gateway-accounts');
const body = workspacePage.locator('.workspace-page__body');
const footer = workspacePage.locator('.workspace-page__footer');
const select = async (label:string) => {
await editor.locator('.el-select').filter({has:page.getByRole('combobox',{name:'编辑网关账号',exact:true})}).click();
await page.getByRole('option',{name:label,exact:true}).click();
};
for (const viewport of [{width:1440,height:900},{width:375,height:812},{width:320,height:568}]) {
await page.setViewportSize(viewport);
for (const tab of ['登录','目标','权限','更多']) {
await editor.getByRole('tab',{name:tab,exact:true}).click();
expect(await workspacePage.evaluate(el=>el.scrollWidth<=el.clientWidth+1)).toBe(true);
expect(await body.evaluate(el=>el.scrollWidth<=el.clientWidth+1)).toBe(true);
await editor.getByRole('button',{name:'添加账号',exact:true}).scrollIntoViewIfNeeded();
await expect(editor.getByRole('button',{name:'添加账号',exact:true})).toBeInViewport();
await footer.scrollIntoViewIfNeeded();
await expect(footer).toBeInViewport();
}
}
await editor.getByRole('button',{name:'添加账号',exact:true}).click();
const username = editor.getByRole('textbox',{name:'用户名',exact:true});
await expect(username).toBeFocused();
await expect(username).toBeInViewport();
await username.fill('new-client');
await editor.getByRole('textbox',{name:'密码',exact:true}).fill('fixture-new');
await select('1. client-0');
await username.fill('');
await select('13. new-client');
await expect(username).toHaveValue('new-client');
await workspacePage.getByRole('button',{name:'保存配置',exact:true}).click();
await expect(username).toBeFocused();
await expect(username).toHaveValue('');
await username.fill('client-0');
await workspacePage.getByRole('button',{name:'保存配置',exact:true}).click();
await expect(workspacePage).not.toBeVisible();
const saved = await (await page.request.get(`/api/v1/proxies/${id}`)).json();
expect(saved.config.gatewayAccounts).toHaveLength(13);
expect(saved.config.gatewayAccounts[11]).toMatchObject({username:'client-11',accessMode:'readonly'});
expect(saved.config.gatewayAccounts[12].username).toBe('new-client');
for (const account of saved.config.gatewayAccounts) expect(saved.secretStatus[`gatewayAccount:${account.id}:password`]).toBe(true);
} finally { await page.request.delete(`/api/v1/proxies/${id}`,{headers}).catch(()=>{}); }
});