fix(insomnia-test): fix lint warnings in cloud-sync and git-sync specs

Share the backend project meta.json reader across cloud-sync specs, use locator assertions in the git-sync disabled specs, and split the pull-conflict spec into explicit cases.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Bob QiuandClaude Sonnet 5.5 committed 2026-11-05 14:18:20 +08:00
1 parent f8d2388842
commit b45ccec0dc
9 files changed
+83 -143

No files matched your search

@@ -2,12 +2,12 @@ import * as fs from "node:fs";
import path from "node:path";
import { faker } from "@faker-js/faker";
import { readBackendProjectMetas } from "@package/misc/backend-projects";
import { getCloudSyncGraphQLRequestLog, setCloudSyncGraphQLDelay } from "@package/misc/cloud-sync-mock";
import { MOCK_API_SERVER, resetCloudSyncState, SESSION_ID, test } from "@package/misc/fixtures";
import { Collection } from "@package/models/collection";
import { expect } from "@playwright/test";
import { getCloudSyncGraphQLRequestLog, setCloudSyncGraphQLDelay } from "@package/misc/cloud-sync-mock";
// Every Cloud Sync workspace used to share one VCS singleton, so creating a sibling
// collection Y could repoint the singleton's `_backendProject` mid-flight,
// while workspace X's `pull()` was still awaiting a network response. X's
@@ -55,19 +55,10 @@ test("Verify creating a new collection does not misattribute a concurrent pull's
const dataPath = await appFlow.getDataPath();
const projectsDir = path.join(dataPath, "version-control", "projects");
const readProjectMeta = async (workspaceId: string) => {
const dirs = await fs.promises.readdir(projectsDir);
for (const dir of dirs) {
const meta = JSON.parse(
await fs.promises.readFile(
path.join(projectsDir, dir, "meta.json"),
"utf8",
),
);
if (meta.rootDocumentId === workspaceId) {
return { backendProjectId: meta.id as string, dir };
}
}
return;
const [match] = (await readBackendProjectMetas(projectsDir))
.filter((m) => m.rootDocumentId === workspaceId)
.map((m) => ({ backendProjectId: m.id, dir: m.dir }));
return match;
};
const countBlobFiles = async (dir: string) => {
const blobsDir = path.join(projectsDir, dir, "blobs");
@@ -3,12 +3,12 @@ import path from "node:path";
import { faker } from "@faker-js/faker";
import { HttpMethod } from "@package/enums/http-method";
import { readBackendProjectMetas } from "@package/misc/backend-projects";
import { getCloudSyncProjectInfo, setCloudSyncArchiveFailure } from "@package/misc/cloud-sync-mock";
import { HTTP_SERVER, resetCloudSyncState, test } from "@package/misc/fixtures";
import { Collection } from "@package/models/collection";
import { expect } from "@playwright/test";
import { getCloudSyncProjectInfo, setCloudSyncArchiveFailure } from "@package/misc/cloud-sync-mock";
test.afterAll(async () => {
await resetCloudSyncState();
});
@@ -68,19 +68,10 @@ test("Verify the dashboard can delete a never-pulled unsynced remote file and a
const dataPath = await appFlow.getDataPath();
const projectsDir = path.join(dataPath, "version-control", "projects");
const readProjectMeta = async (workspaceId: string) => {
const dirs = await fs.promises.readdir(projectsDir);
for (const dir of dirs) {
const meta = JSON.parse(
await fs.promises.readFile(
path.join(projectsDir, dir, "meta.json"),
"utf8",
),
);
if (meta.rootDocumentId === workspaceId) {
return { rootDocumentId: meta.rootDocumentId as string, dir };
}
}
return;
const [match] = (await readBackendProjectMetas(projectsDir))
.filter((m) => m.rootDocumentId === workspaceId)
.map((m) => ({ rootDocumentId: m.rootDocumentId, dir: m.dir }));
return match;
};
const readLatestSnapshotState = async (dir: string) => {
const snapshotsDir = path.join(projectsDir, dir, "snapshots");
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
import path from "node:path";
import { DeleteMode } from "@package/enums/delete-mode";
import { readBackendProjectMetas } from "@package/misc/backend-projects";
import { resetCloudSyncState, test } from "@package/misc/fixtures";
import { expect } from "@playwright/test";
@@ -19,20 +20,9 @@ test("Verify deleting a synced Cloud Sync workspace archives its own backend pro
const workspace = await workspaceFlow.get({ name: "My Environment" });
const dataPath = await appFlow.getDataPath();
const projectsDir = path.join(dataPath, "version-control", "projects");
const projectDirs = await fs.promises.readdir(projectsDir);
let backendProjectId: string | undefined;
for (const dir of projectDirs) {
const meta = JSON.parse(
await fs.promises.readFile(
path.join(projectsDir, dir, "meta.json"),
"utf8",
),
);
if (meta.rootDocumentId === workspace!.id) {
backendProjectId = meta.id;
break;
}
}
const backendProjectId = (await readBackendProjectMetas(projectsDir)).find(
(m) => m.rootDocumentId === workspace!.id,
)?.id;
await cloudSyncPage.backToAllProjects();
const logLines = await appFlow.captureMainProcessLog(async () => {
@@ -4,6 +4,7 @@ import path from "node:path";
import { faker } from "@faker-js/faker";
import { HttpMethod } from "@package/enums/http-method";
import { SyncStatus } from "@package/enums/sync-status";
import { readBackendProjectMetas } from "@package/misc/backend-projects";
import { HTTP_SERVER, test } from "@package/misc/fixtures";
import { Collection } from "@package/models/collection";
import { expect } from "@playwright/test";
@@ -37,19 +38,10 @@ test("Verify a new collection commits and pushes under its own backend project",
const dataPath = await appFlow.getDataPath();
const projectsDir = path.join(dataPath, "version-control", "projects");
const readProjectMeta = async (workspaceId: string) => {
const dirs = await fs.promises.readdir(projectsDir);
for (const dir of dirs) {
const meta = JSON.parse(
await fs.promises.readFile(
path.join(projectsDir, dir, "meta.json"),
"utf8",
),
);
if (meta.rootDocumentId === workspaceId) {
return { rootDocumentId: meta.rootDocumentId as string, dir };
}
}
return;
const [match] = (await readBackendProjectMetas(projectsDir))
.filter((m) => m.rootDocumentId === workspaceId)
.map((m) => ({ rootDocumentId: m.rootDocumentId, dir: m.dir }));
return match;
};
const readLatestSnapshotState = async (dir: string) => {
const snapshotsDir = path.join(projectsDir, dir, "snapshots");
@@ -4,6 +4,7 @@ import path from "node:path";
import { faker } from "@faker-js/faker";
import { HttpMethod } from "@package/enums/http-method";
import { SyncStatus } from "@package/enums/sync-status";
import { readBackendProjectMetas } from "@package/misc/backend-projects";
import { HTTP_SERVER, test } from "@package/misc/fixtures";
import { Collection } from "@package/models/collection";
import { expect } from "@playwright/test";
@@ -48,19 +49,9 @@ test("Verify a new collection is not left in an unsynced state after an app rest
const dataPath = await appFlow.getDataPath();
const projectsDir = path.join(dataPath, "version-control", "projects");
const dirs = await fs.promises.readdir(projectsDir);
const matchingDirs: string[] = [];
for (const dir of dirs) {
const meta = JSON.parse(
await fs.promises.readFile(
path.join(projectsDir, dir, "meta.json"),
"utf8",
),
);
if (meta.rootDocumentId === collectionYId) {
matchingDirs.push(dir);
}
}
const matchingDirs = (await readBackendProjectMetas(projectsDir))
.filter((m) => m.rootDocumentId === collectionYId)
.map((m) => m.dir);
const combinedLog = [...creationLog, ...restartLog].join("\n");
@@ -2,13 +2,13 @@ import * as fs from "node:fs";
import path from "node:path";
import { faker } from "@faker-js/faker";
import { readBackendProjectMetas } from "@package/misc/backend-projects";
import { getCloudSyncGraphQLRequestLog, setCloudSyncGraphQLDelay } from "@package/misc/cloud-sync-mock";
import { MOCK_API_SERVER, resetCloudSyncState, SESSION_ID, test } from "@package/misc/fixtures";
import { Collection } from "@package/models/collection";
import type { Environment } from "@package/models/environment";
import { expect } from "@playwright/test";
import { getCloudSyncGraphQLRequestLog, setCloudSyncGraphQLDelay } from "@package/misc/cloud-sync-mock";
test.afterAll(async () => {
await setCloudSyncGraphQLDelay(0);
await fetch(`${MOCK_API_SERVER}/_admin/cloud-sync/new-commit`, {
@@ -36,23 +36,10 @@ test("Verify an unrelated action during collection creation is equally safe", as
const dataPath = await appFlow.getDataPath();
const projectsDir = path.join(dataPath, "version-control", "projects");
const readProjectMeta = async (workspaceId: string) => {
const dirs = await fs.promises.readdir(projectsDir);
for (const dir of dirs) {
const meta = JSON.parse(
await fs.promises.readFile(
path.join(projectsDir, dir, "meta.json"),
"utf8",
),
);
if (meta.rootDocumentId === workspaceId) {
return {
rootDocumentId: meta.rootDocumentId as string,
backendProjectId: meta.id as string,
dir,
};
}
}
return;
const [match] = (await readBackendProjectMetas(projectsDir))
.filter((m) => m.rootDocumentId === workspaceId)
.map((m) => ({ rootDocumentId: m.rootDocumentId, backendProjectId: m.id, dir: m.dir }));
return match;
};
const countBlobFiles = async (dir: string) => {
const blobsDir = path.join(projectsDir, dir, "blobs");
@@ -30,17 +30,11 @@ test(
)
.toBeTruthy();
expect(bannerText).toContain("Git Sync limited to organizations");
await expect
.poll(() => projectSettingsPage.isHidden(projectSettingsPage.gitSetupForm), {
timeout: DEFAULT_TIMEOUT,
})
.toBe(true);
await expect
.poll(
() =>
projectSettingsPage.isDisabled(projectSettingsPage.scanForFilesButton),
{ timeout: DEFAULT_TIMEOUT },
)
.toBe(true);
await expect(projectSettingsPage.gitSetupForm).toBeHidden({
timeout: DEFAULT_TIMEOUT,
});
await expect(projectSettingsPage.scanForFilesButton).toBeDisabled({
timeout: DEFAULT_TIMEOUT,
});
},
);
@@ -30,14 +30,8 @@ test(
.toBeTruthy();
expect(bannerText).toContain("Cloud Sync and Local Vault");
expect(bannerText).not.toContain("Git Sync");
await expect
.poll(
() =>
projectSettingsPage.isDisabled(
projectSettingsPage.projectTypeTile(ProjectType.Git),
),
{ timeout: DEFAULT_TIMEOUT },
)
.toBe(true);
await expect(
projectSettingsPage.projectTypeTile(ProjectType.Git),
).toBeDisabled({ timeout: DEFAULT_TIMEOUT });
},
);
@@ -1,43 +1,53 @@
import { faker } from '@faker-js/faker';
import { ProjectType } from '@package/enums/project-types';
import type { UserSession } from '@package/misc/fixtures';
import { buildCollectionFile, DEFAULT_TIMEOUT, GIT_CREDENTIAL, pushServerFile, test } from '@package/misc/git-fixtures';
import { Collection } from '@package/models/collection';
import { Project } from '@package/models/project';
import { expect } from "@playwright/test";
for (const { version, keepsLocal } of [
{ version: 'Current', keepsLocal: true },
{ version: 'Incoming', keepsLocal: false },
] as const) {
test(`Verify resolving a pull conflict by choosing the ${version} version keeps that side's collection name`, async ({
user,
}) => {
const { gitSyncFlow, preferencesFlow, workspaceFlow } = user.flowManager;
const { gitSyncPage, workspacePage, gitBranchesDialogPage } = user.pageManager;
async function pullIntoConflict(user: UserSession, version: 'Current' | 'Incoming') {
const { gitSyncFlow, preferencesFlow, workspaceFlow } = user.flowManager;
const { gitBranchesDialogPage } = user.pageManager;
await preferencesFlow.addGitCredential(GIT_CREDENTIAL);
const project = await workspaceFlow.cloneGitProject(
new Project(faker.string.alphanumeric(10), ProjectType.Git),
GIT_CREDENTIAL.name,
);
const fileName = faker.string.alpha(10).toLowerCase();
const collection = await workspaceFlow.createCollection(project, new Collection(faker.string.alphanumeric(10)), fileName);
await gitSyncFlow.commitAndPush(faker.string.alphanumeric(10));
await preferencesFlow.addGitCredential(GIT_CREDENTIAL);
const project = await workspaceFlow.cloneGitProject(
new Project(faker.string.alphanumeric(10), ProjectType.Git),
GIT_CREDENTIAL.name,
);
const fileName = faker.string.alpha(10).toLowerCase();
const collection = await workspaceFlow.createCollection(project, new Collection(faker.string.alphanumeric(10)), fileName);
await gitSyncFlow.commitAndPush(faker.string.alphanumeric(10));
const localCollection = new Collection(faker.string.alpha(10));
const remoteCollection = new Collection(faker.string.alpha(10));
await workspaceFlow.renameCollection(collection, localCollection.name);
await gitSyncFlow.commit(faker.string.alphanumeric(10));
await pushServerFile({ path: `${fileName}.yaml`, content: buildCollectionFile(remoteCollection.name) });
await gitSyncFlow.pull();
await gitBranchesDialogPage.resolveMergeConflicts(version);
const keptCollection = keepsLocal ? localCollection : remoteCollection;
await expect
.poll(async () => workspacePage.findItemNode(keptCollection), { timeout: DEFAULT_TIMEOUT })
.toBeDefined();
if (keepsLocal) {
expect(await workspacePage.findItemNode(remoteCollection)).toBeUndefined();
}
});
const localCollection = new Collection(faker.string.alpha(10));
const remoteCollection = new Collection(faker.string.alpha(10));
await workspaceFlow.renameCollection(collection, localCollection.name);
await gitSyncFlow.commit(faker.string.alphanumeric(10));
await pushServerFile({ path: `${fileName}.yaml`, content: buildCollectionFile(remoteCollection.name) });
await gitSyncFlow.pull();
await gitBranchesDialogPage.resolveMergeConflicts(version);
return { localCollection, remoteCollection };
}
test("Verify resolving a pull conflict by choosing the Current version keeps that side's collection name", async ({
user,
}) => {
const { workspacePage } = user.pageManager;
const { localCollection, remoteCollection } = await pullIntoConflict(user, 'Current');
await expect
.poll(async () => workspacePage.findItemNode(localCollection), { timeout: DEFAULT_TIMEOUT })
.toBeDefined();
expect(await workspacePage.findItemNode(remoteCollection)).toBeUndefined();
});
test("Verify resolving a pull conflict by choosing the Incoming version keeps that side's collection name", async ({
user,
}) => {
const { workspacePage } = user.pageManager;
const { remoteCollection } = await pullIntoConflict(user, 'Incoming');
await expect
.poll(async () => workspacePage.findItemNode(remoteCollection), { timeout: DEFAULT_TIMEOUT })
.toBeDefined();
});