1import { beforeEach, describe, expect, it, vi } from "vite-plus/test";
2import * as NodeURL from "node:url";
3
4vi.mock("react-native", () => ({
5 Appearance: {
6 addChangeListener: vi.fn(),
7 getColorScheme: () => "light",
8 setColorScheme: vi.fn(),
9 },
10 Platform: { constants: {}, OS: "ios" },
11}));
12
13vi.mock("../../node_modules/uniwind/src/core/listener", () => ({
14 UniwindListener: { notify() {}, notifyAll() {} },
15}));
16
17vi.mock("../../node_modules/uniwind/src/core/native", () => ({
18 UniwindStore: {
19 reinit: (generateStyleSheetCallback: () => unknown) => {
20 generateStyleSheetCallback();
21 },
22 runtime: { currentThemeName: "light", insets: {} },
23 vars: {},
24 },
25}));
26
27const loadUniwind = async () => {
28 const modulePath = NodeURL.fileURLToPath(
29 new URL("../../node_modules/uniwind/src/core/config/config.native.ts", import.meta.url),
30 );
31 const { Uniwind } = (await import(/* @vite-ignore */ modulePath)) as {
32 Uniwind: { readonly themes: Array<string> };
33 };
34 return Uniwind as typeof Uniwind & {
35 __reinit: (initialize: () => unknown, themes: Array<string>, fingerprint?: string) => void;
36 };
37};
38
39describe("Uniwind native stylesheet refresh", () => {
40 beforeEach(() => {
41 vi.resetModules();
42 vi.clearAllMocks();
43 vi.stubGlobal("__DEV__", true);
44 });
45
46 it("initializes once for identical generated styles", async () => {
47 const Uniwind = await loadUniwind();
48 const initialize = vi.fn(() => ({}));
49
50 Uniwind.__reinit(initialize, ["light", "dark"], "same-output");
51 Uniwind.__reinit(initialize, ["light", "dark"], "same-output");
52
53 expect(initialize).toHaveBeenCalledTimes(1);
54 });
55
56 it("reinitializes for changed generated styles and themes", async () => {
57 const Uniwind = await loadUniwind();
58 const initialize = vi.fn(() => ({}));
59
60 Uniwind.__reinit(initialize, ["light", "dark"], "before");
61 Uniwind.__reinit(initialize, ["light", "dark"], "after");
62 Uniwind.__reinit(initialize, ["light", "dark", "dim"], "themes-with-dim");
63
64 expect(initialize).toHaveBeenCalledTimes(3);
65 expect(Uniwind.themes).toEqual(["light", "dark", "dim"]);
66 });
67
68 it("retries the same output after initialization fails", async () => {
69 const Uniwind = await loadUniwind();
70 const initialize = vi
71 .fn()
72 .mockImplementationOnce(() => {
73 throw new Error("initialization failed");
74 })
75 .mockImplementationOnce(() => ({}));
76
77 expect(() => Uniwind.__reinit(initialize, ["light", "dark"], "retry-output")).toThrow(
78 "initialization failed",
79 );
80 Uniwind.__reinit(initialize, ["light", "dark"], "retry-output");
81
82 expect(initialize).toHaveBeenCalledTimes(2);
83 });
84
85 it("keeps no-fingerprint and production reinitialization semantics", async () => {
86 const Uniwind = await loadUniwind();
87 const initialize = vi.fn(() => ({}));
88
89 Uniwind.__reinit(initialize, ["light", "dark"]);
90 Uniwind.__reinit(initialize, ["light", "dark"]);
91 vi.stubGlobal("__DEV__", false);
92 Uniwind.__reinit(initialize, ["light", "dark"], "same-output");
93 Uniwind.__reinit(initialize, ["light", "dark"], "same-output");
94
95 expect(initialize).toHaveBeenCalledTimes(4);
96 });
97});