cozy-sharing 28.5.0 → 28.7.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 (36) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/SharingProvider.js +186 -87
  3. package/dist/SharingProvider.spec.js +152 -0
  4. package/dist/components/Recipient/LinkRecipient.js +27 -8
  5. package/dist/components/Recipient/LinkRecipient.stories.js +0 -1
  6. package/dist/components/Recipient/LinkRecipientPermissions.js +62 -15
  7. package/dist/components/Recipient/MemberRecipient.spec.js +13 -0
  8. package/dist/components/Recipient/MemberRecipientPermissions.js +80 -20
  9. package/dist/components/Recipient/MemberRecipientPermissions.spec.js +214 -0
  10. package/dist/components/Recipient/actions/revokeLink.js +34 -0
  11. package/dist/components/Recipient/actions/setReadOnlySharedPermission.js +0 -1
  12. package/dist/components/Recipient/actions/setReadOnlySharedPermission.spec.js +72 -0
  13. package/dist/components/Recipient/actions/setReadWriteSharedPermission.js +0 -1
  14. package/dist/components/Recipient/actions/setReadWriteSharedPermission.spec.js +72 -0
  15. package/dist/components/ShareDialogCozyToCozy.spec.js +9 -0
  16. package/dist/components/WhoHasAccess.js +0 -1
  17. package/locales/en.json +4 -1
  18. package/locales/fr.json +4 -1
  19. package/locales/ru.json +4 -1
  20. package/locales/vi.json +4 -1
  21. package/package.json +2 -2
  22. package/src/SharingProvider.jsx +52 -1
  23. package/src/SharingProvider.spec.jsx +94 -0
  24. package/src/components/Recipient/LinkRecipient.jsx +30 -7
  25. package/src/components/Recipient/LinkRecipient.stories.jsx +0 -1
  26. package/src/components/Recipient/LinkRecipientPermissions.jsx +54 -16
  27. package/src/components/Recipient/MemberRecipient.spec.jsx +11 -0
  28. package/src/components/Recipient/MemberRecipientPermissions.jsx +69 -16
  29. package/src/components/Recipient/MemberRecipientPermissions.spec.jsx +165 -0
  30. package/src/components/Recipient/actions/revokeLink.js +33 -0
  31. package/src/components/Recipient/actions/setReadOnlySharedPermission.js +1 -1
  32. package/src/components/Recipient/actions/setReadOnlySharedPermission.spec.jsx +95 -0
  33. package/src/components/Recipient/actions/setReadWriteSharedPermission.js +1 -1
  34. package/src/components/Recipient/actions/setReadWriteSharedPermission.spec.jsx +95 -0
  35. package/src/components/ShareDialogCozyToCozy.spec.jsx +6 -0
  36. package/src/components/WhoHasAccess.jsx +0 -1
@@ -1,15 +1,15 @@
1
1
  import PropTypes from 'prop-types'
2
- import React from 'react'
2
+ import React, { useState } from 'react'
3
3
  import { useI18n } from 'twake-i18n'
4
4
 
5
5
  import Avatar from 'cozy-ui/transpiled/react/Avatar'
6
+ import DropdownButton from 'cozy-ui/transpiled/react/DropdownButton'
6
7
  import Fade from 'cozy-ui/transpiled/react/Fade'
7
8
  import Icon from 'cozy-ui/transpiled/react/Icon'
8
9
  import LinkIcon from 'cozy-ui/transpiled/react/Icons/Link'
9
10
  import ListItem from 'cozy-ui/transpiled/react/ListItem'
10
11
  import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
11
12
  import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
12
- import Typography from 'cozy-ui/transpiled/react/Typography'
13
13
  import useBreakpoints from 'cozy-ui/transpiled/react/providers/Breakpoints'
14
14
 
15
15
  import LinkRecipientPermissions from './LinkRecipientPermissions'
@@ -20,14 +20,17 @@ import {
20
20
  } from '../../helpers/permissions'
21
21
  import { FADE_IN_DURATION } from '../../helpers/recipients'
22
22
  import { useSharingContext } from '../../hooks/useSharingContext'
