121 lines
5.0 KiB
TypeScript
121 lines
5.0 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { _electron as electron } from 'playwright';
|
|
import { promises as fs } from 'node:fs';
|
|
import nodePath from 'node:path';
|
|
import os from 'node:os';
|
|
|
|
const MAIN_JS = nodePath.join(process.cwd(), 'dist-electron/main/index.js');
|
|
const PNG_B64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
|
|
|
|
async function launch(userData: string) {
|
|
const app = await electron.launch({ args: ['--user-data-dir=' + userData, MAIN_JS] });
|
|
const page = await app.firstWindow();
|
|
await page.waitForLoadState('domcontentloaded');
|
|
const invoke = (ch: string, args: any) => page.evaluate(({ ch, args }) => (globalThis as any).dsh.invoke(ch, args), { ch, args });
|
|
return { app, page, invoke };
|
|
}
|
|
|
|
async function newDoc(a: { page: any; invoke: any }, title: string) {
|
|
await a.page.getByRole('button', { name: /新建文档/ }).click();
|
|
await a.page.getByPlaceholder(/输入文档标题/).fill(title);
|
|
await a.page.getByPlaceholder(/输入文档标题/).press('Enter');
|
|
await expect(a.page.getByTestId('tabbar').getByText(title, { exact: true })).toBeVisible({ timeout: 10000 });
|
|
}
|
|
|
|
test('FR-E6:链接气泡编辑(添加+移除)', async () => {
|
|
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-e6-link-'));
|
|
const userData = nodePath.join(tmp, 'userdata');
|
|
const vault = nodePath.join(tmp, 'vault');
|
|
await fs.mkdir(userData, { recursive: true });
|
|
await fs.mkdir(vault, { recursive: true });
|
|
|
|
const a = await launch(userData);
|
|
await a.invoke('vault:switch', { root: vault });
|
|
await newDoc(a, '链接测试');
|
|
|
|
const editor = a.page.locator('.ProseMirror');
|
|
await editor.click();
|
|
await a.page.keyboard.type('点这里');
|
|
await a.page.keyboard.press('Control+A');
|
|
await a.page.locator('button[title="链接"]').click();
|
|
|
|
const dlg = a.page.getByPlaceholder(/example\.com/);
|
|
await dlg.fill('https://example.com');
|
|
await dlg.press('Enter');
|
|
|
|
let html: string = await a.page.evaluate(() => document.querySelector('.ProseMirror')?.innerHTML ?? '');
|
|
expect(html).toContain('href="https://example.com"');
|
|
|
|
// 气泡只在「选中链接文字」时弹出(纯点击链接改为调用系统浏览器打开)
|
|
await a.page.locator('.ProseMirror a').click();
|
|
await a.page.keyboard.press('Control+A');
|
|
await expect(a.page.locator('.link-bubble')).toBeVisible({ timeout: 5000 });
|
|
await expect(a.page.locator('.link-bubble input')).toHaveValue('https://example.com');
|
|
|
|
await a.page.locator('.link-bubble').getByText('移除').click();
|
|
html = await a.page.evaluate(() => document.querySelector('.ProseMirror')?.innerHTML ?? '');
|
|
expect(html).not.toContain('<a');
|
|
expect(html).not.toContain('href');
|
|
|
|
await a.app.close();
|
|
});
|
|
|
|
test('FR-E6:网络图片(手输网址)', async () => {
|
|
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-e6-url-'));
|
|
const userData = nodePath.join(tmp, 'userdata');
|
|
const vault = nodePath.join(tmp, 'vault');
|
|
await fs.mkdir(userData, { recursive: true });
|
|
await fs.mkdir(vault, { recursive: true });
|
|
|
|
const a = await launch(userData);
|
|
await a.invoke('vault:switch', { root: vault });
|
|
await newDoc(a, '网图测试');
|
|
|
|
await a.page.locator('.ProseMirror').click();
|
|
await a.page.locator('button[title="网络图片(手输网址)"]').click();
|
|
const dlg = a.page.getByPlaceholder(/粘贴图片地址/);
|
|
await dlg.fill('https://cdn.example.com/x.png');
|
|
await dlg.press('Enter');
|
|
|
|
await expect(a.page.locator('.ProseMirror img')).toHaveCount(1, { timeout: 10000 });
|
|
const src = await a.page.locator('.ProseMirror img').getAttribute('src');
|
|
expect(src).toBe('https://cdn.example.com/x.png');
|
|
|
|
await a.app.close();
|
|
});
|
|
|
|
test('FR-E6:本地图片入库+展示(vaultasset 协议)', async () => {
|
|
const tmp = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'hn-e6-local-'));
|
|
const userData = nodePath.join(tmp, 'userdata');
|
|
const vault = nodePath.join(tmp, 'vault');
|
|
await fs.mkdir(userData, { recursive: true });
|
|
await fs.mkdir(vault, { recursive: true });
|
|
|
|
const a = await launch(userData);
|
|
await a.invoke('vault:switch', { root: vault });
|
|
|
|
const rel: string = await a.invoke('asset:write', { name: 't.png', dataBase64: PNG_B64 });
|
|
expect(rel.startsWith('.attachments/')).toBeTruthy();
|
|
|
|
// 磁盘文件确实写入
|
|
const disk = await fs.readFile(nodePath.join(vault, rel));
|
|
expect(disk.length).toBeGreaterThan(0);
|
|
|
|
await newDoc(a, 'doca');
|
|
await newDoc(a, 'docb');
|
|
await a.invoke('doc:write', { path: 'doca.md', meta: { title: 'doca' }, body: '' });
|
|
|
|
await a.page.getByTestId('filetree').getByText('doca', { exact: true }).click();
|
|
await expect(a.page.locator('.ProseMirror img')).toHaveCount(1, { timeout: 10000 });
|
|
|
|
const src = await a.page.locator('.ProseMirror img').getAttribute('src');
|
|
expect(src?.startsWith('vaultasset:')).toBeTruthy();
|
|
|
|
await expect.poll(
|
|
() => a.page.locator('.ProseMirror img').evaluate((el: HTMLImageElement) => el.naturalWidth),
|
|
{ timeout: 8000 },
|
|
).toBeGreaterThan(0);
|
|
|
|
await a.app.close();
|
|
});
|