Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
feature(context): move ThemeProvider inside walletkit-ui (#30)
Browse files Browse the repository at this point in the history
* feature(context): move ThemeProvider inside walletkit-ui

* fetaure(context): unskip hook test for themeprovider
  • Loading branch information
lykalabrada authored Dec 15, 2022
1 parent 993a007 commit 96ec956
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/walletkit-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/react-hooks": "^8.0.1",
"jest-environment-jsdom": "^29.3.1"
},
"scripts": {
Expand Down
84 changes: 84 additions & 0 deletions packages/walletkit-ui/src/contexts/ThemeProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @jest-environment jsdom
*/

import { render } from "@testing-library/react";
import { renderHook } from "@testing-library/react-hooks";
import React from "react";

import { ThemeProvider, useTheme, useThemeContext } from "./ThemeProvider";

const consoleLog = jest.spyOn(console, "log").mockImplementation(jest.fn);
const consoleError = jest.spyOn(console, "error").mockImplementation(jest.fn);
const logger = { error: () => consoleError, info: () => consoleLog };

describe("useTheme hook test", () => {
it("should pass when theme is not set", async () => {
const desiredTheme = "dark";
const api = {
set: jest.fn(),
get: async () => null,
};
const { result, waitForNextUpdate } = renderHook(() =>
useTheme({
api,
colorScheme: desiredTheme,
logger,
})
);
await waitForNextUpdate();
expect(result.current.theme).toBe(desiredTheme);
expect(result.current.isThemeLoaded).toBe(true);
});

it("should pass when theme is already set", async () => {
const desiredTheme = "dark";
const api = {
set: jest.fn(),
get: async () => desiredTheme,
};
const { result, waitForNextUpdate } = renderHook(() =>
useTheme({ api, colorScheme: "light", logger })
);
await waitForNextUpdate();
expect(result.current.theme).toBe(desiredTheme);
expect(result.current.isThemeLoaded).toBe(true);
});

it("should pass when theme is not set and colorScheme is not defined", async () => {
const api = {
set: jest.fn(),
get: async () => null,
};
const { result, waitForNextUpdate } = renderHook(() =>
useTheme({ api, logger })
);
await waitForNextUpdate();
expect(result.current.theme).toBe("light");
expect(result.current.isThemeLoaded).toBe(true);
});
});

describe("ThemeProvider Context test", () => {
it("should match snapshot", () => {
function ThemeProviderComponent(): JSX.Element {
const { isLight, theme } = useThemeContext();
return (
<div>
<span>{isLight.toString()}</span>
<span>{theme}</span>
</div>
);
}
const api = {
set: jest.fn(),
get: async () => "light",
};
const rendered = render(
<ThemeProvider api={api} colorScheme={jest.fn()}>
<ThemeProviderComponent />
</ThemeProvider>
);
expect(rendered).toMatchSnapshot();
});
});
95 changes: 95 additions & 0 deletions packages/walletkit-ui/src/contexts/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, {
createContext,
PropsWithChildren,
useContext,
useEffect,
useState,
} from "react";

import { BaseLogger } from "./logger";

interface ThemeLoader {
theme: NonNullable<ColorSchemeName>;
isThemeLoaded: boolean;
}

type ColorSchemeName = "light" | "dark" | null | undefined;

interface ThemeContextI {
api: {
get: () => Promise<string | null>;
set: (language: NonNullable<ColorSchemeName>) => Promise<void>;
};
logger: BaseLogger;
colorScheme?: ColorSchemeName;
}

export function useTheme({
api,
colorScheme,
logger,
}: ThemeContextI): ThemeLoader {
const [isThemeLoaded, setIsThemeLoaded] = useState<boolean>(false);
const [theme, setTheme] = useState<NonNullable<ColorSchemeName>>("light");

useEffect(() => {
api
.get()
.then((t) => {
let currentTheme: NonNullable<ColorSchemeName> = "light";
if (t !== null && t !== undefined) {
currentTheme = t as NonNullable<ColorSchemeName>;
} else if (colorScheme !== null && colorScheme !== undefined) {
currentTheme = colorScheme;
}
setTheme(currentTheme);
})
.catch(logger?.error)
.finally(() => setIsThemeLoaded(true));
}, []);

return {
isThemeLoaded,
theme,
};
}

interface Theme {
theme: NonNullable<ColorSchemeName>;
setTheme: (theme: NonNullable<ColorSchemeName>) => void;
isLight: boolean;
}

const ThemeContext = createContext<Theme>(undefined as any);

export function useThemeContext(): Theme {
return useContext(ThemeContext);
}

export interface ThemeProviderProps extends PropsWithChildren<{}> {
logger: BaseLogger;
}

export function ThemeProvider(
props: ThemeContextI & React.PropsWithChildren<any>
): JSX.Element | null {
const { children, api, colorScheme, logger } = props;
const { theme } = useTheme({ api, colorScheme, logger });
const [currentTheme, setTheme] =
useState<NonNullable<ColorSchemeName>>(theme);

useEffect(() => {
setTheme(theme);
}, [theme]);

// eslint-disable-next-line react/jsx-no-constructed-context-values
const context: Theme = {
theme: currentTheme,
setTheme,
isLight: currentTheme === "light",
};

return (
<ThemeContext.Provider value={context}>{children}</ThemeContext.Provider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ThemeProvider Context test should match snapshot 1`] = `
{
"asFragment": [Function],
"baseElement": <body>
<div>
<div>
<span>
true
</span>
<span>
light
</span>
</div>
</div>
</body>,
"container": <div>
<div>
<span>
true
</span>
<span>
light
</span>
</div>
</div>,
"debug": [Function],
"findAllByAltText": [Function],
"findAllByDisplayValue": [Function],
"findAllByLabelText": [Function],
"findAllByPlaceholderText": [Function],
"findAllByRole": [Function],
"findAllByTestId": [Function],
"findAllByText": [Function],
"findAllByTitle": [Function],
"findByAltText": [Function],
"findByDisplayValue": [Function],
"findByLabelText": [Function],
"findByPlaceholderText": [Function],
"findByRole": [Function],
"findByTestId": [Function],
"findByText": [Function],
"findByTitle": [Function],
"getAllByAltText": [Function],
"getAllByDisplayValue": [Function],
"getAllByLabelText": [Function],
"getAllByPlaceholderText": [Function],
"getAllByRole": [Function],
"getAllByTestId": [Function],
"getAllByText": [Function],
"getAllByTitle": [Function],
"getByAltText": [Function],
"getByDisplayValue": [Function],
"getByLabelText": [Function],
"getByPlaceholderText": [Function],
"getByRole": [Function],
"getByTestId": [Function],
"getByText": [Function],
"getByTitle": [Function],
"queryAllByAltText": [Function],
"queryAllByDisplayValue": [Function],
"queryAllByLabelText": [Function],
"queryAllByPlaceholderText": [Function],
"queryAllByRole": [Function],
"queryAllByTestId": [Function],
"queryAllByText": [Function],
"queryAllByTitle": [Function],
"queryByAltText": [Function],
"queryByDisplayValue": [Function],
"queryByLabelText": [Function],
"queryByPlaceholderText": [Function],
"queryByRole": [Function],
"queryByTestId": [Function],
"queryByText": [Function],
"queryByTitle": [Function],
"rerender": [Function],
"unmount": [Function],
}
`;
1 change: 1 addition & 0 deletions packages/walletkit-ui/src/contexts/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./NetworkContext";
export * from "./ThemeProvider";
export * from "./WhaleContext";
34 changes: 34 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 96ec956

Please sign in to comment.