cozy-ui 113.7.1 → 113.9.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 (43) hide show
  1. package/.nvmrc +1 -1
  2. package/CHANGELOG.md +15 -0
  3. package/assets/icons/ui/number.svg +1 -0
  4. package/jest.config.js +1 -2
  5. package/package.json +2 -8
  6. package/react/AppSections/components/AppsSection.spec.jsx +10 -19
  7. package/react/AppSections/index.spec.jsx +98 -77
  8. package/react/ContactsList/ContactRow.spec.js +28 -53
  9. package/react/DateMonthPicker/index.spec.jsx +17 -45
  10. package/react/Field/index.spec.js +28 -5
  11. package/react/Figure/Figure.spec.jsx +9 -4
  12. package/react/Figure/__snapshots__/Figure.spec.jsx.snap +289 -225
  13. package/react/FileInput/index.jsx +1 -0
  14. package/react/FileInput/index.spec.jsx +16 -38
  15. package/react/Icon/Readme.md +5 -1
  16. package/react/Icons/Number.jsx +16 -0
  17. package/react/Popup/index.spec.jsx +90 -41
  18. package/react/QualificationIconStack/Readme.md +14 -0
  19. package/react/QualificationIconStack/index.jsx +132 -0
  20. package/react/deprecated/ViewStack/example.jsx +1 -1
  21. package/react/hooks/useClientErrors.spec.jsx +16 -24
  22. package/react/providers/I18n/index.spec.jsx +13 -5
  23. package/react/providers/I18n/withLocales.spec.jsx +4 -4
  24. package/transpiled/react/FileInput/index.js +2 -1
  25. package/transpiled/react/Icon/icons-sprite.js +1 -1
  26. package/transpiled/react/Icons/Number.js +15 -0
  27. package/transpiled/react/QualificationIconStack/index.js +132 -0
  28. package/transpiled/react/deprecated/ViewStack/example.js +1 -1
  29. package/react/AppSections/__snapshots__/index.spec.jsx.snap +0 -1843
  30. package/react/AppSections/components/__snapshots__/AppsSection.spec.jsx.snap +0 -41
  31. package/react/ContactsList/__snapshots__/ContactRow.spec.js.snap +0 -69
  32. package/react/FileInput/__snapshots__/index.spec.jsx.snap +0 -86
  33. package/react/Input/__snapshots__/index.spec.jsx.snap +0 -11
  34. package/react/Input/index.spec.jsx +0 -12
  35. package/react/__snapshots__/examples.spec.jsx.snap +0 -3720
  36. package/react/deprecated/ActionMenu/__snapshots__/index.spec.jsx.snap +0 -157
  37. package/react/deprecated/ActionMenu/index.spec.jsx +0 -115
  38. package/react/deprecated/Alerter/__snapshots__/alerter.spec.js.snap +0 -88
  39. package/react/deprecated/Alerter/alerter.spec.js +0 -78
  40. package/react/deprecated/InfosCarrousel/index.spec.jsx +0 -71
  41. package/react/deprecated/Modal/index.spec.jsx +0 -70
  42. package/react/deprecated/ViewStack/index.spec.jsx +0 -64
  43. package/react/examples.spec.jsx +0 -67
@@ -1,3 +1,4 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react'
1
2
  import uniqueId from 'lodash/uniqueId'
2
3
  import React from 'react'
3
4
 
@@ -20,66 +21,43 @@ describe('FileInput component', () => {
20
21
  })
21
22
 
22
23
  it('should render a file selector', () => {
23
- const component = shallow(
24
+ render(
24
25
  <FileInput onChange={onChangeSpy}>
25
26
  <span>Click me</span>
26
27
  </FileInput>
27
- ).getElement()
28
- expect(component).toMatchSnapshot()
29
- })
30
-
31
- it('should render a default file selector', () => {
32
- const component = shallow(
33
- <FileInput hidden={false} onChange={onChangeSpy} />
34
- ).getElement()
35
- expect(component).toMatchSnapshot()
36
- })
28
+ )
37
29
 
38
- it('should render a disabled file selector', () => {
39
- const component = shallow(
40
- <FileInput disabled onChange={onChangeSpy}>
41
- <span>Click me</span>
42
- </FileInput>
43
- ).getElement()
44
- expect(component).toMatchSnapshot()
45
- })
30
+ const button = screen.getByText('Click me')
46
31
 
47
- it('should pass props to the input', () => {
48
- const component = shallow(
49
- <FileInput accept="image/*" onChange={onChangeSpy}>
50
- <span>Click me</span>
51
- </FileInput>
52
- ).getElement()
53
- expect(component).toMatchSnapshot()
32
+ expect(button).toBeInTheDocument()
33
+ expect(screen.getByTestId('file-input')).toBeInTheDocument()
54
34
  })
