feat(app): checkout diff pane styling and e2e test support

- Style diff file cards edge-to-edge with single divider between files
- Remove monospace font from filenames for better readability
- Add checkout-ship e2e test for app
- Export Page type from e2e fixtures
- Add checkout query hooks for diff, status, and PR status
This commit is contained in:
Mohamed Boudra
2026-01-23 08:37:15 +07:00
parent 746d413082
commit 53155ebcc9
15 changed files with 1450 additions and 135 deletions
+63 -4
View File
@@ -151,17 +151,76 @@ export const openSettings = async (page: Page) => {
export const setWorkingDirectory = async (page: Page, directory: string) => {
const workingDirectoryLabel = page.getByText('WORKING DIRECTORY', { exact: true }).first();
await expect(workingDirectoryLabel).toBeVisible();
await workingDirectoryLabel.click();
const input = page.getByRole('textbox', { name: '/path/to/project' });
await expect(input).toBeVisible();
const worktreePicker = page.getByTestId('worktree-attach-picker');
const worktreeSheetTitle = page.getByText('Select worktree', { exact: true });
const closeBottomSheet = async () => {
const bottomSheetBackdrop = page
.getByRole('button', { name: 'Bottom sheet backdrop' })
.first();
const bottomSheetHandle = page
.getByRole('slider', { name: 'Bottom sheet handle' })
.first();
for (let attempt = 0; attempt < 3; attempt += 1) {
if (!(await bottomSheetBackdrop.isVisible())) {
return;
}
await bottomSheetBackdrop.click({ force: true });
await page.keyboard.press('Escape').catch(() => undefined);
await page.waitForTimeout(200);
}
if (await bottomSheetBackdrop.isVisible()) {
const box = await bottomSheetHandle.boundingBox();
if (box) {
const startX = box.x + box.width / 2;
const startY = box.y + box.height / 2;
await page.mouse.move(startX, startY);
await page.mouse.down();
await page.mouse.move(startX, startY + 400);
await page.mouse.up();
await page.waitForTimeout(200);
}
}
};
const closeWorktreeSheetIfOpen = async () => {
if (!(await worktreeSheetTitle.isVisible()) && !(await worktreePicker.isVisible())) {
return;
}
const attachToggle = page.getByTestId('worktree-attach-toggle');
if (await attachToggle.isVisible()) {
await attachToggle.click({ force: true });
await page.waitForTimeout(200);
}
await closeBottomSheet();
};
await closeWorktreeSheetIfOpen();
if (!(await input.isVisible())) {
await closeBottomSheet();
await workingDirectoryLabel.click({ force: true });
if (!(await input.isVisible())) {
await closeBottomSheet();
await workingDirectoryLabel.click({ force: true });
}
await expect(input).toBeVisible();
}
await input.fill(directory);
await input.press('Enter');
const useOption = page.getByText(`Use "${directory}"`);
await expect(useOption).toBeVisible();
await useOption.click();
await expect(page.getByText(directory, { exact: true })).toBeVisible();
await useOption.click({ force: true });
const normalizedDirectory = directory.startsWith('/var/')
? `/private${directory}`
: directory;
const workingDirectoryContainer = workingDirectoryLabel.locator('..');
await expect.poll(async () => {
const text = await workingDirectoryContainer.innerText();
return text.includes(directory) || text.includes(normalizedDirectory);
}).toBe(true);
};
export const ensureHostSelected = async (page: Page) => {
+39 -2
View File
@@ -5,20 +5,57 @@ import path from 'node:path';
type TempRepo = {
path: string;
owner?: string;
name?: string;
cleanup: () => Promise<void>;
};
export const createTempGitRepo = async (prefix = 'paseo-e2e-'): Promise<TempRepo> => {
export const createTempGitRepo = async (
prefix = 'paseo-e2e-',
options?: { withRemote?: boolean }
): Promise<TempRepo> => {
const repoPath = await mkdtemp(path.join(tmpdir(), prefix));
const repoName = `paseo-e2e-${Date.now().toString(36)}-${Math.random()
.toString(36)
.slice(2, 8)}`;
let owner: string | undefined;
const withRemote = options?.withRemote ?? false;
execSync('git init', { cwd: repoPath, stdio: 'ignore' });
execSync('git init -b main', { cwd: repoPath, stdio: 'ignore' });
execSync('git config user.email "e2e@paseo.test"', { cwd: repoPath, stdio: 'ignore' });
execSync('git config user.name "Paseo E2E"', { cwd: repoPath, stdio: 'ignore' });
await writeFile(path.join(repoPath, 'README.md'), '# Temp Repo\n');
execSync('git add README.md', { cwd: repoPath, stdio: 'ignore' });
execSync('git commit -m "Initial commit"', { cwd: repoPath, stdio: 'ignore' });
if (withRemote) {
try {
owner = execSync('gh api user -q .login', { encoding: 'utf8' }).trim();
execSync(
`gh repo create ${repoName} --private --confirm --source=. --remote=origin --push`,
{
cwd: repoPath,
stdio: 'ignore',
}
);
} catch (error) {
await rm(repoPath, { recursive: true, force: true });
throw error;
}
}
return {
path: repoPath,
owner,
name: repoName,
cleanup: async () => {
if (owner && withRemote) {
try {
execSync(`gh repo delete ${owner}/${repoName} --yes`, { stdio: 'ignore' });
} catch {
// Best-effort cleanup
}
}
await rm(repoPath, { recursive: true, force: true });
},
};