1import { describe } from "@effect/vitest";
2
3import { createOxlintRuleHarness } from "../test/utils.ts";
4
5const rule = createOxlintRuleHarness("t3code/no-hookless-use-function", {
6 filename: "fixture.tsx",
7});
8
9describe("t3code/no-hookless-use-function", () => {
10 rule.valid(
11 "allows a hook that calls useState",
12 `function useCount() { const [count] = useState(0); return count; }`,
13 );
14
15 rule.valid(
16 "allows a hook that only calls use()",
17 `const useTheme = () => { return use(ThemeContext); };`,
18 );
19
20 rule.valid(
21 "allows a hook that calls a member hook",
22 `const useStore = () => React.useContext(StoreContext);`,
23 );
24
25 rule.valid("allows a plain function", `function formatLabel(value) { return String(value); }`);
26
27 rule.valid("allows names that only start with use", `function user() { return null; }`);
28
29 rule.invalid(
30 "reports a hook-less function declaration",
31 `function useFontFamily(weight) { return FONT_FAMILIES[weight]; }`,
32 );
33
34 rule.invalid(
35 "reports a hook-less arrow returning a closure",
36 `const useUpdateSettings = () => (patch) => persist(patch);`,
37 );
38
39 rule.invalid(
40 "reports a hook-less function expression",
41 `const useCompleteOnboarding = function () { return completeOnboarding; };`,
42 );
43
44 rule.invalid(
45 "reports a hook call that only happens inside a nested callback",
46 `function useHandler() { return () => useState(0); }`,
47 );
48});