55
35
 
56
36
  it('should process selected file on change', () => {
57
37
  const filelist = [pic1]
58
- const component = shallow(
38
+ render(
59
39
  <FileInput accept="image/*" onChange={onChangeSpy}>
60
40
  <span>Click me</span>
61
41
  </FileInput>
62
42
  )
63
- component.find('input').simulate('change', {
64
- target: {
65
- files: filelist
66
- }
67
- })
43
+
44
+ const input = screen.getByTestId('file-input')
45
+ fireEvent.change(input, { target: { files: filelist } })
46
+
68
47
  expect(onChangeSpy).toHaveBeenCalledWith(pic1)
69
48
  })
70
49
 
71
50
  it('should process selected files on change if it is multiple', () => {
72
51
  const filelist = [pic1, pic2]
73
- const component = shallow(
52
+ render(
74
53
  <FileInput accept="image/*" multiple onChange={onChangeSpy}>
75
54
  <span>Click me</span>
76
55
  </FileInput>
77
56
  )
78
- component.find('input').simulate('change', {
79
- target: {
80
- files: filelist
81
- }
82
- })
57
+
58
+ const input = screen.getByTestId('file-input')
59
+ fireEvent.change(input, { target: { files: filelist } })
60
+
83
61
  expect(onChangeSpy).toHaveBeenCalledWith([pic1, pic2])
84
62
  })
85
63
  })
@@ -233,6 +233,7 @@ import New from 'cozy-ui/transpiled/react/Icons/New'
233
233
  import Next from 'cozy-ui/transpiled/react/Icons/Next'
234
234
  import Note from 'cozy-ui/transpiled/react/Icons/Note'
235
235
  import NotificationEmail from 'cozy-ui/transpiled/react/Icons/NotificationEmail'
236
+ import Number from 'cozy-ui/transpiled/react/Icons/Number'
236
237
  import Offline from 'cozy-ui/transpiled/react/Icons/Offline'
237
238
  import Online from 'cozy-ui/transpiled/react/Icons/Online'
238
239
  import Openapp from 'cozy-ui/transpiled/react/Icons/Openapp'
