Skip to content
Source
Sign inSign up

V5StackHeader.ios.test.tsx

76 lines2.7 KB

1import type { NativeStackHeaderItem } from "@react-navigation/native-stack";
2import { act } from "react";
3import { createRoot } from "react-dom/client";
4import type { StackHeaderConfigProps } from "react-native-screens";
5import { expect, it, vi } from "vite-plus/test";
6​
7const bridge = vi.hoisted(() => ({ ios: undefined as StackHeaderConfigProps["ios"] }));
8​
9vi.mock("react-native", () => ({ StyleSheet: { flatten: (style: unknown) => style } }));
10vi.mock("react-native-keyboard-controller", () => ({
11 KeyboardController: { dismiss: vi.fn() },
12 useKeyboardState: () => false,
13}));
14vi.mock("../lib/useMobileNavigationTheme", () => ({
15 useMobileNavigationTheme: () => ({ colors: { card: "white" } }),
16}));
17vi.mock("./native-layout-metrics", () => ({
18 useDeviceType: () => "phone",
19 useNativeLayoutMetrics: () => null,
20}));
21vi.mock("react-native-screens", () => ({
22 Stack: {
23 HeaderConfig: ({ ios }: StackHeaderConfigProps) => {
24 bridge.ios = ios;
25 return null;
26 },
27 },
28}));
29​
30import { V5StackHeader } from "./V5StackHeader.ios";
31​
32it.each(["leadingItems", "trailingItems", "toolbarItems"] as const)(
33 "updates native enabled state after permissions change in %s",
34 (placement) => {
35 bridge.ios = undefined;
36 vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
37 const root = createRoot(document.createElement("div"));
38 const onPress = () => {};
39 try {
40 for (const disabled of [true, false, undefined, true]) {
41 const items: NativeStackHeaderItem[] = [
42 { type: "button", label: "Files", disabled, onPress },
43 {
44 type: "menu",
45 label: "Terminal",
46 disabled,
47 menu: { items: [{ type: "action", label: "Open terminal", onPress }] },
48 },
49 ];
50 act(() =>
51 root.render(
52 <V5StackHeader
53 canGoBack={false}
54 options={{
55 unstable_headerLeftItems: () => (placement === "leadingItems" ? items : []),
56 unstable_headerRightItems: () => (placement === "trailingItems" ? items : []),
57 unstable_headerToolbarItems: () => (placement === "toolbarItems" ? items : []),
58 }}
59 />,
60 ),
61 );
62 const nativeItems = (bridge.ios as StackHeaderConfigProps["ios"])?.[placement];
63 expect(nativeItems).toHaveLength(2);
64 for (const item of nativeItems ?? []) {
65 if (item.type !== "item" || "render" in item)
66 throw new Error("Expected a native bar item");
67 // RNSHeaderContentFactory sets UIBarButtonItem.enabled to !item.disabled.
68 expect(!item.disabled).toBe(!disabled);
69 }
70 }
71 } finally {
72 act(() => root.unmount());
73 vi.unstubAllGlobals();
74 }
75 },
76);