Skip to content

Commit

Permalink
test: (RewardTile) Add new test for reward tile and refactor elements…
Browse files Browse the repository at this point in the history
… from failing tests
  • Loading branch information
iamgraeme committed Jan 26, 2025
1 parent 3466a9d commit bcf11e6
Show file tree
Hide file tree
Showing 12 changed files with 440 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/// <reference types="@testing-library/jest-dom" />

import React from 'react';
import { PointsTile } from '..';
import { Tile, TileHeight, TileType } from '../../../../types/tile';
import { render } from '../../../__test__/test-utils';
import { Tile, TileHeight, TileType } from '../../../types/tile';
import { render } from '../../__test__/test-utils';
import { PointsTile } from './index';

const tileMock: Tile = {
id: '1',
Expand All @@ -22,7 +22,7 @@ const tileMock: Tile = {
},
};

describe('PointsTile', () => {
describe('<PointsTile />', () => {
it('renders and matches snapshot', () => {
const { container } = render(<PointsTile tile={tileMock} />);
expect(container).toMatchSnapshot();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`PointsTile renders and matches snapshot 1`] = `
exports[`<PointsTile /> renders and matches snapshot 1`] = `
<div>
<button
aria-disabled="true"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { View } from 'react-native';
import { PointsTileConfig } from '../../../types/tile';
import { calculatePoints } from '../../../utils/pointsHelpers';
import { applyMultiplier } from '../../../utils/pointsHelpers';
import { Text } from '../../atoms';
import { useTileContext } from '../../atoms/BaseTile';
import { Row } from '../../atoms/Primatives';
Expand All @@ -24,7 +24,7 @@ export const PointsTileFormattedPoints = (): JSX.Element | null => {
} = configuration as PointsTileConfig;

if (points === undefined) return null;
const calculatedPoints = calculatePoints(points, pointsMultiplier);
const calculatedPoints = applyMultiplier(points, pointsMultiplier);
const fullPointsText = `${pointsPrefix}${calculatedPoints} ${pointsSuffix}`;

return (
Expand Down
188 changes: 188 additions & 0 deletions lib/components/organisms/RewardTile/RewardTile.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import React from 'react';
import { Tile, TileHeight, TileType } from '../../../types/tile';
import { render } from '../../__test__/test-utils';
import { RewardTile } from './index';

const RewardTileMock: Tile = {
tileHeight: TileHeight.Full,
active: true,
type: TileType.Reward,
configuration: {
rewardId: 'f7ce508f-ca52-46ff-bfb7-03e3761feb4a',
showArtwork: true,
showDetails: true,
showPrice: true,
name: 'Sweet Chilli Lobster Noodles',
summary: 'Fresh Lobster Noodles with a spicy chilli sauce',
id: 'f7ce508f-ca52-46ff-bfb7-03e3761feb4a',
createdAt: '2023-05-05T15:11:42.342Z',
updatedAt: '2024-07-17T10:45:04.350Z',
pictureUrl: 'https://ucarecdn.com/a486d015-b4ab-4831-bfa5-68f5bbbf63b1/',
value: 800,
price: 10,
pointsPrefix: '',
pointsSuffix: '',
priority: 10,
availability: {
start: '2023-05-05T15:10:31.274Z',
end: '',
},
purchasable: true,
tier: null,
category: {
name: 'Chicken Salad',
priority: 0,
type: 'REWARD',
id: '677b6b88-d97c-4b8d-80f4-88b04c86948f',
createdAt: '2023-05-05T10:39:57.595Z',
updatedAt: '2023-05-05T10:39:57.595Z',
description: null,
metadata: null,
pictureUrl: 'https://ucarecdn.com/9cda5d3c-75f4-48f0-9f3f-1ece144f6136/',
},
discounts: [],
redemptionMessage: null,
visibilityCriteria: null,
type: 'VOUCHER',
codeType: 'HUMAN',
code: null,
purchaseExpiration: null,
hideCode: false,
notificationConfig: null,
artworkUrl: 'https://ucarecdn.com/a486d015-b4ab-4831-bfa5-68f5bbbf63b1/',
pointsMultiplier: '1',
},
id: '39ac25f0-35b3-4668-acba-032dccc63e91',
createdAt: '2024-10-17T10:50:12.673Z',
updatedAt: '2024-10-17T10:50:12.673Z',
priority: 3,
};

describe('<RewardTile />', () => {
it('renders and matches snapshot', () => {
const { container } = render(<RewardTile tile={RewardTileMock} />);
expect(container).toMatchSnapshot();
});
});

describe('<RewardTile /> Rendering States', () => {
it('returns null when tile prop is not provided', () => {
const { container } = render(<RewardTile tile={undefined} />);
expect(container.firstChild).toBeNull();
});

describe('Size-based rendering', () => {
it('renders correctly in full size mode', () => {
const { getByTestId, getAllByTestId } = render(
<RewardTile tile={RewardTileMock} />
);

expect(getByTestId('reward-tile-media')).toBeInTheDocument();
expect(getByTestId('reward-tile-title')).toBeInTheDocument();
expect(getByTestId('reward-tile-summary')).toBeInTheDocument();
});

it('should not render a half-height tile', () => {
const halfHeightTile = {
...RewardTileMock,
tileHeight: TileHeight.Half,
};
const { container } = render(<RewardTile tile={halfHeightTile} />);
expect(container).toBeEmptyDOMElement();
});
});
});

describe('<RewardTile /> Media', () => {
it('renders correctly when artworkUrl and showArtwork are provided', () => {
const { getByTestId } = render(<RewardTile tile={RewardTileMock} />);
expect(getByTestId('reward-tile-media')).toBeInTheDocument();
});

it('does not render when showArtwork is false', () => {
const tileWithoutShowArtwork = {
...RewardTileMock,
configuration: {
...RewardTileMock.configuration,
showArtwork: false,
},
};
const { queryByTestId } = render(
<RewardTile tile={tileWithoutShowArtwork} />
);
expect(queryByTestId('reward-tile-media')).not.toBeInTheDocument();
});

it('does not render when artworkUrl is missing', () => {
const tileWithoutArtwork = {
...RewardTileMock,
configuration: {
...RewardTileMock.configuration,
artworkUrl: undefined,
},
};
const { queryByTestId } = render(<RewardTile tile={tileWithoutArtwork} />);
expect(queryByTestId('reward-tile-media')).not.toBeInTheDocument();
});
});

describe('<RewardTile /> Points', () => {
it('renders points when showPrice is true', () => {
const { getByTestId } = render(<RewardTile tile={RewardTileMock} />);
expect(getByTestId('reward-tile-points')).toBeInTheDocument();
});

it('does not render points when showPrice is false', () => {
const tileWithoutPrice = {
...RewardTileMock,
configuration: {
...RewardTileMock.configuration,
showPrice: false,
},
};
const { queryByTestId } = render(<RewardTile tile={tileWithoutPrice} />);
expect(queryByTestId('reward-tile-points')).not.toBeInTheDocument();
});

it('calculates points correctly with default multiplier', () => {
const { getByTestId } = render(<RewardTile tile={RewardTileMock} />);
const pointsElement = getByTestId('reward-tile-points');
expect(pointsElement).toHaveAccessibleName('Reward points: 10');
});

it('calculates points correctly with custom multiplier', () => {
const tileWithMultiplier = {
...RewardTileMock,
configuration: {
...RewardTileMock.configuration,
pointsMultiplier: 200,
pointsPrefix: '',
pointsSuffix: 'pts',
},
};
const { getByTestId } = render(<RewardTile tile={tileWithMultiplier} />);
const pointsElement = getByTestId('reward-tile-points');
expect(pointsElement).toHaveAccessibleName('Reward points: 2000 pts');
});

it('uses custom prefix and suffix when provided', () => {
const tileWithCustomLabels = {
...RewardTileMock,
configuration: {
...RewardTileMock.configuration,
price: 10,
pointsPrefix: '$',
pointsSuffix: 'Dollars',
},
};
const { getByTestId } = render(<RewardTile tile={tileWithCustomLabels} />);
const pointsElement = getByTestId('reward-tile-points');
expect(pointsElement).toHaveAccessibleName('Reward points: $ 10 Dollars');
});

it('handles empty prefix and suffix correctly', () => {
const { getByTestId } = render(<RewardTile tile={RewardTileMock} />);
const pointsElement = getByTestId('reward-tile-points');
expect(pointsElement).toHaveAccessibleName('Reward points: 10');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<RewardTile /> renders and matches snapshot 1`] = `
<div>
<button
aria-label="undefined"
class="css-view-175oi2r r-cursor-1loqt21 r-touchAction-1otgn73 r-aspectRatio-1ujkv8a r-borderRadius-y47klf r-height-1pi2tsx r-overflow-1udh08x r-position-bnwqim r-width-13qz1uu"
role="button"
style="background-color: rgb(248, 247, 252); opacity: 1; flex-direction: column; justify-content: flex-start; align-items: stretch;"
tabindex="0"
type="button"
>
<div
class="css-view-175oi2r r-marginBottom-6gpygo r-width-13qz1uu"
data-testid="reward-tile-media"
style="flex-basis: 50%;"
>
<div
class="css-view-175oi2r r-alignItems-1awozwy r-justifyContent-1777fci r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu"
style="background-color: rgba(57, 46, 215, 0.2);"
>
<div
class="css-view-175oi2r r-bottom-1p0dtai r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af"
style="background-color: rgba(57, 46, 215, 0.2); opacity: 1;"
/>
<div
class="css-view-175oi2r r-flexBasis-1mlwlqe r-overflow-1udh08x r-zIndex-417010 r-bottom-1p0dtai r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af"
style="opacity: 0;"
>
<div
class="css-view-175oi2r r-backgroundColor-1niwhzg r-backgroundPosition-vvn4in r-backgroundRepeat-u6sd8q r-bottom-1p0dtai r-height-1pi2tsx r-left-1d2f490 r-position-u8s1d r-right-zchlnj r-top-ipm5af r-width-13qz1uu r-zIndex-1wyyakw r-backgroundSize-4gszlv"
style="background-image: url(https://ucarecdn.com/a486d015-b4ab-4831-bfa5-68f5bbbf63b1/);"
/>
<img
alt=""
class="css-accessibilityImage-9pa8cd"
draggable="false"
src="https://ucarecdn.com/a486d015-b4ab-4831-bfa5-68f5bbbf63b1/"
/>
</div>
</div>
</div>
<div
class="css-view-175oi2r r-alignItems-1habvwh r-flex-13awgt0 r-flexDirection-eqz5dr r-justifyContent-1h0z5md r-paddingBottom-kzbkwu r-paddingInline-3o4zer"
>
<div
class="css-view-175oi2r r-alignItems-1awozwy r-flexDirection-18u37iz r-justifyContent-1wtj0ep r-marginBottom-5oul0u r-width-13qz1uu"
>
<div
aria-label="Reward title: Sweet Chilli Lobster Noodles"
class="css-text-146c3p1 r-maxWidth-dnmrzs r-overflow-1udh08x r-textOverflow-1udbk01 r-whiteSpace-3s2u2q r-wordWrap-1iln25a"
data-testid="reward-tile-title"
dir="auto"
style="color: rgb(0, 0, 0); font-size: 24px; font-weight: bold;"
>
Sweet Chilli Lobster Noodles
</div>
<div
class="css-view-175oi2r"
>
<svg
class="lucide lucide-chevron-right"
fill="none"
height="24"
stroke="hsl(0, 0%, 20%)"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="m9 18 6-6-6-6"
/>
</svg>
</div>
</div>
<div
aria-label="Fresh Lobster Noodles with a spicy chilli sauce"
class="css-view-175oi2r"
>
<div
class="css-text-146c3p1"
data-testid="reward-tile-summary"
dir="auto"
style="color: rgb(51, 51, 51); font-size: 14px;"
>
Fresh Lobster Noodles with a spicy chilli sauce
</div>
</div>
<div
aria-label="Reward points: 10"
class="css-view-175oi2r"
data-testid="reward-tile-points"
>
<div
class="css-view-175oi2r r-alignItems-1awozwy r-flexDirection-18u37iz r-justifyContent-1h0z5md"
style="margin-top: 8px;"
>
<div
class="css-text-146c3p1"
data-testid="reward-tile-points-value"
dir="auto"
style="color: rgb(57, 46, 215); font-weight: bold; font-size: 24px;"
>
10
</div>
</div>
</div>
</div>
</button>
</div>
`;
7 changes: 3 additions & 4 deletions lib/components/organisms/RewardTile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { RewardTileConfig, Tile } from '../../../types/tile';
import { RewardTileConfig, Tile, TileHeight } from '../../../types/tile';
import { BaseTile, Layout, Row } from '../../atoms';
import { withTileFetching } from '../../hoc/withTileFetching';

Expand All @@ -11,7 +11,7 @@ import { RewardTileTitle } from './reward-tile-title';
import { useRewardTileStyles } from './styles';

type RewardTileProps = {
tile: Tile;
tile?: Tile;
};

/**
Expand All @@ -31,14 +31,13 @@ const isArtworkOnly = (configuration: RewardTileConfig): boolean => {
*/
const RewardTileRoot = ({ tile }: RewardTileProps): JSX.Element | null => {
const styles = useRewardTileStyles();
if (!tile) return null;
if (!tile || tile.tileHeight !== TileHeight.Full) return null;

const { configuration } = tile as { configuration: RewardTileConfig };

return (
<BaseTile tile={tile}>
<RewardTile.Media isArtworkOnly={isArtworkOnly(configuration)} />

<Layout>
<Row justify="between" align="center" style={styles.header}>
<RewardTile.Title />
Expand Down
7 changes: 5 additions & 2 deletions lib/components/organisms/RewardTile/reward-tile-media.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ export const RewardTileMedia = ({
};

return (
// @ts-ignore: We are using percentage values for flexBasis, which is valid in React Native but TypeScript expects a number.
<View style={[styles.imageContainer, containerStyle]}>
<View
// @ts-ignore: We are using percentage values for flexBasis, which is valid in React Native but TypeScript expects a number.
style={[styles.imageContainer, containerStyle]}
testID="reward-tile-media"
>
<ProgressiveImage source={{ uri: artworkUrl }} style={styles.image} />
</View>
);
Expand Down
Loading

0 comments on commit bcf11e6

Please sign in to comment.