test: fix root test and typecheck gates

This commit is contained in:
Peter Steinberger
2026-04-27 20:51:00 +01:00
parent e63031c452
commit 2ddc52c0b0
5 changed files with 146 additions and 21 deletions
+8 -6
View File
@@ -17,14 +17,16 @@ vi.mock("./lib/badges", () => ({
Boolean(skill.badges?.highlighted),
}));
type WrappedHandler = {
_handler: (
ctx: unknown,
args: unknown,
) => Promise<Array<{ skill: { slug: string; _id: string } }>>;
type WrappedHandler<Result = { skill: { slug: string; _id: string } }> = {
_handler: (ctx: unknown, args: unknown) => Promise<Array<Result>>;
};
const searchSkillsHandler = (searchSkills as unknown as WrappedHandler)._handler;
const searchSkillsHandler = (
searchSkills as unknown as WrappedHandler<{
skill: { slug: string; _id: string };
score: number;
}>
)._handler;
const lexicalFallbackSkillsHandler = (lexicalFallbackSkills as unknown as WrappedHandler)._handler;
const hydrateResultsHandler = (
hydrateResults as unknown as {
+15 -14
View File
@@ -8,7 +8,6 @@ const useAuthStatusMock = vi.fn();
process.env.VITE_CONVEX_URL = process.env.VITE_CONVEX_URL ?? "https://example.convex.cloud";
vi.mock("../components/UserBadge", () => ({
UserBadge: () => null,
}));
@@ -229,10 +228,12 @@ describe("SkillDetailPage", () => {
);
expect(screen.getByRole("heading", { name: "CLI Commands" })).toBeTruthy();
expect(screen.getByText("openclaw skills install steipete/weather")).toBeTruthy();
expect(screen.getByText("openclaw skills install weather")).toBeTruthy();
expect(screen.getByText("npx clawhub@latest install weather")).toBeTruthy();
expect(screen.getByText(/After install, inspect the skill metadata/i)).toBeTruthy();
expect(installHeading.compareDocumentPosition(scanDisclaimer) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
expect(
installHeading.compareDocumentPosition(scanDisclaimer) & Node.DOCUMENT_POSITION_FOLLOWING,
).toBeTruthy();
});
it("does not refetch readme when SSR data already matches the latest version", async () => {
@@ -324,17 +325,17 @@ describe("SkillDetailPage", () => {
useQueryMock.mockImplementation((_fn: unknown, args: unknown) => {
if (args === "skip") return undefined;
if (args && typeof args === "object" && "skillId" in args) return [];
return {
skill: {
_id: "skills:1",
slug: "weather",
displayName: "Weather",
summary: "Get current weather.",
ownerUserId: "users:1",
ownerPublisherId: "publishers:steipete",
tags: {},
stats: { stars: 0, downloads: 0 },
},
return {
skill: {
_id: "skills:1",
slug: "weather",
displayName: "Weather",
summary: "Get current weather.",
ownerUserId: "users:1",
ownerPublisherId: "publishers:steipete",
tags: {},
stats: { stars: 0, downloads: 0 },
},
owner: {
_id: "publishers:steipete",
_creationTime: 0,
+4
View File
@@ -9,6 +9,10 @@
/* Bundler mode */
"moduleResolution": "bundler",
"paths": {
"convex": ["./node_modules/convex"],
"convex/*": ["./node_modules/convex/*"]
},
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": false,
"noEmit": true,
+25
View File
@@ -1,8 +1,33 @@
import { createRequire } from "node:module";
import { defineConfig } from "vitest/config";
const require = createRequire(import.meta.url);
const testingLibraryRequire = createRequire(require.resolve("@testing-library/react"));
export default defineConfig({
resolve: {
dedupe: ["react", "react-dom"],
alias: [
{
find: "react/jsx-dev-runtime",
replacement: testingLibraryRequire.resolve("react/jsx-dev-runtime"),
},
{
find: "react/jsx-runtime",
replacement: testingLibraryRequire.resolve("react/jsx-runtime"),
},
{ find: "react-dom/client", replacement: testingLibraryRequire.resolve("react-dom/client") },
{ find: "react-dom", replacement: testingLibraryRequire.resolve("react-dom") },
{ find: "react", replacement: testingLibraryRequire.resolve("react") },
],
},
test: {
environment: "jsdom",
environmentOptions: {
jsdom: {
url: "http://localhost/",
},
},
globals: true,
setupFiles: ["./vitest.setup.ts"],
testTimeout: 15_000,
+94 -1
View File
@@ -1 +1,94 @@
// Vitest setup (intentionally minimal for now)
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const storageData = new WeakMap<Storage, Map<string, string>>();
function getStorageData(storage: Storage) {
let data = storageData.get(storage);
if (!data) {
data = new Map();
storageData.set(storage, data);
}
return data;
}
function installLocalStorageShim() {
if (typeof window === "undefined" || typeof Storage === "undefined") return;
if (typeof window.localStorage?.clear === "function") return;
Object.defineProperties(Storage.prototype, {
length: {
configurable: true,
get() {
return getStorageData(this as Storage).size;
},
},
clear: {
configurable: true,
value() {
getStorageData(this as Storage).clear();
},
},
getItem: {
configurable: true,
value(key: string) {
return getStorageData(this as Storage).get(String(key)) ?? null;
},
},
key: {
configurable: true,
value(index: number) {
return Array.from(getStorageData(this as Storage).keys())[index] ?? null;
},
},
removeItem: {
configurable: true,
value(key: string) {
getStorageData(this as Storage).delete(String(key));
},
},
setItem: {
configurable: true,
value(key: string, value: string) {
getStorageData(this as Storage).set(String(key), String(value));
},
},
});
const localStorage = Object.create(Storage.prototype) as Storage;
storageData.set(localStorage, new Map());
Object.defineProperty(window, "localStorage", {
configurable: true,
value: localStorage,
});
}
installLocalStorageShim();
function proxyReactInternals() {
try {
const rootReact = require("react");
const testingLibraryRequire = createRequire(require.resolve("@testing-library/react"));
const rendererReact = testingLibraryRequire("react");
const rootInternals = rootReact.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
const rendererInternals =
rendererReact.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
if (!rootInternals || !rendererInternals || rootInternals === rendererInternals) return;
for (const key of ["H", "A", "T", "S", "V"] as const) {
Object.defineProperty(rootInternals, key, {
configurable: true,
get() {
return rendererInternals[key];
},
set(value) {
rendererInternals[key] = value;
},
});
}
} catch {
// Best effort for package-manager layouts that install duplicate React copies.
}
}
proxyReactInternals();