mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #4099 from overleaf/as-clean-up-share-modal-window
Pull `user` and `isRestrictedTokenMember` from `ApplicationContext`/`EditorContext` instead of `window` GitOrigin-RevId: 9084d4f1b075123fe4b10b1156c7b844595827e2
This commit is contained in:
parent
568e99ad47
commit
3f4fa4c6cc
7 changed files with 202 additions and 143 deletions
|
@ -1,12 +1,19 @@
|
|||
import React, { useState } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { useApplicationContext } from '../../../shared/context/application-context'
|
||||
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { upgradePlan } from '../../../main/account-upgrade'
|
||||
import StartFreeTrialButton from '../../../shared/components/start-free-trial-button'
|
||||
|
||||
export default function AddCollaboratorsUpgrade() {
|
||||
const { t } = useTranslation()
|
||||
const { user } = useApplicationContext({
|
||||
user: PropTypes.shape({ allowedFreeTrial: PropTypes.boolean }),
|
||||
})
|
||||
|
||||
const [startedFreeTrial, setStartedFreeTrial] = useState(false)
|
||||
|
||||
|
@ -53,7 +60,7 @@ export default function AddCollaboratorsUpgrade() {
|
|||
</ul>
|
||||
|
||||
<p className="text-center row-spaced-thin">
|
||||
{window.user.allowedFreeTrial ? (
|
||||
{user.allowedFreeTrial ? (
|
||||
<StartFreeTrialButton
|
||||
buttonStyle="success"
|
||||
setStartedFreeTrial={setStartedFreeTrial}
|
||||
|
|
|
@ -6,6 +6,7 @@ import Icon from '../../../shared/components/icon'
|
|||
import AccessibleModal from '../../../shared/components/accessible-modal'
|
||||
import PropTypes from 'prop-types'
|
||||
import { ReadOnlyTokenLink } from './link-sharing'
|
||||
import { useEditorContext } from '../../../shared/context/editor-context'
|
||||
|
||||
export default function ShareProjectModalContent({
|
||||
show,
|
||||
|
@ -14,6 +15,10 @@ export default function ShareProjectModalContent({
|
|||
inFlight,
|
||||
error,
|
||||
}) {
|
||||
const { isRestrictedTokenMember } = useEditorContext({
|
||||
isRestrictedTokenMember: PropTypes.bool,
|
||||
})
|
||||
|
||||
return (
|
||||
<AccessibleModal show={show} onHide={cancel} animation={animation}>
|
||||
<Modal.Header closeButton>
|
||||
|
@ -24,11 +29,7 @@ export default function ShareProjectModalContent({
|
|||
|
||||
<Modal.Body className="modal-body-share">
|
||||
<Grid fluid>
|
||||
{window.isRestrictedTokenMember ? (
|
||||
<ReadOnlyTokenLink />
|
||||
) : (
|
||||
<ShareModalBody />
|
||||
)}
|
||||
{isRestrictedTokenMember ? <ReadOnlyTokenLink /> : <ShareModalBody />}
|
||||
</Grid>
|
||||
</Modal.Body>
|
||||
|
||||
|
|
|
@ -2,11 +2,16 @@ import App from '../../../base'
|
|||
import { react2angular } from 'react2angular'
|
||||
|
||||
import ShareProjectModal from '../components/share-project-modal'
|
||||
import { rootContext } from '../../../shared/context/root-context'
|
||||
import { listProjectInvites, listProjectMembers } from '../utils/api'
|
||||
|
||||
App.component(
|
||||
'shareProjectModal',
|
||||
react2angular(ShareProjectModal, undefined, ['ide'])
|
||||
react2angular(
|
||||
rootContext.use(ShareProjectModal),
|
||||
Object.keys(ShareProjectModal.propTypes),
|
||||
['ide']
|
||||
)
|
||||
)
|
||||
|
||||
export default App.controller(
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import createSharedContext from 'react2angular-shared-context'
|
||||
|
||||
import { ApplicationProvider } from './application-context'
|
||||
import { EditorProvider } from './editor-context'
|
||||
import createSharedContext from 'react2angular-shared-context'
|
||||
import { ChatProvider } from '../../features/chat/context/chat-context'
|
||||
import { LayoutProvider } from './layout-context'
|
||||
import { CompileProvider } from './compile-context'
|
||||
import { LayoutProvider } from './layout-context'
|
||||
import { ChatProvider } from '../../features/chat/context/chat-context'
|
||||
|
||||
export function ContextRoot({ children, ide, settings }) {
|
||||
const isAnonymousUser = window.user.id == null
|
||||
|
|
|
@ -1,89 +1,8 @@
|
|||
import React, { useEffect } from 'react'
|
||||
import ShareProjectModal from '../js/features/share-project-modal/components/share-project-modal'
|
||||
import { ContextRoot } from '../js/shared/context/root-context'
|
||||
import useFetchMock from './hooks/use-fetch-mock'
|
||||
|
||||
const contacts = [
|
||||
// user with edited name
|
||||
{
|
||||
type: 'user',
|
||||
email: 'test-user@example.com',
|
||||
first_name: 'Test',
|
||||
last_name: 'User',
|
||||
name: 'Test User',
|
||||
},
|
||||
// user with default name (email prefix)
|
||||
{
|
||||
type: 'user',
|
||||
email: 'test@example.com',
|
||||
first_name: 'test',
|
||||
},
|
||||
// no last name
|
||||
{
|
||||
type: 'user',
|
||||
first_name: 'Eratosthenes',
|
||||
email: 'eratosthenes@example.com',
|
||||
},
|
||||
// more users
|
||||
{
|
||||
type: 'user',
|
||||
first_name: 'Claudius',
|
||||
last_name: 'Ptolemy',
|
||||
email: 'ptolemy@example.com',
|
||||
},
|
||||
{
|
||||
type: 'user',
|
||||
first_name: 'Abd al-Rahman',
|
||||
last_name: 'Al-Sufi',
|
||||
email: 'al-sufi@example.com',
|
||||
},
|
||||
{
|
||||
type: 'user',
|
||||
first_name: 'Nicolaus',
|
||||
last_name: 'Copernicus',
|
||||
email: 'copernicus@example.com',
|
||||
},
|
||||
]
|
||||
|
||||
const setupFetchMock = fetchMock => {
|
||||
const delay = 1000
|
||||
|
||||
fetchMock
|
||||
// list contacts
|
||||
.get('express:/user/contacts', { contacts }, { delay })
|
||||
// change privacy setting
|
||||
.post('express:/project/:projectId/settings/admin', 200, { delay })
|
||||
// update project member (e.g. set privilege level)
|
||||
.put('express:/project/:projectId/users/:userId', 200, { delay })
|
||||
// remove project member
|
||||
.delete('express:/project/:projectId/users/:userId', 200, { delay })
|
||||
// transfer ownership
|
||||
.post('express:/project/:projectId/transfer-ownership', 200, {
|
||||
delay,
|
||||
})
|
||||
// send invite
|
||||
.post('express:/project/:projectId/invite', 200, { delay })
|
||||
// delete invite
|
||||
.delete('express:/project/:projectId/invite/:inviteId', 204, {
|
||||
delay,
|
||||
})
|
||||
// resend invite
|
||||
.post('express:/project/:projectId/invite/:inviteId/resend', 200, {
|
||||
delay,
|
||||
})
|
||||
// send analytics event
|
||||
.post('express:/event/:key', 200)
|
||||
}
|
||||
|
||||
const ideWithProject = project => {
|
||||
return {
|
||||
$scope: {
|
||||
$watch: () => () => {},
|
||||
$applyAsync: () => {},
|
||||
project,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const LinkSharingOff = args => {
|
||||
useFetchMock(setupFetchMock)
|
||||
|
||||
|
@ -92,7 +11,9 @@ export const LinkSharingOff = args => {
|
|||
publicAccesLevel: 'private',
|
||||
}
|
||||
|
||||
return <ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
return renderWithContext(
|
||||
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
)
|
||||
}
|
||||
|
||||
export const LinkSharingOn = args => {
|
||||
|
@ -103,7 +24,9 @@ export const LinkSharingOn = args => {
|
|||
publicAccesLevel: 'tokenBased',
|
||||
}
|
||||
|
||||
return <ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
return renderWithContext(
|
||||
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
)
|
||||
}
|
||||
|
||||
export const LinkSharingLoading = args => {
|
||||
|
@ -115,7 +38,9 @@ export const LinkSharingLoading = args => {
|
|||
tokens: undefined,
|
||||
}
|
||||
|
||||
return <ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
return renderWithContext(
|
||||
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
)
|
||||
}
|
||||
|
||||
export const NonAdminLinkSharingOff = args => {
|
||||
|
@ -124,7 +49,7 @@ export const NonAdminLinkSharingOff = args => {
|
|||
publicAccesLevel: 'private',
|
||||
}
|
||||
|
||||
return (
|
||||
return renderWithContext(
|
||||
<ShareProjectModal
|
||||
{...args}
|
||||
isAdmin={false}
|
||||
|
@ -139,7 +64,7 @@ export const NonAdminLinkSharingOn = args => {
|
|||
publicAccesLevel: 'tokenBased',
|
||||
}
|
||||
|
||||
return (
|
||||
return renderWithContext(
|
||||
<ShareProjectModal
|
||||
{...args}
|
||||
isAdmin={false}
|
||||
|
@ -149,20 +74,26 @@ export const NonAdminLinkSharingOn = args => {
|
|||
}
|
||||
|
||||
export const RestrictedTokenMember = args => {
|
||||
// Override isRestrictedTokenMember to be true, then revert it back to the
|
||||
// original value on unmount
|
||||
// Currently this is necessary because the context value is set from window,
|
||||
// however in the future we should change this to set via props
|
||||
const originalIsRestrictedTokenMember = window.isRestrictedTokenMember
|
||||
window.isRestrictedTokenMember = true
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
window.isRestrictedTokenMember = false
|
||||
window.isRestrictedTokenMember = originalIsRestrictedTokenMember
|
||||
}
|
||||
}, [])
|
||||
})
|
||||
|
||||
const project = {
|
||||
...args.project,
|
||||
publicAccesLevel: 'tokenBased',
|
||||
}
|
||||
|
||||
return <ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
return renderWithContext(
|
||||
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
)
|
||||
}
|
||||
|
||||
export const LegacyLinkSharingReadAndWrite = args => {
|
||||
|
@ -173,7 +104,9 @@ export const LegacyLinkSharingReadAndWrite = args => {
|
|||
publicAccesLevel: 'readAndWrite',
|
||||
}
|
||||
|
||||
return <ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
return renderWithContext(
|
||||
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
)
|
||||
}
|
||||
|
||||
export const LegacyLinkSharingReadOnly = args => {
|
||||
|
@ -184,7 +117,9 @@ export const LegacyLinkSharingReadOnly = args => {
|
|||
publicAccesLevel: 'readOnly',
|
||||
}
|
||||
|
||||
return <ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
return renderWithContext(
|
||||
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
)
|
||||
}
|
||||
|
||||
export const LimitedCollaborators = args => {
|
||||
|
@ -198,7 +133,9 @@ export const LimitedCollaborators = args => {
|
|||
},
|
||||
}
|
||||
|
||||
return <ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
return renderWithContext(
|
||||
<ShareProjectModal {...args} ide={ideWithProject(project)} />
|
||||
)
|
||||
}
|
||||
|
||||
const project = {
|
||||
|
@ -261,3 +198,97 @@ export default {
|
|||
handleHide: { action: 'hide' },
|
||||
},
|
||||
}
|
||||
|
||||
// Unfortunately, we cannot currently use decorators here, since we need to
|
||||
// set a value on window, before the contexts are rendered.
|
||||
// When using decorators, the contexts are rendered before the story, so we
|
||||
// don't have the opportunity to set the window value first.
|
||||
function renderWithContext(Story) {
|
||||
return (
|
||||
<ContextRoot ide={window._ide} settings={{}}>
|
||||
{Story}
|
||||
</ContextRoot>
|
||||
)
|
||||
}
|
||||
|
||||
const contacts = [
|
||||
// user with edited name
|
||||
{
|
||||
type: 'user',
|
||||
email: 'test-user@example.com',
|
||||
first_name: 'Test',
|
||||
last_name: 'User',
|
||||
name: 'Test User',
|
||||
},
|
||||
// user with default name (email prefix)
|
||||
{
|
||||
type: 'user',
|
||||
email: 'test@example.com',
|
||||
first_name: 'test',
|
||||
},
|
||||
// no last name
|
||||
{
|
||||
type: 'user',
|
||||
first_name: 'Eratosthenes',
|
||||
email: 'eratosthenes@example.com',
|
||||
},
|
||||
// more users
|
||||
{
|
||||
type: 'user',
|
||||
first_name: 'Claudius',
|
||||
last_name: 'Ptolemy',
|
||||
email: 'ptolemy@example.com',
|
||||
},
|
||||
{
|
||||
type: 'user',
|
||||
first_name: 'Abd al-Rahman',
|
||||
last_name: 'Al-Sufi',
|
||||
email: 'al-sufi@example.com',
|
||||
},
|
||||
{
|
||||
type: 'user',
|
||||
first_name: 'Nicolaus',
|
||||
last_name: 'Copernicus',
|
||||
email: 'copernicus@example.com',
|
||||
},
|
||||
]
|
||||
|
||||
function setupFetchMock(fetchMock) {
|
||||
const delay = 1000
|
||||
|
||||
fetchMock
|
||||
// list contacts
|
||||
.get('express:/user/contacts', { contacts }, { delay })
|
||||
// change privacy setting
|
||||
.post('express:/project/:projectId/settings/admin', 200, { delay })
|
||||
// update project member (e.g. set privilege level)
|
||||
.put('express:/project/:projectId/users/:userId', 200, { delay })
|
||||
// remove project member
|
||||
.delete('express:/project/:projectId/users/:userId', 200, { delay })
|
||||
// transfer ownership
|
||||
.post('express:/project/:projectId/transfer-ownership', 200, {
|
||||
delay,
|
||||
})
|
||||
// send invite
|
||||
.post('express:/project/:projectId/invite', 200, { delay })
|
||||
// delete invite
|
||||
.delete('express:/project/:projectId/invite/:inviteId', 204, {
|
||||
delay,
|
||||
})
|
||||
// resend invite
|
||||
.post('express:/project/:projectId/invite/:inviteId/resend', 200, {
|
||||
delay,
|
||||
})
|
||||
// send analytics event
|
||||
.post('express:/event/:key', 200)
|
||||
}
|
||||
|
||||
function ideWithProject(project) {
|
||||
return {
|
||||
$scope: {
|
||||
$watch: () => () => {},
|
||||
$applyAsync: () => {},
|
||||
project,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ import { expect } from 'chai'
|
|||
import sinon from 'sinon'
|
||||
import React from 'react'
|
||||
import {
|
||||
cleanup,
|
||||
render,
|
||||
screen,
|
||||
fireEvent,
|
||||
waitFor,
|
||||
|
@ -11,7 +9,12 @@ import {
|
|||
} from '@testing-library/react'
|
||||
import fetchMock from 'fetch-mock'
|
||||
import { get } from 'lodash'
|
||||
|
||||
import ShareProjectModal from '../../../../../frontend/js/features/share-project-modal/components/share-project-modal'
|
||||
import {
|
||||
renderWithEditorContext,
|
||||
cleanUpContext,
|
||||
} from '../../../helpers/render-with-context'
|
||||
import * as locationModule from '../../../../../frontend/js/features/share-project-modal/utils/location'
|
||||
|
||||
describe('<ShareProjectModal/>', function () {
|
||||
|
@ -98,11 +101,11 @@ describe('<ShareProjectModal/>', function () {
|
|||
|
||||
afterEach(function () {
|
||||
fetchMock.restore()
|
||||
cleanup()
|
||||
cleanUpContext()
|
||||
})
|
||||
|
||||
it('renders the modal', async function () {
|
||||
render(<ShareProjectModal {...modalProps} />)
|
||||
renderWithEditorContext(<ShareProjectModal {...modalProps} />)
|
||||
|
||||
await screen.findByText('Share Project')
|
||||
})
|
||||
|
@ -110,7 +113,9 @@ describe('<ShareProjectModal/>', function () {
|
|||
it('calls handleHide when a Close button is pressed', async function () {
|
||||
const handleHide = sinon.stub()
|
||||
|
||||
render(<ShareProjectModal {...modalProps} handleHide={handleHide} />)
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal {...modalProps} handleHide={handleHide} />
|
||||
)
|
||||
|
||||
const [
|
||||
headerCloseButton,
|
||||
|
@ -124,7 +129,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
})
|
||||
|
||||
it('handles access level "private"', async function () {
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({ ...project, publicAccesLevel: 'private' })}
|
||||
|
@ -143,7 +148,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
})
|
||||
|
||||
it('handles access level "tokenBased"', async function () {
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({ ...project, publicAccesLevel: 'tokenBased' })}
|
||||
|
@ -160,7 +165,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
})
|
||||
|
||||
it('handles legacy access level "readAndWrite"', async function () {
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({ ...project, publicAccesLevel: 'readAndWrite' })}
|
||||
|
@ -174,7 +179,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
})
|
||||
|
||||
it('handles legacy access level "readOnly"', async function () {
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({ ...project, publicAccesLevel: 'readOnly' })}
|
||||
|
@ -197,7 +202,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
]
|
||||
|
||||
// render as admin: actions should be present
|
||||
const { rerender } = render(
|
||||
const { rerender } = renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -212,7 +217,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
await screen.findByRole('button', { name: 'Turn off link sharing' })
|
||||
await screen.findByRole('button', { name: 'Resend' })
|
||||
|
||||
// render as non-admin, link sharing on: actions should be missing and message should be present
|
||||
// render as non-admin (non-owner), link sharing on: actions should be missing and message should be present
|
||||
rerender(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
|
@ -260,17 +265,14 @@ describe('<ShareProjectModal/>', function () {
|
|||
})
|
||||
|
||||
it('only shows read-only token link to restricted token members', async function () {
|
||||
window.isRestrictedTokenMember = true
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({ ...project, publicAccesLevel: 'tokenBased' })}
|
||||
/>
|
||||
/>,
|
||||
{ isRestrictedTokenMember: true }
|
||||
)
|
||||
|
||||
window.isRestrictedTokenMember = false
|
||||
|
||||
// no buttons
|
||||
expect(screen.queryByRole('button', { name: 'Turn on link sharing' })).to.be
|
||||
.null
|
||||
|
@ -310,7 +312,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
},
|
||||
]
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -354,7 +356,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
},
|
||||
]
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -389,7 +391,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
},
|
||||
]
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -423,7 +425,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
},
|
||||
]
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -466,7 +468,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
},
|
||||
]
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -506,7 +508,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
},
|
||||
]
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -549,7 +551,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
})
|
||||
|
||||
it('sends invites to input email addresses', async function () {
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -637,11 +639,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
})
|
||||
|
||||
it('displays a message when the collaborator limit is reached', async function () {
|
||||
const originalUser = window.user
|
||||
|
||||
window.user = { allowedFreeTrial: true }
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -651,7 +649,13 @@ describe('<ShareProjectModal/>', function () {
|
|||
collaborators: 0,
|
||||
},
|
||||
})}
|
||||
/>
|
||||
/>,
|
||||
{
|
||||
user: {
|
||||
id: '123abd',
|
||||
allowedFreeTrial: true,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(screen.queryByLabelText('Share with your collaborators')).to.be.null
|
||||
|
@ -659,12 +663,10 @@ describe('<ShareProjectModal/>', function () {
|
|||
screen.getByText(
|
||||
/You need to upgrade your account to add more collaborators/
|
||||
)
|
||||
|
||||
window.user = originalUser
|
||||
})
|
||||
|
||||
it('handles server error responses', async function () {
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({
|
||||
|
@ -747,7 +749,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
}
|
||||
}
|
||||
|
||||
render(
|
||||
renderWithEditorContext(
|
||||
<ShareProjectModal
|
||||
{...modalProps}
|
||||
ide={ideWithProject({ ...project, publicAccesLevel: 'private' })}
|
||||
|
@ -795,7 +797,7 @@ describe('<ShareProjectModal/>', function () {
|
|||
})
|
||||
|
||||
it('avoids selecting unmatched contact', async function () {
|
||||
render(<ShareProjectModal {...modalProps} />)
|
||||
renderWithEditorContext(<ShareProjectModal {...modalProps} />)
|
||||
|
||||
const [inputElement] = await screen.findAllByLabelText(
|
||||
'Share with your collaborators'
|
||||
|
|
|
@ -16,11 +16,13 @@ export function EditorProviders({
|
|||
on: sinon.stub(),
|
||||
removeListener: sinon.stub(),
|
||||
},
|
||||
isRestrictedTokenMember = false,
|
||||
children,
|
||||
}) {
|
||||
window.user = user || window.user
|
||||
window.gitBridgePublicBaseUrl = 'git.overleaf.test'
|
||||
window.project_id = projectId != null ? projectId : window.project_id
|
||||
window.isRestrictedTokenMember = isRestrictedTokenMember
|
||||
|
||||
window._ide = {
|
||||
$scope: {
|
||||
|
@ -47,8 +49,13 @@ export function EditorProviders({
|
|||
)
|
||||
}
|
||||
|
||||
export function renderWithEditorContext(children, props) {
|
||||
return render(<EditorProviders {...props}>{children}</EditorProviders>)
|
||||
export function renderWithEditorContext(component, contextProps) {
|
||||
return render(component, {
|
||||
// eslint-disable-next-line react/display-name
|
||||
wrapper: ({ children }) => (
|
||||
<EditorProviders {...contextProps}>{children}</EditorProviders>
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
export function ChatProviders({ children, ...props }) {
|
||||
|
@ -59,8 +66,13 @@ export function ChatProviders({ children, ...props }) {
|
|||
)
|
||||
}
|
||||
|
||||
export function renderWithChatContext(children, props) {
|
||||
return render(<ChatProviders {...props}>{children}</ChatProviders>)
|
||||
export function renderWithChatContext(component, props) {
|
||||
return render(component, {
|
||||
// eslint-disable-next-line react/display-name
|
||||
wrapper: ({ children }) => (
|
||||
<ChatProviders {...props}>{children}</ChatProviders>
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
export function cleanUpContext() {
|
||||
|
|
Loading…
Reference in a new issue