diff --git a/Storybook/components/TopAppBar/TopAppBar.stories.tsx b/Storybook/components/TopAppBar/TopAppBar.stories.tsx
index c279da69..fb83110c 100644
--- a/Storybook/components/TopAppBar/TopAppBar.stories.tsx
+++ b/Storybook/components/TopAppBar/TopAppBar.stories.tsx
@@ -1,13 +1,19 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import type { Meta, StoryObj } from '@storybook/react-native';
import React from 'react';
-import { StyleSheet, View } from 'react-native';
-import { Headline, TopAppBar } from 'smartway-react-native-ui';
+import { Pressable, StyleSheet, Text, View } from 'react-native';
+import {
+ Headline,
+ TopAppBar,
+} from '../../../src/components/topAppBar/TopAppBar';
+
+import TopAppBarMenuItem from '../../../src/components/topAppBar/TopAppBarMenuItem';
+
import type { Title } from 'src/components/topAppBar/TopAppBar';
const asString = { value: 'menu' };
const asButton = { value: 'menu', onPress: () => {} };
-const asComponent = { value: Headline H1 };
+const asComponent = { value: Headline H1 };
type ComponentProps = React.ComponentProps & {
withBackButton?: boolean;
@@ -28,10 +34,14 @@ export default {
control: { type: 'radio' },
options: ['small', 'medium', 'large', 'center-aligned'],
},
- withTitleAs: { control: { type: 'radio' }, options: ['string', 'button', 'component'] },
+ withTitleAs: {
+ control: { type: 'radio' },
+ options: ['string', 'button', 'component'],
+ },
withBackButton: { type: 'boolean' },
onBack: { action: 'onBack' },
onPressIcon: { action: 'onPressIcon' },
+ onMenuItemPress: { action: 'onMenuItemPress' },
},
decorators: [
@@ -60,9 +70,46 @@ export const Default: Story = {
size={args.size}
onBack={args.withBackButton ? args.onBack : undefined}
title={titleComponent}
- icon={{ name: 'dots-vertical', onPress: args.onPressIcon }}
/>
);
},
};
+export const WithMenu = (args) => {
+ let titleComponent: Title = asString;
+ if (args.withTitleAs === 'button') titleComponent = asButton;
+ if (args.withTitleAs === 'component') titleComponent = asComponent;
+
+ const handlePress = (menuItem, hideMenu) => () => {
+ hideMenu();
+ args.onMenuItemPress(menuItem);
+ };
+
+ const menu = {
+ items: [
+ {
+ title: 'Ne plus surveiller',
+ id: 'noLongerMonitor',
+ },
+ ],
+ renderItem: (menuItem, { hideMenu }) => {
+ return (
+
+ );
+ },
+ };
+
+ return (
+
+ );
+};
+
Default.parameters = { noSafeArea: false };
diff --git a/Storybook/package-lock.json b/Storybook/package-lock.json
index 9e4eb3f4..71381112 100644
--- a/Storybook/package-lock.json
+++ b/Storybook/package-lock.json
@@ -56,7 +56,7 @@
"@storybook/testing-library": "^0.0.13",
"@tsconfig/react-native": "^2.0.2",
"@types/jest": "^29.2.1",
- "@types/react": "^18.0.24",
+ "@types/react": "^18.2.0",
"@types/react-native": "^0.70.6",
"@types/react-test-renderer": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.37.0",
@@ -17874,9 +17874,9 @@
"dev": true
},
"node_modules/@types/react": {
- "version": "18.2.21",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz",
- "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==",
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==",
"devOptional": true,
"dependencies": {
"@types/prop-types": "*",
diff --git a/Storybook/package.json b/Storybook/package.json
index d2c9c432..5b26bb82 100644
--- a/Storybook/package.json
+++ b/Storybook/package.json
@@ -64,7 +64,7 @@
"@storybook/testing-library": "^0.0.13",
"@tsconfig/react-native": "^2.0.2",
"@types/jest": "^29.2.1",
- "@types/react": "^18.0.24",
+ "@types/react": "^18.2.0",
"@types/react-native": "^0.70.6",
"@types/react-test-renderer": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.37.0",
diff --git a/jest.config.ts b/jest.config.ts
index 69d5daec..6303f3a8 100644
--- a/jest.config.ts
+++ b/jest.config.ts
@@ -16,7 +16,7 @@ const jestConfig: JestConfigWithTsJest = {
testMatch: ['**/?(*.)test.(ts|tsx)'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
transformIgnorePatterns: [
- 'node_modules/(?!(@react-native|react-native|react-native-drop-shadow|@gorhom/bottom-sheet|react-native-reanimated)/)',
+ 'node_modules/(?!(@react-native|react-native|react-native-drop-shadow|@gorhom/bottom-sheet|react-native-reanimated|react-native-paper)/)',
],
moduleDirectories: ['node_modules', 'src'],
setupFilesAfterEnv: ['./jest.setup.ts'],
diff --git a/package-lock.json b/package-lock.json
index 21a40e95..c840a4f1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,7 @@
"devDependencies": {
"@testing-library/react-native": "^12.4.2",
"@types/jest": "^29.5.5",
- "@types/react": "^18.2.45",
+ "@types/react": "^18.2.0",
"@types/react-native": "^0.73.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"eslint": "^8.56.0",
@@ -4403,9 +4403,9 @@
"devOptional": true
},
"node_modules/@types/react": {
- "version": "18.2.45",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz",
- "integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==",
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==",
"devOptional": true,
"dependencies": {
"@types/prop-types": "*",
@@ -18127,9 +18127,9 @@
"devOptional": true
},
"@types/react": {
- "version": "18.2.45",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz",
- "integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==",
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==",
"devOptional": true,
"requires": {
"@types/prop-types": "*",
diff --git a/package.json b/package.json
index 37cf415f..38e3cab4 100644
--- a/package.json
+++ b/package.json
@@ -47,11 +47,11 @@
"devDependencies": {
"@testing-library/react-native": "^12.4.2",
"@types/jest": "^29.5.5",
- "@types/react": "^18.2.45",
+ "@types/react": "^18.2.0",
"@types/react-native": "^0.73.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
- "eslint-config-prettier": "^9.1.0",
"eslint": "^8.56.0",
+ "eslint-config-prettier": "^9.1.0",
"eslint-config-standard-with-typescript": "19.0.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.32.2",
diff --git a/src/__tests__/components/TopAppBar.test.tsx b/src/__tests__/components/TopAppBar.test.tsx
new file mode 100644
index 00000000..8ba6e91a
--- /dev/null
+++ b/src/__tests__/components/TopAppBar.test.tsx
@@ -0,0 +1,157 @@
+import React from 'react';
+import { TopAppBar } from '../../components/topAppBar/TopAppBar';
+import {
+ render,
+ screen,
+ setupFakeTimer,
+ userEvent,
+ waitForElementToBeRemoved,
+} from '../../shared/testUtils';
+import { Text } from 'react-native';
+import TopAppBarMenuItem from '../../components/topAppBar/TopAppBarMenuItem';
+
+const topBarTitle = 'Menu';
+
+describe('TopAppBar mounting with a simple title', () => {
+ it('displays a title', () => {
+ const title = {
+ value: topBarTitle,
+ };
+
+ render();
+
+ expect(screen.getByText(topBarTitle)).toBeOnTheScreen();
+ });
+
+ it.todo("testing menu title 'as string' on press");
+});
+
+describe('TopAppBar mounting with a title by passing a custom component', () => {
+ it('displays a title', () => {
+ const title = {
+ value: {topBarTitle},
+ };
+
+ render();
+
+ expect(screen.getByText(topBarTitle)).toBeOnTheScreen();
+ });
+
+ it.todo("testing menu title 'as component' on press");
+});
+
+describe('TopAppBar mounting with a go back button', () => {
+ it('triggers `goBack` event when user press the go back button', async () => {
+ setupFakeTimer();
+
+ const user = userEvent.setup();
+
+ const mockOnGoBack = jest.fn();
+
+ const title = {
+ value: topBarTitle,
+ };
+
+ render();
+
+ expect(mockOnGoBack).not.toHaveBeenCalled();
+
+ await user.press(screen.getByLabelText(/back/i));
+
+ expect(mockOnGoBack).toHaveBeenCalled();
+ });
+});
+
+describe('TopAppBar mounting with a menu', () => {
+ const noLongerMonitorMenuItem = {
+ id: 'noLongerMonitor' as const,
+ title: 'Ne plus surveiller',
+ };
+ const title = {
+ value: topBarTitle,
+ };
+ let mockOnMenuItemPress: jest.Mock;
+
+ beforeEach(() => {
+ mockOnMenuItemPress = jest.fn();
+
+ const handlePress =
+ (menuItem: typeof noLongerMonitorMenuItem, hideMenu: () => void) =>
+ () => {
+ hideMenu();
+ mockOnMenuItemPress(menuItem);
+ };
+
+ render(
+ {
+ return (
+
+ );
+ },
+ }}
+ />,
+ );
+ });
+
+ it('displays action menu button', () => {
+ expect(screen.getByLabelText(/menu/i)).toBeOnTheScreen();
+ });
+
+ it('displays menu items when user press the action menu button', async () => {
+ setupFakeTimer();
+
+ const user = userEvent.setup();
+
+ expect(
+ screen.queryByText(noLongerMonitorMenuItem.title),
+ ).not.toBeOnTheScreen();
+
+ await user.press(screen.getByLabelText(/menu/i));
+
+ expect(
+ screen.getByText(noLongerMonitorMenuItem.title),
+ ).toBeOnTheScreen();
+ });
+
+ it('retreives menu item data when user press a menu item', async () => {
+ setupFakeTimer();
+
+ const user = userEvent.setup();
+
+ await user.press(screen.getByLabelText(/menu/i));
+
+ expect(mockOnMenuItemPress).not.toHaveBeenCalled();
+
+ await user.press(screen.getByText(noLongerMonitorMenuItem.title));
+
+ expect(mockOnMenuItemPress).toHaveBeenCalledWith(
+ noLongerMonitorMenuItem,
+ );
+ });
+
+ it('hides menu when user press a menu item', async () => {
+ setupFakeTimer();
+
+ const user = userEvent.setup();
+
+ await user.press(screen.getByLabelText(/menu/i));
+
+ expect(
+ screen.getByText(noLongerMonitorMenuItem.title),
+ ).toBeOnTheScreen();
+
+ await user.press(screen.getByText(noLongerMonitorMenuItem.title));
+
+ await waitForElementToBeRemoved(() =>
+ screen.queryByText(noLongerMonitorMenuItem.title),
+ );
+ });
+});
diff --git a/src/__tests__/components/TopAppBarMenuItem.test.tsx b/src/__tests__/components/TopAppBarMenuItem.test.tsx
new file mode 100644
index 00000000..50ded9cf
--- /dev/null
+++ b/src/__tests__/components/TopAppBarMenuItem.test.tsx
@@ -0,0 +1,53 @@
+import React, { ComponentProps } from 'react';
+import {
+ setupFakeTimer,
+ render,
+ screen,
+ userEvent,
+} from '../../shared/testUtils';
+
+import TopAppBarMenuItem from '../../components/topAppBar/TopAppBarMenuItem';
+
+describe('TopAppBarMenuItem mounting', () => {
+ const title = 'Ne plus surveiller';
+ const id = 'noLongerMonitor';
+ const onPress = jest.fn();
+
+ it('displays a menu item', () => {
+ render();
+
+ expect(screen.getByText(title)).toBeOnTheScreen();
+ });
+
+ it('triggers onPress event when user press the menu item', async () => {
+ setupFakeTimer();
+
+ const user = userEvent.setup();
+
+ render();
+
+ await user.press(screen.getByText(title));
+
+ expect(onPress).toHaveBeenCalledTimes(1);
+ });
+});
+
+describe('TopAppBarMenuItem failing to mount', () => {
+ const title = 'Ne plus surveiller';
+ const notExpectedId = '__not_expected_id__' as ComponentProps<
+ typeof TopAppBarMenuItem
+ >['id'];
+ const onPress = jest.fn();
+
+ it('throw an error if menu item id is not handled', () => {
+ expect(() =>
+ render(
+ ,
+ ),
+ ).toThrowError();
+ });
+});
diff --git a/src/components/topAppBar/TopAppBar.tsx b/src/components/topAppBar/TopAppBar.tsx
index bc721019..4cb48a1b 100644
--- a/src/components/topAppBar/TopAppBar.tsx
+++ b/src/components/topAppBar/TopAppBar.tsx
@@ -1,61 +1,45 @@
-import React, { ReactNode } from 'react';
+import React, { ComponentPropsWithoutRef, ReactNode } from 'react';
import { Appbar } from 'react-native-paper';
import { useTheme } from '../../styles/themes';
import { StyleSheet, type ViewStyle } from 'react-native';
import { Headline } from '../typography/Headline';
-import DeviceInfo from "react-native-device-info";
-import type { IconSource } from 'react-native-paper/lib/typescript/components/Icon';
+import DeviceInfo from 'react-native-device-info';
import type { WithTestID } from 'src/shared/type';
-
-interface Icon {
- name: IconSource;
- onPress?: () => void;
-}
+import TopAppBarMenuAction from './TopAppBarMenuAction';
+import { TopAppBarMenuProvider } from './TopAppMenuBarContext';
export interface Title {
value: ReactNode;
onPress?: () => void;
}
-export type Props = WithTestID<{
+export type TopAppBarProps = WithTestID<{
size?: 'small' | 'medium' | 'large' | 'center-aligned';
title: Title;
- icon?: Icon;
onBack?: () => void;
style?: ViewStyle;
+ menu?: {
+ items: ComponentPropsWithoutRef<
+ typeof TopAppBarMenuProvider
+ >['menuItems'];
+ renderItem: ComponentPropsWithoutRef<
+ typeof TopAppBarMenuProvider
+ >['renderMenuItem'];
+ };
}>;
export const TopAppBar = ({
size = 'small',
title,
- icon,
onBack,
style,
testID,
-}: Props) => {
+ menu,
+}: TopAppBarProps) => {
const theme = useTheme();
- const isTablet = DeviceInfo.isTablet();
- const styles = StyleSheet.create({
- button: {
- backgroundColor: 'rgba(145, 158, 171, 0.24)',
- borderRadius: 18,
- marginLeft: isTablet ? 12 : theme.sw.spacing.xs,
- },
- title: {
- paddingTop: size === 'medium' ? 9 : 0,
- paddingBottom: 0,
- justifyContent: 'flex-start',
- },
- header: {
- paddingHorizontal: 12,
- paddingBottom: 0,
- ...style,
- },
- });
- const getIconColor = () => {
- return theme.sw.colors.neutral[600];
- };
+ const styles = useStyles(size, style);
+
return (
- {icon !== undefined && (
-
+ {menu && (
+
+
+
)}
);
};
+
+function useStyles(
+ size: TopAppBarProps['size'],
+ style: TopAppBarProps['style'],
+) {
+ const theme = useTheme();
+ const isTablet = DeviceInfo.isTablet();
+ return StyleSheet.create({
+ button: {
+ backgroundColor: 'rgba(145, 158, 171, 0.24)',
+ borderRadius: 18,
+ marginLeft: isTablet ? 12 : theme.sw.spacing.xs,
+ },
+ title: {
+ paddingTop: size === 'medium' ? 9 : 0,
+ paddingBottom: 0,
+ justifyContent: 'flex-start',
+ },
+ header: {
+ paddingHorizontal: 12,
+ paddingBottom: 0,
+ ...style,
+ },
+ });
+}
diff --git a/src/components/topAppBar/TopAppBarMenuAction.tsx b/src/components/topAppBar/TopAppBarMenuAction.tsx
new file mode 100644
index 00000000..09aad074
--- /dev/null
+++ b/src/components/topAppBar/TopAppBarMenuAction.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { Appbar } from 'react-native-paper';
+import { useTopBarMenu } from './TopAppMenuBarContext';
+import { Theme, useTheme } from '../../styles/themes';
+import DeviceInfo from 'react-native-device-info';
+import { StyleSheet } from 'react-native';
+
+const TopAppBarMenuAction = () => {
+ const { showMenu } = useTopBarMenu();
+
+ const theme = useTheme();
+ const styles = useStyles(theme);
+
+ return (
+
+ );
+};
+
+function useStyles(theme: Theme) {
+ const isTablet = DeviceInfo.isTablet();
+
+ return StyleSheet.create({
+ button: {
+ backgroundColor: 'rgba(145, 158, 171, 0.24)',
+ borderRadius: 18,
+ marginLeft: isTablet ? 12 : theme.sw.spacing.xs,
+ },
+ });
+}
+
+export default TopAppBarMenuAction;
diff --git a/src/components/topAppBar/TopAppBarMenuItem.tsx b/src/components/topAppBar/TopAppBarMenuItem.tsx
new file mode 100644
index 00000000..37c5cedd
--- /dev/null
+++ b/src/components/topAppBar/TopAppBarMenuItem.tsx
@@ -0,0 +1,92 @@
+import React, { ComponentPropsWithoutRef } from 'react';
+import { Menu } from 'react-native-paper';
+import { Theme, useTheme } from '../../styles/themes';
+import { StyleSheet } from 'react-native';
+import { Icon } from '../icons/Icon';
+import { IconName } from '../icons/IconProps';
+
+const topAppBarMenuItemIds = ['noLongerMonitor'] as const;
+type TopAppBarMenuItemId = (typeof topAppBarMenuItemIds)[number];
+
+type TopAppBarMenuItemProps = Required<
+ Pick, 'title' | 'onPress'> & {
+ id: TopAppBarMenuItemId;
+ }
+>;
+const TopAppBarMenuItem = ({ onPress, title, id }: TopAppBarMenuItemProps) => {
+ const swtheme = useTheme();
+ const styles = useStyles(swtheme);
+ const menuItemConfig = getMenuItemConfig(swtheme, id);
+
+ if (!menuItemConfig) {
+ throw new Error(
+ `Can't get MenuItem with the given id : ${id}. \n It must be one of those ids : ${topAppBarMenuItemIds.join(
+ ', ',
+ )}`,
+ );
+ }
+
+ const theme = {
+ colors: {
+ onSurface: menuItemConfig.color,
+ },
+ };
+
+ const leadingIcon = () => (
+
+ );
+
+ return (
+
+ );
+};
+
+function getMenuItemConfig(theme: Theme, id: TopAppBarMenuItemId) {
+ type MenuItemConfig = Record<
+ TopAppBarMenuItemId,
+ {
+ testID: string;
+ iconName: IconName;
+ color: string;
+ }
+ >;
+
+ const menuItemConfig: MenuItemConfig = {
+ noLongerMonitor: {
+ testID: 'topAppBarMenuItem/noLongerMonitor',
+ iconName: 'notifications-off',
+ color: theme.sw.colors.primary.main,
+ },
+ };
+
+ return menuItemConfig[id];
+}
+
+function useStyles(theme: Theme) {
+ return StyleSheet.create({
+ menuItem: {
+ borderRadius: 18,
+ paddingHorizontal: theme.sw.spacing.l,
+ paddingVertical: theme.sw.spacing.m,
+ height: 'auto',
+ },
+ title: {
+ fontSize: 16,
+ fontWeight: '600',
+ },
+ });
+}
+
+export default TopAppBarMenuItem;
diff --git a/src/components/topAppBar/TopAppMenuBarContext.tsx b/src/components/topAppBar/TopAppMenuBarContext.tsx
new file mode 100644
index 00000000..dfd85f85
--- /dev/null
+++ b/src/components/topAppBar/TopAppMenuBarContext.tsx
@@ -0,0 +1,99 @@
+import React, { ComponentProps, ReactNode } from 'react';
+import { StyleSheet, View } from 'react-native';
+import { Menu, Modal, Portal } from 'react-native-paper';
+import { useTheme } from '../../styles/themes';
+import TopAppBarMenuItem from './TopAppBarMenuItem';
+
+type TopAppBarMenuContextValue =
+ | {
+ showMenu: () => void;
+ hideMenu: () => void;
+ }
+ | undefined;
+
+type MenuItemId = ComponentProps['id'];
+
+type MenuItem = Record & {
+ title: string;
+ id: MenuItemId;
+};
+
+const TopAppBarMenuContext =
+ React.createContext(undefined);
+
+type TopAppBarMenuProviderProps = {
+ children: ReactNode;
+ menuItems: MenuItem[];
+ renderMenuItem: (
+ menuItem: MenuItem,
+ { hideMenu }: { hideMenu: () => void },
+ ) => React.ReactElement;
+};
+const TopAppBarMenuProvider: React.FC = ({
+ children,
+ renderMenuItem,
+ menuItems,
+}) => {
+ const [visible, setVisible] = React.useState(false);
+ const showMenu = () => setVisible(true);
+ const hideMenu = () => setVisible(false);
+
+ const styles = useStyles();
+
+ const value = { showMenu, hideMenu };
+
+ return (
+
+
+
+
+ {menuItems.map((item) => {
+ return (
+
+ {renderMenuItem(item, { hideMenu })}
+
+ );
+ })}
+
+
+
+ {children}
+
+ );
+};
+
+function useTopBarMenu() {
+ const context = React.useContext(TopAppBarMenuContext);
+ if (context === undefined) {
+ throw new Error(
+ 'useTopBarMenu must be used within a TopAppBarMenuProvider',
+ );
+ }
+ return context;
+}
+
+function useStyles() {
+ const theme = useTheme();
+ return StyleSheet.create({
+ modal: {
+ alignItems: 'flex-end',
+ justifyContent: 'flex-start',
+ },
+ modalContent: {
+ marginTop: 84,
+ marginRight: theme.sw.spacing.xs,
+ },
+ menu: {
+ backgroundColor: theme.sw.colors.neutral['50'],
+ borderRadius: 18,
+ width: 248,
+ },
+ });
+}
+
+export { TopAppBarMenuProvider, useTopBarMenu };
diff --git a/src/shared/testUtils.tsx b/src/shared/testUtils.tsx
index 92e79d4a..23434fab 100644
--- a/src/shared/testUtils.tsx
+++ b/src/shared/testUtils.tsx
@@ -1,6 +1,7 @@
import React, { ReactElement } from 'react';
import {
RenderOptions,
+ act,
render as rtlRender,
} from '@testing-library/react-native';
import { ThemeProvider } from '../styles/themes'; // Replace with the actual path to your ThemeProvider
@@ -13,5 +14,13 @@ const uiRender = (ui: ReactElement, options?: RenderOptions) => {
return rtlRender(ui, { wrapper: Wrapper, ...options });
};
+const setupFakeTimer = () => {
+ jest.useFakeTimers();
+
+ act(() => {
+ jest.runAllTimers();
+ });
+};
+
export * from '@testing-library/react-native';
-export { uiRender as render };
+export { uiRender as render, setupFakeTimer };
diff --git a/tsconfig.json b/tsconfig.json
index 69d3cbc8..e4e8b67b 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,31 +1,31 @@
{
- "compilerOptions": {
- "baseUrl": "./",
- "paths": {
- "smartway-react-native-ui": ["./src/index"]
+ "compilerOptions": {
+ "baseUrl": "./",
+ "paths": {
+ "smartway-react-native-ui": ["./src/index"]
+ },
+ "allowUnreachableCode": false,
+ "allowUnusedLabels": false,
+ "declaration": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "jsx": "react",
+ "lib": ["esnext"],
+ "module": "esnext",
+ "moduleResolution": "node",
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitReturns": true,
+ "noImplicitUseStrict": false,
+ "noStrictGenericChecks": false,
+ "noUncheckedIndexedAccess": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "outDir": "lib",
+ "resolveJsonModule": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "target": "esnext"
},
- "allowUnreachableCode": false,
- "allowUnusedLabels": false,
- "declaration": true,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "jsx": "react",
- "lib": ["esnext"],
- "module": "esnext",
- "moduleResolution": "node",
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "noImplicitUseStrict": false,
- "noStrictGenericChecks": false,
- "noUncheckedIndexedAccess": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "outDir": "lib",
- "resolveJsonModule": true,
- "skipLibCheck": true,
- "strict": true,
- "target": "esnext"
- },
- "include": ["src", "./.eslintrc.json", "./modules.d.ts", "./jest.setup.ts"],
- "exclude": ["src/components/charts/*"]
+ "include": ["src", "./.eslintrc.json", "./modules.d.ts", "./jest.setup.ts"],
+ "exclude": ["src/components/charts/*"]
}