@transferwise/components 46.39.0 → 46.40.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 (123) hide show
  1. package/build/index.js +176 -419
  2. package/build/index.js.map +1 -1
  3. package/build/index.mjs +176 -419
  4. package/build/index.mjs.map +1 -1
  5. package/build/types/index.d.ts +2 -1
  6. package/build/types/index.d.ts.map +1 -1
  7. package/build/types/processIndicator/ProcessIndicator.d.ts +1 -1
  8. package/build/types/processIndicator/ProcessIndicator.d.ts.map +1 -1
  9. package/build/types/upload/Upload.d.ts +91 -55
  10. package/build/types/upload/Upload.d.ts.map +1 -1
  11. package/build/types/upload/Upload.messages.d.ts +42 -60
  12. package/build/types/upload/Upload.messages.d.ts.map +1 -1
  13. package/build/types/upload/index.d.ts +2 -2
  14. package/build/types/upload/index.d.ts.map +1 -1
  15. package/build/types/upload/steps/completeStep/completeStep.d.ts +11 -18
  16. package/build/types/upload/steps/completeStep/completeStep.d.ts.map +1 -1
  17. package/build/types/upload/steps/completeStep/index.d.ts +2 -1
  18. package/build/types/upload/steps/completeStep/index.d.ts.map +1 -1
  19. package/build/types/upload/steps/index.d.ts +3 -4
  20. package/build/types/upload/steps/index.d.ts.map +1 -1
  21. package/build/types/upload/steps/processingStep/index.d.ts +2 -1
  22. package/build/types/upload/steps/processingStep/index.d.ts.map +1 -1
  23. package/build/types/upload/steps/processingStep/processingStep.d.ts +11 -13
  24. package/build/types/upload/steps/processingStep/processingStep.d.ts.map +1 -1
  25. package/build/types/upload/steps/uploadImageStep/index.d.ts +2 -1
  26. package/build/types/upload/steps/uploadImageStep/index.d.ts.map +1 -1
  27. package/build/types/upload/steps/uploadImageStep/uploadImageStep.d.ts +14 -18
  28. package/build/types/upload/steps/uploadImageStep/uploadImageStep.d.ts.map +1 -1
  29. package/build/types/upload/utils/asyncFileRead/asyncFileRead.d.ts +1 -1
  30. package/build/types/upload/utils/asyncFileRead/asyncFileRead.d.ts.map +1 -1
  31. package/build/types/upload/utils/asyncFileRead/index.d.ts +1 -1
  32. package/build/types/upload/utils/asyncFileRead/index.d.ts.map +1 -1
  33. package/build/types/upload/utils/getFileType/getFileType.d.ts +1 -1
  34. package/build/types/upload/utils/getFileType/getFileType.d.ts.map +1 -1
  35. package/build/types/upload/utils/getFileType/index.d.ts +1 -1
  36. package/build/types/upload/utils/getFileType/index.d.ts.map +1 -1
  37. package/build/types/upload/utils/index.d.ts +5 -7
  38. package/build/types/upload/utils/index.d.ts.map +1 -1
  39. package/build/types/upload/utils/isSizeValid/index.d.ts +1 -1
  40. package/build/types/upload/utils/isSizeValid/index.d.ts.map +1 -1
  41. package/build/types/upload/utils/isSizeValid/isSizeValid.d.ts +1 -1
  42. package/build/types/upload/utils/isSizeValid/isSizeValid.d.ts.map +1 -1
  43. package/build/types/upload/utils/isTypeValid/index.d.ts +1 -1
  44. package/build/types/upload/utils/isTypeValid/index.d.ts.map +1 -1
  45. package/build/types/upload/utils/isTypeValid/isTypeValid.d.ts +1 -1
  46. package/build/types/upload/utils/isTypeValid/isTypeValid.d.ts.map +1 -1
  47. package/build/types/upload/utils/postData/index.d.ts +1 -1
  48. package/build/types/upload/utils/postData/index.d.ts.map +1 -1
  49. package/build/types/upload/utils/postData/postData.d.ts +11 -1
  50. package/build/types/upload/utils/postData/postData.d.ts.map +1 -1
  51. package/package.json +3 -3
  52. package/src/index.ts +2 -1
  53. package/src/processIndicator/ProcessIndicator.tsx +1 -1
  54. package/src/upload/Upload.spec.js +3 -14
  55. package/src/upload/Upload.story.tsx +37 -0
  56. package/src/upload/{Upload.js → Upload.tsx} +164 -169
  57. package/src/upload/index.ts +2 -0
  58. package/src/upload/steps/completeStep/completeStep.spec.js +3 -2
  59. package/src/upload/steps/completeStep/completeStep.tsx +74 -0
  60. package/src/upload/steps/completeStep/index.ts +2 -0
  61. package/src/upload/steps/{index.js → index.ts} +0 -1
  62. package/src/upload/steps/processingStep/index.ts +2 -0
  63. package/src/upload/steps/processingStep/processingStep.tsx +53 -0
  64. package/src/upload/steps/uploadImageStep/index.ts +2 -0
  65. package/src/upload/steps/uploadImageStep/{uploadImageStep.js → uploadImageStep.tsx} +17 -23
  66. package/src/upload/utils/asyncFileRead/asyncFileRead.spec.ts +14 -0
  67. package/src/upload/utils/asyncFileRead/asyncFileRead.ts +12 -0
  68. package/src/upload/utils/getFileType/getFileType.spec.ts +22 -0
  69. package/src/upload/utils/getFileType/getFileType.ts +16 -0
  70. package/src/upload/utils/{index.js → index.ts} +0 -2
  71. package/src/upload/utils/isSizeValid/{isSizeValid.spec.js → isSizeValid.spec.ts} +3 -3
  72. package/src/upload/utils/isSizeValid/isSizeValid.ts +3 -0
  73. package/src/upload/utils/isTypeValid/isTypeValid.spec.ts +62 -0
  74. package/src/upload/utils/isTypeValid/isTypeValid.ts +19 -0
  75. package/src/upload/utils/postData/postData.spec.ts +65 -0
  76. package/src/upload/utils/postData/postData.ts +36 -0
  77. package/src/uploadInput/UploadInput.tsx +1 -1
  78. package/build/types/upload/steps/mediaUploadStep/index.d.ts +0 -2
  79. package/build/types/upload/steps/mediaUploadStep/index.d.ts.map +0 -1
  80. package/build/types/upload/steps/mediaUploadStep/mediaUploadStep.d.ts +0 -24
  81. package/build/types/upload/steps/mediaUploadStep/mediaUploadStep.d.ts.map +0 -1
  82. package/build/types/upload/uploadSteps.d.ts +0 -5
  83. package/build/types/upload/uploadSteps.d.ts.map +0 -1
  84. package/build/types/upload/utils/getSupportedSpotMimeTypes/getSupportedSpotMimeTypes.d.ts +0 -2
  85. package/build/types/upload/utils/getSupportedSpotMimeTypes/getSupportedSpotMimeTypes.d.ts.map +0 -1
  86. package/build/types/upload/utils/getSupportedSpotMimeTypes/index.d.ts +0 -2
  87. package/build/types/upload/utils/getSupportedSpotMimeTypes/index.d.ts.map +0 -1
  88. package/build/types/upload/utils/requestMedia/index.d.ts +0 -2
  89. package/build/types/upload/utils/requestMedia/index.d.ts.map +0 -1
  90. package/build/types/upload/utils/requestMedia/requestMedia.d.ts +0 -2
  91. package/build/types/upload/utils/requestMedia/requestMedia.d.ts.map +0 -1
  92. package/src/upload/Upload.story.js +0 -36
  93. package/src/upload/index.js +0 -2
  94. package/src/upload/steps/completeStep/completeStep.js +0 -98
  95. package/src/upload/steps/completeStep/index.js +0 -1
  96. package/src/upload/steps/mediaUploadStep/index.js +0 -1
  97. package/src/upload/steps/mediaUploadStep/mediaUploadStep.js +0 -80
  98. package/src/upload/steps/mediaUploadStep/mediaUploadStep.spec.js +0 -77
  99. package/src/upload/steps/processingStep/index.js +0 -1
  100. package/src/upload/steps/processingStep/processingStep.js +0 -73
  101. package/src/upload/steps/uploadImageStep/index.js +0 -1
  102. package/src/upload/uploadSteps.ts +0 -5
  103. package/src/upload/utils/asyncFileRead/asyncFileRead.js +0 -11
  104. package/src/upload/utils/asyncFileRead/asyncFileRead.spec.js +0 -17
  105. package/src/upload/utils/getFileType/getFileType.js +0 -19
  106. package/src/upload/utils/getFileType/getFileType.spec.js +0 -33
  107. package/src/upload/utils/getSupportedSpotMimeTypes/getSupportedSpotMimeTypes.js +0 -18
  108. package/src/upload/utils/getSupportedSpotMimeTypes/getSupportedSpotMimeTypes.spec.js +0 -22
  109. package/src/upload/utils/getSupportedSpotMimeTypes/index.js +0 -1
  110. package/src/upload/utils/isSizeValid/isSizeValid.js +0 -1
  111. package/src/upload/utils/isTypeValid/isTypeValid.js +0 -26
  112. package/src/upload/utils/isTypeValid/isTypeValid.spec.js +0 -68
  113. package/src/upload/utils/postData/postData.js +0 -18
  114. package/src/upload/utils/postData/postData.spec.js +0 -109
  115. package/src/upload/utils/requestMedia/index.js +0 -1
  116. package/src/upload/utils/requestMedia/requestMedia.js +0 -26
  117. package/src/upload/utils/requestMedia/requestMedia.spec.js +0 -44
  118. /package/src/upload/{Upload.messages.js → Upload.messages.ts} +0 -0
  119. /package/src/upload/utils/asyncFileRead/{index.js → index.ts} +0 -0
  120. /package/src/upload/utils/getFileType/{index.js → index.ts} +0 -0
  121. /package/src/upload/utils/isSizeValid/{index.js → index.ts} +0 -0
  122. /package/src/upload/utils/isTypeValid/{index.js → index.ts} +0 -0
  123. /package/src/upload/utils/postData/{index.js → index.ts} +0 -0
