mirror of
https://github.com/openclaw/clawhub.git
synced 2026-08-14 00:47:57 +00:00
test: fix root test and typecheck gates
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"paths": {
|
||||
"convex": ["./node_modules/convex"],
|
||||
"convex/*": ["./node_modules/convex/*"]
|
||||
},
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": false,
|
||||
"noEmit": true,
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user