Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: refactored code to use custom hooks #86

Merged
merged 13 commits into from
Oct 4, 2024
13 changes: 13 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: 'coverage'
on:
pull_request:
branches: [ "main" ]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ArtiomTr/jest-coverage-report-action@v2
with:
package-manager: yarn
test-script: npm test
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,7 @@ android/keystores/debug.keystore
lib/

# npm
.npmrc
.npmrc

# coverage
coverage
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ For more examples visit our [wiki page](https://github.com/azeezat/react-native-
| listControls | `Object` | `{ selectAllText: 'Choose all', unselectAllText: 'Remove all', selectAllCallback: () => {}, unselectAllCallback: () => {}, hideSelectAll: boolean, emptyListMessage: 'No record found'}` |
| searchControls | `Object` | `{ textInputStyle: ViewStyle \| TextStyle, textInputContainerStyle: ViewStyle, textInputProps: TextInputProps, searchCallback:(value)=>{}}` |
| modalControls | `Object` | `{ modalBackgroundStyle: ViewStyle, modalOptionsContainerStyle: ViewStyle, modalProps: ModalProps}` |
| maxSelectableItems | `number` | 5 |


## Deprecation Notice

Expand Down
19 changes: 12 additions & 7 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
overrides: [{
"plugins": [
["@babel/plugin-transform-private-methods", {
"loose": true
}]
]
}]
overrides: [
{
plugins: [
[
'@babel/plugin-transform-private-methods',
{
loose: true,
},
],
],
},
],
};
2 changes: 1 addition & 1 deletion example/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
root: true,
extends: ['@react-native', "@babel/plugin-transform-private-property-in-object"],
extends: ['@react-native'],
};
57 changes: 51 additions & 6 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {countries} from './data';
export default function App() {
const [user, setUser] = useState<string>('');
const [country, setCountry] = useState<any>('');
const [gender, setGender] = useState<number>();
const [gender, setGender] = useState<number>(0);
const [currency, setCurrency] = useState<string[]>([]);
const [meals, setMeals] = useState<string[]>([]);
const [item, setItem] = useState<any>('');
Expand Down Expand Up @@ -45,6 +45,7 @@ export default function App() {
<ScrollView>
<View style={styles.container}>
<DropdownSelect
selectedValue=""
label="Currency"
placeholder="Empty State"
options={[]}
Expand Down Expand Up @@ -72,8 +73,36 @@ export default function App() {
label="Gender"
placeholder="Select an option..."
options={[
{name: 'Male', id: '1'},
{name: 'Female', id: '2'},
{
name: (
<View style={styles.itemStyle}>
<Image
style={styles.avatarStyle}
source={{
uri: 'https://avatar.iran.liara.run/username?username=Azeezat+Raheem',
}}
/>

<Text>Male</Text>
</View>
),
id: 1,
},
{
name: (
<View style={styles.itemStyle}>
<Image
style={styles.avatarStyle}
source={{
uri: 'https://avatar.iran.liara.run/public/boy?username=Ash',
}}
/>

<Text>Female</Text>
</View>
),
id: 2,
},
]}
optionLabel={'name'}
optionValue={'id'}
Expand Down Expand Up @@ -143,15 +172,20 @@ export default function App() {
label="Meal preferences"
placeholder="Select your meal preferences"
options={[
{name: '🍛 Rice', value: '1', disabled: true},
{name: '🍛 Rice', value: '1', disabled: false},
{name: '🍗 Chicken', value: '2'},
{name: '🥦 Brocoli', value: '3', disabled: true},
{name: '🥦 Brocoli', value: '3', disabled: false},
{name: '🍕 Pizza', value: '4'},
]}
maxSelectableItems={2}
optionLabel={'name'}
optionValue={'value'}
selectedValue={meals}
onValueChange={(itemValue: any) => setMeals(itemValue)}
onValueChange={(itemValue: any) => {
meals.length === 2 && console.log('You can only select 2 meals');

setMeals(itemValue);
}}
dropdownStyle={{
backgroundColor: 'yellow',
paddingVertical: 5,
Expand Down Expand Up @@ -467,4 +501,15 @@ const styles = StyleSheet.create({
borderWidth: 3,
borderColor: 'white',
},
avatarStyle: {
height: 20,
width: 20,
borderRadius: 20,
marginRight: 5,
},
itemStyle: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
});
2 changes: 1 addition & 1 deletion jest-setup.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import '@testing-library/react-native/extend-expect';
import '@testing-library/react-native/extend-expect';
26 changes: 20 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@
"@types/react": "18.3.2",
"@types/react-native": "^0.73.0",
"commitlint": "^19.3.0",
"eslint": "^9.2.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint": "^7.2.0",
"eslint-config-prettier": "^7.0.0",
"eslint-plugin-prettier": "^3.1.3",
"husky": "^9.0.11",
"jest": "^29.7.0",
"metro-react-native-babel-preset": "^0.77.0",
"pod-install": "^0.2.2",
"prettier": "^3.2.5",
"prettier": "^2.0.5",
"react": "^18.3.1",
"react-native": "^0.74.1",
"react-native-builder-bob": "^0.23.2",
Expand All @@ -92,7 +92,19 @@
"modulePathIgnorePatterns": [
"<rootDir>/example/node_modules",
"<rootDir>/lib/"
]
],
"coverageReporters": [
"html",
"text"
],
"coverageThreshold": {
"global": {
"branches": 75,
"functions": 75,
"lines": 75,
"statements": 75
}
}
},
"commitlint": {
"extends": [
Expand Down Expand Up @@ -120,7 +132,9 @@
},
"eslintIgnore": [
"node_modules/",
"lib/"
"lib/",
"coverage/",
"src/__tests__/**"
],
"prettier": {
"quoteProps": "consistent",
Expand Down
75 changes: 69 additions & 6 deletions src/__tests__/empty-dropdown.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,92 @@ describe('Initial state of component', () => {
afterAll(() => {
jest.useRealTimers();
});

// TODO: test these mocks once you are able to simulate specific device types like android and iOS
const mockOpenModal = jest.fn();
const mockCloseModal = jest.fn();

const testId = 'some-random-test-id';
const placeholder = 'Select an option';
const error = 'This is an error';
const helperText = 'This is an helper text';

const defaultDropdown = (
<DropdownSelect options={[]} onValueChange={() => {}} testID='some-random-test-id' />
<DropdownSelect
label="Default dropdown"
selectedValue={''}
options={[]}
onValueChange={() => {}}
testID={testId}
modalControls={{
modalProps: {
onShow: mockOpenModal,
onDismiss: mockCloseModal,
},
}}
error={error}
/>
);

test('show default texts', () => {
render(defaultDropdown);
expect(screen.getByTestId('some-random-test-id'));
expect(screen.getByText('Select an option'));
const entireDropdown = screen.getByTestId(testId);
expect(entireDropdown);
expect(screen.getByText(placeholder));
expect(screen.getByText(error));
});

test('show default styles', () => {
render(defaultDropdown);
const placeholderStyle = screen.getByText('Select an option');
const placeholderStyle = screen.getByText(placeholder);
expect(placeholderStyle.props.style).toMatchObject([
{ color: '#000000' },
undefined,
]);
});

test('open modal when dropdown is clicked', async () => {
test('open and close modal', async () => {
const user = userEvent.setup();
render(defaultDropdown);
await user.press(screen.getByText('Select an option'));

//open modal when dropdown is clicked
await user.press(screen.getByText(placeholder));
expect(screen.getByText('No options available'));

// close the modal after opening
const closeModal = screen.getByLabelText('close modal');
await user.press(closeModal);
expect(screen.getByText(placeholder));
});

const disabledDropdown = (
<DropdownSelect
selectedValue={''}
options={[]}
onValueChange={() => {}}
modalControls={{
modalProps: {
onShow: mockOpenModal,
onDismiss: mockCloseModal,
},
}}
disabled
helperText={helperText}
/>
);

test('helper text', async () => {
render(disabledDropdown);
expect(screen.getByText(helperText));
});

test('Disabled dropdown should not be clickable', async () => {
const user = userEvent.setup();
render(disabledDropdown);

let dropdownInput = screen.getByTestId('dropdown-input-container');
await user.press(dropdownInput);

expect(dropdownInput.props?.accessibilityState?.disabled).toBe(true);
});
});
Loading
Loading