Skip unrelated required checks without losing their names (#2542)
* fix(ci): skip unrelated required checks cleanly Matrix jobs had to start no-op runners to preserve interpolated required-check names. Static named jobs let GitHub report genuine skipped conclusions while keeping those names stable. * fix(ci): gate changes to install patching script * fix(ci): route cross-package test contracts narrowly * fix(ci): keep routed contracts merge-blocking * fix(server): exclude nested test utilities from builds * fix(ci): cover app-owned native and browser domains * refactor(ci): align tests with runtime domains Own browser specs, desktop specs, and Electron-only app code by stable directories so PR routing does not depend on filename conventions. Keep desktop integration coverage inside the required desktop check. * fix(ci): keep routing and desktop suites isolated The routing regression must run before dependency installation, and desktop Vitest must not collect Playwright-owned specs. * fix(ci): isolate desktop e2e runtime * perf(test): isolate Playwright workers * perf(test): parallelize Playwright within specs * fix(test): keep Playwright file scheduling * fix(test): share dynamic Metro fixture * fix(test): preserve own-host restart fixtures * fix(ci): preserve routed contracts after rebase * Stabilize Playwright wheel-scroll assertions
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
import { expect, test as base } from "../support/fixtures";
|
||||
import { openProjectDirectoryWithHosts } from "../support/helpers/project-grouping";
|
||||
import { projectPlacementViewKey } from "../support/helpers/project-view-key";
|
||||
import {
|
||||
type IsolatedHostDaemon,
|
||||
startIsolatedHostDaemon,
|
||||
} from "../support/helpers/isolated-host-daemon";
|
||||
import {
|
||||
expectNewWorkspaceProjectSelected,
|
||||
openGlobalNewWorkspaceComposer,
|
||||
selectNewWorkspaceHost,
|
||||
selectNewWorkspaceProject,
|
||||
} from "../support/helpers/new-workspace";
|
||||
import { connectSeedClient, type SeedDaemonClient } from "../support/helpers/seed-client";
|
||||
import { getServerId } from "../support/helpers/server-id";
|
||||
import { switchWorkspaceViaSidebar } from "../support/helpers/workspace-ui";
|
||||
import { createTempGitRepo } from "../support/helpers/workspace";
|
||||
|
||||
const PRIMARY_HOST_LABEL = "Primary host";
|
||||
const SECONDARY_HOST_LABEL = "Secondary host";
|
||||
const SHARED_PROJECT_NAME = "Paseo";
|
||||
const SHARED_REMOTE_URL = "https://github.com/getpaseo/paseo.git";
|
||||
|
||||
interface CreatedProject {
|
||||
projectId: string;
|
||||
projectKey: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
interface CrossHostProjectScenario {
|
||||
contextWorkspaceId: string;
|
||||
selectedProjectViewKey: string;
|
||||
sharedProjectKey: string;
|
||||
secondaryHost: {
|
||||
serverId: string;
|
||||
label: string;
|
||||
port: number;
|
||||
};
|
||||
}
|
||||
|
||||
async function createProject(
|
||||
client: SeedDaemonClient,
|
||||
input: { projectPath: string; projectName: string; workspaceName: string },
|
||||
): Promise<CreatedProject> {
|
||||
const created = await client.createWorkspace({
|
||||
source: { kind: "directory", path: input.projectPath },
|
||||
title: input.workspaceName,
|
||||
});
|
||||
if (!created.workspace) {
|
||||
throw new Error(created.error ?? `Failed to create project ${input.projectName}`);
|
||||
}
|
||||
|
||||
await client.renameProject(created.workspace.projectId, input.projectName);
|
||||
const listed = await client.listProjects();
|
||||
const project = listed.projects.find(
|
||||
(candidate) => candidate.projectId === created.workspace?.projectId,
|
||||
);
|
||||
if (!project?.projectKey) {
|
||||
throw new Error(`Created project ${created.workspace.projectId} has no project key`);
|
||||
}
|
||||
|
||||
return {
|
||||
projectId: created.workspace.projectId,
|
||||
projectKey: project.projectKey,
|
||||
workspaceId: created.workspace.id,
|
||||
};
|
||||
}
|
||||
|
||||
async function openNewWorkspaceFromContextProject(
|
||||
page: Parameters<typeof openProjectDirectoryWithHosts>[0],
|
||||
scenario: CrossHostProjectScenario,
|
||||
): Promise<void> {
|
||||
await openProjectDirectoryWithHosts(page, {
|
||||
hosts: [scenario.secondaryHost],
|
||||
primaryLabel: PRIMARY_HOST_LABEL,
|
||||
});
|
||||
await expect(
|
||||
page.getByTestId(`sidebar-project-row-${scenario.selectedProjectViewKey}`),
|
||||
).toBeVisible();
|
||||
await switchWorkspaceViaSidebar({
|
||||
page,
|
||||
serverId: getServerId(),
|
||||
workspaceId: scenario.contextWorkspaceId,
|
||||
});
|
||||
await openGlobalNewWorkspaceComposer(page);
|
||||
await expectNewWorkspaceProjectSelected(page, "Context project");
|
||||
}
|
||||
|
||||
const test = base.extend<{ crossHostProject: CrossHostProjectScenario }>({
|
||||
crossHostProject: async ({ page: _page }, provide) => {
|
||||
const secondaryDaemon: IsolatedHostDaemon = await startIsolatedHostDaemon(
|
||||
"new-workspace-project-preservation-secondary",
|
||||
);
|
||||
const contextRepo = await createTempGitRepo("new-workspace-context-");
|
||||
const primarySharedRepo = await createTempGitRepo("new-workspace-paseo-primary-", {
|
||||
originUrl: SHARED_REMOTE_URL,
|
||||
});
|
||||
const primaryDuplicateRepo = await createTempGitRepo("new-workspace-paseo-duplicate-", {
|
||||
originUrl: SHARED_REMOTE_URL,
|
||||
});
|
||||
const secondaryFallbackRepo = await createTempGitRepo("new-workspace-fallback-");
|
||||
const secondarySharedRepo = await createTempGitRepo("new-workspace-paseo-secondary-", {
|
||||
originUrl: SHARED_REMOTE_URL,
|
||||
});
|
||||
const primaryClient = await connectSeedClient();
|
||||
const secondaryClient = await connectSeedClient({ port: secondaryDaemon.port });
|
||||
const primaryProjects: CreatedProject[] = [];
|
||||
const secondaryProjects: CreatedProject[] = [];
|
||||
|
||||
try {
|
||||
const contextProject = await createProject(primaryClient, {
|
||||
projectPath: contextRepo.path,
|
||||
projectName: "Context project",
|
||||
workspaceName: "Context workspace",
|
||||
});
|
||||
primaryProjects.push(contextProject);
|
||||
const primarySharedProject = await createProject(primaryClient, {
|
||||
projectPath: primarySharedRepo.path,
|
||||
projectName: SHARED_PROJECT_NAME,
|
||||
workspaceName: "Primary Paseo workspace",
|
||||
});
|
||||
primaryProjects.push(primarySharedProject);
|
||||
const primaryDuplicateProject = await createProject(primaryClient, {
|
||||
projectPath: primaryDuplicateRepo.path,
|
||||
projectName: "Paseo duplicate",
|
||||
workspaceName: "Duplicate Paseo workspace",
|
||||
});
|
||||
primaryProjects.push(primaryDuplicateProject);
|
||||
secondaryProjects.push(
|
||||
await createProject(secondaryClient, {
|
||||
projectPath: secondaryFallbackRepo.path,
|
||||
projectName: "Aardvark project",
|
||||
workspaceName: "Secondary fallback workspace",
|
||||
}),
|
||||
);
|
||||
const secondarySharedProject = await createProject(secondaryClient, {
|
||||
projectPath: secondarySharedRepo.path,
|
||||
projectName: SHARED_PROJECT_NAME,
|
||||
workspaceName: "Secondary Paseo workspace",
|
||||
});
|
||||
secondaryProjects.push(secondarySharedProject);
|
||||
|
||||
if (
|
||||
primarySharedProject.projectKey !== primaryDuplicateProject.projectKey ||
|
||||
primarySharedProject.projectKey !== secondarySharedProject.projectKey
|
||||
) {
|
||||
throw new Error("Expected the Paseo clones to have the same equivalence key");
|
||||
}
|
||||
|
||||
await provide({
|
||||
contextWorkspaceId: contextProject.workspaceId,
|
||||
selectedProjectViewKey: projectPlacementViewKey(
|
||||
getServerId(),
|
||||
primarySharedProject.projectId,
|
||||
),
|
||||
sharedProjectKey: primarySharedProject.projectKey,
|
||||
secondaryHost: {
|
||||
serverId: secondaryDaemon.serverId,
|
||||
label: SECONDARY_HOST_LABEL,
|
||||
port: secondaryDaemon.port,
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
for (const project of primaryProjects) {
|
||||
await primaryClient.removeProject(project.projectId).catch(() => undefined);
|
||||
}
|
||||
for (const project of secondaryProjects) {
|
||||
await secondaryClient.removeProject(project.projectId).catch(() => undefined);
|
||||
}
|
||||
await primaryClient.close().catch(() => undefined);
|
||||
await secondaryClient.close().catch(() => undefined);
|
||||
await contextRepo.cleanup().catch(() => undefined);
|
||||
await primarySharedRepo.cleanup().catch(() => undefined);
|
||||
await primaryDuplicateRepo.cleanup().catch(() => undefined);
|
||||
await secondaryFallbackRepo.cleanup().catch(() => undefined);
|
||||
await secondarySharedRepo.cleanup().catch(() => undefined);
|
||||
await secondaryDaemon.close().catch(() => undefined);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
test.describe("New workspace host project preservation", () => {
|
||||
test.describe.configure({ timeout: 180_000 });
|
||||
|
||||
test("keeps the equivalent project selected when one host has another clone", async ({
|
||||
page,
|
||||
crossHostProject,
|
||||
}) => {
|
||||
await openNewWorkspaceFromContextProject(page, crossHostProject);
|
||||
await selectNewWorkspaceProject(page, {
|
||||
projectKey: crossHostProject.sharedProjectKey,
|
||||
projectViewKey: crossHostProject.selectedProjectViewKey,
|
||||
projectDisplayName: SHARED_PROJECT_NAME,
|
||||
});
|
||||
await selectNewWorkspaceHost(page, SECONDARY_HOST_LABEL);
|
||||
|
||||
await expectNewWorkspaceProjectSelected(page, SHARED_PROJECT_NAME);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user