@transferwise/components 46.91.0 → 46.93.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/build/actionOption/ActionOption.js +11 -5
  2. package/build/actionOption/ActionOption.js.map +1 -1
  3. package/build/actionOption/ActionOption.mjs +11 -5
  4. package/build/actionOption/ActionOption.mjs.map +1 -1
  5. package/build/common/Option/Option.js +9 -4
  6. package/build/common/Option/Option.js.map +1 -1
  7. package/build/common/Option/Option.mjs +10 -5
  8. package/build/common/Option/Option.mjs.map +1 -1
  9. package/build/dateLookup/dateTrigger/DateTrigger.js +11 -6
  10. package/build/dateLookup/dateTrigger/DateTrigger.js.map +1 -1
  11. package/build/dateLookup/dateTrigger/DateTrigger.mjs +11 -6
  12. package/build/dateLookup/dateTrigger/DateTrigger.mjs.map +1 -1
  13. package/build/definitionList/DefinitionList.js +5 -3
  14. package/build/definitionList/DefinitionList.js.map +1 -1
  15. package/build/definitionList/DefinitionList.mjs +5 -3
  16. package/build/definitionList/DefinitionList.mjs.map +1 -1
  17. package/build/main.css +23 -32
  18. package/build/snackbar/Snackbar.js +4 -2
  19. package/build/snackbar/Snackbar.js.map +1 -1
  20. package/build/snackbar/Snackbar.mjs +4 -2
  21. package/build/snackbar/Snackbar.mjs.map +1 -1
  22. package/build/styles/common/Option/Option.css +22 -0
  23. package/build/styles/dateLookup/dateTrigger/DateTrigger.css +1 -32
  24. package/build/styles/main.css +23 -32
  25. package/build/types/actionOption/ActionOption.d.ts +4 -3
  26. package/build/types/actionOption/ActionOption.d.ts.map +1 -1
  27. package/build/types/common/Option/Option.d.ts +1 -0
  28. package/build/types/common/Option/Option.d.ts.map +1 -1
  29. package/build/types/dateLookup/dateTrigger/DateTrigger.d.ts.map +1 -1
  30. package/build/types/definitionList/DefinitionList.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/src/actionOption/ActionOption.spec.tsx +20 -0
  33. package/src/actionOption/ActionOption.story.tsx +2 -0
  34. package/src/actionOption/ActionOption.tsx +15 -5
  35. package/src/button/Button.story.tsx +8 -0
  36. package/src/common/Option/Option.css +22 -0
  37. package/src/common/Option/Option.less +21 -0
  38. package/src/common/Option/Option.spec.tsx +21 -0
  39. package/src/common/Option/Option.tsx +7 -1
  40. package/src/dateLookup/DateLookup.spec.tsx +445 -0
  41. package/src/dateLookup/dateTrigger/DateTrigger.css +1 -32
  42. package/src/dateLookup/dateTrigger/DateTrigger.less +4 -28
  43. package/src/dateLookup/dateTrigger/DateTrigger.tsx +9 -5
  44. package/src/definitionList/DefinitionList.tsx +3 -3
  45. package/src/inputs/InputGroup.story.tsx +5 -3
  46. package/src/listItem/ListItem.spec.tsx +10 -2
  47. package/src/listItem/ListItem.story.tsx +11 -3
  48. package/src/main.css +23 -32
  49. package/src/snackbar/Snackbar.tsx +3 -3
  50. package/src/withNextPortal/withNextPortal.spec.tsx +24 -0
  51. package/src/common/Option/Option.spec.js +0 -129
  52. package/src/dateLookup/DateLookup.proptypes.spec.js +0 -28
  53. package/src/dateLookup/DateLookup.rtl.spec.tsx +0 -199
  54. package/src/dateLookup/DateLookup.state.spec.js +0 -76
  55. package/src/dateLookup/DateLookup.testingLibrary.spec.js +0 -256
  56. package/src/dateLookup/DateLookup.view.spec.js +0 -151
  57. package/src/dateLookup/dateHeader/DateHeader.spec.js +0 -95
  58. package/src/dateLookup/dateTrigger/DateTrigger.spec.js +0 -123
  59. package/src/dateLookup/dayCalendar/DayCalendar.spec.js +0 -122
  60. package/src/dateLookup/dayCalendar/table/DayCalendarTable.spec.js +0 -147
  61. package/src/dateLookup/monthCalendar/MonthCalendar.spec.js +0 -105
  62. package/src/dateLookup/monthCalendar/table/MonthCalendarTable.spec.js +0 -120
  63. package/src/dateLookup/tableLink/TableLink.spec.js +0 -109
  64. package/src/dateLookup/yearCalendar/YearCalendar.spec.js +0 -88
  65. package/src/dateLookup/yearCalendar/table/YearCalendarTable.spec.js +0 -121
  66. package/src/modal/Modal.spec.js +0 -197
  67. package/src/withNextPortal/withNextPortal.spec.js +0 -22
  68. /package/src/modal/{Modal.rtl.spec.tsx → Modal.spec.tsx} +0 -0
