Skip to content

Commit 02cbdfd

Browse files
authored
Merge pull request #25 from user-interviews/feature/UIDS-24-flash-component
UIDS-24 Flash message components
2 parents 8c235f6 + 2253e5a commit 02cbdfd

22 files changed

+2231
-3171
lines changed

.eslintrc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"browser": true
1818
},
1919
"parser": "babel-eslint",
20-
"plugins": [ "babel", "react" ],
20+
"plugins": [ "babel", "react", "react-hooks" ],
2121
"rules": {
2222
"babel/semi": 2,
2323
"import/prefer-default-export": 0,
@@ -33,9 +33,7 @@
3333
"no-alert": 0,
3434
"react/destructuring-assignment": 0,
3535
"react/forbid-prop-types": 0,
36-
"react/jsx-props-no-spreading": [2, {
37-
"html": "ignore"
38-
}],
36+
"react/jsx-props-no-spreading": 0,
3937
"react/jsx-no-target-blank": 1,
4038
"react/jsx-no-undef": 0,
4139
"react/jsx-one-expression-per-line": 0,
@@ -102,6 +100,8 @@
102100
"requiredFirst": false,
103101
"sortShapeProp": true
104102
}],
103+
"react-hooks/exhaustive-deps": "warn",
104+
"react-hooks/rules-of-hooks": "error",
105105
"semi": 0
106106
},
107107
}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ lib
2121
.env.test.local
2222
.env.production.local
2323

24+
# Ignore Jetbrains IDE settings
25+
/.idea
26+
2427
npm-debug.log*
2528
yarn-debug.log*
2629
yarn-error.log*

