Files
2026-07-13 13:20:22 +08:00

121 lines
5.2 KiB
TypeScript

/**
* E2E: Workspace Changes tab — real user flow.
*
* Creates a team with a seeded workspace, writes a file to disk to produce a
* diff, then drives the Changes tab in the workspace panel:
* 1. Click the Changes tab
* 2. Verify the unstaged file appears
* 3. Click Stage → verify it moves to Staged
*
* The snake-case staging pipeline (init/compare/stage/unstage/discard) is
* covered by direct unit tests against `WorkspaceSnapshotService` in the
* integration suite; this file only asserts the rendered UI state.
*/
import { test, expect } from '../../fixtures';
import { cleanupTeamsByName, TEAM_SUPPORTED_BACKENDS } from '../../helpers';
import fs from 'fs';
import path from 'path';
import os from 'os';
const TEAM_NAME = `E2E Workspace Snapshot ${Date.now()}`;
test.describe('Workspace Changes — UI panel', () => {
let workspace: string;
test.beforeAll(() => {
workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'aionui-e2e-ws-snap-'));
fs.writeFileSync(path.join(workspace, 'baseline.txt'), 'original');
});
test.afterAll(() => {
fs.rmSync(workspace, { recursive: true, force: true });
});
test('changes tab surfaces a newly written file and stage button moves it', async ({ page, electronApp }) => {
test.setTimeout(180_000);
if (TEAM_SUPPORTED_BACKENDS.size === 0) {
test.skip(true, 'No supported team backends available');
return;
}
await electronApp.evaluate(async ({ dialog }, target) => {
dialog.showOpenDialog = () => Promise.resolve({ canceled: false, filePaths: [target] });
}, workspace);
await cleanupTeamsByName(page, TEAM_NAME);
// ── Create team with seeded workspace ────────────────────────────────
const createBtn = page.locator('[data-testid="team-create-btn"]').first();
await expect(createBtn).toBeVisible({ timeout: 10_000 });
await createBtn.click();
const modal = page.locator('.team-create-modal');
await expect(modal).toBeVisible({ timeout: 10_000 });
await modal.locator('input').first().fill(TEAM_NAME);
const agentCard = modal.locator('[data-testid^="team-create-agent-card-"]').first();
if (!(await agentCard.isVisible().catch(() => false))) {
test.skip(true, 'No supported agents available');
return;
}
await agentCard.click();
const wsTrigger = modal.locator('[data-testid="team-create-workspace-trigger"]');
if (await wsTrigger.isVisible({ timeout: 3_000 }).catch(() => false)) {
await wsTrigger.click();
const menu = page.locator('[data-testid="team-create-workspace-menu"]');
if (await menu.isVisible({ timeout: 3_000 }).catch(() => false)) {
const chooseDifferent = menu
.locator('text=/Choose a different folder|选择其他文件夹/i')
.or(menu.locator('.cursor-pointer').last());
await chooseDifferent.first().click();
}
}
const createConfirmBtn = modal.locator('.arco-btn-primary');
await expect(createConfirmBtn).toBeEnabled({ timeout: 5_000 });
await createConfirmBtn.click();
await expect(modal).toBeHidden({ timeout: 15_000 });
await page.waitForURL(/\/team\//, { timeout: 15_000 });
const panel = page.locator('.chat-workspace');
await expect(panel).toBeVisible({ timeout: 30_000 });
// ── Seed a diff on disk (snapshot baseline was captured on team create) ─
fs.writeFileSync(path.join(workspace, 'created.txt'), 'hello-snapshot');
// ── Switch to Changes tab ────────────────────────────────────────────
const changesTab = panel.locator('.arco-tabs-header-title').filter({ hasText: /Changes|更改/ });
await expect(changesTab.first()).toBeVisible({ timeout: 10_000 });
await changesTab.first().click();
await page.screenshot({ path: 'tests/e2e/results/workspace-snapshot-01-changes-tab.png' });
// ── Newly created file should surface somewhere in the Changes list ──
const createdEntry = panel.getByText('created.txt').first();
await expect(createdEntry).toBeVisible({ timeout: 30_000 });
await page.screenshot({ path: 'tests/e2e/results/workspace-snapshot-02-unstaged.png' });
// ── Click a Stage button if available (per-file or Stage All) ────────
// The FileChangeList renders a Stage-all action + per-file stage buttons.
const stageButton = panel
.locator('button, [role="button"]')
.filter({ hasText: /Stage All|全部暂存|Stage|暂存/ })
.first();
const stageVisible = await stageButton.isVisible({ timeout: 5_000 }).catch(() => false);
if (stageVisible) {
await stageButton.click({ trial: false }).catch(() => {});
// After staging, the file should still be in the list (just under Staged).
await expect(panel.getByText('created.txt').first()).toBeVisible({ timeout: 10_000 });
await page.screenshot({ path: 'tests/e2e/results/workspace-snapshot-03-staged.png' });
}
// ── Cleanup ──────────────────────────────────────────────────────────
await cleanupTeamsByName(page, TEAM_NAME);
});
});