Files
openidea/e2e/workspaceProjectTypes.spec.ts
T
Shohruh Ismoilovandshohruh-genius 025e3e9255 fix(project): detect project types and honor workspace type sorting (#2522)
Workspace roots always sorted by name and only Maven/Gradle roots had a type icon. Project types are now detected from root build/SDK file names (no file contents or tools are read, up to four concurrent listings) through one registry (projectType.ts) that supplies names, icons, markers and refresh handling; roots show the type's icon, and Sort by Type groups roots by type with natural name order inside each type. Flutter and Vite logos come from Simple Icons (CC0, recorded in THIRD_PARTY_LICENSES.md).

Co-authored-by: shohruh-genius <7658451+shohruh-genius@users.noreply.github.com>
2026-11-11 01:07:40 +08:00

137 lines
4.3 KiB
TypeScript

import { expect, stubDesktop, test } from "./fixtures";
test.use({ video: "on" });
test("sorts collapsed workspace roots by project type, shows their icons and refreshes changed markers", async ({
workbench: page,
}) => {
await stubDesktop(page);
await page.evaluate(async () => {
const markers: Record<string, string[]> = {
"z-web": ["package.json"],
go10: ["go.mod"],
Go2: ["go.mod"],
mobile: ["pubspec.yaml", ".metadata"],
dart: ["pubspec.yaml"],
library: ["build.gradle.kts"],
server: ["pom.xml"],
py: ["pyproject.toml"],
rust: ["Cargo.toml"],
site: ["package.json", "vite.config.ts"],
notes: ["README.md"],
};
const listing = (path: string) =>
(markers[path.slice("/work/".length)] ?? []).map((name) => ({
path: `${path}/${name}`,
name,
kind: "file",
size: 10,
mtimeMs: 0,
ignored: false,
excluded: false,
hidden: name.startsWith("."),
}));
window.__ipc.handlers.fs_read_dir = ({ path }) => listing(String(path));
const module = "/src/features/project-tree/store.ts";
const { initProjectTree, useProjectTree } = await import(/* @vite-ignore */ module);
initProjectTree(
"/workspace",
"Workspace",
Object.keys(markers).map((name) => `/work/${name}`),
);
useProjectTree.setState({ expanded: new Set() });
});
const tree = page.getByRole("tree", { name: "Project" });
await page
.getByRole("region", { name: "Project", exact: true })
.getByRole("button", { name: "Options", exact: true })
.click();
await page.getByRole("menuitemcheckbox", { name: "Sort by Type", exact: true }).click();
await expect(tree.locator("[data-project-path]")).toHaveText([
"rust/work/rust",
"dart/work/dart",
"mobile/work/mobile",
"Go2/work/Go2",
"go10/work/go10",
"library/work/library",
"server/work/server",
"z-web/work/z-web",
"py/work/py",
"site/work/site",
"notes/work/notes",
]);
const shape = (name: string) =>
page.evaluate(async (icon) => {
const module = "/src/ui/icons.tsx";
const { iconMarkup } = await import(/* @vite-ignore */ module);
return [...new DOMParser().parseFromString(iconMarkup(icon)!, "image/svg+xml").querySelectorAll("path")].map(
(path) => path.getAttribute("d"),
);
}, name);
for (const [name, icon] of [
["z-web", "file-npm"],
["Go2", "file-go"],
["go10", "file-go"],
["mobile", "project-flutter"],
["dart", "file-dart"],
["library", "gradle-project"],
["server", "maven-project"],
["rust", "file-cargo"],
["py", "file-python"],
["site", "project-vite"],
["notes", "module"],
]) {
const row = tree.locator(`[data-project-path="/work/${name}"]`);
await expect
.poll(() => row.locator("svg path").evaluateAll((paths) => paths.map((path) => path.getAttribute("d"))))
.toEqual(await shape(icon!));
await expect(row.locator("[data-project-path]")).toHaveCount(0);
}
await tree.locator('[data-project-path="/work/z-web"]').click();
await page.evaluate(() => {
const original = window.__ipc.handlers.fs_read_dir!;
window.__ipc.handlers.fs_read_dir = (args) =>
args.path === "/work/z-web"
? [
{
path: "/work/z-web/go.mod",
name: "go.mod",
kind: "file",
size: 10,
mtimeMs: 0,
ignored: false,
excluded: false,
hidden: false,
},
]
: original(args);
window.__ipc.emit({
type: "fsChanged",
created: ["/work/z-web/go.mod"],
modified: [],
removed: ["/work/z-web/package.json"],
});
});
await expect
.poll(() =>
tree
.locator('[data-project-path="/work/z-web"] svg path')
.evaluateAll((paths) => paths.map((path) => path.getAttribute("d"))),
)
.toEqual(await shape("file-go"));
await expect(tree.locator("[data-project-path]")).toHaveText([
"rust/work/rust",
"dart/work/dart",
"mobile/work/mobile",
"Go2/work/Go2",
"go10/work/go10",
"z-web/work/z-web",
"library/work/library",
"server/work/server",
"py/work/py",
"site/work/site",
"notes/work/notes",
]);
await expect(tree.getByRole("treeitem", { selected: true })).toContainText("z-web");
});