@@ -501,6 +502,7 @@ const icons = [
501
502
  Next,
502
503
  Note,
503
504
  NotificationEmail,
505
+ Number,
504
506
  Offline,
505
507
  Online,
506
508
  Openapp,
@@ -692,6 +694,7 @@ import FileTypeCodeIcon from 'cozy-ui/transpiled/react/Icons/FileTypeCode'
692
694
  import FileTypeFilesIcon from 'cozy-ui/transpiled/react/Icons/FileTypeFiles'
693
695
  import FileTypeFolderIcon from 'cozy-ui/transpiled/react/Icons/FileTypeFolder'
694
696
  import FileTypeImageIcon from 'cozy-ui/transpiled/react/Icons/FileTypeImage'
697
+ import FileTypeNoteIcon from 'cozy-ui/transpiled/react/Icons/FileTypeNote'
695
698
  import FileTypePdfIcon from 'cozy-ui/transpiled/react/Icons/FileTypePdf'
696
699
  import FileTypeSheetIcon from 'cozy-ui/transpiled/react/Icons/FileTypeSheet'
697
700
  import FileTypeSlideIcon from 'cozy-ui/transpiled/react/Icons/FileTypeSlide'
@@ -731,6 +734,7 @@ const icons = [
731
734
  FileTypeFilesIcon,
732
735
  FileTypeFolderIcon,
733
736
  FileTypeImageIcon,
737
+ FileTypeNoteIcon,
734
738
  FileTypePdfIcon,
735
739
  FileTypeSheetIcon,
736
740
  FileTypeSlideIcon,
@@ -935,7 +939,7 @@ import Typography from 'cozy-ui/transpiled/react/Typography'
935
939
 
936
940
  const colors = ['#297EF2', '#08b442', '#B449E7', '#F52D2D', '#FF962F']
937
941
  let i = 0
938
- const availableIcons = ['album-add','album-remove','album','answer','apple','archive','arrowUp','attachment','attention','bank-check','bank','banking-add','banking','bell','benefit','bike','bill','bottom','browser-brave','browser-chrome','browser-duckduckgo','browser-edge','browser-edge-chromium','browser-firefox','browser-ie','browser-opera','browser-safari','burger','bus','calendar','camera','car','carbonCopy','carpooling','categories','certified','check-circle','check-list','check-square','check','checkbox','chess','child','circle-filled','clock','clock-outline','cloud-happy','cloud-plus-outlined','cloud','collect','cocktail','comment','company','compare','compass','connector','contract','contrast','copy','cozy-circle','cozy-laugh', 'cozy-lock', 'cozy-text', 'cozy-release', 'credit-card-add','credit-card','credit','crop','cross-circle-outline','cross-circle','cross-medium','cross-small','cross','cube','dash','dashboard','data-control','debit','devices','dots','down','download','drawing-arrow-up','dropdown-close','dropdown-open','dropdown','dropup','electric-bike','electric-car','electric-scooter','email-notification','email','eu','euro','exchange','eye-closed','eye','face-id','file-add','file-duotone','file-new','file-none','file-outline','file','filter','fingerprint','fitness','flag-outlined','flag','flash-auto','flashlight','folder-add','folder-moveto','folder-open','folder','forbidden','from-user','gear','globe','gouv','graph-circle','grid','group-list','groups','growth','hand','heart','help','help-outlined','history','home','hourglass','image','info-outlined','info','justice','key','label-outlined','laudry','laptop','left','library','lightbulb','lightning','link-out','link','list','list-min','location','lock', 'lock-screen', 'logout','magic-trick','magnet','magnifier','merge','moped','mosaic-min','motorcycle','mountain','movement-in','movement-out','mouvement','moveto','multi-files','music','new','next','note','notification-email','offline','online', 'openapp', 'openwith','palette','paper','paperplane','password','pen','people','percent-circle','percent','personal-data','phone-download','phone-upload','phone','pie-chart','pin','plane','plus-small','plus', 'pop-inside', 'previous','printer','qualify','radio-checked','radio-unchecked','refresh','relationship','remboursement','rename','repare','reply','restaurant','restore-straight','restore','right','rise','rotate-left','rotate-right','sad-cozy','safe','school','scooter','select-all','server','setting','share-circle','share','shield','shop','sound','spinner','sport-bag','stack','star','star-outline','stats','stop', 'subway', 'support', 'swap', 'sync-cozy','sync','tab','tag','target','task','team','telecom','telephone','text','text-info','to-the-cloud','top','train','tram','trash','trophy', 'uncloud', 'unknow','unlink','unlock','up','upload','videos','walk','wallet-add','wallet-new','wallet','warn','warning-circle','warning','water','wrench-circle','work']
942
+ const availableIcons = ['album-add','album-remove','album','answer','apple','archive','arrowUp','attachment','attention','bank-check','bank','banking-add','banking','bell','benefit','bike','bill','bottom','browser-brave','browser-chrome','browser-duckduckgo','browser-edge','browser-edge-chromium','browser-firefox','browser-ie','browser-opera','browser-safari','burger','bus','calendar','camera','car','carbonCopy','carpooling','categories','certified','check-circle','check-list','check-square','check','checkbox','chess','child','circle-filled','clock','clock-outline','cloud-happy','cloud-plus-outlined','cloud','collect','cocktail','comment','company','compare','compass','connector','contract','contrast','copy','cozy-circle','cozy-laugh', 'cozy-lock', 'cozy-text', 'cozy-release', 'credit-card-add','credit-card','credit','crop','cross-circle-outline','cross-circle','cross-medium','cross-small','cross','cube','dash','dashboard','data-control','debit','devices','dots','down','download','drawing-arrow-up','dropdown-close','dropdown-open','dropdown','dropup','electric-bike','electric-car','electric-scooter','email-notification','email','eu','euro','exchange','eye-closed','eye','face-id','file-add','file-duotone','file-new','file-none','file-outline','file','filter','fingerprint','fitness','flag-outlined','flag','flash-auto','flashlight','folder-add','folder-moveto','folder-open','folder','forbidden','from-user','gear','globe','gouv','graph-circle','grid','group-list','groups','growth','hand','heart','help','help-outlined','history','home','hourglass','image','info-outlined','info','justice','key','label-outlined','laudry','laptop','left','library','lightbulb','lightning','link-out','link','list','list-min','location','lock', 'lock-screen', 'logout','magic-trick','magnet','magnifier','merge','moped','mosaic-min','motorcycle','mountain','movement-in','movement-out','mouvement','moveto','multi-files','music','new','next','note','notification-email','number','offline','online', 'openapp', 'openwith','palette','paper','paperplane','password','pen','people','percent-circle','percent','personal-data','phone-download','phone-upload','phone','pie-chart','pin','plane','plus-small','plus', 'pop-inside', 'previous','printer','qualify','radio-checked','radio-unchecked','refresh','relationship','remboursement','rename','repare','reply','restaurant','restore-straight','restore','right','rise','rotate-left','rotate-right','sad-cozy','safe','school','scooter','select-all','server','setting','share-circle','share','shield','shop','sound','spinner','sport-bag','stack','star','star-outline','stats','stop', 'subway', 'support', 'swap', 'sync-cozy','sync','tab','tag','target','task','team','telecom','telephone','text','text-info','to-the-cloud','top','train','tram','trash','trophy', 'uncloud', 'unknow','unlink','unlock','up','upload','videos','walk','wallet-add','wallet-new','wallet','warn','warning-circle','warning','water','wrench-circle','work']
939
943
  ;
940
944
  <div style={{ fontSize: '2rem', display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)' }}>
941
945
  <Sprite />
@@ -0,0 +1,16 @@
1
+ // Automatically created, please run `scripts/generate-svgr-icon.sh assets/icons/ui/number.svg` to regenerate;
2
+ import React from 'react'
3
+
4
+ function SvgNumber(props) {
5
+ return (
6
+ <svg viewBox="0 0 16 16" {...props}>
7
+ <path
8
+ fillRule="evenodd"
9
+ clipRule="evenodd"
10
+ d="M4 12V4h-.452l-.117.024-2.73 1.177v1.883l1.323-.54V12H4zm11.245-7.363C14.8 4.21 14.192 4 13.44 4c-.437 0-.84.096-1.204.29a2.155 2.155 0 00-.864.816c-.17.29-.27.61-.298.957l-.021.527h2.08v-.318l.004-.09a.507.507 0 01.11-.28.276.276 0 01.233-.11c.111 0 .184.035.248.116.077.097.12.252.12.472 0 .24-.045.418-.128.54-.05.073-.118.111-.232.123l-.09.005h-.994v1.757h1.021l.08.004c.301.03.434.238.434.742 0 .228-.05.395-.144.512-.08.1-.178.144-.325.144-.108 0-.188-.04-.265-.137a.647.647 0 01-.132-.337l-.023-.431H11v.318l.007.206c.04.607.265 1.116.673 1.513.453.44 1.042.661 1.75.661.751 0 1.374-.22 1.85-.663.48-.446.72-1.04.72-1.762 0-.447-.098-.843-.296-1.182l-.094-.145-.107-.134a1.798 1.798 0 00-.252-.235l-.008-.006.014-.01.128-.133c.082-.092.157-.192.225-.3a2 2 0 00.305-1.07c0-.714-.222-1.296-.67-1.723zm-5.83-.007C8.996 4.208 8.417 4 7.696 4c-.475 0-.907.118-1.289.354a2.37 2.37 0 00-.888.99 2.98 2.98 0 00-.3 1.123L5.2 7.03h2.05v-.322l.004-.157c.015-.25.066-.44.146-.568.077-.122.157-.17.271-.17.096 0 .152.033.204.12.076.127.12.323.12.59 0 .192-.049.397-.148.618-.085.19-.211.41-.378.66L7.331 8 5.33 10.57V12h4.87v-1.815H8.05l.573-.824.185-.226c.417-.519.722-.98.906-1.374.215-.462.323-.923.323-1.38 0-.739-.205-1.328-.623-1.751z"
11
+ />
12
+ </svg>
13
+ )
14
+ }
15
+
16
+ export default SvgNumber
@@ -1,4 +1,4 @@
1
- import { shallow } from 'enzyme'
1
+ import { render, fireEvent } from '@testing-library/react'
2
2
  import React from 'react'
3
3
 
4
4
  import { isMobileApp } from 'cozy-device-helper'
@@ -17,35 +17,56 @@ const props = {
17
17
  height: '200'
18
18
  }
19
19
 
20
- const popupMock = {}
21
- class MessageEventMock {
22
- constructor(options = {}) {
23
- this.source = options.source || popupMock
20
+ class MessageEventMock extends Event {
21
+ constructor(options = {}, mock) {
22
+ super('message', options)
23
+ this.source = options.source || mock
24
+ }
25
+ }
26
+
27
+ class LoadStartEventMock extends Event {
28
+ constructor(url) {
29
+ super('loadstart')
30
+ this.url = url
31
+ }
32
+ }
33
+
34
+ class ExitEventMock extends Event {
35
+ constructor() {
36
+ super('exit')
24
37
  }
25
38
  }
26
39
 
27
40
  describe('Popup', () => {
28
- beforeAll(() => {
29
- jest.useFakeTimers()
41
+ const setup = ({ mockAddEventListener = true }) => {
42
+ const popupMock = new EventTarget()
43
+
44
+ isMobileApp.mockReturnValue(false)
30
45
 
31
46
  jest.spyOn(global, 'open').mockReturnValue(popupMock)
32
47
  jest.spyOn(global, 'addEventListener')
33
- })
34
48
 
35
- afterAll(() => {
36
- global.open.mockRestore()
37
- global.addEventListener.mockRestore()
38
- })
49
+ if (mockAddEventListener) {
50
+ popupMock.addEventListener = jest.fn()
51
+ }
39
52
 
40
- beforeEach(() => {
41
- isMobileApp.mockReturnValue(false)
42
- popupMock.addEventListener = jest.fn()
43
53
  popupMock.close = jest.fn()
44
54
  popupMock.focus = jest.fn()
45
55
  popupMock.closed = false
46
56
  props.onClose = jest.fn()
47
57
  props.onMessage = jest.fn()
48
58
  props.onMobileUrlChange = jest.fn()
59
+
60
+ return popupMock
61
+ }
62
+
63
+ beforeAll(() => {
64
+ jest.useFakeTimers()
65
+ })
66
+
67
+ afterAll(() => {
68
+ global.open.mockRestore()
69
+ global.addEventListener.mockRestore()
49
70
  })
50
71
 
51
72
  afterEach(() => {
@@ -54,7 +75,10 @@ describe('Popup', () => {
54
75
  })
55
76
 
56
77
  it('should open new window', () => {
57
- shallow(<Popup {...props} />)
78
+ const popupMock = setup({})
79
+
80
+ render(<Popup {...props} />)
81
+
58
82
  expect(global.open).toHaveBeenCalledWith(
59
83
  props.initialUrl,
60
84
  props.title,
@@ -64,66 +88,91 @@ describe('Popup', () => {
64
88
  })
65
89
 
66
90
  it('should subscribe to message events', () => {
67
- const wrapper = shallow(<Popup {...props} />)
91
+ setup({})
92
+
93
+ render(<Popup {...props} />)
94
+
68
95
  expect(global.addEventListener).toHaveBeenCalledWith(
69
96
  'message',
70
- wrapper.instance().handleMessage
97
+ expect.any(Function)
71
98
  )
72
99
  })
73
100
 
74
101
  it('should subcribe to mobile events', () => {
102
+ const popupMock = setup({})
75
103
  isMobileApp.mockReturnValue(true)
76
- const wrapper = shallow(<Popup {...props} />)
104
+
105
+ render(<Popup {...props} />)
106
+
77
107
  expect(popupMock.addEventListener).toHaveBeenCalledWith(
78
108
  'loadstart',
79
- wrapper.instance().handleLoadStart
109
+ expect.any(Function)
80
110
  )
81
111
  expect(popupMock.addEventListener).toHaveBeenCalledWith(
82
112
  'exit',
83
- wrapper.instance().handleClose
113
+ expect.any(Function)
84
114
  )
85
115
  })
86
116
 
87
- describe('monitorClosing', () => {
88
- it('should detect closing', () => {
89
- const wrapper = shallow(<Popup {...props} />)
90
- jest.spyOn(wrapper.instance(), 'handleClose')
91
- popupMock.closed = true
92
- jest.runAllTimers()
93
- expect(wrapper.instance().handleClose).toHaveBeenCalled()
94
- })
95
- })
96
-
97
117
  describe('handleClose', () => {
98
118
  it('should call onClose', () => {
99
- const wrapper = shallow(<Popup {...props} />)
100
- wrapper.instance().handleClose()
119
+ const popupMock = setup({
120
+ mockAddEventListener: false
121
+ })
122
+ isMobileApp.mockReturnValue(true)
123
+
124
+ render(<Popup {...props} />)
125
+
126
+ const messageEvent = new ExitEventMock()
127
+ fireEvent(popupMock, messageEvent)
128
+
101
129
  expect(props.onClose).toHaveBeenCalled()
102
130
  })
103
131
  })
104
132
 
105
133
  describe('handleMessage', () => {
106
134
  it('should call onMessage', () => {
107
- const wrapper = shallow(<Popup {...props} />)
108
- const messageEvent = new MessageEventMock()
109
- wrapper.instance().handleMessage(messageEvent)
135
+ const popupMock = setup({
136
+ mockAddEventListener: false
137
+ })
138
+ isMobileApp.mockReturnValue(true)
139
+
140
+ render(<Popup {...props} />)
141
+
142
+ const messageEvent = new MessageEventMock({}, popupMock)
143
+ fireEvent(window, messageEvent)
144
+
110
145
  expect(props.onMessage).toHaveBeenCalledWith(messageEvent)
111
146
  })
112
147
 
113
148
  it('should ignore messageEvent from another window ', () => {
114
- const wrapper = shallow(<Popup {...props} />)
149
+ setup({
150
+ mockAddEventListener: false
151
+ })
152
+ isMobileApp.mockReturnValue(true)
153
+
154
+ render(<Popup {...props} />)
155
+
115
156
  const messageEvent = new MessageEventMock({ source: {} })
116
- wrapper.instance().handleMessage(messageEvent)
157
+ fireEvent(window, messageEvent)
158
+
117
159
  expect(props.onMessage).not.toHaveBeenCalled()
118
160
  })
119
161
  })
120
162
 
121
163
  describe('handleLoadStart', () => {
122
164
  it('should call onMobileUrlChange', () => {
123
- const wrapper = shallow(<Popup {...props} />)
165
+ const popupMock = setup({
166
+ mockAddEventListener: false
167
+ })
168
+ isMobileApp.mockReturnValue(true)
169
+
170
+ render(<Popup {...props} />)
171
+
124
172
  const url = 'https://cozy.io'
125
- const urlEvent = { url }
126
- wrapper.instance().handleLoadStart(urlEvent)
173
+ const messageEvent = new LoadStartEventMock(url)
174
+ fireEvent(popupMock, messageEvent)
175
+
127
176
  expect(props.onMobileUrlChange).toHaveBeenCalledWith(expect.any(URL))
128
177
  expect(props.onMobileUrlChange).toHaveBeenCalledWith(new URL(url))
129
178
  })
@@ -0,0 +1,14 @@
1
+ ```jsx
2
+ import QualificationIconStack from 'cozy-ui/transpiled/react/QualificationIconStack'
3
+
4
+ ;
5
+
6
+ <>
7
+ <QualificationIconStack className="u-mr-1" />
8
+ <QualificationIconStack className="u-mr-1" qualification="isp_invoice" />
9
+ <QualificationIconStack className="u-mr-1" qualification="phone_invoice" />
10
+ <QualificationIconStack className="u-mr-1" qualification="family_record_book" />
11
+ <QualificationIconStack className="u-mr-1" theme="identity" />
12
+ <QualificationIconStack theme="transport" />
13
+ </>
14
+ ```
@@ -0,0 +1,132 @@
1
+ import PropTypes from 'prop-types'
2
+ import React from 'react'
3
+
4
+ import { getIconByLabel } from 'cozy-client/dist/models/document/qualification'
5
+
6
+ import Icon from '../Icon'
7
+ import IconStack from '../IconStack'
8
+ import BankIcon from '../Icons/Bank'
9
+ import BankCheckIcon from '../Icons/BankCheck'
10
+ import BenefitIcon from '../Icons/Benefit'
11
+ import BillIcon from '../Icons/Bill'
12
+ import CarIcon from '../Icons/Car'
13
+ import ChessIcon from '../Icons/Chess'
14
+ import ChildIcon from '../Icons/Child'
15
+ import DotsIcon from '../Icons/Dots'
16
+ import EmailIcon from '../Icons/Email'
17
+ import EuroIcon from '../Icons/Euro'
18
+ import ExchangeIcon from '../Icons/Exchange'
19
+ import FileDuotoneIcon from '../Icons/FileDuotone'
20
+ import FileTypeNoteIcon from '../Icons/FileTypeNote'
21
+ import FitnessIcon from '../Icons/Fitness'
22
+ import GlobeIcon from '../Icons/Globe'
23
+ import GouvIcon from '../Icons/Gouv'
24
+ import HeartIcon from '../Icons/Heart'
25
+ import HomeIcon from '../Icons/Home'
26
+ import ImageIcon from '../Icons/Image'
27
+ import JusticeIcon from '../Icons/Justice'
28
+ import LaudryIcon from '../Icons/Laudry'
29
+ import LightningIcon from '../Icons/Lightning'
30
+ import PeopleIcon from '../Icons/People'
31
+ import PlaneIcon from '../Icons/Plane'
32
+ import RemboursementIcon from '../Icons/Remboursement'
33
+ import RestaurantIcon from '../Icons/Restaurant'
34
+ import SchoolIcon from '../Icons/School'
35
+ import ShopIcon from '../Icons/Shop'
36
+ import TeamIcon from '../Icons/Team'
37
+ import TelecomIcon from '../Icons/Telecom'
38
+ import TelephoneIcon from '../Icons/Telephone'
39
+ import WaterIcon from '../Icons/Water'
40
+ import WorkIcon from '../Icons/Work'
41
+
42
+ // this is a copy of FileDuotone without the flap and with a white background
43
+ function FileDuotoneWhite(props) {
44
+ return (
45
+ <svg viewBox="0 0 26 32" {...props}>
46
+ <g fillRule="evenodd">
47
+ <path
48
+ d="M0 2.002C0 .896.89 0 1.997 0H19l7 7v22.996A2 2 0 0124.003 32H1.997A1.995 1.995 0 010 29.998C.048 16 0 16 0 2.002z"
49
+ fill="#ffffff"
50
+ />
51
+ </g>
52
+ </svg>
53
+ )
54
+ }
55
+
56
+ const IconByLabel = {
57
+ 'bank-check': BankCheckIcon,
58
+ bank: BankIcon,
59
+ benefit: BenefitIcon,
60
+ bill: BillIcon,
61
+ car: CarIcon,
62
+ chess: ChessIcon,
63
+ child: ChildIcon,
64
+ dots: DotsIcon,
65
+ email: EmailIcon,
66
+ euro: EuroIcon,
67
+ exchange: ExchangeIcon,
68
+ 'file-type-note': FileTypeNoteIcon,
69
+ fitness: FitnessIcon,
70
+ globe: GlobeIcon,
71
+ gouv: GouvIcon,
72
+ heart: HeartIcon,
73
+ home: HomeIcon,
74
+ image: ImageIcon,
75
+ justice: JusticeIcon,
76
+ laudry: LaudryIcon,
77
+ lightning: LightningIcon,
78
+ people: PeopleIcon,
79
+ plane: PlaneIcon,
80
+ remboursement: RemboursementIcon,
81
+ restaurant: RestaurantIcon,
82
+ school: SchoolIcon,
83
+ shop: ShopIcon,
84
+ team: TeamIcon,
85
+ telecom: TelecomIcon,
86
+ telephone: TelephoneIcon,
87
+ water: WaterIcon,
88
+ work: WorkIcon
89
+ }
90
+
91
+ const themeIconByLabel = {
92
+ identity: 'people',
93
+ family: 'team',
94
+ work_study: 'work',
95
+ health: 'heart',
96
+ home: 'home',
97
+ transport: 'car',
98
+ activity: 'chess',
99
+ finance: 'bank',
100
+ invoice: 'bill',
101
+ others: 'dots'
102
+ }
103
+
104
+ const QualificationIconStack = ({ theme, qualification, ...props }) => {
105
+ const ForegroundIcon = qualification
106
+ ? IconByLabel[getIconByLabel(qualification)]
107
+ : theme
108
+ ? IconByLabel[themeIconByLabel[theme]]
109
+ : null
110
+
111
+ return (
112
+ <IconStack
113
+ {...props}
114
+ backgroundIcon={
115
+ <>
116
+ <Icon className="u-pos-absolute" icon={FileDuotoneWhite} size={32} />
117
+ <Icon icon={FileDuotoneIcon} color="#E049BF" size={32} />
118
+ </>
119
+ }
120
+ foregroundIcon={<Icon icon={ForegroundIcon} color="#E049BF" size={16} />}
121
+ />
122
+ )
123
+ }
124
+
125
+ QualificationIconStack.propTypes = {
126
+ /** The name of the qualification (isp\_invoice, family\_record\_book, etc.) */
127
+ qualification: PropTypes.string,
128
+ /** The name of the qualification theme (indentity, family, etc.) */
129
+ theme: PropTypes.string
130
+ }
131
+
132
+ export default QualificationIconStack
@@ -17,7 +17,7 @@ const Slide = ({ number }) => {
17
17
  const handleClickPop = async () => {
18
18
  await stackPop()
19
19
 
20
- // No alerts during enzyme tests
20
+ // No alerts during tests
21
21
  if (number === 2 && !global.mount) {
22
22
  alert('You went back to the first slide')
23
23
  }
@@ -1,11 +1,11 @@
1
- import { renderHook, act } from '@testing-library/react-hooks'
2
- import { shallow } from 'enzyme'
1
+ import { screen, render, act } from '@testing-library/react'
2
+ import { renderHook } from '@testing-library/react-hooks'
3
3
  import React from 'react'
4
4
 
5
- import { CozyProvider } from 'cozy-client'
6
5
  import { FetchError } from 'cozy-stack-client'
7
6
 
8
7
  import useClientErrors from './useClientErrors'
8
+ import DemoProvider from '../providers/DemoProvider'
9
9
 
10
10
  function createCozyClient() {
11
11
  return {
@@ -14,9 +14,15 @@ function createCozyClient() {
14
14
  }
15
15
  }
16
16
 
17
+ jest.mock('../deprecated/QuotaAlert', () => ({ onClose }) => (
18
+ <>
19
+ QuotaAlert <button onClick={onClose}>Dismiss</button>
20
+ </>
21
+ ))
22
+
17
23
  function createWrapper(client = createCozyClient()) {
18
24
  function Wrapper({ children }) {
19
- return <CozyProvider client={client}>{children}</CozyProvider>
25
+ return <DemoProvider client={client}>{children}</DemoProvider>
20
26
  }
21
27
  return Wrapper
22
28
  }
@@ -27,7 +33,7 @@ function renderWrappedHook(client) {
27
33
  }
28
34
 
29
35
  function wrappedShallow(tree, client) {
30
- return shallow(tree, { wrappingComponent: createWrapper(client) })
36
+ return render(tree, { wrapper: createWrapper(client) })
31
37
  }
32
38
 
33
39
  describe('useClientErrors', () => {
@@ -47,14 +53,12 @@ describe('useClientErrors', () => {
47
53
  it('displays nothing by default', () => {
48
54
  const { result } = renderWrappedHook()
49
55
  const { ClientErrors } = result.current
50
- const node = wrappedShallow(<ClientErrors />)
51
- expect(node).toHaveLength(0)
56
+ wrappedShallow(<ClientErrors />)
57
+
58
+ expect(screen.queryByText('QuotaAlert')).not.toBeInTheDocument()
52
59
  })
53
60
 
54
61
  describe('for quota errors', () => {
55
- const findQuotaAlert = node => {
56
- return node.at(0).dive()
57
- }
58
62
  const setup = async () => {
59
63
  const client = createCozyClient()
60
64
  const response = new Response(null, {
@@ -81,21 +85,9 @@ describe('useClientErrors', () => {
81
85
  }
82
86
 
83
87
  it('displays a a QuotaAlert', async () => {
84
- const { node } = await setup()
85
- expect(node).toHaveLength(1)
86
- expect(findQuotaAlert(node).type().name).toEqual('QuotaAlert')
87
- })
88
-
89
- it('can be dismissed', async () => {
90
- const { node, result, client } = await setup()
91
- const quotaAlert = findQuotaAlert(node)
92
- const onClose = quotaAlert.props().onClose
93
- act(() => onClose())
88
+ await setup()
94
89
 
95
- // re-render ClientErrors returned by the hook
96
- const { ClientErrors } = result.current
97
- const updatedNode = wrappedShallow(<ClientErrors />, client)
98
- expect(updatedNode.at(0).length).toBe(0)
90
+ expect(screen.queryByText('QuotaAlert')).toBeInTheDocument()
99
91
  })
100
92
  })
101
93
  })
@@ -1,4 +1,4 @@
1
- import { render, fireEvent } from '@testing-library/react'
1
+ import { render, fireEvent, screen } from '@testing-library/react'
2
2
  import PropTypes from 'prop-types'
3
3
  import React, { useState } from 'react'
4
4
 
@@ -34,23 +34,31 @@ I18nHelloWorldOldAPI.contextTypes = {
34
34
 
35
35
  describe('new context api', () => {
36
36
  it('should provide t and f and lang through useI18n hook', () => {
37
- const root = mount(
37
+ render(
38
38
  <I18n lang="en" dictRequire={() => locales}>
39
39
  <I18nHelloWorldHook />
40
40
  </I18n>
41
41
  )
42
- expect(root.html()).toBe('<div>Hello World !<br>6 Jan<br>en</div>')
42
+ expect(
43
+ screen.getByText('Hello World !', { exact: false })
44
+ ).toBeInTheDocument()
45
+ expect(screen.getByText('6 Jan', { exact: false })).toBeInTheDocument()
46
+ expect(screen.getByText('en', { exact: false })).toBeInTheDocument()
43
47
  })
44
48
  })
45
49
 
46
50
  describe('old context api', () => {
47
51
  it('should provide t and f and lang through old context API', () => {
48
- const root = mount(
52
+ render(
49
53
  <I18n lang="en" dictRequire={() => locales}>
50
54
  <I18nHelloWorldOldAPI />
51
55
  </I18n>
52
56
  )
53
- expect(root.html()).toBe('<div>Hello World !<br>6 Jan<br>en</div>')
57
+ expect(
58
+ screen.getByText('Hello World !', { exact: false })
59
+ ).toBeInTheDocument()
60
+ expect(screen.getByText('6 Jan', { exact: false })).toBeInTheDocument()
61
+ expect(screen.getByText('en', { exact: false })).toBeInTheDocument()
54
62
  })
55
63
  })
56
64