Skip to content

Commit

Permalink
Section and pagination components (#186)
Browse files Browse the repository at this point in the history
* Add the new Section component from Admin

* Add the new Pagination component from Admin

* Add Jest support and test Pagination

* Export both components

* Add Github action for tests

* Fix review comments

* Update pagination
  • Loading branch information
obedparla authored Aug 3, 2020
1 parent 54e6c44 commit 656c69d
Show file tree
Hide file tree
Showing 14 changed files with 2,572 additions and 57 deletions.
21 changes: 0 additions & 21 deletions .babelrc

This file was deleted.

4 changes: 2 additions & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"extends": ["airbnb", "airbnb/hooks", "plugin:prettier/recommended"],
"extends": ["airbnb", "airbnb/hooks", "plugin:prettier/recommended","plugin:jest/recommended"],
"env": {
"browser": true,
"es6": true
},
"plugins": ["prettier"],
"plugins": ["prettier", "jest"],
"parserOptions": {
"sourceType": "module"
},
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ jobs:
- name: Linting
run: yarn lint

- name: Test
run: yarn test
34 changes: 34 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module.exports = api => {
const isTestEnv = api.env('test');

return {
exclude: 'node_modules/**',
plugins: [
'@babel/plugin-proposal-nullish-coalescing-operator',
[
'babel-plugin-styled-components',
{
pure: true,
},
],
],
presets: [
isTestEnv
? [
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
]
: [
'@babel/preset-env',
{
modules: false,
},
],
'@babel/preset-react',
],
};
};
17 changes: 17 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html

module.exports = {
// Automatically clear mock calls and instances between every test
clearMocks: true,

// Automatically reset mock state between every test
resetMocks: true,

// We only want to test JS components and not other stuff
// Like webpack's test.js
roots: ['./src/components'],
moduleNameMapper: {
'\\.(css)$': '<rootDir>/src/__mocks__/styleMock.js',
},
};
15 changes: 11 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"predeploy": "npm run build && npm run build:storybook",
"icons": "node scripts/icons",
"prettier": "prettier --check 'src/**/*.{js,jsx,json,md,css}'",
"analyze-bundle": "npm run build && open dist/stats.html"
"analyze-bundle": "npm run build && open dist/stats.html",
"test": "jest"
},
"peerDependencies": {
"prop-types": "^15.7.2",
Expand All @@ -40,8 +41,8 @@
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
"@babel/preset-env": "^7.9.5",
"@babel/preset-react": "^7.9.4",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"@storybook/addon-actions": "^5.3.18",
"@storybook/addon-info": "^5.3.18",
"@storybook/addon-knobs": "^5.3.18",
Expand Down Expand Up @@ -71,6 +72,7 @@
"react-dom": "^16.8.6",
"react-scripts": "^3.4.1",
"react-table": "next",
"react-test-renderer": "^16.13.1",
"rollup": "^2.7.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-commonjs": "^10.1.0",
Expand All @@ -79,7 +81,12 @@
"rollup-plugin-postcss": "^2.9.0",
"rollup-plugin-url": "^3.0.1",
"rollup-plugin-visualizer": "^4.0.4",
"svgo": "^1.3.2"
"svgo": "^1.3.2",
"@testing-library/react": "^10.4.7",
"@testing-library/user-event": "^12.0.17",
"babel-jest": "^26.2.2",
"eslint-plugin-jest": "^23.20.0",
"jest": "^26.2.2"
},
"files": [
"dist"
Expand Down
6 changes: 6 additions & 0 deletions src/__mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// eslint-disable-next-line import/no-default-export
/*
Mocks styles files imported in Jest
See jest config > moduleNameMapper
*/
module.exports = {};
64 changes: 64 additions & 0 deletions src/components/Pagination/__test__/Pagination.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Pagination from '../index';

describe('Pagination', () => {
it('displays the prev/next buttons', () => {
const { getByTestId } = render(
<Pagination goNext={() => {}} goPrev={() => {}} />,
);

expect(getByTestId('pagination-prev')).toBeDefined();
expect(getByTestId('pagination-next')).toBeDefined();
});

it("Doesn't render if both are disabled", () => {
const { queryByTestId } = render(
<Pagination
goNext={() => {}}
goPrev={() => {}}
nextDisabled
prevDisabled
/>,
);

expect(queryByTestId('pagination-prev')).toBeNull();
expect(queryByTestId('pagination-next')).toBeNull();
});

it('triggers the goNext/goPrev props on click', () => {
const goNext = jest.fn();
const goPrev = jest.fn();

const { getByTestId } = render(
<Pagination goNext={goNext} goPrev={goPrev} />,
);

userEvent.click(getByTestId('pagination-prev'));
expect(goPrev).toHaveBeenCalled();

userEvent.click(getByTestId('pagination-next'));
expect(goNext).toHaveBeenCalled();
});

it('The next arrow shows as disabled correctly', () => {
const { queryByTestId } = render(
<Pagination goNext={() => {}} goPrev={() => {}} nextDisabled />,
);

expect(
queryByTestId('pagination-next').hasAttribute('disabled'),
).toBeTruthy();
});

it('The prev arrow shows as disabled correctly', () => {
const { queryByTestId } = render(
<Pagination goNext={() => {}} goPrev={() => {}} prevDisabled />,
);

expect(
queryByTestId('pagination-prev').hasAttribute('disabled'),
).toBeTruthy();
});
});
97 changes: 97 additions & 0 deletions src/components/Pagination/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

import IconButton from '../IconButton';
import { theme } from '../../theme';

const texts = {
next: {
id: 'flamingo.pagination.next',
defaultText: 'Next',
},
previous: {
id: 'flamingo.pagination.previous',
defaultText: 'Previous',
},
disabled: {
id: 'flamingo.pagination.disabled',
defaultText: 'Disabled',
},
};

const Pagination = ({
className,
position,
prevDisabled,
nextDisabled,
translate,
goPrev,
goNext,
}) => {
// Don't show it if both are disabled
if (prevDisabled && nextDisabled) {
return null;
}

return (
<Container className={className} position={position}>
<ArrowIcon
data-testid={'pagination-prev'}
icon={'IconArrowLeft'}
onClick={goPrev}
disabled={prevDisabled}
title={`${translate(texts.previous)} ${
prevDisabled ? `- ${translate(texts.disabled)}` : ''
}`}
/>

<ArrowIcon
data-testid={'pagination-next'}
icon={'IconArrowRight'}
onClick={goNext}
disabled={nextDisabled}
title={`${translate(texts.next)} ${
nextDisabled ? `- ${translate(texts.disabled)}` : ''
}`}
/>
</Container>
);
};

Pagination.displayName = 'Pagination';

Pagination.propTypes = {
goPrev: PropTypes.func.isRequired,
prevDisabled: PropTypes.bool,
goNext: PropTypes.func.isRequired,
nextDisabled: PropTypes.bool,
className: PropTypes.string,
translate: PropTypes.func,
position: PropTypes.string,
};

Pagination.defaultProps = {
translate: ({ defaultText }) => defaultText,
};

const Container = styled('div')`
display: flex;
justify-content: ${({ position }) => position || 'flex-end'};
padding: 20px 0 10px;
`;

const ArrowIcon = styled(IconButton)`
i {
width: 16px;
height: 16px;
svg {
fill: ${({ disabled }) =>
disabled ? theme.color.element.inactive : theme.color.text.link};
width: 16px;
}
}
`;

export default Pagination;
28 changes: 28 additions & 0 deletions src/components/Pagination/index.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* eslint-disable no-return-assign */

import React, { useState } from 'react';
import { storiesOf } from '@storybook/react';
import { select } from '@storybook/addon-knobs';

import Heading from '../Heading';
import Pagination from './index';

const stories = storiesOf('Pagination', module);

stories.add('Playground', () => {
const [page, setPage] = useState(0);
return (
<>
<Heading>Pagination</Heading>
<Heading level={2}>Page #{page}</Heading>

<Pagination
prevDisabled={page === 0}
nextDisabled={page === 3}
goNext={() => setPage(p => p + 1)}
goPrev={() => setPage(p => p - 1)}
position={select('Position', ['flex-end', 'flex-start', 'center'])}
/>
</>
);
});
Loading

1 comment on commit 656c69d

@vercel
Copy link

@vercel vercel bot commented on 656c69d Aug 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.