Usage with react native testing library #88
Replies: 5 comments 17 replies
-
I managed to have something that works by doing this in a jest setup file import { NativeModules } from 'react-native';
NativeModules.Unistyles = {
install: jest.fn().mockReturnValue(true),
};
global.__UNISTYLES__ = {
enabledPlugins: [],
useBreakpoints: jest.fn(),
useAdaptiveThemes: jest.fn(),
useTheme: jest.fn(),
themeName: 'default',
}; It's not perfect yet because the themeName won't change so it could for sure be improved. I'll try to investigate further, I think it would be nice to have a setup file provided by the lib, I can work on a PR if you're interested |
Beta Was this translation helpful? Give feedback.
-
I found the Originally I trying to use a I also noticed that Here's what I've got up and running: import type {UnistylesBreakpoints, UnistylesThemes} from 'react-native-unistyles';
import type {ColorSchemeName, UnistylesBridge} from 'react-native-unistyles/lib/typescript/src/types';
jest.mock('react-native', () => {
const RN = jest.requireActual('react-native');
class MockUnistylesBridge {
#timerRef?: ReturnType<typeof setTimeout> = undefined;
#hasAdaptiveThemes: boolean = false;
#supportsAutomaticColorScheme = false;
#screenWidth = 375;
#screenHeight = 812;
#themes: Array<keyof UnistylesThemes> = [];
#breakpoints: UnistylesBreakpoints = {} as UnistylesBreakpoints;
#colorScheme: ColorSchemeName = 'light';
#themeName: keyof UnistylesThemes = '' as keyof UnistylesThemes;
#enabledPlugins: Array<string> = [];
#unistylesEvents = new RN.NativeEventEmitter(RN.NativeModules.Unistyles);
#sortedBreakpointPairs: Array<[keyof UnistylesBreakpoints, number]> = [];
#breakpoint: keyof UnistylesBreakpoints = '' as keyof UnistylesBreakpoints;
#contentSizeCategory = 'unspecified';
public install() {
// @ts-ignore
global.__UNISTYLES__ = this;
return true;
}
public useTheme(themeName: keyof UnistylesThemes) {
this.#themeName = themeName;
this.emitThemeChange();
}
public useBreakpoints(breakpoints: UnistylesBreakpoints) {
this.#breakpoints = breakpoints;
this.#sortedBreakpointPairs = Object.entries(breakpoints).sort(([, a], [, b]) => (a ?? 0) - (b ?? 0)) as Array<
[keyof UnistylesBreakpoints, number]
>;
this.#breakpoint = this.getBreakpointFromScreenWidth(this.#screenWidth as number);
}
public useAdaptiveThemes(enable: boolean) {
this.#hasAdaptiveThemes = enable;
if (!this.#hasAdaptiveThemes || !this.#supportsAutomaticColorScheme) return;
if (this.#themeName !== this.#colorScheme) {
this.#themeName = this.#colorScheme as keyof UnistylesThemes;
this.emitThemeChange();
}
}
public addPlugin(pluginName: string, notify: boolean) {
this.#enabledPlugins = [pluginName].concat(this.#enabledPlugins);
if (notify) this.emitPluginChange();
}
public removePlugin(pluginName: string) {
this.#enabledPlugins = this.#enabledPlugins.filter(name => name !== pluginName);
this.emitPluginChange();
}
get themeName(): keyof UnistylesThemes {
if (this.#themes.length === 1) return this.#themes.at(0)!;
return this.#themeName;
}
set themeName(themeName: keyof UnistylesThemes) {
this.#themeName = themeName as keyof UnistylesThemes;
this.emitThemeChange();
}
set themes(themes: Array<keyof UnistylesThemes>) {
this.#themes = themes;
this.#supportsAutomaticColorScheme = themes.includes('light') && themes.includes('dark');
}
get screenWidth() {
return this.#screenWidth;
}
get screenHeight() {
return this.#screenHeight;
}
get contentSizeCategory(): any {
return this.#contentSizeCategory;
}
get breakpoint() {
return this.#breakpoint || undefined;
}
get breakpoints() {
return this.#breakpoints;
}
get hasAdaptiveThemes() {
return this.#hasAdaptiveThemes;
}
get sortedBreakpointPairs() {
return this.#sortedBreakpointPairs;
}
get enabledPlugins() {
return this.#enabledPlugins;
}
get colorScheme() {
return this.#colorScheme;
}
private emitPluginChange() {
this.#unistylesEvents.emit('__unistylesOnChange', {type: 'plugin'});
}
private emitThemeChange() {
this.#unistylesEvents.emit('__unistylesOnChange', {type: 'theme', payload: {themeName: this.#themeName}});
}
private getBreakpointFromScreenWidth(width: number): keyof UnistylesBreakpoints {
const breakpoint = this.#sortedBreakpointPairs.find(([, value], index, otherBreakpoints) => {
const minVal = value;
const maxVal = otherBreakpoints[index + 1]?.[1];
if (!maxVal) return true;
return width >= minVal && width < maxVal;
});
return breakpoint?.at(0) as keyof UnistylesBreakpoints;
}
}
if (!RN.NativeModules.Unistyles) RN.NativeModules.Unistyles = new MockUnistylesBridge() satisfies UnistylesBridge;
return RN;
}); |
Beta Was this translation helpful? Give feedback.
-
Hello.. I'm starting my studies in unit testing in react native and I ended up running into this problem of 'Unistyles runtime is not available. '. Has there been any progress on how to proceed in these cases? |
Beta Was this translation helpful? Give feedback.
-
Hey all, mocks are ready! Please give it a try, I want to gather some feedback before official release. In order to use mocks you need to:
follow this guide: https://www.unistyl.es/reference/testing/ |
Beta Was this translation helpful? Give feedback.
-
One question, how do you mock the theme call back from TypeError: Cannot read properties of undefined (reading 'xxs')
52 |
53 | deleteAccountContainer: {
> 54 | marginHorizontal: theme.margins.xxs, I followed all the instructions of the documentation Thank you @jpudysz ! |
Beta Was this translation helpful? Give feedback.
-
Hello @jpudysz! First thank you for this awesome library, I find the API really amazing!
I want to test components using react-native-testing-library but I get the error that says that Unistyles runtime is not available. This makes sense because native module is not there so I guess we'd need to mock the lib but there is no available jest preset. I have started trying to mock but it's quite complicated and I'm not sure at all if it's really feasible. Have you already thought about this? What would be your recommended approach?
Beta Was this translation helpful? Give feedback.
All reactions