diff --git a/example/src/TapRatingScreen.tsx b/example/src/TapRatingScreen.tsx index 7b7082b..8f08d0f 100644 --- a/example/src/TapRatingScreen.tsx +++ b/example/src/TapRatingScreen.tsx @@ -51,6 +51,7 @@ class TapRatingScreen extends Component { diff --git a/package.json b/package.json index 5a6e6e0..0a24c40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rn-vui/ratings", - "version": "0.4.2", + "version": "0.4.3", "description": "..", "source": "./src/index.tsx", "main": "./lib/module/index.js", @@ -71,6 +71,7 @@ "@react-native/babel-preset": "0.78.2", "@react-native/eslint-config": "^0.78.0", "@release-it/conventional-changelog": "^9.0.2", + "@testing-library/react-native": "^13.2.0", "@types/jest": "^29.5.5", "@types/react": "^19.0.12", "commitlint": "^19.6.1", @@ -84,6 +85,7 @@ "react-dom": "19.0.0", "react-native": "0.79.1", "react-native-builder-bob": "^0.40.7", + "react-test-renderer": "19.0.0", "release-it": "^17.10.0", "typescript": "^5.2.2" }, @@ -140,7 +142,7 @@ [ "module", { - "esm": true + "esm": false } ], [ diff --git a/src/SwipeRating.tsx b/src/SwipeRating.tsx index 0377d0a..12ff1c9 100644 --- a/src/SwipeRating.tsx +++ b/src/SwipeRating.tsx @@ -123,12 +123,12 @@ export type SwipeRatingProps = { /** * Callback method when the user starts rating. */ - onStartRating?: Function; + onStartRating?: (value: number) => void; /** * Callback method when the user finishes rating. Gives you the final rating value as a whole number */ - onFinishRating?: Function; + onFinishRating?: (value: number) => void; /** * Displays the Built-in Rating UI to show the rating value in real-time @@ -404,9 +404,10 @@ const SwipeRating: React.FC = ({ const renderRatings = React.useMemo(() => { const source = TYPES[type]?.source; return Array.from({ length: ratingCount }, (_, index) => ( - + = ({ }, [ratingCount, imageSize, ratingColor, type]); return ( - + {showRating && ( - + Rating:{' '} @@ -443,7 +451,11 @@ const SwipeRating: React.FC = ({ )} - + { diff --git a/src/TapRating.tsx b/src/TapRating.tsx index d821c03..db2df28 100644 --- a/src/TapRating.tsx +++ b/src/TapRating.tsx @@ -43,7 +43,7 @@ export type TapRatingProps = { reviewColor?: string; /** - * Size value for review. + * Size value for review text. * * @default 40 */ @@ -120,6 +120,7 @@ const TapRating: React.FunctionComponent = ({ showRating = true, reviewColor = 'rgba(230, 196, 46, 1)', reviewSize = 25, + size: reviewImageSize = 40, defaultRating = 3, starContainerStyle, ratingContainerStyle, @@ -163,7 +164,7 @@ const TapRating: React.FunctionComponent = ({ isDisabled={isDisabled} selectedColor={selectedColor} unSelectedColor={unSelectedColor} - size={reviewSize} + size={reviewImageSize} starImage={starImage} starStyle={starStyle} /> @@ -173,19 +174,22 @@ const TapRating: React.FunctionComponent = ({ return ( {showRating && ( {reviews[position - 1]} )} {renderStars(rating_array)} diff --git a/src/__tests__/SwipeRating.test.tsx b/src/__tests__/SwipeRating.test.tsx new file mode 100644 index 0000000..170da3c --- /dev/null +++ b/src/__tests__/SwipeRating.test.tsx @@ -0,0 +1,88 @@ +import { render } from '@testing-library/react-native'; +import SwipeRating from '../SwipeRating'; + +describe('SwipeRating', () => { + it('should export SwipeRating', () => { + const SwipeRatingLocal = require('../SwipeRating'); + expect(SwipeRatingLocal).toBeDefined(); + }); + + it('should match snapshot', () => { + const { toJSON } = render(); //to ensure default props are not changed + expect(toJSON()).toMatchSnapshot(); + }); + + it('should render with custom props', () => { + const ratingsCount = 9; + + const { getAllByTestId } = render( + + ); + const stars = getAllByTestId('RNVUI__Star'); + expect(stars).toHaveLength(ratingsCount); + }); + + it('should render with different type', () => { + const heartImage = require('../images/heart.png'); + const { getAllByTestId } = render(); + const swipeRatings = getAllByTestId('RNVUI__Star-image'); + + swipeRatings.forEach((swipeRating) => { + expect(swipeRating.props.source).toEqual(heartImage); // Check if the image source is the heart image + }); + }); + + // it('should render with custom image', () => { + // const customImage = require('../images/bell.png'); + // const { getAllByTestId } = render( + // + // ); + // const swipeRatings = getAllByTestId('RNVUI__Star-image'); + + // swipeRatings.forEach((swipeRating) => { + // expect(swipeRating.props.source).toEqual(customImage); // Check if the image source is the custom image + // }); + // }); + + it('should render with custom star color', () => { + const customStarColor = 'red'; + const { getAllByTestId } = render( + + ); + const stars = getAllByTestId('RNVUI__Star-image'); + stars.forEach((star) => { + expect(star.props.style.tintColor).toBe(customStarColor); + }); + }); + + it('should render with custom star size', () => { + const customStarSize = 50; + const { getAllByTestId } = render( + + ); + const stars = getAllByTestId('RNVUI__Star-image'); + stars.forEach((star) => { + expect(star.props.style.width).toBe(customStarSize); + expect(star.props.style.height).toBe(customStarSize); + }); + }); + + it('should show the correct number of stars', () => { + const ratingsCount = 5; + const { getAllByTestId } = render( + + ); + const stars = getAllByTestId('RNVUI__Star'); + expect(stars).toHaveLength(ratingsCount); + }); + + //show rating should show the text + it('should show the correct rating text', () => { + const ratingsCount = 5; + const { getByTestId } = render( + + ); + const ratingText = getByTestId('RNVUI__SwipeRating-showRating'); + expect(ratingText).toBeTruthy(); + }); +}); diff --git a/src/__tests__/TapRating.test.tsx b/src/__tests__/TapRating.test.tsx new file mode 100644 index 0000000..f24a9c5 --- /dev/null +++ b/src/__tests__/TapRating.test.tsx @@ -0,0 +1,154 @@ +import { fireEvent, render } from '@testing-library/react-native'; +import TapRating from '../TapRating'; + +describe('TapRating Aka AirbnbRating', () => { + it('should export SwipeRating', () => { + const TapRatingLocal = require('../TapRating'); + expect(TapRatingLocal).toBeDefined(); + }); + + it('should match snapshot', () => { + const { toJSON } = render(); //to ensure default props are not changed + expect(toJSON()).toMatchSnapshot(); + }); + + it('show rating true should show rating', () => { + const { getByTestId } = render(); + const ratingText = getByTestId('RNVUI__TapRating-showRating'); + expect(ratingText).toBeOnTheScreen(); + }); + + it('number of stars should match count prop', () => { + const { getAllByTestId } = render(); + const ratingStar = getAllByTestId('RNVUI__Star'); + expect(ratingStar).toHaveLength(4); + }); + + it('should show reviews', () => { + const defaultRating = 1; + const ratingReviews = ['Terrible', 'Bad', 'Okay', 'Good', 'Great']; + + const { getByTestId } = render( + + ); + const ratingText = getByTestId('RNVUI__TapRating-showRating'); + expect(ratingText).toBeOnTheScreen(); + expect(ratingText).toHaveTextContent( + ratingReviews[defaultRating - 1] || '' + ); + }); + + it('review size should match reviewSize prop', () => { + const reviewSize = 32; + const { getByTestId } = render(); + const ratingText = getByTestId('RNVUI__TapRating-showRating'); + expect(ratingText.props.style.fontSize).toBe(reviewSize); + }); + + it('rating image size should should match image size', () => { + const imageSize = 32; + const { getAllByTestId } = render(); + const ratingStars = getAllByTestId('RNVUI__Star-image'); + ratingStars.forEach((star) => { + expect(star.props.style.width).toBe(imageSize); + expect(star.props.style.height).toBe(imageSize); + }); + }); + + it('should call onFinishRating with the correct rating when rating is selected', () => { + const pressableRating = 2; + const onFinishRating = jest.fn(); + const { getAllByTestId } = render( + + ); + const ratingStars = getAllByTestId('RNVUI__Star'); + fireEvent.press(ratingStars[pressableRating - 1]); + expect(onFinishRating).toHaveBeenCalledWith(pressableRating); + }); + + it('should not call onFinishRating when isDisabled is true', () => { + const onFinishRating = jest.fn(); + const { getAllByTestId } = render( + + ); + const ratingStars = getAllByTestId('RNVUI__Star'); + fireEvent.press(ratingStars[0]); + expect(onFinishRating).not.toHaveBeenCalled(); + }); + + //image test + it('should use custom star image', () => { + const customStarImage = require('../images/bell.png'); + const { getAllByTestId } = render( + + ); + const ratingStars = getAllByTestId('RNVUI__Star-image'); + ratingStars.forEach((star) => { + expect(star.props.source).toEqual(customStarImage); + }); + }); + + it('selected color should match selectedColor prop', () => { + const selectedColor = 'red'; + const { getAllByTestId } = render( + + ); + const ratingStars = getAllByTestId('RNVUI__Star-image'); + ratingStars.forEach((star) => { + expect(star.props.style.tintColor).toBe(selectedColor); + }); + }); + + it('unselected color should match unSelectedColor prop', () => { + const unSelectedColor = 'blue'; + const { getAllByTestId } = render( + + ); + const ratingStars = getAllByTestId('RNVUI__Star-image'); + ratingStars.forEach((star) => { + expect(star.props.style.tintColor).toBe(unSelectedColor); + }); + }); + it('should apply custom star style', () => { + const customStarStyle = { backgroundColor: '#aabbcc' }; + const { getAllByTestId } = render( + + ); + const ratingStars = getAllByTestId('RNVUI__Star-image'); + ratingStars.forEach((star) => { + expect(star.props.style.backgroundColor).toEqual( + customStarStyle.backgroundColor + ); + }); + }); + + it('should apply custom rating container style', () => { + const customContainerStyle = { backgroundColor: '#aabbcc' }; + const { getByTestId } = render( + + ); + const ratingContainer = getByTestId('RNVUI__TapRating'); + expect(ratingContainer.props.style.backgroundColor).toEqual( + customContainerStyle.backgroundColor + ); + }); + + it('should apply custom star container style', () => { + const customStarContainerStyle = { backgroundColor: '#aabbcc' }; + const { getByTestId } = render( + + ); + const ratingContainer = getByTestId('RNVUI__TapRating-starContainer'); + expect(ratingContainer.props.style.backgroundColor).toEqual( + customStarContainerStyle.backgroundColor + ); + }); +}); diff --git a/src/__tests__/__snapshots__/SwipeRating.test.tsx.snap b/src/__tests__/__snapshots__/SwipeRating.test.tsx.snap new file mode 100644 index 0000000..55cbd1a --- /dev/null +++ b/src/__tests__/__snapshots__/SwipeRating.test.tsx.snap @@ -0,0 +1,198 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SwipeRating should match snapshot 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + +`; diff --git a/src/__tests__/__snapshots__/TapRating.test.tsx.snap b/src/__tests__/__snapshots__/TapRating.test.tsx.snap new file mode 100644 index 0000000..1c3e836 --- /dev/null +++ b/src/__tests__/__snapshots__/TapRating.test.tsx.snap @@ -0,0 +1,330 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TapRating Aka AirbnbRating should match snapshot 1`] = ` + + + Okay + + + + + + + + + + + + + + + + + + + +`; diff --git a/src/__tests__/index.test.tsx b/src/__tests__/index.test.tsx index bf84291..3b06bc9 100644 --- a/src/__tests__/index.test.tsx +++ b/src/__tests__/index.test.tsx @@ -1 +1,7 @@ -it.todo('write a test'); +describe('index', () => { + it('should export Rating and AirbnbRating', () => { + const { Rating, AirbnbRating } = require('../index'); + expect(Rating).toBeDefined(); + expect(AirbnbRating).toBeDefined(); + }); +}); diff --git a/src/components/Star.tsx b/src/components/Star.tsx index 792c2f7..eed8e92 100644 --- a/src/components/Star.tsx +++ b/src/components/Star.tsx @@ -55,9 +55,15 @@ const Star: React.FunctionComponent = ({ fill && selectedColor === null ? STAR_SELECTED_IMAGE : starImage; return ( - + =29.0.0" + react: ">=18.2.0" + react-native: ">=0.71" + react-test-renderer: ">=18.2.0" + peerDependenciesMeta: + jest: + optional: true + checksum: fa2f59353b27a5afea72c04296e94e597b7e20f09f7e69d5dd1693da15bdeabfdd1ba655b1e194dbf5727b9dfa92de5af06ec77484b3392aab96dab4f7c05e44 + languageName: node + linkType: hard + "@tootallnate/quickjs-emscripten@npm:^0.23.0": version: 0.23.0 resolution: "@tootallnate/quickjs-emscripten@npm:0.23.0" @@ -10088,7 +10110,7 @@ __metadata: languageName: node linkType: hard -"min-indent@npm:^1.0.1": +"min-indent@npm:^1.0.0, min-indent@npm:^1.0.1": version: 1.0.1 resolution: "min-indent@npm:1.0.1" checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 @@ -11446,6 +11468,13 @@ __metadata: languageName: node linkType: hard +"react-is@npm:^19.0.0": + version: 19.1.0 + resolution: "react-is@npm:19.1.0" + checksum: 3eb4eac7f09bf178bdc6fa98d384f5f243b85de7c99679a88b0154ead4d818ad94386ccb00ea31ec52409ffd13299057f5ec6ca2eaec06f9f7eddc1ad4832332 + languageName: node + linkType: hard + "react-native-builder-bob@npm:^0.40.7": version: 0.40.7 resolution: "react-native-builder-bob@npm:0.40.7" @@ -11596,6 +11625,18 @@ __metadata: languageName: node linkType: hard +"react-test-renderer@npm:19.0.0": + version: 19.0.0 + resolution: "react-test-renderer@npm:19.0.0" + dependencies: + react-is: ^19.0.0 + scheduler: ^0.25.0 + peerDependencies: + react: ^19.0.0 + checksum: 2e1e527588c69e822b7aa25262c9f4a48161ede9cee5109b88228ecafbd91ce82f7afed176645efcba903ba5a43d05842a8229cdde220049e42a0cf679715dbc + languageName: node + linkType: hard + "react@npm:19.0.0": version: 19.0.0 resolution: "react@npm:19.0.0" @@ -11698,6 +11739,16 @@ __metadata: languageName: node linkType: hard +"redent@npm:^3.0.0": + version: 3.0.0 + resolution: "redent@npm:3.0.0" + dependencies: + indent-string: ^4.0.0 + strip-indent: ^3.0.0 + checksum: fa1ef20404a2d399235e83cc80bd55a956642e37dd197b4b612ba7327bf87fa32745aeb4a1634b2bab25467164ab4ed9c15be2c307923dd08b0fe7c52431ae6b + languageName: node + linkType: hard + "redent@npm:^4.0.0": version: 4.0.0 resolution: "redent@npm:4.0.0" @@ -12842,6 +12893,15 @@ __metadata: languageName: node linkType: hard +"strip-indent@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-indent@npm:3.0.0" + dependencies: + min-indent: ^1.0.0 + checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530 + languageName: node + linkType: hard + "strip-indent@npm:^4.0.0": version: 4.0.0 resolution: "strip-indent@npm:4.0.0"