@@ -4,7 +4,7 @@ import { action } from '@storybook/addon-actions';
4
4
  import { Documents, FastFlag } from '@transferwise/icons';
5
5
  import { ComponentProps } from 'react';
6
6
 
7
- import ActionButton from '../actionButton/ActionButton';
7
+ import { Button } from '..';
8
8
  import AvatarView from '../avatarView';
9
9
  import Info from '../info';
10
10
  import Title from '../title/Title';
@@ -58,7 +58,11 @@ export const Variants = () => {
58
58
  title="Account holder"
59
59
  value="Sandra Pepper"
60
60
  media={<AvatarView profileName="Super Pepa" badge={{ icon: <FastFlag /> }} />}
61
- action={<ActionButton>Share details</ActionButton>}
61
+ action={
62
+ <Button v2 size="sm">
63
+ Share details
64
+ </Button>
65
+ }
62
66
  />
63
67
  </List>
64
68
  </div>
@@ -75,7 +79,11 @@ export const Variants = () => {
75
79
  <Template
76
80
  title="SWIFT/BIC"
77
81
  value="••• •••"
78
- action={<ActionButton onClick={() => action('clicked')}>Reveal</ActionButton>}
82
+ action={
83
+ <Button v2 size="sm" onClick={() => action('clicked')}>
84
+ Reveal
85
+ </Button>
86
+ }
79
87
  />
80
88
  </List>
81
89
  </div>
package/src/main.css CHANGED
@@ -1770,6 +1770,28 @@ button.np-option {
1770
1770
  border-radius: var(--radius-small);
1771
1771
  }
1772
1772
  }
1773
+ .np-theme-personal .np-option-additional-content {
1774
+ margin-left: 80px;
1775
+ margin-left: var(--size-80);
1776
+ margin-right: 16px;
1777
+ margin-right: var(--size-16);
1778
+ margin-top: -10px;
1779
+ padding-bottom: 16px;
1780
+ padding-bottom: var(--size-16);
1781
+ max-width: -moz-fit-content;
1782
+ max-width: fit-content;
1783
+ }
1784
+ @media (max-width: 480px) {
1785
+ .np-theme-personal .np-option-additional-content {
1786
+ margin-left: 16px;
1787
+ margin-left: var(--size-16);
1788
+ }
1789
+ }
1790
+ @media (max-width: 320px) {
1791
+ .np-theme-personal .np-option-additional-content {
1792
+ margin-top: -3px;
1793
+ }
1794
+ }
1773
1795
  .np-select-option {
1774
1796
  border-radius: 10px;
1775
1797
  border-radius: var(--radius-small);
@@ -2003,55 +2025,24 @@ button.np-option {
2003
2025
  padding-left: var(--size-16);
2004
2026
  }
2005
2027
  .clear-btn {
2006
- transition: color 0.15s ease-in-out;
2007
- color: #c9cbce;
2008
- color: var(--color-interactive-secondary);
2009
2028
  position: absolute;
2010
- top: 16px;
2011
- top: var(--size-16);
2012
- right: 16px;
2013
- right: var(--size-16);
2014
- }
2015
- [dir="rtl"] .clear-btn {
2016
- left: 16px;
2017
- left: var(--size-16);
2018
- right: auto;
2019
- right: initial;
2020
- }
2021
- .np-theme-personal .clear-btn {
2022
2029
  top: 8px;
2023
2030
  top: var(--size-8);
2024
2031
  right: 8px;
2025
2032
  right: var(--size-8);
2026
2033
  }
2027
- [dir="rtl"] .np-theme-personal .clear-btn {
2034
+ [dir="rtl"] .clear-btn {
2028
2035
  left: 8px;
2029
2036
  left: var(--size-8);
2030
2037
  right: auto;
2031
2038
  right: initial;
2032
2039
  }
2033
2040
  .clear-btn--sm {
2034
- top: 8px;
2035
- top: var(--size-8);
2036
- }
2037
- .np-theme-personal .clear-btn--sm {
2038
2041
  top: 0;
2039
2042
  }
2040
2043
  .clear-btn--lg {
2041
- top: 28px;
2042
- }
2043
- .np-theme-personal .clear-btn--lg {
2044
2044
  top: 20px;
2045
2045
  }
2046
- .clear-btn:not(.disabled):not(:disabled):hover,
2047
- .clear-btn:not(.disabled):not(:disabled):focus {
2048
- color: #d03238;
2049
- color: var(--color-interactive-negative-hover);
2050
- }
2051
- .clear-btn:not(.disabled):not(:disabled):active {
2052
- color: #bf1e2c;
2053
- color: var(--color-interactive-negative-active);
2054
- }
2055
2046
  .np-decision .decision {
2056
2047
  display: flex;
2057
2048
  }
@@ -1,7 +1,7 @@
1
1
  import { Component, createRef } from 'react';
2
2
  import { CSSTransition } from 'react-transition-group';
3
3
 
4
- import ActionButton from '../actionButton';
4
+ import Button from '../button';
5
5
  import Body from '../body';
6
6
  import { Theme, type ThemeDark, type ThemeLight } from '../common';
7
7
  import { DirectionContext } from '../provider/direction';
@@ -110,9 +110,9 @@ export class Snackbar extends Component<SnackbarProps, SnackbarState> {
110
110
  <Body ref={this.bodyRef} as="span" className="snackbar__text">
111
111
  {text}
112
112
  {action ? (
113
- <ActionButton className="snackbar__text__action" onClick={action.onClick}>
113
+ <Button className="snackbar__text__action" v2 size="sm" onClick={action.onClick}>
114
114
  {action.label}
115
- </ActionButton>
115
+ </Button>
116
116
  ) : null}
117
117
  </Body>
118
118
  </CSSTransition>
@@ -0,0 +1,24 @@
1
+ import { HTMLAttributes } from 'react';
2
+ import { render } from '../test-utils';
3
+ import withNextPortalWrapper from './withNextPortal';
4
+
5
+ describe('withNextPortalWrapper', () => {
6
+ it('renders component in React portal', () => {
7
+ type Props = Pick<
8
+ HTMLAttributes<HTMLButtonElement>,
9
+ 'id' | 'children' | 'className' | 'aria-label'
10
+ >;
11
+ const RandomComponentForTest = withNextPortalWrapper((props: Props) => <span {...props} />);
12
+ const data: Props = {
13
+ 'aria-label': 'Test aria-label',
14
+ id: 'random-component',
15
+ children: 'Test Children',
16
+ };
17
+ render(<RandomComponentForTest {...data} />);
18
+
19
+ const componentDomRef = document.body.lastChild;
20
+ expect(componentDomRef).toHaveAttribute('aria-label', data['aria-label']);
21
+ expect(componentDomRef).toHaveTextContent(data.children as string);
22
+ expect(componentDomRef).toHaveAttribute('id', data.id);
23
+ });
24
+ });
@@ -1,129 +0,0 @@
1
- import { shallow } from 'enzyme';
2
- import { createRef } from 'react';
3
-
4
- import { render, screen } from '../../test-utils';
5
-
6
- import Option from '.';
7
-
8
- describe('Option', () => {
9
- let component;
10
- beforeEach(() => {
11
- component = shallow(<Option title="" content="" media={<span />} button={<span />} />);
12
- });
13
-
14
- it('does not have decision class when the flag is set to false', () => {
15
- expect(hasDecisonClass()).toBe(true);
16
- component.setProps({ decision: false });
17
- expect(hasDecisonClass()).toBe(false);
18
- });
19
-
20
- it('has complex class when the flag is passed', () => {
21
- expect(hasComplexClass()).toBe(false);
22
- component.setProps({ complex: true });
23
- expect(hasComplexClass()).toBe(true);
24
- });
25
-
26
- it('has disabled class when the flag is passed', () => {
27
- expect(hasDisabledClass()).toBe(false);
28
- component.setProps({ disabled: true });
29
- expect(hasDisabledClass()).toBe(true);
30
- });
31
-
32
- it('has disabled attibute when the flag is passed for a button', () => {
33
- expect(hasDisabledAttribute()).toBe(false);
34
- component.setProps({ disabled: true });
35
- expect(hasDisabledAttribute()).toBe(false);
36
- component.setProps({ disabled: false, as: 'button' });
37
- expect(hasDisabledAttribute()).toBe(false);
38
- component.setProps({ disabled: true, as: 'button' });
39
- expect(hasDisabledAttribute()).toBe(true);
40
- });
41
-
42
- it('passes the className it is given to the element it renders', () => {
43
- expect(component.hasClass('some-class')).toBe(false);
44
- component.setProps({ className: 'some-class' });
45
- expect(component.hasClass('some-class')).toBe(true);
46
- });
47
-
48
- it('calls click handler on click', () => {
49
- const onClick = jest.fn();
50
- const event = { iAmAnEvent: true };
51
- component.setProps({ onClick });
52
-
53
- expect(onClick).not.toHaveBeenCalled();
54
- component.simulate('click', event);
55
- expect(onClick).toHaveBeenCalledWith(event);
56
- });
57
-
58
- it('has for attribute to label when prop is passed', () => {
59
- expect(htmlFor()).toBeUndefined();
60
- component.setProps({ htmlFor: 'some-id' });
61
- expect(htmlFor()).toBe('some-id');
62
- });
63
-
64
- it('has passed media in the circle on the left', () => {
65
- const Icon = () => <svg />;
66
- component.setProps({ media: <Icon /> });
67
-
68
- expect(circleContentIsElement(<Icon />)).toBe(true);
69
- });
70
-
71
- it('does not render the circle content with circle-inverse class when inverseMediaCircle is set to false', () => {
72
- expect(circleContentHasInverseClass()).toBe(true);
73
- component.setProps({ inverseMediaCircle: false });
74
- expect(circleContentHasInverseClass()).toBe(false);
75
- });
76
-
77
- it('renders the title', () => {
78
- render(<Option title="Option title" content="" media={<span />} button={<span />} />);
79
-
80
- expect(() => screen.getByText('Option title')).not.toThrow();
81
- });
82
-
83
- it('has passed content', () => {
84
- component.setProps({ content: <p>A content</p> });
85
- expect(bodyHasElement(<p>A content</p>)).toBe(true);
86
- });
87
-
88
- it('renders as a label by default', () => {
89
- expect(mainComponentTag()).toBe('label');
90
- });
91
-
92
- it('renders as the tag that you pass it', () => {
93
- component.setProps({ as: 'a', href: 'https://example.com' });
94
- expect(mainComponentTag()).toBe('a');
95
- });
96
-
97
- it('does not render the circle if media not passed', () => {
98
- expect(circle().exists()).toBe(true);
99
- component.setProps({ media: null });
100
- expect(circle().exists()).toBe(false);
101
- });
102
-
103
- it('passes href to the underlying component if passed', () => {
104
- expect(component.prop('href')).toBeFalsy();
105
- component.setProps({ href: 'https://example.com' });
106
- expect(component.prop('href')).toBe('https://example.com');
107
- });
108
-
109
- it('`ref` attribute is passed to Option and reference is created', () => {
110
- const reference = createRef();
111
-
112
- expect(reference.current).toBeFalsy();
113
- render(<Option ref={reference} title="" content="" media={<span />} button={<span />} />);
114
- expect(reference.current).toBeTruthy();
115
- });
116
-
117
- const hasDecisonClass = () => component.hasClass('decision');
118
- const hasComplexClass = () => component.hasClass('decision-complex');
119
- const hasDisabledClass = () => component.hasClass('disabled');
120
- const hasDisabledAttribute = () => component.prop('disabled');
121
- const htmlFor = () => component.prop('htmlFor');
122
- const circle = () => component.find('.media-left');
123
- const circleContent = () => component.find('.media-left .circle');
124
- const circleContentHasInverseClass = () => circleContent().hasClass('circle-inverse');
125
- const circleContentIsElement = (element) => circleContent().childAt(0).matchesElement(element);
126
- const mainComponentTag = () => component.name();
127
- const bodyHasElement = (element) =>
128
- component.find('.media-body').containsMatchingElement(element);
129
- });
@@ -1,28 +0,0 @@
1
- import { render, mockMatchMedia } from '../test-utils';
2
-
3
- import DateLookup from '.';
4
-
5
- mockMatchMedia();
6
-
7
- // This test suite could become redundant
8
- // once we refactor the DateLookup component to TypeScript
9
-
10
- describe('DateLookup propTypes', () => {
11
- describe('when the value prop is set to null', () => {
12
- it('renders without prop type warnings in the console', () => {
13
- const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
14
-
15
- render(<DateLookup value={null} onChange={jest.fn()} />);
16
-
17
- // eslint-disable-next-line no-console
18
- expect(console.error).not.toHaveBeenCalledWith(
19
- expect.stringContaining('Warning: Failed %s type'),
20
- 'prop',
21
- 'The prop `value` is marked as required in `DateLookup`, but its value is `null`.',
22
- expect.anything(),
23
- );
24
-
25
- consoleSpy.mockRestore();
26
- });
27
- });
28
- });
@@ -1,199 +0,0 @@
1
- import { Field } from '../field/Field';
2
- import { mockMatchMedia, mockResizeObserver, render, screen, userEvent } from '../test-utils';
3
- import DateLookup, { DateLookupProps } from './DateLookup';
4
-
5
- import { act } from 'react';
6
-
7
- const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTimeAsync });
8
-
9
- mockMatchMedia();
10
- mockResizeObserver();
11
-
12
- const initialValue = new Date(2000, 0, 1);
13
-
14
- describe('DateLookup', () => {
15
- beforeEach(() => {
16
- jest.useFakeTimers();
17
- });
18
-
19
- afterEach(async () => {
20
- await jest.runOnlyPendingTimersAsync();
21
- jest.useRealTimers();
22
- jest.clearAllMocks();
23
- });
24
-
25
- it('supports `Field` for labeling', () => {
26
- render(
27
- <Field label="Date of birth">
28
- <DateLookup value={initialValue} onChange={() => {}} />
29
- </Field>,
30
- );
31
- const button = screen.getByRole('button', { name: /^Date of birth/ });
32
-
33
- expect(button).toBeInTheDocument();
34
- expect(button).toHaveAttribute('aria-haspopup');
35
- });
36
-
37
- it.each([' ', '{Enter}', '{ArrowDown}', '{ArrowUp}', '{ArrowRight}', '{ArrowLeft}'])(
38
- "opens with '%s' and closes with '{Escape}'",
39
- async (text) => {
40
- render(<DateLookup value={initialValue} onChange={() => {}} />);
41
-
42
- await user.tab();
43
- await user.keyboard(text);
44
-
45
- expect(screen.getByRole('button', { name: /next/iu })).toBeInTheDocument();
46
-
47
- await user.keyboard('{Escape}');
48
- await act(async () => {
49
- await jest.runOnlyPendingTimersAsync();
50
- });
51
-
52
- expect(screen.queryByRole('button', { name: /next/iu })).not.toBeInTheDocument();
53
- },
54
- );
55
-
56
- const setupAndOpenWithMouse = async (props: Partial<DateLookupProps> = {}) => {
57
- const view = render(<DateLookup value={initialValue} onChange={() => {}} {...props} />);
58
-
59
- await user.click(screen.getByRole('button'));
60
- await act(async () => {
61
- await jest.runOnlyPendingTimersAsync();
62
- });
63
-
64
- return view;
65
- };
66
-
67
- it('opens and closes with mouse', async () => {
68
- await setupAndOpenWithMouse();
69
-
70
- expect(screen.getByRole('button', { name: /next/iu })).toBeInTheDocument();
71
-
72
- const dimmerElement = screen.getByRole('dialog').parentElement?.parentElement;
73
- if (dimmerElement != null) {
74
- await user.click(dimmerElement);
75
- }
76
- await act(async () => {
77
- await jest.runOnlyPendingTimersAsync();
78
- });
79
-
80
- expect(screen.queryByRole('button', { name: /next/iu })).not.toBeInTheDocument();
81
- });
82
-
83
- describe('in day view', () => {
84
- it.each([
85
- ['{ArrowLeft}', -1],
86
- ['{ArrowRight}', +1],
87
- ['{ArrowUp}', -7],
88
- ['{ArrowDown}', +7],
89
- ])("handles '%s' to step %d day(s)", async (text, step) => {
90
- const handleChange = jest.fn();
91
- await setupAndOpenWithMouse({ onChange: handleChange });
92
-
93
- expect(handleChange).not.toHaveBeenCalled();
94
-
95
- await user.keyboard(text);
96
-
97
- const value = new Date(initialValue);
98
- value.setDate(initialValue.getDate() + step);
99
- expect(handleChange).toHaveBeenCalledWith(value);
100
-
101
- await user.keyboard('{Escape}');
102
- await act(async () => {
103
- await jest.runOnlyPendingTimersAsync();
104
- });
105
-
106
- expect(handleChange).toHaveBeenCalledWith(initialValue);
107
- });
108
- });
109
-
110
- describe('in year view', () => {
111
- it.each([
112
- ['{ArrowLeft}', -1],
113
- ['{ArrowRight}', +1],
114
- ['{ArrowUp}', -4],
115
- ['{ArrowDown}', +4],
116
- ])("handles '%s' to step %d year(s)", async (text, step) => {
117
- const handleChange = jest.fn();
118
- await setupAndOpenWithMouse({ onChange: handleChange });
119
-
120
- await user.click(screen.getByRole('button', { name: /year view/iu }));
121
- await act(async () => {
122
- await jest.runOnlyPendingTimersAsync();
123
- });
124
-
125
- expect(handleChange).not.toHaveBeenCalled();
126
-
127
- await user.keyboard(text);
128
-
129
- const value = new Date(initialValue);
130
- value.setFullYear(initialValue.getFullYear() + step);
131
- expect(handleChange).toHaveBeenCalledWith(value);
132
-
133
- await user.keyboard('{Escape}');
134
- await act(async () => {
135
- await jest.runOnlyPendingTimersAsync();
136
- });
137
-
138
- expect(handleChange).toHaveBeenCalledWith(initialValue);
139
- });
140
- });
141
-
142
- describe('in month view', () => {
143
- it.each([
144
- ['{ArrowLeft}', -1],
145
- ['{ArrowRight}', +1],
146
- ['{ArrowUp}', -4],
147
- ['{ArrowDown}', +4],
148
- ])("handles '%s' to step %d month(s)", async (text, step) => {
149
- const handleChange = jest.fn();
150
- await setupAndOpenWithMouse({ onChange: handleChange });
151
-
152
- await user.click(screen.getByRole('button', { name: /year view/iu }));
153
- await act(async () => {
154
- await jest.runOnlyPendingTimersAsync();
155
- });
156
- await user.keyboard(' ');
157
- await act(async () => {
158
- await jest.runOnlyPendingTimersAsync();
159
- });
160
-
161
- expect(handleChange).not.toHaveBeenCalled();
162
-
163
- await user.keyboard(text);
164
-
165
- const value = new Date(initialValue);
166
- value.setMonth(initialValue.getMonth() + step);
167
- expect(handleChange).toHaveBeenCalledWith(value);
168
-
169
- await user.keyboard('{Escape}');
170
- await act(async () => {
171
- await jest.runOnlyPendingTimersAsync();
172
- });
173
-
174
- expect(handleChange).toHaveBeenCalledWith(initialValue);
175
- });
176
- });
177
-
178
- it('limits min value', async () => {
179
- const min = new Date(initialValue);
180
- min.setDate(min.getDate() - 1);
181
- const handleChange = jest.fn();
182
- await setupAndOpenWithMouse({ min, onChange: handleChange });
183
-
184
- await user.keyboard('{ArrowLeft}{ArrowLeft}');
185
-
186
- expect(handleChange).toHaveBeenCalledWith(min);
187
- });
188
-
189
- it('limits max value', async () => {
190
- const max = new Date(initialValue);
191
- max.setDate(max.getDate() + 1);
192
- const handleChange = jest.fn();
193
- await setupAndOpenWithMouse({ max, onChange: handleChange });
194
-
195
- await user.keyboard('{ArrowRight}{ArrowRight}');
196
-
197
- expect(handleChange).toHaveBeenCalledWith(max);
198
- });
199
- });
@@ -1,76 +0,0 @@
1
- import { shallow } from 'enzyme';
2
- import { useIntl } from 'react-intl';
3
-
4
- import { DateLookupWithoutInputAttributes as DateLookup } from './DateLookup';
5
-
6
- jest.mock('react-intl');
7
-
8
- // Tests for getDerivedStateFromProps results
9
- describe('DateLookup state', () => {
10
- let component;
11
- let defaultProps;
12
- let initialValue;
13
- const defaultState = { selectedDate: null, min: null, max: null };
14
-
15
- beforeEach(() => {
16
- initialValue = new Date();
17
- defaultProps = { onChange: jest.fn(), value: initialValue };
18
- useIntl.mockReturnValue({ locale: 'en-GB' });
19
- component = shallow(<DateLookup {...defaultProps} />);
20
- });
21
-
22
- it('sets correct defaults', () => {
23
- const { selectedDate, min, max, viewMonth, viewYear, open, mode } = component.instance().state;
24
- expect(selectedDate).not.toBeNull();
25
- expect(min).toBeNull();
26
- expect(max).toBeNull();
27
- expect(viewMonth).not.toBeNull();
28
- expect(viewYear).not.toBeNull();
29
- expect(open).toBe(false);
30
- expect(mode).toBe('day');
31
- });
32
-
33
- it('does not update when date props did not change', () => {
34
- const props = { open: true };
35
- expect(DateLookup.getDerivedStateFromProps(props, defaultState)).toBeNull();
36
- });
37
-
38
- it('updates selectedDate on props value change', () => {
39
- const props = { value: new Date(2018, 11, 27) };
40
- const newState = DateLookup.getDerivedStateFromProps(props, defaultState);
41
- expect(Number(newState.selectedDate)).toBe(Number(new Date(2018, 11, 27)));
42
- });
43
-
44
- it('sets date values to midnight', () => {
45
- const props = {
46
- value: new Date(2018, 11, 27, 15, 23),
47
- min: new Date(2018, 10, 27, 22, 23),
48
- max: new Date(2018, 11, 28, 0, 30),
49
- };
50
- const newState = DateLookup.getDerivedStateFromProps(props, defaultState);
51
- expect(Number(newState.selectedDate)).toBe(Number(new Date(2018, 11, 27, 0, 0)));
52
- expect(Number(newState.min)).toBe(Number(new Date(2018, 10, 27, 0, 0)));
53
- expect(Number(newState.max)).toBe(Number(new Date(2018, 11, 28, 0, 0)));
54
- });
55
-
56
- it('calls onChange with min when it is < min', () => {
57
- const onChange = jest.fn();
58
- const props = { value: new Date(2018, 11, 27), min: new Date(2018, 11, 28), onChange };
59
- DateLookup.getDerivedStateFromProps(props, defaultState);
60
- expect(onChange).toHaveBeenCalledWith(new Date(2018, 11, 28));
61
- });
62
-
63
- it('calls onChange with max when it is > min', () => {
64
- const onChange = jest.fn();
65
- const props = { value: new Date(2018, 11, 27), max: new Date(2018, 10, 1), onChange };
66
- DateLookup.getDerivedStateFromProps(props, defaultState);
67
- expect(onChange).toHaveBeenCalledWith(new Date(2018, 10, 1));
68
- });
69
-
70
- it('updates viewMonth and viewYear to date within min/max on Clear', () => {
71
- const props = { value: null, min: new Date(2018, 11, 26), max: new Date(2018, 11, 26) };
72
- const newState = DateLookup.getDerivedStateFromProps(props, defaultState);
73
- expect(newState.viewMonth).toBe(11);
74
- expect(newState.viewYear).toBe(2018);
75
- });
76
- });