@transferwise/components 46.84.1 → 46.86.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 (163) hide show
  1. package/build/avatarLayout/AvatarLayout.js +1 -0
  2. package/build/avatarLayout/AvatarLayout.js.map +1 -1
  3. package/build/avatarLayout/AvatarLayout.mjs +1 -0
  4. package/build/avatarLayout/AvatarLayout.mjs.map +1 -1
  5. package/build/circularButton/CircularButton.js +18 -21
  6. package/build/circularButton/CircularButton.js.map +1 -1
  7. package/build/circularButton/CircularButton.mjs +19 -22
  8. package/build/circularButton/CircularButton.mjs.map +1 -1
  9. package/build/definitionList/DefinitionList.js.map +1 -1
  10. package/build/definitionList/DefinitionList.mjs.map +1 -1
  11. package/build/dimmer/Dimmer.js.map +1 -1
  12. package/build/dimmer/Dimmer.mjs.map +1 -1
  13. package/build/i18n/de.json +1 -0
  14. package/build/i18n/de.json.js +1 -0
  15. package/build/i18n/de.json.js.map +1 -1
  16. package/build/i18n/de.json.mjs +1 -0
  17. package/build/i18n/de.json.mjs.map +1 -1
  18. package/build/i18n/en.json +1 -0
  19. package/build/i18n/en.json.js +1 -0
  20. package/build/i18n/en.json.js.map +1 -1
  21. package/build/i18n/en.json.mjs +1 -0
  22. package/build/i18n/en.json.mjs.map +1 -1
  23. package/build/i18n/es.json +1 -0
  24. package/build/i18n/es.json.js +1 -0
  25. package/build/i18n/es.json.js.map +1 -1
  26. package/build/i18n/es.json.mjs +1 -0
  27. package/build/i18n/es.json.mjs.map +1 -1
  28. package/build/i18n/fr.json +6 -5
  29. package/build/i18n/fr.json.js +6 -5
  30. package/build/i18n/fr.json.js.map +1 -1
  31. package/build/i18n/fr.json.mjs +6 -5
  32. package/build/i18n/fr.json.mjs.map +1 -1
  33. package/build/i18n/hu.json +1 -0
  34. package/build/i18n/hu.json.js +1 -0
  35. package/build/i18n/hu.json.js.map +1 -1
  36. package/build/i18n/hu.json.mjs +1 -0
  37. package/build/i18n/hu.json.mjs.map +1 -1
  38. package/build/i18n/id.json +1 -0
  39. package/build/i18n/id.json.js +1 -0
  40. package/build/i18n/id.json.js.map +1 -1
  41. package/build/i18n/id.json.mjs +1 -0
  42. package/build/i18n/id.json.mjs.map +1 -1
  43. package/build/i18n/it.json +1 -0
  44. package/build/i18n/it.json.js +1 -0
  45. package/build/i18n/it.json.js.map +1 -1
  46. package/build/i18n/it.json.mjs +1 -0
  47. package/build/i18n/it.json.mjs.map +1 -1
  48. package/build/i18n/pl.json +1 -0
  49. package/build/i18n/pl.json.js +1 -0
  50. package/build/i18n/pl.json.js.map +1 -1
  51. package/build/i18n/pl.json.mjs +1 -0
  52. package/build/i18n/pl.json.mjs.map +1 -1
  53. package/build/i18n/ro.json +1 -0
  54. package/build/i18n/ro.json.js +1 -0
  55. package/build/i18n/ro.json.js.map +1 -1
  56. package/build/i18n/ro.json.mjs +1 -0
  57. package/build/i18n/ro.json.mjs.map +1 -1
  58. package/build/i18n/th.json +6 -0
  59. package/build/i18n/th.json.js +6 -0
  60. package/build/i18n/th.json.js.map +1 -1
  61. package/build/i18n/th.json.mjs +6 -0
  62. package/build/i18n/th.json.mjs.map +1 -1
  63. package/build/i18n/tr.json +1 -0
  64. package/build/i18n/tr.json.js +1 -0
  65. package/build/i18n/tr.json.js.map +1 -1
  66. package/build/i18n/tr.json.mjs +1 -0
  67. package/build/i18n/tr.json.mjs.map +1 -1
  68. package/build/i18n/zh-CN.json +11 -0
  69. package/build/i18n/zh-CN.json.js +11 -0
  70. package/build/i18n/zh-CN.json.js.map +1 -1
  71. package/build/i18n/zh-CN.json.mjs +11 -0
  72. package/build/i18n/zh-CN.json.mjs.map +1 -1
  73. package/build/i18n/zh-HK.json +5 -0
  74. package/build/i18n/zh-HK.json.js +5 -0
  75. package/build/i18n/zh-HK.json.js.map +1 -1
  76. package/build/i18n/zh-HK.json.mjs +5 -0
  77. package/build/i18n/zh-HK.json.mjs.map +1 -1
  78. package/build/main.css +17 -158
  79. package/build/moneyInput/MoneyInput.js.map +1 -1
  80. package/build/moneyInput/MoneyInput.mjs.map +1 -1
  81. package/build/stepper/Stepper.js +6 -3
  82. package/build/stepper/Stepper.js.map +1 -1
  83. package/build/stepper/Stepper.mjs +6 -3
  84. package/build/stepper/Stepper.mjs.map +1 -1
  85. package/build/styles/circularButton/CircularButton.css +17 -158
  86. package/build/styles/main.css +17 -158
  87. package/build/types/avatarLayout/AvatarLayout.d.ts.map +1 -1
  88. package/build/types/circularButton/CircularButton.d.ts +11 -4
  89. package/build/types/circularButton/CircularButton.d.ts.map +1 -1
  90. package/build/types/definitionList/DefinitionList.d.ts +1 -2
  91. package/build/types/definitionList/DefinitionList.d.ts.map +1 -1
  92. package/build/types/dimmer/Dimmer.d.ts +1 -1
  93. package/build/types/dimmer/Dimmer.d.ts.map +1 -1
  94. package/build/types/moneyInput/MoneyInput.d.ts +1 -1
  95. package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
  96. package/build/types/stepper/Stepper.d.ts +2 -1
  97. package/build/types/stepper/Stepper.d.ts.map +1 -1
  98. package/build/types/test-utils/index.d.ts +2 -0
  99. package/build/types/test-utils/index.d.ts.map +1 -1
  100. package/build/types/uploadInput/uploadButton/UploadButton.messages.d.ts +5 -0
  101. package/build/types/uploadInput/uploadButton/UploadButton.messages.d.ts.map +1 -1
  102. package/build/uploadInput/uploadButton/UploadButton.js +3 -1
  103. package/build/uploadInput/uploadButton/UploadButton.js.map +1 -1
  104. package/build/uploadInput/uploadButton/UploadButton.messages.js +3 -0
  105. package/build/uploadInput/uploadButton/UploadButton.messages.js.map +1 -1
  106. package/build/uploadInput/uploadButton/UploadButton.messages.mjs +3 -0
  107. package/build/uploadInput/uploadButton/UploadButton.messages.mjs.map +1 -1
  108. package/build/uploadInput/uploadButton/UploadButton.mjs +3 -1
  109. package/build/uploadInput/uploadButton/UploadButton.mjs.map +1 -1
  110. package/package.json +5 -5
  111. package/src/avatar/Avatar.story.tsx +4 -1
  112. package/src/avatarLayout/AvatarLayout.story.tsx +2 -0
  113. package/src/avatarLayout/AvatarLayout.tsx +3 -1
  114. package/src/avatarWrapper/AvatarWrapper.story.tsx +4 -0
  115. package/src/badge/Badge.story.tsx +4 -0
  116. package/src/circularButton/CircularButton.css +17 -158
  117. package/src/circularButton/CircularButton.less +22 -91
  118. package/src/circularButton/CircularButton.story.tsx +45 -24
  119. package/src/circularButton/CircularButton.tsx +38 -25
  120. package/src/definitionList/DefinitionList.story.tsx +57 -57
  121. package/src/definitionList/DefinitionList.tsx +1 -1
  122. package/src/dimmer/{Dimmer.rtl.spec.tsx → Dimmer.spec.tsx} +33 -29
  123. package/src/dimmer/Dimmer.tsx +4 -4
  124. package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +3 -1
  125. package/src/i18n/de.json +1 -0
  126. package/src/i18n/en.json +1 -0
  127. package/src/i18n/es.json +1 -0
  128. package/src/i18n/fr.json +6 -5
  129. package/src/i18n/hu.json +1 -0
  130. package/src/i18n/id.json +1 -0
  131. package/src/i18n/it.json +1 -0
  132. package/src/i18n/pl.json +1 -0
  133. package/src/i18n/ro.json +1 -0
  134. package/src/i18n/th.json +6 -0
  135. package/src/i18n/tr.json +1 -0
  136. package/src/i18n/zh-CN.json +11 -0
  137. package/src/i18n/zh-HK.json +5 -0
  138. package/src/iconButton/IconButton.story.tsx +6 -6
  139. package/src/main.css +17 -158
  140. package/src/moneyInput/MoneyInput.spec.tsx +468 -0
  141. package/src/moneyInput/MoneyInput.tsx +2 -1
  142. package/src/navigationOption/NavigationOption.spec.tsx +113 -0
  143. package/src/phoneNumberInput/PhoneNumberInput.spec.tsx +283 -0
  144. package/src/radioOption/RadioOption.spec.tsx +73 -0
  145. package/src/slidingPanel/SlidingPanel.spec.tsx +69 -0
  146. package/src/stepper/Stepper.spec.tsx +236 -0
  147. package/src/stepper/Stepper.tests.story.tsx +89 -0
  148. package/src/stepper/Stepper.tsx +9 -4
  149. package/src/stepper/{deviceDetection.spec.js → deviceDetection.spec.ts} +6 -3
  150. package/src/uploadInput/uploadButton/UploadButton.messages.ts +7 -0
  151. package/src/uploadInput/uploadButton/UploadButton.tsx +1 -1
  152. package/src/circularButton/_button-label-states.less +0 -34
  153. package/src/definitionList/DefinitionList.spec.js +0 -91
  154. package/src/dimmer/Dimmer.spec.js +0 -87
  155. package/src/moneyInput/MoneyInput.rtl.spec.tsx +0 -149
  156. package/src/moneyInput/MoneyInput.spec.js +0 -820
  157. package/src/navigationOption/NavigationOption.spec.js +0 -93
  158. package/src/phoneNumberInput/PhoneNumberInput.rtl.spec.tsx +0 -32
  159. package/src/phoneNumberInput/PhoneNumberInput.spec.js +0 -356
  160. package/src/radioOption/RadioOption.spec.js +0 -67
  161. package/src/slidingPanel/SlidingPanel.spec.js +0 -56
  162. package/src/stepper/Stepper.spec.js +0 -233
  163. /package/src/alert/{Alert.spec.story.tsx → Alert.tests.story.tsx} +0 -0
