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

Switch to Redux Toolkit and ducks pattern #2812

Draft
wants to merge 26 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1d8b7d4
Add Redux Toolkit
markerikson Nov 18, 2019
1b29294
Remove explicit dependencies on packages used by RTK
markerikson Nov 18, 2019
ae78600
Replace references to plain Redux package
markerikson Nov 18, 2019
5c558e4
Convert store setup to use configureStore from RTK
markerikson Nov 18, 2019
15d390d
Replace references to plain Reselect library
markerikson Nov 18, 2019
3f924ef
Add an initial app slice
markerikson Nov 18, 2019
026e7aa
Update other uses of app slice actions
markerikson Nov 18, 2019
f0dd5d1
Fix lint errors in appSlice
markerikson Nov 18, 2019
6ac2663
Fix mismatched argument in saga test
markerikson Nov 18, 2019
849aadc
Fix incorrect `preloadedState` argument for configureStore
markerikson Nov 18, 2019
6dc9d93
Remove obsolete configureStore test
markerikson Nov 18, 2019
54fff0b
Fix broken initial state in template store setup
markerikson Nov 18, 2019
0cf7263
Fix broken test
markerikson Nov 18, 2019
7c7375c
Use appSlice reducer in application
markerikson Nov 18, 2019
ec1cf41
- Fix and refactor sample app:
julienben Nov 19, 2019
4ee4642
Group HomePage components into one subfolder for cleanliness
julienben Nov 19, 2019
b4bd59e
- Remove empty if from configureStore
julienben Nov 19, 2019
f50f930
Update the LangugageProvider in sample and template apps
julienben Nov 19, 2019
241e0c6
Fix LocaleToggle test
julienben Nov 19, 2019
d3d0f3b
Remove Mensae from CODEOWNERS
julienben Nov 19, 2019
7a7d7bd
Rename some tests
julienben Nov 19, 2019
3618574
Move repo management to ReposManager
julienben Nov 20, 2019
4d6fd9a
[REDUX TOOLKIT] Update generators (#2811)
julienben Nov 21, 2019
fe41c35
Fix HomePage tests after RTK update and add tests for uncovered compo…
julienben Nov 21, 2019
24a8fcc
Merge branch 'dev' into redux-toolkit-switch
julienben Nov 24, 2019
c252e9d
Merge branch 'dev' into redux-toolkit-switch
julienben Dec 2, 2019
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
8 changes: 8 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,19 @@ module.exports = {
},
overrides: [
{
/* internals and server folder are for dev */
files: ['internals/**/*.*', 'server/**/*.*'],
rules: {
'import/no-extraneous-dependencies': 0,
},
},
{
/* slice.js files contain immer-based reducers where param reassignment is a requirement */
files: ['**/slice.js', '**/slice.test.js'],
rules: {
'no-param-reassign': 0,
},
},
],
settings: {
'import/resolver': {
Expand Down
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Global owners
* @julienben @gretzky @justingreenberg @jwinn @Mensae
* @julienben @gretzky @justingreenberg @jwinn
30 changes: 30 additions & 0 deletions app/components/Header/tests/HeaderLink.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import 'jest-styled-components';

import HeaderLink from '../HeaderLink';

const renderComponent = (props = {}) => {
const utils = render(
<MemoryRouter>
<HeaderLink to="/test" {...props}>
HeaderLink
</HeaderLink>
</MemoryRouter>,
);
const headerLink = utils.queryByText('HeaderLink');
return { ...utils, headerLink };
};

describe('<HeaderLink />', () => {
it('should match the snapshot', () => {
const { container } = renderComponent();
expect(container.firstChild).toMatchSnapshot();
});

it('should have a class attribute', () => {
const { headerLink } = renderComponent();
expect(headerLink).toHaveAttribute('class');
});
});
27 changes: 27 additions & 0 deletions app/components/Header/tests/NavBar.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { render } from '@testing-library/react';
import 'jest-styled-components';

import NavBar from '../NavBar';

const renderComponent = (props = {}) => {
const { container } = render(<NavBar {...props} />);
return container;
};

describe('<NavBar />', () => {
it('should match the snapshot', () => {
const container = renderComponent();
expect(container.firstChild).toMatchSnapshot();
});

it('should have a class attribute', () => {
const container = renderComponent();
expect(container.firstChild).toHaveAttribute('class');
});

it('should not adopt an invalid attribute', () => {
const container = renderComponent({ attribute: 'test' });
expect(container.firstChild).not.toHaveAttribute('attribute');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<HeaderLink /> should match the snapshot 1`] = `
.c0 {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
padding: 0.25em 2em;
margin: 1em;
-webkit-text-decoration: none;
text-decoration: none;
border-radius: 4px;
-webkit-font-smoothing: antialiased;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
outline: 0;
font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif;
font-weight: bold;
font-size: 16px;
border: 2px solid #41addd;
color: #41addd;
}

.c0:active {
background: #41addd;
color: #fff;
}

<a
class="c0"
href="/test"
>
HeaderLink
</a>
`;
11 changes: 11 additions & 0 deletions app/components/Header/tests/__snapshots__/NavBar.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<NavBar /> should match the snapshot 1`] = `
.c0 {
text-align: center;
}

<div
class="c0"
/>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,28 @@

import React from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { FormattedNumber } from 'react-intl';

import { makeSelectCurrentUser } from 'containers/App/selectors';
import ListItem from 'components/ListItem';
import IssueIcon from './IssueIcon';
import IssueLink from './IssueLink';
import RepoLink from './RepoLink';
import Wrapper from './Wrapper';

const stateSelector = createStructuredSelector({
currentUser: makeSelectCurrentUser(),
});

export default function RepoListItem({ item }) {
const { currentUser } = useSelector(stateSelector);
let nameprefix = '';
let namePrefix = '';

// If the repository is owned by a different person than we got the data for
// it's a fork and we should show the name of the owner
if (item.owner.login !== currentUser) {
nameprefix = `${item.owner.login}/`;
// If the repository is owned by a different user then the submitted
// username, it's a fork and we will show the name of the owner
if (!item.isOwnRepo) {
namePrefix = `${item.owner.login}/`;
}

// Put together the content of the repository
const content = (
<Wrapper>
<RepoLink href={item.html_url} target="_blank">
{nameprefix + item.name}
{namePrefix + item.name}
</RepoLink>
<IssueLink href={`${item.html_url}/issues`} target="_blank">
<IssueIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ exports[`<RepoListItem /> should render a ListItem 1`] = `
class="Item-sc-3y9mie-0 fKXSkT"
>
<div
class="Wrapper-sc-17s0rao-0 dlZQhZ"
class="Wrapper-sc-13xnchy-0 kxxMFK"
>
<a
class="A-br8h0y-0 RepoLink-pvpwpn-0 eEveIZ"
href="https://github.com/react-boilerplate/react-boilerplate"
class="A-br8h0y-0 RepoLink-sc-1x99nq5-0 cUSWhT"
href="https://github.com/repo-owner/repo_name"
target="_blank"
>
react-boilerplate/react-boilerplate
repo-owner/repo_name
</a>
<a
class="A-br8h0y-0 IssueLink-uyzonb-0 kUUUnc"
href="https://github.com/react-boilerplate/react-boilerplate/issues"
class="A-br8h0y-0 IssueLink-sc-16kygqm-0 giwGlR"
href="https://github.com/repo-owner/repo_name/issues"
target="_blank"
>
<svg
class="IssueIcon-s8m34y-0 jEBeEF"
class="IssueIcon-k8snxy-0 GsPBd"
height="1em"
width="0.875em"
>
Expand Down
86 changes: 86 additions & 0 deletions app/components/RepoListItem/tests/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Test the repo list item
*/

import React from 'react';
import { getByText, render } from '@testing-library/react';
import { IntlProvider } from 'react-intl';

import RepoListItem from '../index';

const renderComponent = item =>
render(
<IntlProvider locale="en">
<RepoListItem item={item} />
</IntlProvider>,
);

describe('<RepoListItem />', () => {
let ownedItem;
let notOwnedItem;

// Before each test reset the item data for safety
beforeEach(() => {
// Repo owned by the user whose account we're querying
ownedItem = {
isOwnRepo: true,
owner: {
login: 'repo-owner',
},
html_url: 'https://github.com/repo-owner/repo_name',
name: 'repo_name',
open_issues_count: 20,
full_name: 'repo-owner/repo-name',
};

// Repo NOT owned by the user whose account we're querying
notOwnedItem = {
isOwnRepo: false,
owner: {
login: 'repo-owner',
},
html_url: 'https://github.com/repo-owner/repo_name',
name: 'repo_name',
open_issues_count: 20,
full_name: 'repo-owner/repo-name',
};
});

it('should render a ListItem', () => {
const { container } = renderComponent(notOwnedItem);
expect(container.firstChild).toMatchSnapshot();
});

it('should not render the username if repo is owned by user', () => {
const { queryByText } = renderComponent(ownedItem);
expect(queryByText(ownedItem.owner.login)).toBeNull();
});

it('should render username if the repo belongs to a differet user or org', () => {
const { container } = renderComponent(notOwnedItem);
expect(
getByText(container, content =>
content.startsWith(notOwnedItem.owner.login),
),
).not.toBeNull();
});

it('should render the repo name', () => {
const { container } = renderComponent(ownedItem);
expect(
getByText(container, content => content.endsWith(ownedItem.name)),
).not.toBeNull();
});

it('should render the issue count', () => {
const { container } = renderComponent(ownedItem);
expect(
getByText(container, ownedItem.open_issues_count.toString(10)),
).not.toBeNull();
});

it('should render the IssueIcon', () => {
const { container } = renderComponent(ownedItem);
expect(container.querySelector('svg')).not.toBeNull();
});
});
2 changes: 1 addition & 1 deletion app/components/ReposList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import List from 'components/List';
import ListItem from 'components/ListItem';
import LoadingIndicator from 'components/LoadingIndicator';
import RepoListItem from 'containers/RepoListItem';
import RepoListItem from 'components/RepoListItem';

function ReposList({ loading, error, repos }) {
if (loading) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,22 @@ exports[`<ReposList /> should render the repositories if loading was successful
class="Item-sc-3y9mie-0 fKXSkT"
>
<div
class="Wrapper-sc-17s0rao-0 dlZQhZ"
class="Wrapper-sc-13xnchy-0 kxxMFK"
>
<a
class="A-br8h0y-0 RepoLink-pvpwpn-0 eEveIZ"
class="A-br8h0y-0 RepoLink-sc-1x99nq5-0 cUSWhT"
href="https://github.com/react-boilerplate/react-boilerplate"
target="_blank"
>
react-boilerplate
</a>
<a
class="A-br8h0y-0 IssueLink-uyzonb-0 kUUUnc"
class="A-br8h0y-0 IssueLink-sc-16kygqm-0 giwGlR"
href="https://github.com/react-boilerplate/react-boilerplate/issues"
target="_blank"
>
<svg
class="IssueIcon-s8m34y-0 jEBeEF"
class="IssueIcon-k8snxy-0 GsPBd"
height="1em"
width="0.875em"
>
Expand Down
12 changes: 4 additions & 8 deletions app/components/ReposList/tests/index.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React from 'react';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import { render } from '@testing-library/react';

import ReposList from '../index';
import configureStore from '../../../configureStore';

describe('<ReposList />', () => {
it('should render the loading indicator when its loading', () => {
Expand All @@ -22,9 +20,9 @@ describe('<ReposList />', () => {
});

it('should render the repositories if loading was successful', () => {
const store = configureStore({ global: { currentUser: 'mxstbr' } });
const repos = [
{
isOwnRepo: true,
owner: {
login: 'mxstbr',
},
Expand All @@ -35,11 +33,9 @@ describe('<ReposList />', () => {
},
];
const { container } = render(
<Provider store={store}>
<IntlProvider locale="en">
<ReposList repos={repos} error={false} />
</IntlProvider>
</Provider>,
<IntlProvider locale="en">
<ReposList repos={repos} error={false} />
</IntlProvider>,
);

expect(container.firstChild).toMatchSnapshot();
Expand Down
Loading