Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/app/tests/stress/_helpers/content-reset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { readdirSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { REQUIRED_FIXTURE_ENTRY_NAMES } from './fixtures.ts';

async function deletePathIfExists(
baseURL: string,
kind: 'file' | 'folder',
path: string,
): Promise<void> {
const res = await fetch(`${baseURL}/api/delete-path`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ kind, path }),
});
if (res.ok || res.status === 404) return;
throw new Error(`delete-path failed for ${kind}:${path}: ${res.status} ${await res.text()}`);
}

export async function resetContentToFixtureBaseline(
baseURL: string,
contentDir: string,
): Promise<void> {
const preserved = new Set<string>(REQUIRED_FIXTURE_ENTRY_NAMES);
for (const entry of readdirSync(contentDir, { withFileTypes: true })) {
if (entry.name.startsWith('.')) continue;
if (preserved.has(entry.name)) continue;
if (entry.isDirectory()) {
await deletePathIfExists(baseURL, 'folder', entry.name);
continue;
}
const docName = entry.name.replace(/\.(md|mdx)$/i, '');
if (docName !== entry.name) {
await deletePathIfExists(baseURL, 'file', docName);
continue;
}
rmSync(join(contentDir, entry.name), { recursive: true, force: true });
}
}
1 change: 1 addition & 0 deletions packages/app/tests/stress/_helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { simulateCopyAndRead, simulateCutAndRead } from './clipboard.ts';
export { resetContentToFixtureBaseline } from './content-reset.ts';
export {
focusEditor,
selectAllAndWaitForSelection,
Expand Down
14 changes: 9 additions & 5 deletions packages/app/tests/stress/file-tree-deselect-to-root.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* still lands inside the active folder.
*/
import type { Page } from '@playwright/test';
import { expect, test } from './_helpers';
import { expect, resetContentToFixtureBaseline, test } from './_helpers';

const SIDEBAR = '[data-slot="sidebar-container"]';

Expand Down Expand Up @@ -50,10 +50,14 @@ async function createFileAndGetDocName(
}

test.describe('file-tree deselect-to-root', () => {
test.beforeEach(async ({ workerServer }) => {
await resetContentToFixtureBaseline(workerServer.baseURL, workerServer.contentDir);
});

test('empty-space click deselects the row for creation but leaves the editor view', async ({
page,
api,
baseURL,
workerServer,
}) => {
await api.seedDocs([
{ name: 'folder/note', markdown: '# Note\n' },
Expand Down Expand Up @@ -93,15 +97,15 @@ test.describe('file-tree deselect-to-root', () => {
await expect(sidebar.getByRole('treeitem', { name: 'note.md', exact: true })).toBeVisible();
await expect(page).toHaveURL(/folder\/note$/);

const names = await createFileAndGetDocName(page, baseURL, 'created-at-root');
const names = await createFileAndGetDocName(page, workerServer.baseURL, 'created-at-root');
expect(names).toContain('created-at-root');
expect(names).not.toContain('folder/created-at-root');
});

test('without the empty-space click, New File still lands in the active folder', async ({
page,
api,
baseURL,
workerServer,
}) => {
await api.seedDocs([
{ name: 'folder/note', markdown: '# Note\n' },
Expand All @@ -114,7 +118,7 @@ test.describe('file-tree deselect-to-root', () => {
sidebar.getByRole('treeitem', { name: 'note.md', exact: true, selected: true }),
).toBeVisible({ timeout: 20_000 });

const names = await createFileAndGetDocName(page, baseURL, 'created-in-folder');
const names = await createFileAndGetDocName(page, workerServer.baseURL, 'created-in-folder');
expect(names).toContain('folder/created-in-folder');
expect(names).not.toContain('created-in-folder');
});
Expand Down
17 changes: 12 additions & 5 deletions packages/app/tests/stress/file-tree-drag-to-root.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Page } from '@playwright/test';
import { expect, test } from './_helpers';
import { expect, resetContentToFixtureBaseline, test } from './_helpers';

async function dragRowToEmptyRootArea(
page: Page,
Expand Down Expand Up @@ -114,10 +114,14 @@ async function expectDocNames(
}

test.describe('file-tree drag-to-root (PRD-7043)', () => {
test.beforeEach(async ({ workerServer }) => {
await resetContentToFixtureBaseline(workerServer.baseURL, workerServer.contentDir);
});

test('dropping a nested folder on empty tree space promotes it to the project root', async ({
page,
api,
baseURL,
workerServer,
}) => {
await api.seedDocs([
{ name: 'parent/child/note', markdown: '# Note\n\nNested.\n' },
Expand All @@ -136,7 +140,10 @@ test.describe('file-tree drag-to-root (PRD-7043)', () => {

await dragRowToEmptyRootArea(page, 'parent/child', true);

await expectDocNames(page, baseURL, { present: 'child/note', absent: 'parent/child/note' });
await expectDocNames(page, workerServer.baseURL, {
present: 'child/note',
absent: 'parent/child/note',
});

await expect(sidebar.getByRole('treeitem', { name: 'child', exact: true })).toBeVisible({
timeout: 10_000,
Expand All @@ -146,7 +153,7 @@ test.describe('file-tree drag-to-root (PRD-7043)', () => {
test('dropping a nested file on empty tree space promotes it to the project root', async ({
page,
api,
baseURL,
workerServer,
}) => {
await api.seedDocs([
{ name: 'folder/note', markdown: '# Note\n\nNested file.\n' },
Expand All @@ -165,7 +172,7 @@ test.describe('file-tree drag-to-root (PRD-7043)', () => {

await dragRowToEmptyRootArea(page, 'folder/note', false);

await expectDocNames(page, baseURL, { present: 'note', absent: 'folder/note' });
await expectDocNames(page, workerServer.baseURL, { present: 'note', absent: 'folder/note' });

await expect(sidebar.getByRole('treeitem', { name: 'note.md', exact: true })).toBeVisible({
timeout: 10_000,
Expand Down