@@ -1,80 +0,0 @@
1
- import { Upload as UploadIcon } from '@transferwise/icons';
2
- import PropTypes from 'prop-types';
3
-
4
- import Body from '../../../body';
5
- import Button from '../../../button/Button';
6
- import { Typography } from '../../../common';
7
- import Title from '../../../title';
8
- import { getSupportedSpotMimeTypes, requestMedia } from '../../utils';
9
-
10
- const MediaUploadStep = ({
11
- isComplete,
12
- usAccept,
13
- usButtonText,
14
- usDisabled,
15
- usHelpImage,
16
- usLabel,
17
- usPlaceholder,
18
- fileDropped,
19
- }) => {
20
- const getMediaFile = () => {
21
- const allowedMimeTypes = getSupportedSpotMimeTypes(usAccept);
22
-
23
- if (allowedMimeTypes.length === 0) {
24
- throw new Error('provided mimeTypes not supported');
25
- }
26
-
27
- const mediaRequest = { allowedMimeTypes };
28
- requestMedia(mediaRequest).then((file) => fileDropped(file));
29
- };
30
-
31
- const getImage = () => {
32
- if (!usHelpImage) {
33
- return (
34
- <div className="circle circle-sm circle-inverse p-t-1">
35
- <UploadIcon size={24} />
36
- </div>
37
- );
38
- }
39
-
40
- if (typeof usHelpImage === 'string') {
41
- return <img src={usHelpImage} alt={usLabel} className="thumbnail text-xs-center" />;
42
- }
43
-
44
- return usHelpImage;
45
- };
46
-
47
- return (
48
- <div>
49
- <div className="droppable-default-card" aria-hidden={isComplete}>
50
- <div className="droppable-card-content">
51
- <div className="m-b-3">{getImage()}</div>
52
- {usLabel && (
53
- <Title type={Typography.TITLE_BODY} className="m-b-1">
54
- {usLabel}
55
- </Title>
56
- )}
57
- {usPlaceholder && (
58
- <Body as="p" type={Typography.BODY_LARGE} className="m-b-3">{`${usPlaceholder}`}</Body>
59
- )}
60
- <Button disabled={usDisabled} onClick={getMediaFile}>
61
- {usButtonText || <UploadIcon size={24} className="m-r-0" />}
62
- </Button>
63
- </div>
64
- </div>
65
- </div>
66
- );
67
- };
68
-
69
- MediaUploadStep.propTypes = {
70
- fileDropped: PropTypes.func.isRequired,
71
- isComplete: PropTypes.bool.isRequired,
72
- usAccept: PropTypes.string.isRequired,
73
- usButtonText: PropTypes.string.isRequired,
74
- usDisabled: PropTypes.bool.isRequired,
75
- usHelpImage: PropTypes.node.isRequired,
76
- usLabel: PropTypes.string.isRequired,
77
- usPlaceholder: PropTypes.string.isRequired,
78
- };
79
-
80
- export default MediaUploadStep;
@@ -1,77 +0,0 @@
1
- import { render, fireEvent, screen } from '../../../test-utils';
2
-
3
- import MediaUploadStep from '.';
4
-
5
- describe('mediaUploadStep', () => {
6
- const defaultProps = {
7
- fileDropped: jest.fn(),
8
- isComplete: false,
9
- usAccept: '*',
10
- usButtonText: '',
11
- usDisabled: false,
12
- usLabel: '',
13
- usHelpImage: '',
14
- usPlaceholder: '',
15
- };
16
-
17
- const renderMediaUploadStep = (props = {}) =>
18
- render(<MediaUploadStep {...defaultProps} {...props} />);
19
-
20
- const originalMicroApps = window.microapps;
21
- const image64 = {
22
- bytes:
23
- 'iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAA1BMVEX/AAAZ4gk3AAAASElEQVR4nO3BgQAAAADDoPlTX+AIVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDcaiAAFXD1ujAAAAAElFTkSuQmCC',
24
- mimeType: 'image/jpeg',
25
- };
26
- const requestMedia = jest.fn().mockImplementation(() => Promise.resolve(image64));
27
-
28
- beforeAll(() => {
29
- window.microapps = { requestMedia };
30
- });
31
-
32
- afterAll(() => {
33
- window.microapps = originalMicroApps;
34
- });
35
-
36
- it('renders help image passed as url string', () => {
37
- renderMediaUploadStep({
38
- usHelpImage: 'usHelpImage',
39
- usLabel: 'usLabel',
40
- });
41
- expect(screen.getByAltText('usLabel')).toBeInTheDocument();
42
- });
43
-
44
- it('renders help images passed as image node', () => {
45
- const usHelpImage = (
46
- <span role="img" aria-label="rocket">
47
- 🚀
48
- </span>
49
- );
50
-
51
- renderMediaUploadStep({ usHelpImage });
52
- expect(screen.getByLabelText('rocket')).toBeInTheDocument();
53
- });
54
-
55
- it('renders label', () => {
56
- renderMediaUploadStep({ usLabel: 'usLabel' });
57
- expect(screen.getByText('usLabel')).toBeInTheDocument();
58
- });
59
-
60
- it('renders placeholder', () => {
61
- renderMediaUploadStep({ usPlaceholder: 'usPlaceholder' });
62
- expect(screen.getByText('usPlaceholder')).toBeInTheDocument();
63
- });
64
-
65
- it('renders buttonText', () => {
66
- renderMediaUploadStep({ usButtonText: 'usButtonText' });
67
- expect(screen.getByText('usButtonText')).toBeInTheDocument();
68
- });
69
-
70
- it(`calls microapps' requestMedia API to get file while upload button is clicked`, () => {
71
- const allowedMimeTypes = ['image/jpeg', 'video/*', 'application/pdf'];
72
- renderMediaUploadStep({ usButtonText: 'usButtonText' });
73
- expect(requestMedia).not.toHaveBeenCalled();
74
- fireEvent.click(screen.getByText('usButtonText'));
75
- expect(requestMedia).toHaveBeenCalledWith({ allowedMimeTypes });
76
- });
77
- });
@@ -1 +0,0 @@
1
- export { default } from './processingStep';
@@ -1,73 +0,0 @@
1
- import { useTheme } from '@wise/components-theming';
2
- import classNames from 'classnames';
3
- import PropTypes from 'prop-types';
4
-
5
- import Button from '../../../button';
6
- import { Status, Size, Typography } from '../../../common';
7
- import ProcessIndicator from '../../../processIndicator';
8
- import Title from '../../../title';
9
-
10
- const ProcessingStep = (props) => {
11
- const {
12
- isComplete,
13
- isError,
14
- isSuccess,
15
- onAnimationCompleted,
16
- onClear,
17
- psButtonText,
18
- psProcessingText,
19
- psButtonDisabled,
20
- } = props;
21
-
22
- const { isModern } = useTheme();
23
-
24
- let processStatus = Status.PROCESSING;
25
- if (isError) {
26
- processStatus = Status.FAILED;
27
- }
28
- if (isSuccess) {
29
- processStatus = Status.SUCCEEDED;
30
- }
31
-
32
- return (
33
- <div className="droppable-processing-card droppable-card" aria-hidden={isComplete}>
34
- <div className="droppable-card-content">
35
- <ProcessIndicator
36
- size={Size.Small}
37
- status={processStatus}
38
- onAnimationCompleted={(status) => onAnimationCompleted(status)}
39
- />
40
- <Title
41
- className={classNames({
42
- 'm-t-3': !isModern,
43
- 'm-b-3': !isModern,
44
- 'm-t-2': isModern,
45
- 'm-b-2': isModern,
46
- })}
47
- type={Typography.TITLE_BODY}
48
- aria-live="polite"
49
- >
50
- {psProcessingText}
51
- </Title>
52
- {psButtonText && (
53
- <Button disabled={psButtonDisabled} onClick={(event) => onClear(event)}>
54
- {psButtonText}
55
- </Button>
56
- )}
57
- </div>
58
- </div>
59
- );
60
- };
61
-
62
- ProcessingStep.propTypes = {
63
- isComplete: PropTypes.bool.isRequired,
64
- isError: PropTypes.bool.isRequired,
65
- isSuccess: PropTypes.bool.isRequired,
66
- onAnimationCompleted: PropTypes.func.isRequired,
67
- onClear: PropTypes.func.isRequired,
68
- psButtonText: PropTypes.string.isRequired,
69
- psProcessingText: PropTypes.string.isRequired,
70
- psButtonDisabled: PropTypes.bool.isRequired,
71
- };
72
-
73
- export default ProcessingStep;
@@ -1 +0,0 @@
1
- export { default } from './uploadImageStep';
@@ -1,5 +0,0 @@
1
- // TODO: consider to move this enum into component file once we migrate it on TypeScript or replace with some common enum
2
- export enum UploadStep {
3
- UPLOAD_IMAGE_STEP = 'uploadImageStep',
4
- MEDIA_UPLOAD_STEP = 'mediaUploadStep',
5
- }
@@ -1,11 +0,0 @@
1
- export const asyncFileRead = (file) =>
2
- new Promise((resolve, reject) => {
3
- const reader = new FileReader();
4
- reader.readAsDataURL(file);
5
- reader.addEventListener('load', (event) => {
6
- resolve(event.target.result);
7
- });
8
- reader.addEventListener('error', (event) => {
9
- reject(event);
10
- });
11
- });
@@ -1,17 +0,0 @@
1
- import { asyncFileRead } from '.';
2
-
3
- describe('asyncFileRead', () => {
4
- it('should resolve with data64', () => {
5
- const file = new Blob(['foo'], { type: 'text/plain' });
6
- expect.assertions(1);
7
- return asyncFileRead(file).then((data) =>
8
- expect(data).toStrictEqual('data:text/plain;base64,Zm9v'),
9
- );
10
- });
11
-
12
- it('should reject if wrong file is given', () => {
13
- const file = 'Not a blob';
14
- expect.assertions(1);
15
- return asyncFileRead(file).catch((error) => expect(error).toBeTruthy());
16
- });
17
- });
@@ -1,19 +0,0 @@
1
- export const getFileType = (file, file64) => {
2
- if (!file && !file64) {
3
- return '';
4
- }
5
-
6
- if (file && file.type && file.type !== '') {
7
- return file.type ?? '';
8
- }
9
-
10
- if (file64) {
11
- const regex = /^data:([a-z]+\/[a-z]+);/;
12
- const typeFromEncoded = file64.match(regex);
13
-
14
- if (typeFromEncoded && typeFromEncoded[1]) {
15
- return typeFromEncoded[1] ?? '';
16
- }
17
- }
18
- return '';
19
- };
@@ -1,33 +0,0 @@
1
- import { getFileType } from '.';
2
-
3
- const imageFile = {
4
- type: 'image/png',
5
- };
6
-
7
- const data64Img = 'data:image/png;something';
8
-
9
- describe('getFileType', () => {
10
- describe('returns null', () => {
11
- it(`when both file and file64 haven't been provided`, () => {
12
- expect(getFileType('', '')).toBe('');
13
- });
14
- it(`when file has no type and file64 hasn't been provided`, () => {
15
- expect(getFileType({}, '')).toBe('');
16
- });
17
- it(`when file has empty type and file64 hasn't been provided`, () => {
18
- expect(getFileType({ type: '' }, '')).toBe('');
19
- });
20
- it(`when file hasn't been provided and file64 is not supported`, () => {
21
- expect(getFileType('', 'data:something-unexpected')).toBe('');
22
- });
23
- });
24
-
25
- describe('returns file-type', () => {
26
- it('when file has type defined', () => {
27
- expect(getFileType(imageFile, '')).toBe(imageFile.type);
28
- });
29
- it('when file has no type and file64 is supported', () => {
30
- expect(getFileType('', data64Img)).toBe('image/png');
31
- });
32
- });
33
- });
@@ -1,18 +0,0 @@
1
- // Spot Platform's Media API only support these MIME types
2
- const SUPPORTED_MIME_TYPES = ['image/jpeg', 'video/*', 'application/pdf'];
3
-
4
- export const getSupportedSpotMimeTypes = (mimeTypes) => {
5
- if (mimeTypes === '*') {
6
- return SUPPORTED_MIME_TYPES;
7
- }
8
-
9
- const mimeTypesArray = mimeTypes.split(',');
10
- const mimeMapping = {
11
- 'image/*': 'image/jpeg',
12
- 'application/*': 'application/pdf',
13
- };
14
-
15
- const mapSupportedMimeTypes = mimeTypesArray.map((type) => mimeMapping[type] || type);
16
-
17
- return mapSupportedMimeTypes.filter((type) => SUPPORTED_MIME_TYPES.includes(type));
18
- };
@@ -1,22 +0,0 @@
1
- import { getSupportedSpotMimeTypes } from '.';
2
-
3
- describe(getSupportedSpotMimeTypes, () => {
4
- it('returns all supported mime types when * is passed', () => {
5
- expect(getSupportedSpotMimeTypes('*')).toStrictEqual([
6
- 'image/jpeg',
7
- 'video/*',
8
- 'application/pdf',
9
- ]);
10
- });
11
-
12
- it('maps image/* and application/* according to the supported', () => {
13
- expect(getSupportedSpotMimeTypes('image/*,application/*')).toStrictEqual([
14
- 'image/jpeg',
15
- 'application/pdf',
16
- ]);
17
- });
18
-
19
- it('filters out unsupported mime types', () => {
20
- expect(getSupportedSpotMimeTypes('image/jpeg,text/csv')).toStrictEqual(['image/jpeg']);
21
- });
22
- });
@@ -1 +0,0 @@
1
- export { getSupportedSpotMimeTypes } from './getSupportedSpotMimeTypes';
@@ -1 +0,0 @@
1
- export const isSizeValid = (file, maxSize) => Number.isInteger(maxSize) && file.size <= maxSize;
@@ -1,26 +0,0 @@
1
- import { getFileType } from '../getFileType';
2
-
3
- export const isTypeValid = (file, rule, file64) => {
4
- if (!file || !rule) {
5
- return false;
6
- }
7
-
8
- const allowedTypes = rule.replace(/\s/g, '').split(',');
9
- const fileType = getFileType(file, file64);
10
-
11
- if (rule === '*' || allowedTypes.includes(fileType)) {
12
- return true;
13
- }
14
-
15
- return allowedTypes.some((type) => {
16
- const splittedRule = type.split('/');
17
- const typeAllowed = splittedRule[0];
18
- const extensionAllowed = splittedRule[1];
19
-
20
- if (extensionAllowed !== '*') {
21
- return false;
22
- }
23
-
24
- return fileType.includes(typeAllowed);
25
- });
26
- };
@@ -1,68 +0,0 @@
1
- import { isTypeValid } from '.';
2
-
3
- const pdfFile = {
4
- type: 'application/pdf',
5
- };
6
-
7
- const pngFile = {
8
- type: 'image/png',
9
- };
10
-
11
- const data64Img = 'data:image/png;something';
12
-
13
- describe('isTypeValid', () => {
14
- describe('when file or rule are not provided', () => {
15
- it('returns false for matching format', () => {
16
- expect(isTypeValid('', '*', null)).toBe(false);
17
- expect(isTypeValid(data64Img, '', null)).toBe(false);
18
- });
19
- });
20
- describe('when type is provided', () => {
21
- it.each([pdfFile, pngFile])('returns true for wildcard rule %s', (file) => {
22
- expect(isTypeValid(file, '*', null)).toBe(true);
23
- });
24
-
25
- it('returns true for matching type', () => {
26
- expect(isTypeValid(pdfFile, 'application/*', null)).toBe(true);
27
- });
28
-
29
- it('returns true for matching type when multiple rules provided', () => {
30
- expect(isTypeValid(pdfFile, 'application/*, image/*', null)).toBe(true);
31
- });
32
-
33
- it('returns true for matching subtype', () => {
34
- expect(isTypeValid(pdfFile, 'application/pdf', null)).toBe(true);
35
- });
36
-
37
- it('returns true for matching subtype when multiple rules provided', () => {
38
- expect(isTypeValid(pngFile, 'application/xls, image/png', null)).toBe(true);
39
- });
40
-
41
- it('can parse multiple types with extra whitespace', () => {
42
- expect(isTypeValid(pngFile, ' application/xls, image/png ', null)).toBe(true);
43
- });
44
-
45
- it('returns false for unsupported type', () => {
46
- expect(isTypeValid(pngFile, 'application/*', null)).toBe(false);
47
- });
48
-
49
- it('returns false for unsupported subtype', () => {
50
- expect(isTypeValid(pdfFile, 'application/xls', null)).toBe(false);
51
- });
52
-
53
- it('returns false for unsupported subtype when multiple rules provided', () => {
54
- expect(isTypeValid(pngFile, 'application/xls, image/jpeg', null)).toBe(false);
55
- });
56
- });
57
- describe('when type is not provided', () => {
58
- it('returns true for supported file', () => {
59
- expect(isTypeValid({ type: '' }, 'image/png', data64Img)).toBe(true);
60
- expect(isTypeValid({ type: '' }, 'image/*', data64Img)).toBe(true);
61
- });
62
-
63
- it('returns false for unsupported file', () => {
64
- expect(isTypeValid({ type: '' }, 'image/jpeg', data64Img)).toBe(false);
65
- expect(isTypeValid({ type: '' }, 'application/*', data64Img)).toBe(false);
66
- });
67
- });
68
- });
@@ -1,18 +0,0 @@
1
- export const postData = (httpOptions, data = {}, fetcher = fetch) =>
2
- fetcher(`${httpOptions.url}`, {
3
- method: 'POST',
4
- body: data,
5
- ...httpOptions,
6
- })
7
- .then((response) => {
8
- if (!response.ok) {
9
- const error = new Error(response.statusText);
10
- error.status = response.status;
11
- error.response = response;
12
- throw error;
13
- }
14
- return response;
15
- })
16
- .catch((error) => {
17
- throw error;
18
- });
@@ -1,109 +0,0 @@
1
- import { postData } from '.';
2
-
3
- const HTTPOPTIONS = { url: 'a-url' };
4
- const DATA = 'some-data';
5
-
6
- describe('postData', () => {
7
- afterEach(() => {
8
- global.fetch.mockClear();
9
- });
10
-
11
- it('should work with resolve', async () => {
12
- const RESOLVE_RESPONSE = { ok: true, someOtherStuff: 'someOtherStuff' };
13
- jest.spyOn(global, 'fetch').mockImplementation(() => Promise.resolve(RESOLVE_RESPONSE));
14
-
15
- expect.assertions(1);
16
-
17
- await expect(postData(HTTPOPTIONS, DATA)).resolves.toStrictEqual(RESOLVE_RESPONSE);
18
- });
19
-
20
- it('should throw when call fails', async () => {
21
- const REJECT_RESPONSE = { status: '500', statusText: 'Rejected' };
22
- jest.spyOn(global, 'fetch').mockImplementation(() => Promise.reject(REJECT_RESPONSE));
23
-
24
- expect.assertions(1);
25
- await expect(postData(HTTPOPTIONS, DATA)).rejects.toStrictEqual(REJECT_RESPONSE);
26
- });
27
-
28
- it('should throw an Error when API returns an error code', async () => {
29
- expect.assertions(1);
30
-
31
- const ERROR_RESPONSE = { status: '500', statusText: 'Internal server error', ok: false };
32
- jest.spyOn(global, 'fetch').mockImplementation(() => Promise.resolve(ERROR_RESPONSE));
33
-
34
- await expect(postData(HTTPOPTIONS, DATA)).rejects.toStrictEqual(expect.any(Error));
35
- });
36
-
37
- it('should include the full response in the Error thrown', async () => {
38
- expect.assertions(1);
39
-
40
- const ERROR_RESPONSE = { status: '500', statusText: 'Internal server error', ok: false };
41
- jest.spyOn(global, 'fetch').mockImplementation(() => Promise.resolve(ERROR_RESPONSE));
42
-
43
- try {
44
- await postData(HTTPOPTIONS, DATA);
45
- } catch (error) {
46
- expect(error.response).toStrictEqual(ERROR_RESPONSE);
47
- }
48
- });
49
-
50
- it('should pass additional form data to request body', () => {
51
- const data = { file: 'file', profileId: '1' };
52
- const mockFetch = jest.fn(() => Promise.resolve({ ok: true }));
53
- global.fetch = mockFetch;
54
-
55
- postData(HTTPOPTIONS, data);
56
-
57
- expect(mockFetch.mock.calls[0][1].body).toStrictEqual(data);
58
- });
59
-
60
- it('should override `Content-type` and add any custom headers to the request', () => {
61
- const CUSTOM_CONTENT_TYPE = 'foo';
62
- const CUSTOM_LANGUAGE = 'hu';
63
-
64
- const mockFetch = jest.fn(() => Promise.resolve({ ok: true }));
65
- global.fetch = mockFetch;
66
-
67
- postData(
68
- {
69
- ...HTTPOPTIONS,
70
- headers: { 'Content-type': CUSTOM_CONTENT_TYPE, 'Accept-language': CUSTOM_LANGUAGE },
71
- },
72
- DATA,
73
- );
74
-
75
- expect(mockFetch.mock.calls[0][1].headers['Content-type']).toStrictEqual(CUSTOM_CONTENT_TYPE);
76
- expect(mockFetch.mock.calls[0][1].headers['Accept-language']).toStrictEqual(CUSTOM_LANGUAGE);
77
- });
78
-
79
- it('should set method to `POST` by default', () => {
80
- const mockFetch = jest.fn(() => Promise.resolve({ ok: true }));
81
- global.fetch = mockFetch;
82
-
83
- postData(HTTPOPTIONS, DATA);
84
-
85
- expect(mockFetch.mock.calls[0][1].method).toStrictEqual('POST');
86
- });
87
-
88
- it('should not set `Content-type` by default', () => {
89
- const mockFetch = jest.fn(() => Promise.resolve({ ok: true }));
90
- global.fetch = mockFetch;
91
-
92
- postData(HTTPOPTIONS, DATA);
93
-
94
- expect(mockFetch.mock.calls[0][1]['Content-type']).toBeUndefined();
95
- });
96
-
97
- describe('when passed a fetcher as third argument', () => {
98
- it('should call that instead of global.fetch', () => {
99
- const RESOLVE_RESPONSE = new Response('', { status: 200 });
100
-
101
- const fetcher = jest.fn(async () => RESOLVE_RESPONSE);
102
-
103
- postData(HTTPOPTIONS, DATA, fetcher);
104
-
105
- expect(global.fetch).not.toHaveBeenCalled();
106
- expect(fetcher).toHaveBeenCalledTimes(1);
107
- });
108
- });
109
- });
@@ -1 +0,0 @@
1
- export { requestMedia } from './requestMedia';
@@ -1,26 +0,0 @@
1
- export const requestMedia = (mediaRequest) =>
2
- new Promise((resolve, reject) => {
3
- if (typeof window === 'undefined' || typeof window.microapps === 'undefined') {
4
- reject(`microapps must be available in window to use Spot Platform's Media API`);
5
- }
6
-
7
- window.microapps
8
- .requestMedia(mediaRequest)
9
- .then((response) => {
10
- const fileByteArray = base64ToByteArray(response.bytes);
11
- const blob = new Blob([fileByteArray], { type: response.mimeType });
12
- resolve(blob);
13
- })
14
- .catch((error) => reject(error));
15
- });
16
-
17
- const base64ToByteArray = (base64String) => {
18
- const byteCharacters = atob(base64String);
19
- const byteCharactersLength = byteCharacters.length;
20
- const byteArray = new Array(byteCharactersLength);
21
-
22
- for (let i = 0; i < byteCharactersLength; i += 1) {
23
- byteArray[i] = byteCharacters.charCodeAt(i);
24
- }
25
- return new Uint8Array(byteArray);
26
- };
@@ -1,44 +0,0 @@
1
- import { requestMedia } from '.';
2
-
3
- const mediaRequest = { allowedMimeTypes: ['images/jpeg'] };
4
-
5
- describe('requestMedia', () => {
6
- describe('when microapps is not available in windows', () => {
7
- it('rejects with an error', () => {
8
- expect.assertions(1);
9
- return requestMedia(mediaRequest).catch((error) =>
10
- expect(error).toStrictEqual(
11
- `microapps must be available in window to use Spot Platform's Media API`,
12
- ),
13
- );
14
- });
15
- });
16
-
17
- describe('when microapps is available in windows', () => {
18
- const originalMicroApps = window.microapps;
19
- const image64 = {
20
- bytes:
21
- 'iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAA1BMVEX/AAAZ4gk3AAAASElEQVR4nO3BgQAAAADDoPlTX+AIVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDcaiAAFXD1ujAAAAAElFTkSuQmCC',
22
- mimeType: 'image/jpeg',
23
- };
24
- const microappsRequestMedia = jest.fn().mockImplementation(() => Promise.resolve(image64));
25
-
26
- beforeAll(() => {
27
- window.microapps = { requestMedia: microappsRequestMedia };
28
- });
29
-
30
- afterAll(() => {
31
- window.microapps = originalMicroApps;
32
- });
33
-
34
- it(`calls microapps' requestMedia API when it's available in windows`, () => {
35
- requestMedia(mediaRequest);
36
- expect(microappsRequestMedia).toHaveBeenCalledWith(mediaRequest);
37
- });
38
-
39
- it('resolves with a blob file on success', () => {
40
- expect.assertions(1);
41
- return requestMedia(mediaRequest).then((file) => expect(file instanceof Blob).toBe(true));
42
- });
43
- });
44
- });