Skip to content

Commit

Permalink
Merge pull request #193 from ZeroGachis/task/rew-287-modifier-la-topa…
Browse files Browse the repository at this point in the history
…ppbar-pour-integrer-un-sous-menu

✨ TopAppBarMenu - add custom menu
  • Loading branch information
AdrienCasta authored Feb 29, 2024
2 parents cd51b8f + 1ded399 commit 4c780f9
Show file tree
Hide file tree
Showing 13 changed files with 468 additions and 104 deletions.
85 changes: 78 additions & 7 deletions Storybook/components/TopAppBar/TopAppBar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
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 type { Title } from 'src/components/topAppBar/TopAppBar';
import { TopAppBar, Title } from '../../../src/components/topAppBar/TopAppBar';
import { Headline } from '../../../src/components/typography/Headline';

const asString = { value: 'menu' };
const asButton = { value: 'menu', onPress: () => {} };
const asComponent = { value: <Headline size="h1">Headline H1</Headline> };
const asButton = {
value: 'menu',
onPress: () => {},
};
const asComponent = { value: <Headline size='h1'>Headline H1</Headline> };

type ComponentProps = React.ComponentProps<typeof TopAppBar> & {
withBackButton?: boolean;
Expand All @@ -28,12 +31,15 @@ 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: [
(Story) => {
const styles = StyleSheet.create({
Expand All @@ -60,9 +66,74 @@ export const Default: Story = {
size={args.size}
onBack={args.withBackButton ? args.onBack : undefined}
title={titleComponent}
icon={{ name: 'dots-vertical', onPress: args.onPressIcon }}
/>
);
},
};
export const WithMenuAction = (args) => {
let titleComponent: Title = asString;
if (args.withTitleAs === 'button') titleComponent = asButton;
if (args.withTitleAs === 'component') titleComponent = asComponent;

return (
<TopAppBar
size={args.size}
onBack={args.withBackButton ? args.onBack : undefined}
title={titleComponent}
action={
<TopAppBar.Menu>
<TopAppBar.MenuItem
iconName='notifications-off'
title='Ne plus surveiller'
onPress={() =>
args.onMenuItemPress('Ne plus surveiller')
}
/>
</TopAppBar.Menu>
}
/>
);
};
export const WithCloseAction = (args) => {
let titleComponent: Title = asString;
if (args.withTitleAs === 'button') titleComponent = asButton;
if (args.withTitleAs === 'component') titleComponent = asComponent;

return (
<TopAppBar
size={args.size}
onBack={args.withBackButton ? args.onBack : undefined}
title={titleComponent}
action={
<TopAppBar.Action
icon='close'
accessibilityLabel='Close'
onPress={args.onPressIcon}
/>
}
/>
);
};

export const WithPrinterSettingsAction = (args) => {
let titleComponent: Title = asString;
if (args.withTitleAs === 'button') titleComponent = asButton;
if (args.withTitleAs === 'component') titleComponent = asComponent;

return (
<TopAppBar
size={args.size}
onBack={args.withBackButton ? args.onBack : undefined}
title={titleComponent}
action={
<TopAppBar.Action
icon='cog'
accessibilityLabel='Settings'
onPress={args.onPressIcon}
/>
}
/>
);
};

Default.parameters = { noSafeArea: false };
8 changes: 4 additions & 4 deletions Storybook/package-lock.json

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

2 changes: 1 addition & 1 deletion Storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
133 changes: 133 additions & 0 deletions src/__tests__/components/TopAppBar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React from 'react';
import { TopAppBar } from '../../components/topAppBar/TopAppBar';
import {
cleanUpFakeTimer,
render,
screen,
setupFakeTimer,
userEvent,
waitForElementToBeRemoved,
} from '../../shared/testUtils';
import { Text } from 'react-native';
import { IconName } from '../../components/icons/IconProps';
import TopAppBarMenuItem from '../../components/topAppBar/Menu/TopAppBarMenuItem';

const topBarTitle = 'Menu';

describe('TopAppBar mounting with a simple title', () => {
it('displays a title', () => {
const title = {
value: topBarTitle,
};

render(<TopAppBar title={title} />);

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: <Text>{topBarTitle}</Text>,
};

render(<TopAppBar title={title} />);

expect(screen.getByText(topBarTitle)).toBeOnTheScreen();
});

it.todo("testing menu title 'as component' on press");
});

describe('TopAppBar mounting with a go back button', () => {
beforeEach(() => setupFakeTimer());
afterEach(() => cleanUpFakeTimer());
it('triggers `goBack` event when user press the go back button', async () => {
const user = userEvent.setup();

const mockOnGoBack = jest.fn();

const title = {
value: topBarTitle,
};

render(<TopAppBar title={title} onBack={mockOnGoBack} />);

expect(mockOnGoBack).not.toHaveBeenCalled();

await user.press(screen.getByLabelText(/back/i));

expect(mockOnGoBack).toHaveBeenCalledTimes(1);
});
});

describe('TopAppBar mounting with a menu', () => {
const menuIconName = 'notifications-off' as const satisfies IconName;
const menuTitle = 'Ne plus surveiller';
const title = {
value: topBarTitle,
};
let mockOnMenuItemPress: jest.Mock;

beforeEach(() => {
setupFakeTimer();
mockOnMenuItemPress = jest.fn();

render(
<TopAppBar
title={title}
action={
<TopAppBar.Menu>
<TopAppBarMenuItem
iconName={menuIconName}
title={menuTitle}
onPress={mockOnMenuItemPress}
/>
</TopAppBar.Menu>
}
/>,
);
});
afterEach(() => cleanUpFakeTimer());

it('displays action menu button', () => {
expect(screen.getByLabelText(/menu/i)).toBeOnTheScreen();
});

it('displays menu items when user press the action menu button', async () => {
const user = userEvent.setup();

expect(screen.queryByText(menuTitle)).not.toBeOnTheScreen();

await user.press(screen.getByLabelText(/menu/i));

expect(screen.getByText(menuTitle)).toBeOnTheScreen();
});

it('retrieves menu item data when user press a menu item', async () => {
const user = userEvent.setup();

await user.press(screen.getByLabelText(/menu/i));

expect(mockOnMenuItemPress).not.toHaveBeenCalled();

await user.press(screen.getByText(menuTitle));

expect(mockOnMenuItemPress).toHaveBeenCalledTimes(1);
});

it('hides menu when user press a menu item', async () => {
const user = userEvent.setup();

await user.press(screen.getByLabelText(/menu/i));

expect(screen.getByText(menuTitle)).toBeOnTheScreen();

await user.press(screen.getByText(menuTitle));

await waitForElementToBeRemoved(() => screen.queryByText(menuTitle));
});
});
Loading

0 comments on commit 4c780f9

Please sign in to comment.