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

RUC - 60 product card #62

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@
.firstSelect {
z-index: 1;
}

.productCard {
width: 300px;
height: 400px;
margin: 20px;
}
16 changes: 16 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import './components/atoms/Breadcrumbs/Breadcrumbs.scss';
import Toast from './components/atoms/Toast/Toast';
import Select from './components/atoms/Select/Select';
import selectItems from './common/mocks/selectItems';
import Card from './components/organisms/Card/Card';
import mockProductDetails from './common/mocks/productDetails';

function App() {
const [value, setValue] = useState('');
Expand All @@ -27,6 +29,8 @@ function App() {
const [progress, setProgress] = useState(0);
const [showModal, handleShowModal] = useState(false);
const [showToast, setShowToast] = useState(false);
const [isFav, setIsFav] = useState(false);
const [productCount, setProductCount] = useState(0);

useEffect(() => {
styleReorder();
Expand Down Expand Up @@ -130,6 +134,18 @@ function App() {
setMultipleSelectOption(option);
}}
/>
<Card
productDetails={mockProductDetails}
className="productCard"
onWishlistIconClick={() => {
setIsFav(!isFav);
}}
onCartIconClick={() => {
setProductCount(productCount + 1);
}}
isOnWishlist={isFav}
numberOfItemsInCart={productCount}
/>
</ThemeProvider>
);
}
Expand Down
7 changes: 7 additions & 0 deletions src/common/mocks/productDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
name: 'Croissant',
price: '3.00 EUR',
shortDescription: 'Taste our delicious croissants...',
imageUrl: 'https://cdn.pixabay.com/photo/2016/03/27/21/59/bread-1284438_1280.jpg',
hoverImageUrl: 'https://cdn.pixabay.com/photo/2016/11/29/05/07/baked-goods-1867459_1280.jpg',
}
2 changes: 1 addition & 1 deletion src/components/atoms/Image/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect } from 'react';
import styled from 'styled-components';
import {OBJECT_FIT_OPTIONS} from '../../../common/constants/consts';
import { OBJECT_FIT_OPTIONS } from '../../../common/constants/consts';

interface IImage {
className?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/components/atoms/Text/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { COLOR_OPTIONS, TEXT_ALIGNMENT_OPTIONS, FONT_WEIGHT_OPTIONS } from '../.

interface IText {
className?: string;
children: string;
children?: string;
color?: string;
fontColor?: string;
fontWeight?:
Expand Down
185 changes: 185 additions & 0 deletions src/components/organisms/Card/Card.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import React from 'react';
import { create, act } from 'react-test-renderer';
import { fireEvent, render } from '@testing-library/react';
import 'jest-styled-components';
import { ThemeProvider } from 'styled-components';
import theme from '../../../common/theme';
import Card, { HeartIcon } from './Card';
import CardDetails from './CardDetails';
import { CartIcon } from './CartIconContainer';
import mockProductDetails from '../../../common/mocks/productDetails';
import setupIntersectionObserverMock from '../../../helpers/intersectionObserverMock';
import Badge from '../../atoms/Badge/Badge';

describe('Card component', () => {
beforeEach(() => {
setupIntersectionObserverMock();
});

it('should render correctly', () => {
const card = create(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} />
</ThemeProvider>
).toJSON();
expect(card).toMatchSnapshot();
})

it('should render card with custom class', () => {
const card = create(
<ThemeProvider theme={theme}>
<Card className="test-class" productDetails={mockProductDetails} />
</ThemeProvider>
).toJSON();
expect(card.props.className).toEqual(expect.stringContaining('test-class'));
});

it('should render card product details', () => {
const card = create(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} />
</ThemeProvider>
);
const instance = card.root;
const productDetails = instance.findByType(CardDetails).findByType('div');
expect(productDetails.children[0].props.children).toBe('Croissant');
expect(productDetails.children[1].props.children).toBe('Taste our delicious croissants...');
expect(productDetails.children[2].props.children).toBe('3.00 EUR');
});

it('should not render description when hideDescription props is passed', () => {
const card = create(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} hideDescription hideWishlistIcon />
</ThemeProvider>
);
const instance = card.root;
const productDetails = instance.findByType(CardDetails).findByType('div');
expect(productDetails.children.length).toEqual(2);
expect(productDetails.children[0].props.children).toBe('Croissant');
expect(productDetails.children[1].props.children).toBe('3.00 EUR');
});

it('should not render price when hidePrice props is passed', () => {
const card = create(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} hidePrice hideWishlistIcon />
</ThemeProvider>
);
const instance = card.root;
const productDetails = instance.findByType(CardDetails).findByType('div');
expect(productDetails.children.length).toEqual(2);
expect(productDetails.children[0].props.children).toBe('Croissant');
expect(productDetails.children[1].props.children).toBe('Taste our delicious croissants...');
});

it('should render product details with font color based on color prop', () => {
const { getByText } = render(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} color="secondary" />
</ThemeProvider>
);
const productName = getByText('Croissant');
expect(productName).toHaveStyle('color: #2196f3');
});

it('should render horizontal card by default', () => {
const card = create(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} />
</ThemeProvider>
).toJSON();
expect(card).toHaveStyleRule('flex-direction', 'column');
});

it('should render vertical card when proper direction props is passed', () => {
const card = create(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} direction="vertical" />
</ThemeProvider>
).toJSON();
expect(card).toHaveStyleRule('flex-direction', 'row');
});

it('should render with passed images', () => {
const { container, getByAltText } = render(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} />
</ThemeProvider>
);
const image = getByAltText('Croissant');
expect(image).toHaveAttribute(
'src',
'https://cdn.pixabay.com/photo/2016/03/27/21/59/bread-1284438_1280.jpg'
);
fireEvent.mouseEnter(container.firstChild);
expect(image).toHaveAttribute(
'src',
'https://cdn.pixabay.com/photo/2016/11/29/05/07/baked-goods-1867459_1280.jpg'
);
});

it('should call onCartIconClick', () => {
const mockOnClick = jest.fn();
const e = { stopPropagation: jest.fn() };
const component = create(
<ThemeProvider theme={theme}>
<Card
productDetails={mockProductDetails}
onCartIconClick={mockOnClick}
/>
</ThemeProvider>
);
const instance = component.root;
const cartIcon = instance.findByType(CartIcon);
act(() => {
cartIcon.props.onClick(e);
});
expect(mockOnClick.mock.calls.length).toEqual(1);
});

it('should call onWishlistIconClick', () => {
const mockOnClick = jest.fn();
const e = { stopPropagation: jest.fn() };
const component = create(
<ThemeProvider theme={theme}>
<Card
productDetails={mockProductDetails}
onWishlistIconClick={mockOnClick}
/>
</ThemeProvider>
);
const instance = component.root;
const wishlistIcon = instance.findByType(HeartIcon);
act(() => {
wishlistIcon.props.onClick(e);
})
expect(mockOnClick.mock.calls.length).toEqual(1);
})

it('should call onClick', () => {
const mockOnClick = jest.fn();
const component = create(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} onClick={mockOnClick} />
</ThemeProvider>
);
const instance = component.root;
const card = instance.findByType(Card);
act(() => {
card.props.onClick();
});
expect(mockOnClick.mock.calls.length).toEqual(1);
});

it('should show given cart product number', () => {
const component = create(
<ThemeProvider theme={theme}>
<Card productDetails={mockProductDetails} numberOfItemsInCart={3} />
</ThemeProvider>
);
const instance = component.root;
const badge = instance.findByType(Badge).findByType('span');
expect(badge.props.children).toBe(3);
})
});
Loading