23
+ import { ShareRestrictionModal } from '../ShareRestrictionModal/ShareRestrictionModal'
23
24
 
24
25
  const LinkRecipient = props => {
25
26
  const { t, f, lang } = useI18n()
26
27
  const { isMobile } = useBreakpoints()
27
28
  const { getDocumentPermissions } = useSharingContext()
28
29
 
29
- const { recipientConfirmationData, verifyRecipient, link, fadeIn, document } =
30
- props
30
+ const { recipientConfirmationData, verifyRecipient, fadeIn, document } = props
31
+
32
+ const [openShareRestrictionModal, setOpenShareRestrictionModal] =
33
+ useState(false)
31
34
 
32
35
  const permissions = getDocumentPermissions(document?._id)
33
36
  const hasPassword = checkIsPermissionHasPassword(permissions)
@@ -44,7 +47,7 @@ const LinkRecipient = props => {
44
47
  ? t('Share.recipients.expires', {
45
48
  date: dateFormatted
46
49
  })
47
- : link
50
+ : ''
48
51
 
49
52
  const RightPart = recipientConfirmationData ? (
50
53
  <RecipientConfirm
@@ -64,17 +67,37 @@ const LinkRecipient = props => {
64
67
  </Avatar>
65
68
  </ListItemIcon>
66
69
  <ListItemText
67
- primary={<Typography variant="body1">{textPrimary}</Typography>}
70
+ primary={
71
+ <DropdownButton
72
+ textVariant="body1"
73
+ onClick={() => setOpenShareRestrictionModal(true)}
74
+ >
75
+ {textPrimary}
76
+ </DropdownButton>
77
+ }
68
78
  secondary={textSecondary}
69
79
  />
70
80
  {RightPart}
81
+ {openShareRestrictionModal && (
82
+ <ShareRestrictionModal
83
+ file={document}
84
+ onClose={() => setOpenShareRestrictionModal(false)}
85
+ />
86
+ )}
71
87
  </ListItem>
72
88
  </Fade>
73
89
  )
74
90
  }
75
91
 
76
92
  LinkRecipient.propTypes = {
77
- link: PropTypes.string.isRequired
93
+ recipientConfirmationData: PropTypes.oneOfType([
94
+ PropTypes.bool,
95
+ PropTypes.object
96
+ ]),
97
+ verifyRecipient: PropTypes.func,
98
+ fadeIn: PropTypes.bool,
99
+ document: PropTypes.object,
100
+ permissions: PropTypes.arrayOf(PropTypes.object)
78
101
  }
79
102
 
80
103
  export default LinkRecipient
@@ -5,7 +5,6 @@ const meta = {
5
5
  args: {
6
6
  recipientConfirmationData: false,
7
7
  verifyRecipient: () => true,
8
- link: 'test',
9
8
  fadeIn: false
10
9
  }
11
10
  }
@@ -2,18 +2,58 @@ import PropTypes from 'prop-types'
2
2
  import React, { useState, useRef } from 'react'
3
3
  import { useI18n } from 'twake-i18n'
4
4
 
5
+ import ActionsMenu from 'cozy-ui/transpiled/react/ActionsMenu'
6
+ import {
7
+ makeActions,
8
+ divider
9
+ } from 'cozy-ui/transpiled/react/ActionsMenu/Actions'
5
10
  import DropdownButton from 'cozy-ui/transpiled/react/DropdownButton'
6
11
 
12
+ import { revokeLink } from './actions/revokeLink'
13
+ import { setReadOnlySharedPermission } from './actions/setReadOnlySharedPermission'
14
+ import { setReadWriteSharedPermission } from './actions/setReadWriteSharedPermission'
15
+ import { isOnlyReadOnlyLinkAllowed } from '../../helpers/link'
7
16
  import { checkIsReadOnlyPermissions } from '../../helpers/permissions'
8
- import { ShareRestrictionModal } from '../ShareRestrictionModal/ShareRestrictionModal'
17
+ import { useSharingContext } from '../../hooks/useSharingContext'
18
+ import { WRITE_PERMS, READ_ONLY_PERMS } from '../ShareRestrictionModal/helpers'
9
19
 
10
- const LinkRecipientPermissions = ({ className, document, permissions }) => {
20
+ const LinkRecipientPermissions = ({ className, document }) => {
11
21
  const { t } = useI18n()
12
22
  const buttonRef = useRef()
13
- const [openShareRestrictionModal, setOpenShareRestrictionModal] =
14
- useState(false)
23
+ const [isMenuDisplayed, setMenuDisplayed] = useState(false)
24
+ const {
25
+ updateDocumentPermissions,
26
+ revokeSharingLink,
27
+ documentType,
28
+ getDocumentPermissions
29
+ } = useSharingContext()
15
30
 
31
+ const permissions = getDocumentPermissions(document._id)
16
32
  const isReadOnlyPermissions = checkIsReadOnlyPermissions(permissions)
33
+ const type = isReadOnlyPermissions ? 'one-way' : 'two-way'
34
+
35
+ const toggleMenu = () => setMenuDisplayed(!isMenuDisplayed)
36
+ const hideMenu = () => setMenuDisplayed(false)
37
+
38
+ const handleSetType = newType => {
39
+ const verbs = newType === 'one-way' ? READ_ONLY_PERMS : WRITE_PERMS
40
+ updateDocumentPermissions(document, { verbs })
41
+ }
42
+
43
+ const handleRevocation = () => revokeSharingLink(document)
44
+
45
+ const actionsToShow = [setReadOnlySharedPermission]
46
+ if (!isOnlyReadOnlyLinkAllowed({ documentType })) {
47
+ actionsToShow.push(setReadWriteSharedPermission)
48
+ }
49
+ actionsToShow.push(divider, revokeLink)
50
+
51
+ const actions = makeActions(actionsToShow, {
52
+ t,
53
+ type,
54
+ setType: handleSetType,
55
+ handleRevocation
56
+ })
17
57
 
18
58
  return (
19
59
  <div className={className}>
@@ -21,18 +61,17 @@ const LinkRecipientPermissions = ({ className, document, permissions }) => {
21
61
  <DropdownButton
22
62
  ref={buttonRef}
23
63
  textVariant="body2"
24
- onClick={() => setOpenShareRestrictionModal(true)}
64
+ onClick={toggleMenu}
25
65
  >
26
- {t(
27
- `Share.type.${isReadOnlyPermissions ? 'one-way' : 'two-way'}`
28
- ).toLowerCase()}
66
+ {t(`Share.type.${type}`).toLowerCase()}
29
67
  </DropdownButton>
30
- {openShareRestrictionModal && (
31
- <ShareRestrictionModal
32
- file={document}
33
- onClose={() => setOpenShareRestrictionModal(false)}
34
- />
35
- )}
68
+ <ActionsMenu
69
+ ref={buttonRef}
70
+ open={isMenuDisplayed}
71
+ actions={actions}
72
+ autoClose
73
+ onClose={hideMenu}
74
+ />
36
75
  </>
37
76
  </div>
38
77
  )
@@ -40,8 +79,7 @@ const LinkRecipientPermissions = ({ className, document, permissions }) => {
40
79
 
41
80
  LinkRecipientPermissions.propTypes = {
42
81
  className: PropTypes.string,
43
- document: PropTypes.object.isRequired,
44
- permissions: PropTypes.arrayOf(PropTypes.object).isRequired
82
+ document: PropTypes.object.isRequired
45
83
  }
46
84
 
47
85
  export default LinkRecipientPermissions
@@ -6,6 +6,17 @@ import { createMockClient } from 'cozy-client'
6
6
  import MemberRecipient from './MemberRecipient'
7
7
  import AppLike from '../../../test/AppLike'
8
8
 
9
+ const mockUpdateDocumentPermissions = jest.fn()
10
+ const mockUpdateSharingMemberType = jest.fn()
11
+
12
+ jest.mock('../../hooks/useSharingContext', () => ({
13
+ // eslint-disable-next-line react/display-name
14
+ useSharingContext: () => ({
15
+ updateDocumentPermissions: mockUpdateDocumentPermissions,
16
+ updateSharingMemberType: mockUpdateSharingMemberType
17
+ })
18
+ }))
19
+
9
20
  describe('MemberRecipient component', () => {
10
21
  const client = createMockClient({})
11
22
  client.options = {
@@ -2,6 +2,7 @@ import React, { useState, useRef, useCallback } from 'react'
2
2
  import { useI18n } from 'twake-i18n'
3
3
 
4
4
  import { useClient } from 'cozy-client'
5
+ import minilog from 'cozy-minilog'
5
6
  import ActionsMenu from 'cozy-ui/transpiled/react/ActionsMenu'
6
7
  import {
7
8
  makeActions,
@@ -10,9 +11,14 @@ import {
10
11
  import DropdownButton from 'cozy-ui/transpiled/react/DropdownButton'
11
12
  import Spinner from 'cozy-ui/transpiled/react/Spinner'
12
13
  import Typography from 'cozy-ui/transpiled/react/Typography'
14
+ import { useAlert } from 'cozy-ui/transpiled/react/providers/Alert'
13
15
 
14
- import { permission } from './actions/permission'
15
16
  import { revokeMember } from './actions/revokeMember'
17
+ import { setReadOnlySharedPermission } from './actions/setReadOnlySharedPermission'
18
+ import { setReadWriteSharedPermission } from './actions/setReadWriteSharedPermission'
19
+ import { useSharingContext } from '../../hooks/useSharingContext'
20
+
21
+ const log = minilog('MemberRecipientPermissions')
16
22
 
17
23
  const MemberRecipientPermissions = ({
18
24
  isOwner,
@@ -30,6 +36,8 @@ const MemberRecipientPermissions = ({
30
36
  const { t } = useI18n()
31
37
  const buttonRef = useRef()
32
38
  const client = useClient()
39
+ const { updateSharingMemberType } = useSharingContext()
40
+ const { showAlert } = useAlert()
33
41
 
34
42
  const [revoking, setRevoking] = useState(false)
35
43
  const [isMenuDisplayed, setMenuDisplayed] = useState(false)
@@ -42,27 +50,72 @@ const MemberRecipientPermissions = ({
42
50
  !contactIsOwner &&
43
51
  ((instanceMatchesClient && !isOwner) || isOwner)
44
52
 
45
- const toggleMenu = () => setMenuDisplayed(!isMenuDisplayed)
46
- const hideMenu = () => setMenuDisplayed(false)
53
+ const toggleMenu = useCallback(() => {
54
+ setMenuDisplayed(displayed => !displayed)
55
+ }, [])
56
+ const hideMenu = useCallback(() => {
57
+ setMenuDisplayed(false)
58
+ }, [])
47
59
 
48
60
  const handleRevocation = useCallback(async () => {
49
61
  setRevoking(true)
50
- if (isOwner) {
51
- await onRevoke(document, sharingId, memberIndex)
52
- } else {
53
- await onRevokeSelf(document)
62
+ try {
63
+ if (isOwner) {
64
+ await onRevoke(document, sharingId, memberIndex)
65
+ } else {
66
+ await onRevokeSelf(document)
67
+ }
68
+ } finally {
69
+ setRevoking(false)
54
70
  }
55
- setRevoking(false)
56
71
  }, [isOwner, onRevoke, onRevokeSelf, document, sharingId, memberIndex])
57
72
 
58
- const actions = makeActions([permission, divider, revokeMember], {
59
- client,
60
- t,
61
- type: type ?? 'one-way',
62
- isOwner,
63
- isSharedDrive,
64
- handleRevocation
65
- })
73
+ const setType = useCallback(
74
+ async newType => {
75
+ if (newType === type) {
76
+ hideMenu()
77
+ return
78
+ }
79
+ try {
80
+ await updateSharingMemberType(sharingId, memberIndex, newType)
81
+ } catch (error) {
82
+ log.error('Failed to change member permission type', error)
83
+ showAlert({
84
+ message: t('Share.members.error.changePermission'),
85
+ severity: 'error',
86
+ variant: 'filled'
87
+ })
88
+ }
89
+ hideMenu()
90
+ },
91
+ [
92
+ hideMenu,
93
+ memberIndex,
94
+ sharingId,
95
+ showAlert,
96
+ t,
97
+ type,
98
+ updateSharingMemberType
99
+ ]
100
+ )
101
+
102
+ const actions = makeActions(
103
+ [
104
+ setReadOnlySharedPermission,
105
+ setReadWriteSharedPermission,
106
+ divider,
107
+ revokeMember
108
+ ],
109
+ {
110
+ client,
111
+ t,
112
+ type: type ?? 'one-way',
113
+ isOwner,
114
+ isSharedDrive,
115
+ setType,
116
+ handleRevocation
117
+ }
118
+ )
66
119
 
67
120
  return (
68
121
  <div className={className}>
@@ -0,0 +1,165 @@
1
+ import { render, fireEvent, screen, act, waitFor } from '@testing-library/react'
2
+ import React from 'react'
3
+
4
+ import { createMockClient } from 'cozy-client'
5
+
6
+ import MemberRecipientPermissions from './MemberRecipientPermissions'
7
+ import AppLike from '../../../test/AppLike'
8
+
9
+ const mockUpdateSharingMemberType = jest.fn()
10
+ const mockShowAlert = jest.fn()
11
+
12
+ jest.mock('../../hooks/useSharingContext', () => ({
13
+ useSharingContext: () => ({
14
+ updateSharingMemberType: mockUpdateSharingMemberType
15
+ })
16
+ }))
17
+
18
+ jest.mock('cozy-ui/transpiled/react/providers/Alert', () => ({
19
+ __esModule: true,
20
+ default: ({ children }) => children,
21
+ useAlert: () => ({
22
+ showAlert: mockShowAlert
23
+ })
24
+ }))
25
+
26
+ describe('MemberRecipientPermissions component', () => {
27
+ const client = createMockClient({})
28
+ client.options = {
29
+ uri: 'http://cozy.local:8080'
30
+ }
31
+
32
+ const defaultProps = {
33
+ isOwner: true,
34
+ isSharedDrive: false,
35
+ status: 'ready',
36
+ instance: 'http://cozy.local:8080',
37
+ type: 'two-way',
38
+ document: { id: 'doc-123', type: 'io.cozy.files', path: '/test' },
39
+ sharingId: 'sharing-123',
40
+ memberIndex: 1,
41
+ onRevoke: jest.fn(),
42
+ onRevokeSelf: jest.fn()
43
+ }
44
+
45
+ beforeEach(() => {
46
+ jest.clearAllMocks()
47
+ })
48
+
49
+ const setup = props => {
50
+ return render(
51
+ <AppLike client={client}>
52
+ <MemberRecipientPermissions {...defaultProps} {...props} />
53
+ </AppLike>
54
+ )
55
+ }
56
+
57
+ let createRangeBackup
58
+
59
+ beforeAll(() => {
60
+ createRangeBackup = global.document.createRange
61
+ global.document.createRange = jest.fn(() => ({
62
+ setStart: () => {},
63
+ setEnd: () => {},
64
+ commonAncestorContainer: {
65
+ nodeName: 'BODY',
66
+ ownerDocument: document
67
+ }
68
+ }))
69
+ })
70
+
71
+ afterAll(() => {
72
+ global.document.createRange = createRangeBackup
73
+ })
74
+
75
+ it('should render the current permission type', () => {
76
+ setup()
77
+ expect(screen.getByText('can change')).toBeInTheDocument()
78
+ })
79
+
80
+ it('should call updateSharingMemberType when changing to one-way', async () => {
81
+ mockUpdateSharingMemberType.mockResolvedValue(undefined)
82
+
83
+ const { getByText } = setup({ type: 'two-way' })
84
+
85
+ fireEvent.click(getByText('can change'))
86
+ fireEvent.click(getByText('Can view'))
87
+
88
+ expect(mockUpdateSharingMemberType).toHaveBeenCalledWith(
89
+ 'sharing-123',
90
+ 1,
91
+ 'one-way'
92
+ )
93
+ })
94
+
95
+ it('should call updateSharingMemberType when changing to two-way', async () => {
96
+ mockUpdateSharingMemberType.mockResolvedValue(undefined)
97
+
98
+ const { getByText } = setup({ type: 'one-way' })
99
+
100
+ fireEvent.click(getByText('can view'))
101
+ fireEvent.click(getByText('Can change'))
102
+
103
+ expect(mockUpdateSharingMemberType).toHaveBeenCalledWith(
104
+ 'sharing-123',
105
+ 1,
106
+ 'two-way'
107
+ )
108
+ })
109
+
110
+ it('should show error alert when updateSharingMemberType fails', async () => {
111
+ mockUpdateSharingMemberType.mockRejectedValue(new Error('Network error'))
112
+
113
+ const { getByText } = setup({ type: 'two-way' })
114
+
115
+ await act(async () => {
116
+ fireEvent.click(getByText('can change'))
117
+ fireEvent.click(getByText('Can view'))
118
+ })
119
+
120
+ await waitFor(() => {
121
+ expect(mockShowAlert).toHaveBeenCalledWith({
122
+ message:
123
+ 'An error occurred while changing the permissions. Please try again.',
124
+ severity: 'error',
125
+ variant: 'filled'
126
+ })
127
+ })
128
+ })
129
+
130
+ it('should not call updateSharingMemberType when selecting same type', async () => {
131
+ mockUpdateSharingMemberType.mockResolvedValue(undefined)
132
+
133
+ const { getByText } = setup({ type: 'two-way' })
134
+
135
+ fireEvent.click(getByText('can change'))
136
+ fireEvent.click(getByText('Can change'))
137
+
138
+ expect(mockUpdateSharingMemberType).not.toHaveBeenCalled()
139
+ })
140
+
141
+ it('should not render menu when user is not owner and not the shared drive contact', () => {
142
+ const { queryByText } = setup({
143
+ isOwner: false,
144
+ instance: 'http://other-cozy.local:8080'
145
+ })
146
+
147
+ expect(queryByText('can change')).not.toBeInTheDocument()
148
+ expect(queryByText('can view')).not.toBeInTheDocument()
149
+ })
150
+
151
+ it('should render menu for owner', () => {
152
+ const { getByText } = setup({ isOwner: true })
153
+
154
+ expect(getByText('can change')).toBeInTheDocument()
155
+ })
156
+
157
+ it('should render menu for the user themselves', () => {
158
+ const { getByText } = setup({
159
+ isOwner: false,
160
+ instance: 'http://cozy.local:8080'
161
+ })
162
+
163
+ expect(getByText('can change')).toBeInTheDocument()
164
+ })
165
+ })
@@ -0,0 +1,33 @@
1
+ import React, { forwardRef } from 'react'
2
+
3
+ import ActionsMenuItem from 'cozy-ui/transpiled/react/ActionsMenu/ActionsMenuItem'
4
+ import Icon from 'cozy-ui/transpiled/react/Icon'
5
+ import TrashIcon from 'cozy-ui/transpiled/react/Icons/Trash'
6
+ import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
7
+ import ListItemText from 'cozy-ui/transpiled/react/ListItemText'
8
+ import Typography from 'cozy-ui/transpiled/react/Typography'
9
+
10
+ const revokeLink = ({ t, handleRevocation }) => {
11
+ const title = t('Share.permissionLink.deactivate')
12
+
13
+ return {
14
+ name: 'revokeLink',
15
+ label: title,
16
+ icon: TrashIcon,
17
+ action: handleRevocation,
18
+ Component: forwardRef(function RevokeLinkItem(props, ref) {
19
+ return (
20
+ <ActionsMenuItem {...props} ref={ref}>
21
+ <ListItemIcon>
22
+ <Icon icon={TrashIcon} color="var(--errorColor)" />
23
+ </ListItemIcon>
24
+ <ListItemText
25
+ primary={<Typography color="error">{title}</Typography>}
26
+ />
27
+ </ActionsMenuItem>
28
+ )
29
+ })
30
+ }
31
+ }
32
+
33
+ export { revokeLink }
@@ -8,7 +8,7 @@ import Radios from 'cozy-ui/transpiled/react/Radios'
8
8
  const makeComponent = ({ label, type, onClick }) => {
9
9
  const Component = forwardRef((props, ref) => {
10
10
  return (
11
- <ActionsMenuItem {...props} ref={ref} button={false} onClick={onClick}>
11
+ <ActionsMenuItem {...props} ref={ref} onClick={onClick}>
12
12
  <ListItemIcon>
13
13
  <Radios checked={type === 'one-way'} />
14
14
  </ListItemIcon>
@@ -0,0 +1,95 @@
1
+ import { render, screen, fireEvent } from '@testing-library/react'
2
+ import React from 'react'
3
+
4
+ import { setReadOnlySharedPermission } from './setReadOnlySharedPermission'
5
+ import AppLike from '../../../../test/AppLike'
6
+
7
+ const mockT = key => {
8
+ const translations = {
9
+ 'Share.type.one-way': 'Can view',
10
+ 'Share.type.two-way': 'Can change'
11
+ }
12
+ return translations[key] || key
13
+ }
14
+
15
+ describe('setReadOnlySharedPermission', () => {
16
+ let setType
17
+
18
+ beforeEach(() => {
19
+ setType = jest.fn()
20
+ })
21
+
22
+ it('should return correct action structure', () => {
23
+ const action = setReadOnlySharedPermission({
24
+ t: mockT,
25
+ type: 'one-way',
26
+ setType
27
+ })
28
+
29
+ expect(action.name).toBe('setReadOnlySharedPermission')
30
+ expect(action.label).toBe('Can view')
31
+ expect(action.icon).toBeNull()
32
+ })
33
+
34
+ it('should call setType with one-way when action is triggered', () => {
35
+ const action = setReadOnlySharedPermission({
36
+ t: mockT,
37
+ type: 'two-way',
38
+ setType
39
+ })
40
+
41
+ action.action()
42
+
43
+ expect(setType).toHaveBeenCalledWith('one-way')
44
+ })
45
+
46
+ it('should render radio as checked when type is one-way', () => {
47
+ const { Component } = setReadOnlySharedPermission({
48
+ t: mockT,
49
+ type: 'one-way',
50
+ setType
51
+ })
52
+
53
+ render(
54
+ <AppLike>
55
+ <Component />
56
+ </AppLike>
57
+ )
58
+
59
+ expect(screen.getByRole('radio')).toBeChecked()
60
+ })
61
+
62
+ it('should render radio as unchecked when type is two-way', () => {
63
+ const { Component } = setReadOnlySharedPermission({
64
+ t: mockT,
65
+ type: 'two-way',
66
+ setType
67
+ })
68
+
69
+ render(
70
+ <AppLike>
71
+ <Component />
72
+ </AppLike>
73
+ )
74
+
75
+ expect(screen.getByRole('radio')).not.toBeChecked()
76
+ })
77
+
78
+ it('should call setType with one-way when the component is clicked', () => {
79
+ const { Component } = setReadOnlySharedPermission({
80
+ t: mockT,
81
+ type: 'two-way',
82
+ setType
83
+ })
84
+
85
+ render(
86
+ <AppLike>
87
+ <Component />
88
+ </AppLike>
89
+ )
90
+
91
+ fireEvent.click(screen.getByText('Can view'))
92
+
93
+ expect(setType).toHaveBeenCalledWith('one-way')
94
+ })
95
+ })
@@ -8,7 +8,7 @@ import Radios from 'cozy-ui/transpiled/react/Radios'
8
8
  const makeComponent = ({ label, type, onClick }) => {
9
9
  const Component = forwardRef((props, ref) => {
10
10
  return (
11
- <ActionsMenuItem {...props} ref={ref} button={false} onClick={onClick}>
11
+ <ActionsMenuItem {...props} ref={ref} onClick={onClick}>
12
12
  <ListItemIcon>
13
13
  <Radios checked={type === 'two-way'} />
14
14
  </ListItemIcon>