@@ -0,0 +1,89 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { fn, within, expect, screen } from '@storybook/test';
3
+ import Stepper from './Stepper';
4
+
5
+ const STEPS = [
6
+ {
7
+ label: 'One',
8
+ onClick: fn(),
9
+ },
10
+ {
11
+ label: 'Two',
12
+ hoverLabel: (
13
+ <>
14
+ <div>
15
+ <strong>Diana Jaramillo</strong>
16
+ </div>
17
+ dianajarm123@gmail.com
18
+ </>
19
+ ),
20
+ onClick: fn(),
21
+ },
22
+ { label: 'Three', onClick: fn() },
23
+ { label: 'Four', onClick: fn() },
24
+ { label: 'Five', onClick: fn() },
25
+ ];
26
+
27
+ const meta = {
28
+ component: Stepper,
29
+ title: 'Navigation/Stepper/tests',
30
+ argTypes: {
31
+ activeStep: {
32
+ control: 'radio',
33
+ options: [...Array(STEPS.length).keys()],
34
+ },
35
+ },
36
+ } satisfies Meta<typeof Stepper>;
37
+ export default meta;
38
+
39
+ type Story = StoryObj<typeof meta>;
40
+
41
+ export const ProgressbarWidth: Story = {
42
+ play: async ({ step }) => {
43
+ const getBarBaseWidth = (stepIndex: number) => {
44
+ const instance = screen.getByTestId(`stepper${stepIndex}`);
45
+ return within(instance).getByTestId('progress-bar')?.style.width;
46
+ };
47
+
48
+ await step('activeStep: -10 (negative) ▸ width should be 0', async () => {
49
+ await expect(getBarBaseWidth(-10)).toBe(`0%`);
50
+ });
51
+
52
+ await step('activeStep: 0 ▸ width should be 0', async () => {
53
+ await expect(getBarBaseWidth(0)).toBe(`0%`);
54
+ });
55
+
56
+ const WIDTHS = [0, 25, 50, 75, 100];
57
+ // eslint-disable-next-line no-plusplus
58
+ for (let stepIndex = 1; stepIndex < STEPS.length; stepIndex++) {
59
+ await step(
60
+ `activeStep: ${stepIndex} ▸ base width should be ${WIDTHS[stepIndex]}%`,
61
+ async () => {
62
+ await expect(getBarBaseWidth(stepIndex)).toMatch(
63
+ new RegExp(`^calc\\(${WIDTHS[stepIndex]}%.*?`),
64
+ );
65
+ },
66
+ );
67
+ }
68
+
69
+ await step('activeStep: 1000 ▸ base width should be 100%', async () => {
70
+ await expect(getBarBaseWidth(1000)).toMatch(/^calc\(100%.*?/);
71
+ });
72
+ },
73
+ render: function Render() {
74
+ return (
75
+ <>
76
+ <Stepper steps={STEPS} activeStep={0} testId="stepper-10" />
77
+ <Stepper steps={STEPS} activeStep={0} testId="stepper0" />
78
+ <Stepper steps={STEPS} activeStep={1} testId="stepper1" />
79
+ <Stepper steps={STEPS} activeStep={2} testId="stepper2" />
80
+ <Stepper steps={STEPS} activeStep={3} testId="stepper3" />
81
+ <Stepper steps={STEPS} activeStep={4} testId="stepper4" />
82
+ <Stepper steps={STEPS} activeStep={4} testId="stepper1000" />
83
+ </>
84
+ );
85
+ },
86
+ args: {
87
+ steps: STEPS,
88
+ },
89
+ };
@@ -21,13 +21,14 @@ export interface StepperProps {
21
21
  steps: readonly Step[];
22
22
  activeStep?: number;
23
23
  className?: string;
24
+ testId?: string;
24
25
  }
25
26
 
26
27
  /**
27
28
  * This component is considered user-unfriendly and inaccessible on its own and will likely be made internal in the future. Please use `FlowNavigation` instead.
28
29
  * @see https://storybook.wise.design/?path=/story/navigation-flownavigation--variants
29
30
  */
30
- const Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {
31
+ const Stepper = ({ steps, activeStep = 0, className, testId }: StepperProps) => {
31
32
  const { isRTL } = useDirection();
32
33
 
33
34
  if (steps.length === 0) {
@@ -40,7 +41,7 @@ const Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {
40
41
 
41
42
  const getProgressWidth = (): string => {
42
43
  if (percentageCompleted === 0) {
43
- return '0px';
44
+ return '0%';
44
45
  }
45
46
  /**
46
47
  * Progress bar starts with left/right (depends on rtl) shift `--progress-bar-start-shift` for hiding Progress bar's left and right borders
@@ -95,9 +96,13 @@ const Stepper = ({ steps, activeStep = 0, className }: StepperProps) => {
95
96
  };
96
97
 
97
98
  return (
98
- <div className={clsx('tw-stepper', className)}>
99
+ <div className={clsx('tw-stepper', className)} data-testid={testId}>
99
100
  <div className="progress">
100
- <div className="progress-bar" style={{ width: getProgressWidth() }} />
101
+ <div
102
+ className="progress-bar"
103
+ style={{ width: getProgressWidth() }}
104
+ data-testid="progress-bar"
105
+ />
101
106
  </div>
102
107
  <ol className="tw-stepper-steps p-t-1 m-b-0">{steps.map(renderStep)}</ol>
103
108
  </div>
@@ -1,14 +1,14 @@
1
1
  import { isTouchDevice } from './deviceDetection';
2
2
 
3
3
  describe('Device detection', () => {
4
- function fakeUserAgent(userAgent) {
4
+ function fakeUserAgent(userAgent: string) {
5
5
  Object.defineProperty(navigator, 'userAgent', {
6
6
  value: userAgent,
7
7
  configurable: true,
8
8
  });
9
9
  }
10
10
 
11
- function fakeMaxTouchPoints(maxTouchPoints) {
11
+ function fakeMaxTouchPoints(maxTouchPoints: number | undefined) {
12
12
  Object.defineProperty(navigator, 'maxTouchPoints', {
13
13
  value: maxTouchPoints,
14
14
  configurable: true,
@@ -24,7 +24,10 @@ describe('Device detection', () => {
24
24
 
25
25
  it('recognizes touch devices via window events', () => {
26
26
  expect(isTouchDevice()).toBe(false);
27
- window.ontouchstart = {};
27
+ Object.defineProperty(window, 'ontouchstart', {
28
+ value: () => {},
29
+ writable: true,
30
+ });
28
31
  expect(isTouchDevice()).toBe(true);
29
32
  });
30
33
 
@@ -19,6 +19,13 @@ export default defineMessages({
19
19
  description: 'Description about filetypes and size limit for uploading files',
20
20
  },
21
21
 
22
+ maximumFiles: {
23
+ id: 'neptune.UploadButton.maximumFiles',
24
+ defaultMessage: 'Maximum {maxFiles} files.',
25
+ description:
26
+ 'When number of files to be uploaded is restricted, this information is displayed within the upload button.',
27
+ },
28
+
22
29
  allFileTypes: {
23
30
  id: 'neptune.UploadButton.allFileTypes',
24
31
  defaultMessage: 'All file types',
@@ -200,7 +200,7 @@ const UploadButton = forwardRef<HTMLInputElement | null, UploadButtonProps>(
200
200
  {maxFiles && (
201
201
  <>
202
202
  <br />
203
- {`Maximum ${maxFiles} files.`}
203
+ {formatMessage(MESSAGES.maximumFiles, { maxFiles })}
204
204
  </>
205
205
  )}
206
206
  </Body>
@@ -1,34 +0,0 @@
1
- .button-label-states(@prefix, @type, @normal, @hover, @active, @isModernTheme: false) {
2
- .@{prefix}.@{type} {
3
- .@{prefix}__label {
4
- color: @normal;
5
- }
6
-
7
- &:not(.disabled, :disabled):hover .@{prefix}__label {
8
- color: @hover;
9
- }
10
-
11
- &:active .@{prefix}__label,
12
- input[type="button"]:active ~ .@{prefix}__label {
13
- color: @active;
14
- }
15
-
16
- &.secondary {
17
- .tw-icon {
18
- color: @normal;
19
- }
20
-
21
- &:not(.disabled, :disabled):hover .tw-icon,
22
- input[type="button"]:active + .tw-icon {
23
- color: white;
24
- & when (@isModernTheme = true) {
25
- color: var(--color-interactive-control);
26
- }
27
- }
28
-
29
- &:active input[type="button"] + .tw-icon when (@isModernTheme = true) {
30
- color: var(--color-interactive-control);
31
- }
32
- }
33
- }
34
- }
@@ -1,91 +0,0 @@
1
- import { shallow, mount } from 'enzyme';
2
-
3
- import { DefinitionList } from '..';
4
- import { Layout } from '../common';
5
-
6
- const {
7
- VERTICAL_TWO_COLUMN,
8
- VERTICAL_ONE_COLUMN,
9
- HORIZONTAL_LEFT_ALIGNED,
10
- HORIZONTAL_RIGHT_ALIGNED,
11
- HORIZONTAL_JUSTIFIED,
12
- } = Layout;
13
-
14
- describe('DefinitionList', () => {
15
- const someDefinitions = () => [{ title: 'First', value: 'first value', key: 'first' }, null];
16
-
17
- const withLayout = (layout) =>
18
- shallow(<DefinitionList layout={layout} definitions={someDefinitions()} />);
19
-
20
- const listHasClass = (layout, className) =>
21
- withLayout(layout).find('dl.tw-definition-list').hasClass(className);
22
-
23
- const valueHasClass = (layout, className) =>
24
- withLayout(layout).find('dl.tw-definition-list dd').hasClass(className);
25
-
26
- it('applies correct flex class', () => {
27
- const colClass = 'flex-column';
28
-
29
- expect(listHasClass(VERTICAL_ONE_COLUMN, colClass)).toBe(true);
30
- expect(listHasClass(VERTICAL_TWO_COLUMN, colClass)).toBe(true);
31
- expect(listHasClass(HORIZONTAL_LEFT_ALIGNED, colClass)).toBe(true);
32
- expect(listHasClass(HORIZONTAL_RIGHT_ALIGNED, colClass)).toBe(true);
33
- expect(listHasClass(HORIZONTAL_JUSTIFIED, colClass)).toBe(true);
34
- });
35
-
36
- it('applies correct class for vertical two-column layout', () => {
37
- const colClass = 'tw-definition-list--columns flex-column flex-row--sm';
38
-
39
- expect(listHasClass(VERTICAL_TWO_COLUMN, colClass)).toBe(true);
40
- expect(listHasClass(VERTICAL_ONE_COLUMN, colClass)).toBe(false);
41
- expect(listHasClass(HORIZONTAL_LEFT_ALIGNED, colClass)).toBe(false);
42
- expect(listHasClass(HORIZONTAL_RIGHT_ALIGNED, colClass)).toBe(false);
43
- expect(listHasClass(HORIZONTAL_JUSTIFIED, colClass)).toBe(false);
44
- });
45
-
46
- it('applies correct class for horiztonal layouts', () => {
47
- const rowClass = 'tw-definition-list--horizontal flex-column';
48
-
49
- expect(listHasClass(VERTICAL_TWO_COLUMN, rowClass)).toBe(false);
50
- expect(listHasClass(VERTICAL_ONE_COLUMN, rowClass)).toBe(false);
51
- expect(listHasClass(HORIZONTAL_LEFT_ALIGNED, rowClass)).toBe(true);
52
- expect(listHasClass(HORIZONTAL_RIGHT_ALIGNED, rowClass)).toBe(true);
53
- expect(listHasClass(HORIZONTAL_JUSTIFIED, rowClass)).toBe(true);
54
- });
55
-
56
- it('applies correct class for alignment', () => {
57
- expect(valueHasClass(VERTICAL_TWO_COLUMN, 'd-flex justify-content-between')).toBe(true);
58
- expect(valueHasClass(VERTICAL_ONE_COLUMN, 'd-flex justify-content-between')).toBe(true);
59
- expect(valueHasClass(HORIZONTAL_LEFT_ALIGNED, 'd-flex justify-content-between')).toBe(true);
60
- expect(valueHasClass(HORIZONTAL_RIGHT_ALIGNED, 'text-sm-right')).toBe(true);
61
- expect(valueHasClass(HORIZONTAL_JUSTIFIED, 'text-sm-justify')).toBe(true);
62
- });
63
-
64
- it('has muted text class on title and value when muted flag is passed', () => {
65
- const muted = shallow(<DefinitionList muted definitions={someDefinitions()} />);
66
- const notMuted = shallow(<DefinitionList definitions={someDefinitions()} />);
67
-
68
- expect(muted.find('dl.tw-definition-list').hasClass('text-muted')).toBe(true);
69
- expect(notMuted.find('dl.tw-definition-list').hasClass('text-muted')).toBe(false);
70
- });
71
-
72
- it('shows action button when one is passed in', () => {
73
- const buttonSpy = jest.fn();
74
-
75
- const definitionList = mount(
76
- <DefinitionList
77
- definitions={[
78
- {
79
- title: 'Name',
80
- value: 'Jenkins',
81
- key: '1',
82
- action: { label: 'A button', onClick: buttonSpy },
83
- },
84
- ]}
85
- />,
86
- );
87
-
88
- definitionList.find('button').simulate('click');
89
- expect(buttonSpy).toHaveBeenCalledTimes(1);
90
- });
91
- });
@@ -1,87 +0,0 @@
1
- import { shallow, mount } from 'enzyme';
2
- import ReactDOM from 'react-dom';
3
-
4
- import DimmerAppendingToBody, { Dimmer } from './Dimmer';
5
-
6
- jest.mock('react-dom');
7
-
8
- describe('Dimmer', () => {
9
- let component;
10
- const props = {
11
- open: true,
12
- fadeContentOnExit: false,
13
- fadeContentOnEnter: false,
14
- onClick: jest.fn(),
15
- children: <div />,
16
- className: undefined,
17
- onClose: undefined,
18
- onExited: jest.fn(),
19
- };
20
-
21
- beforeEach(() => {
22
- jest.spyOn(ReactDOM, 'createPortal').mockImplementation();
23
- ReactDOM.createPortal.mockReturnValue(<Dimmer {...props} />);
24
- component = shallow(<Dimmer {...props} />);
25
- });
26
-
27
- afterEach(() => {
28
- ReactDOM.createPortal.mockClear();
29
- jest.clearAllMocks();
30
- });
31
-
32
- it('is appended to body', () => {
33
- expect(ReactDOM.createPortal).not.toHaveBeenCalled();
34
- mount(<DimmerAppendingToBody {...props} />);
35
-
36
- expect(ReactDOM.createPortal).toHaveBeenCalledTimes(1);
37
- });
38
-
39
- it('renders with right props', () => {
40
- component = mount(
41
- <Dimmer {...props} disableClickToClose={false} transparent={false} scrollable={false} />,
42
- );
43
- expect(component.find(Dimmer)).toHaveLength(1);
44
- expect(component.find(Dimmer).props()).toStrictEqual({
45
- ...props,
46
- disableClickToClose: false,
47
- transparent: false,
48
- scrollable: false,
49
- });
50
- });
51
-
52
- it('do not make Dimmer auto scrollable if scrollable=false', () => {
53
- expect(component.find('.dimmer').hasClass('dimmer--scrollable')).toBe(false);
54
- });
55
-
56
- it('makes Dimmer auto scrollable if scrollable=true', () => {
57
- component.setProps({ scrollable: true });
58
- expect(component.find('.dimmer').hasClass('dimmer--scrollable')).toBe(true);
59
- });
60
-
61
- it('fade content on enter if fadeContentOnEnter is true', () => {
62
- component.setProps({ fadeContentOnEnter: true });
63
- const cssTransition = component.find('CSSTransition');
64
- expect(cssTransition.prop('classNames')).toStrictEqual({
65
- enter: 'dimmer--enter-fade',
66
- enterDone: 'dimmer--enter-done dimmer--enter-fade',
67
- exit: 'dimmer--exit',
68
- });
69
- });
70
-
71
- it('fade content on exit if fadeContentOnExit is true', () => {
72
- component.setProps({ fadeContentOnExit: true });
73
- const cssTransition = component.find('CSSTransition');
74
- expect(cssTransition.prop('classNames')).toStrictEqual({
75
- enter: '',
76
- enterDone: 'dimmer--enter-done',
77
- exit: 'dimmer--exit dimmer--exit-fade',
78
- });
79
- });
80
-
81
- it('calls onExited when the exit animation is finished', () => {
82
- component.setProps({ fadeContentOnExit: true });
83
- const transition = component.find('CSSTransition');
84
- transition.prop('onExited')();
85
- expect(props.onExited).toHaveBeenCalled();
86
- });
87
- });
@@ -1,149 +0,0 @@
1
- import { Field } from '../field/Field';
2
- import { mockMatchMedia, mockResizeObserver, render, screen, userEvent } from '../test-utils';
3
-
4
- import MoneyInput from './MoneyInput';
5
- import messages from './MoneyInput.messages';
6
-
7
- mockMatchMedia();
8
- mockResizeObserver();
9
-
10
- describe('MoneyInput', () => {
11
- const currencies = [
12
- {
13
- header: 'Popular currencies',
14
- },
15
- {
16
- value: 'EUR',
17
- label: 'EUR',
18
- note: 'Euro',
19
- currency: 'eur',
20
- searchable: 'Spain, Germany, France, Austria, Estonia',
21
- },
22
- {
23
- value: 'USD',
24
- label: 'USD',
25
- note: 'United States dollar',
26
- currency: 'usd',
27
- searchable: 'Hong Kong, Saudi Arabia',
28
- },
29
- {
30
- value: 'GBP',
31
- label: 'GBP',
32
- note: 'British pound',
33
- currency: 'gbp',
34
- searchable: 'England, Scotland, Wales',
35
- },
36
- {
37
- header: 'Some other currencies',
38
- },
39
- {
40
- value: 'CAD',
41
- label: 'CAD',
42
- note: 'Canadian dollar',
43
- currency: 'cad',
44
- },
45
- {
46
- value: 'AUD',
47
- label: 'AUD',
48
- note: 'Australian dollar',
49
- currency: 'aud',
50
- },
51
- ] as const;
52
- const props = {
53
- currencies,
54
- selectedCurrency: currencies[1],
55
- searchPlaceholder: 'Type a currency / country',
56
- amount: 1000,
57
- onAmountChange: jest.fn(),
58
- onCurrencyChange: jest.fn(),
59
- };
60
- it.each([
61
- ['asd', ''],
62
- ['1a2s3d', '123'],
63
- ['±!@#$^*_+?><', ''],
64
- ['1±!@#$^*,_+?><2', '1,2'],
65
- ['12,3', '12,3'],
66
- ['12.3', '12.3'],
67
- ])("ignores the letters when typed '%s' and shows '%s'", async (testValue, expectedValue) => {
68
- render(<MoneyInput {...props} amount={null} />);
69
-
70
- const input = screen.getByRole('textbox');
71
- await userEvent.type(input, testValue);
72
- expect(input).toHaveValue(expectedValue);
73
- });
74
-
75
- it('supports custom `aria-labelledby` attribute', () => {
76
- render(
77
- <>
78
- {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
79
- <label id="prioritized-label">Prioritized label</label>
80
- <MoneyInput {...props} aria-labelledby="prioritized-label" />
81
- </>,
82
- );
83
-
84
- expect(screen.getAllByLabelText('Prioritized label')[0]).toHaveClass('input-group');
85
- });
86
-
87
- it('supports `Field` for labeling', () => {
88
- render(
89
- <Field label="Recipient gets">
90
- <MoneyInput {...props} />
91
- </Field>,
92
- );
93
- expect(screen.getAllByRole('group')[0]).toHaveAccessibleName(/^Recipient gets/);
94
- });
95
-
96
- describe('ids', () => {
97
- it('should guarantee id and connect the input with the selected currency via withId HoC', () => {
98
- render(<MoneyInput {...props} />);
99
- const input = screen.getByRole('textbox');
100
- const button = screen.getByRole('combobox');
101
- expect(input.getAttribute('id')).toBeTruthy();
102
- expect(input).toHaveAttribute('aria-describedby', button.getAttribute('id'));
103
- });
104
-
105
- it('should have unique id for the select filter with predefined id', async () => {
106
- const fieldId = 'myFieldId';
107
- render(
108
- <Field label="Multiple currencies" id={fieldId}>
109
- <MoneyInput {...props} />
110
- </Field>,
111
- );
112
- await userEvent.click(screen.getByRole('combobox'));
113
- expect(screen.getByLabelText(props.searchPlaceholder)).toHaveAttribute(
114
- 'id',
115
- `${fieldId}SelectedCurrencySearch`,
116
- );
117
- });
118
-
119
- it('should have unique id for the select filter without predefined id', async () => {
120
- render(
121
- <Field label="Multiple currencies">
122
- <MoneyInput {...props} />
123
- </Field>,
124
- );
125
- await userEvent.click(screen.getByRole('combobox'));
126
- expect(screen.getByLabelText(props.searchPlaceholder)).toHaveAttribute(
127
- 'id',
128
- expect.stringMatching(/^:.*?:SelectedCurrencySearch$/),
129
- );
130
- });
131
- });
132
-
133
- it('should have AT label for the currency dropdown', () => {
134
- render(<MoneyInput {...props} />);
135
- expect(screen.getByRole('combobox')).toHaveAttribute(
136
- 'aria-label',
137
- messages.selectCurrencyLabel.defaultMessage,
138
- );
139
- });
140
-
141
- it('should have a listbox label', async () => {
142
- render(<MoneyInput {...props} />);
143
- const trigger = screen.getByRole('combobox');
144
- await userEvent.click(trigger);
145
- const triggerLabel = trigger.getAttribute('aria-label');
146
- expect(triggerLabel).toBeTruthy();
147
- expect(screen.getByRole('listbox', { name: triggerLabel ?? '' })).toBeInTheDocument();
148
- });
149
- });