package.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
"node-sass": "^4.13.1",
88
"polished": "^3.4.2",
99
"prop-types": "^15.7.2",
10-
"react": "^16.12.0",
1110
"react-bootstrap": "^1.0.0-beta.16",
12-
"react-dom": "^16.12.0"
11+
"react-transition-group": "^4.3.0",
12+
"uuid": "^7.0.2"
1313
},
1414
"scripts": {
1515
"build": "NODE_ENV=production babel src --out-dir lib --copy-files",
@@ -35,6 +35,10 @@
3535
"last 1 safari version"
3636
]
3737
},
38+
"peerDependencies": {
39+
"react": "^16.12.0",
40+
"react-dom": "^16.12.0"
41+
},
3842
"devDependencies": {
3943
"@babel/cli": "^7.8.4",
4044
"@babel/core": "^7.8.4",
@@ -51,6 +55,7 @@
5155
"@storybook/addons": "^5.3.13",
5256
"@storybook/react": "^5.3.13",
5357
"@storybook/storybook-deployer": "^2.8.1",
58+
"@testing-library/react-hooks": "^3.2.1",
5459
"babel-eslint": "^10.0.3",
5560
"babel-loader": "^8.0.6",
5661
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
@@ -63,7 +68,10 @@
6368
"eslint-plugin-import": "^2.20.1",
6469
"eslint-plugin-jsx-a11y": "^6.2.3",
6570
"eslint-plugin-react": "^7.18.3",
71+
"eslint-plugin-react-hooks": "^2.5.1",
6672
"eslint-utils": "^1.4.3",
73+
"react": "^16.12.0",
74+
"react-dom": "^16.12.0",
6775
"react-test-renderer": "^16.12.0",
6876
"sass-loader": "^8.0.2",
6977
"style-loader": "^1.1.3"

scss/box_shadow.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
$ux-navbar-shadow-color: rgba( 0, 0, 0, 0.26 );
2+
3+
$ux-box-shadow: 0 2px 5px $ux-navbar-shadow-color;
4+
$ux-box-shadow-light: 0 1px 1px $ux-navbar-shadow-color;
5+
6+
$ux-box-shadow-card: 0 2px 4px rgba(0,0,0,0.1);
7+
8+
$ux-box-shadow-top: 0 -2px 5px $ux-navbar-shadow-color;
9+
$ux-box-shadow-top-light: 0 -1px 1px $ux-navbar-shadow-color;

scss/navbar.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
$ui-navbar-height: 3rem;
2+
$ui-navbar-height-mobile: $ui-navbar-height;

scss/theme.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
@import './box_shadow';
12
@import './lists';
3+
@import './navbar';
24
@import './palette';
35
@import './typography';
46
@import './z_stack';

spec/Flash/Flash.test.jsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from 'react';
2+
import { create } from 'react-test-renderer';
3+
4+
import Flash from '../../src/Flash/Flash';
5+
6+
describe('Flash', () => {
7+
test('no header classes', () => {
8+
const { props } = create(<Flash header messages={[]} />).toJSON();
9+
10+
expect(props.className).toContain('Flash');
11+
expect(props.className).not.toContain('Flash--no-header');
12+
});
13+
14+
test('header classes', () => {
15+
const { props } = create(<Flash header={false} messages={[]} />).toJSON();
16+
17+
expect(props.className).toContain('Flash');
18+
expect(props.className).toContain('Flash--no-header');
19+
});
20+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`test withFlash it can create a new flash message 1`] = `
4+
Array [
5+
<div
6+
className="alert alert-success"
7+
>
8+
<button
9+
className="close"
10+
onClick={[Function]}
11+
type="button"
12+
>
13+
×
14+
</button>
15+
This is just a test...
16+
</div>,
17+
<div />,
18+
]
19+
`;

spec/Flash/useFlash.test.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { renderHook, act } from '@testing-library/react-hooks';
2+
import { MessageTypes, useFlash } from '../../src/Flash';
3+
4+
const GENERATED_UUID = '1234';
5+
6+
jest.mock('uuid', () => (
7+
{
8+
v4: () => '1234',
9+
}
10+
));
11+
12+
describe('useFlash', () => {
13+
test('can set a new message', () => {
14+
const newMessage = 'I want to say something!';
15+
const { result } = renderHook(() => useFlash());
16+
17+
act(() => {
18+
result.current.setMessage(MessageTypes.SUCCESS, newMessage);
19+
});
20+
21+
expect(result.current.messages).toEqual([{
22+
id: GENERATED_UUID,
23+
type: MessageTypes.SUCCESS,
24+
message: newMessage,
25+
}]);
26+
});
27+
28+
test('can dismiss an existing message', () => {
29+
const newMessage = 'I want to say something else!';
30+
const { result } = renderHook(() => useFlash());
31+
32+
act(() => {
33+
result.current.setMessage(MessageTypes.SUCCESS, newMessage);
34+
});
35+
36+
expect(result.current.messages).toEqual([{
37+
id: GENERATED_UUID,
38+
type: MessageTypes.SUCCESS,
39+
message: newMessage,
40+
}]);
41+
42+
act(() => {
43+
result.current.dismissMessage(GENERATED_UUID);
44+
});
45+
46+
expect(result.current.messages).toEqual([]);
47+
});
48+
49+
test('can set two messages', () => {
50+
const newMessages = ['I want to say', 'so many things'];
51+
const { result } = renderHook(() => useFlash());
52+
53+
newMessages.forEach(
54+
(message) => {
55+
act(() => {
56+
result.current.setMessage(MessageTypes.ERROR, message);
57+
});
58+
},
59+
);
60+
61+
expect(result.current.messages).toEqual(
62+
newMessages.map((message) => ({
63+
id: GENERATED_UUID,
64+
type: MessageTypes.ERROR,
65+
message,
66+
})),
67+
);
68+
});
69+
70+
test('can clear all messages', () => {
71+
const messages = ['A new', 'message'].map(
72+
(msg, i) => ({
73+
id: i,
74+
type: MessageTypes.SUCCESS,
75+
message: msg,
76+
}),
77+
);
78+
79+
const { result } = renderHook(() => useFlash(messages));
80+
expect(result.current.messages.length).toEqual(2);
81+
82+
act(() => {
83+
result.current.clearMessages();
84+
});
85+
86+
expect(result.current.messages.length).toEqual(0);
87+
});
88+
});

spec/Flash/withFlash.test.jsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react';
2+
import { act } from '@testing-library/react-hooks';
3+
import { create } from 'react-test-renderer';
4+
5+
import withFlash from '../../src/Flash/withFlash';
6+
import { MessageTypes } from '../../src/Flash';
7+
8+
jest.mock('react-transition-group', () => (
9+
{
10+
CSSTransition: ({ children }) => children,
11+
TransitionGroup: ({ children }) => children,
12+
}
13+
));
14+
15+
const WrappedComponent = () => <div />;
16+
17+
describe('test withFlash', () => {
18+
test('it can create a new flash message', async () => {
19+
const newMessage = 'This is just a test...';
20+
const ComponentWithFlash = withFlash(WrappedComponent);
21+
const flash = create(<ComponentWithFlash />);
22+
const component = flash.root.findByType(WrappedComponent);
23+
24+
act(() => {
25+
component.props.setFlashMessage(MessageTypes.SUCCESS, newMessage);
26+
});
27+
28+
expect(flash).toMatchSnapshot();
29+
});
30+
});

0 commit comments

Comments
 (0)