diff --git a/services/web/frontend/js/features/share-project-modal/components/share-project-modal.js b/services/web/frontend/js/features/share-project-modal/components/share-project-modal.js
index c93c51631c..b46d5f0363 100644
--- a/services/web/frontend/js/features/share-project-modal/components/share-project-modal.js
+++ b/services/web/frontend/js/features/share-project-modal/components/share-project-modal.js
@@ -84,12 +84,11 @@ export default function ShareProjectModal({
show,
animation = true,
isAdmin,
- ide,
}) {
const [inFlight, setInFlight] = useState(false)
const [error, setError] = useState()
- const [project, setProject] = useScopeValue('project', ide.$scope, true)
+ const [project, setProject] = useScopeValue('project', true)
// reset error when the modal is opened
useEffect(() => {
@@ -167,8 +166,5 @@ ShareProjectModal.propTypes = {
animation: PropTypes.bool,
handleHide: PropTypes.func.isRequired,
isAdmin: PropTypes.bool.isRequired,
- ide: PropTypes.shape({
- $scope: PropTypes.object.isRequired,
- }).isRequired,
show: PropTypes.bool.isRequired,
}
diff --git a/services/web/frontend/js/features/share-project-modal/controllers/react-share-project-modal-controller.js b/services/web/frontend/js/features/share-project-modal/controllers/react-share-project-modal-controller.js
index 5fcc87d96b..11060a0e9c 100644
--- a/services/web/frontend/js/features/share-project-modal/controllers/react-share-project-modal-controller.js
+++ b/services/web/frontend/js/features/share-project-modal/controllers/react-share-project-modal-controller.js
@@ -9,8 +9,7 @@ App.component(
'shareProjectModal',
react2angular(
rootContext.use(ShareProjectModal),
- Object.keys(ShareProjectModal.propTypes),
- ['ide']
+ Object.keys(ShareProjectModal.propTypes)
)
)
diff --git a/services/web/frontend/js/shared/context/compile-context.js b/services/web/frontend/js/shared/context/compile-context.js
index 7efd2b907e..7ab63ecf48 100644
--- a/services/web/frontend/js/shared/context/compile-context.js
+++ b/services/web/frontend/js/shared/context/compile-context.js
@@ -13,11 +13,11 @@ CompileContext.Provider.propTypes = {
}),
}
-export function CompileProvider({ children, $scope }) {
- const [pdfUrl] = useScopeValue('pdf.url', $scope)
- const [pdfDownloadUrl] = useScopeValue('pdf.downloadUrl', $scope)
- const [logEntries] = useScopeValue('pdf.logEntries', $scope)
- const [uncompiled] = useScopeValue('pdf.uncompiled', $scope)
+export function CompileProvider({ children }) {
+ const [pdfUrl] = useScopeValue('pdf.url')
+ const [pdfDownloadUrl] = useScopeValue('pdf.downloadUrl')
+ const [logEntries] = useScopeValue('pdf.logEntries')
+ const [uncompiled] = useScopeValue('pdf.uncompiled')
const value = {
pdfUrl,
@@ -27,17 +27,12 @@ export function CompileProvider({ children, $scope }) {
}
return (
- <>
-
- {children}
-
- >
+ {children}
)
}
CompileProvider.propTypes = {
children: PropTypes.any,
- $scope: PropTypes.any.isRequired,
}
export function useCompileContext(propTypes) {
diff --git a/services/web/frontend/js/shared/context/editor-context.js b/services/web/frontend/js/shared/context/editor-context.js
index 740b1cb95d..13a6829f43 100644
--- a/services/web/frontend/js/shared/context/editor-context.js
+++ b/services/web/frontend/js/shared/context/editor-context.js
@@ -2,6 +2,7 @@ import React, { createContext, useCallback, useContext, useEffect } from 'react'
import PropTypes from 'prop-types'
import useScopeValue from './util/scope-value-hook'
import useBrowserWindow from '../hooks/use-browser-window'
+import { useIdeContext } from './ide-context'
export const EditorContext = createContext()
@@ -30,7 +31,9 @@ EditorContext.Provider.propTypes = {
}),
}
-export function EditorProvider({ children, ide, settings }) {
+export function EditorProvider({ children, settings }) {
+ const ide = useIdeContext()
+
const cobranding = window.brandVariation
? {
logoImgUrl: window.brandVariation.logo_url,
@@ -45,26 +48,12 @@ export function EditorProvider({ children, ide, settings }) {
}
: undefined
- const ownerId =
- ide.$scope.project && ide.$scope.project.owner
- ? ide.$scope.project.owner._id
- : null
-
- const [loading] = useScopeValue('state.loading', ide.$scope)
-
- const [projectRootDocId] = useScopeValue('project.rootDoc_id', ide.$scope)
-
- const [projectName, setProjectName] = useScopeValue(
- 'project.name',
- ide.$scope
- )
-
- const [compileGroup] = useScopeValue(
- 'project.features.compileGroup',
- ide.$scope
- )
-
- const [rootFolder] = useScopeValue('rootFolder', ide.$scope)
+ const [loading] = useScopeValue('state.loading')
+ const [projectRootDocId] = useScopeValue('project.rootDoc_id')
+ const [projectName, setProjectName] = useScopeValue('project.name')
+ const [compileGroup] = useScopeValue('project.features.compileGroup')
+ const [rootFolder] = useScopeValue('rootFolder')
+ const [ownerId] = useScopeValue('project.owner.id')
const renameProject = useCallback(
newName => {
@@ -112,22 +101,25 @@ export function EditorProvider({ children, ide, settings }) {
}
return (
- <>
-
- {children}
-
- >
+
+ {children}
+
)
}
EditorProvider.propTypes = {
children: PropTypes.any,
- ide: PropTypes.any.isRequired,
settings: PropTypes.any.isRequired,
}
export function useEditorContext(propTypes) {
- const data = useContext(EditorContext)
- PropTypes.checkPropTypes(propTypes, data, 'data', 'EditorContext.Provider')
- return data
+ const context = useContext(EditorContext)
+
+ if (!context) {
+ throw new Error('useEditorContext is only available inside EditorProvider')
+ }
+
+ PropTypes.checkPropTypes(propTypes, context, 'data', 'EditorContext.Provider')
+
+ return context
}
diff --git a/services/web/frontend/js/shared/context/ide-context.js b/services/web/frontend/js/shared/context/ide-context.js
new file mode 100644
index 0000000000..f28ea7989a
--- /dev/null
+++ b/services/web/frontend/js/shared/context/ide-context.js
@@ -0,0 +1,30 @@
+import React, { createContext, useContext } from 'react'
+import PropTypes from 'prop-types'
+
+const IdeContext = createContext()
+
+IdeContext.Provider.propTypes = {
+ value: PropTypes.shape({
+ $scope: PropTypes.object.isRequired,
+ }),
+}
+
+export function useIdeContext() {
+ const context = useContext(IdeContext)
+
+ if (!context) {
+ throw new Error('useIdeContext is only available inside IdeProvider')
+ }
+
+ return context
+}
+
+export function IdeProvider({ ide, children }) {
+ return {children}
+}
+IdeProvider.propTypes = {
+ children: PropTypes.any.isRequired,
+ ide: PropTypes.shape({
+ $scope: PropTypes.object.isRequired,
+ }).isRequired,
+}
diff --git a/services/web/frontend/js/shared/context/layout-context.js b/services/web/frontend/js/shared/context/layout-context.js
index ee15a93907..79ba58ebb9 100644
--- a/services/web/frontend/js/shared/context/layout-context.js
+++ b/services/web/frontend/js/shared/context/layout-context.js
@@ -1,6 +1,7 @@
import React, { createContext, useContext, useCallback } from 'react'
import PropTypes from 'prop-types'
import useScopeValue from './util/scope-value-hook'
+import { useIdeContext } from './ide-context'
export const LayoutContext = createContext()
@@ -18,8 +19,11 @@ LayoutContext.Provider.propTypes = {
}).isRequired,
}
-export function LayoutProvider({ children, $scope }) {
- const [view, _setView] = useScopeValue('ui.view', $scope)
+export function LayoutProvider({ children }) {
+ const { $scope } = useIdeContext()
+
+ const [view, _setView] = useScopeValue('ui.view')
+
const setView = useCallback(
value => {
_setView(value)
@@ -30,19 +34,14 @@ export function LayoutProvider({ children, $scope }) {
[$scope, _setView]
)
- const [chatIsOpen, setChatIsOpen] = useScopeValue('ui.chatOpen', $scope)
+ const [chatIsOpen, setChatIsOpen] = useScopeValue('ui.chatOpen')
const [reviewPanelOpen, setReviewPanelOpen] = useScopeValue(
- 'ui.reviewPanelOpen',
- $scope
- )
- const [leftMenuShown, setLeftMenuShown] = useScopeValue(
- 'ui.leftMenuShown',
- $scope
+ 'ui.reviewPanelOpen'
)
+ const [leftMenuShown, setLeftMenuShown] = useScopeValue('ui.leftMenuShown')
+ const [pdfLayout] = useScopeValue('ui.pdfLayout')
- const [pdfLayout] = useScopeValue('ui.pdfLayout', $scope)
-
- const layoutContextValue = {
+ const value = {
view,
setView,
chatIsOpen,
@@ -55,17 +54,12 @@ export function LayoutProvider({ children, $scope }) {
}
return (
-
- {children}
-
+ {children}
)
}
LayoutProvider.propTypes = {
children: PropTypes.any,
- $scope: PropTypes.shape({
- toggleHistory: PropTypes.func.isRequired,
- }).isRequired,
}
export function useLayoutContext(propTypes) {
diff --git a/services/web/frontend/js/shared/context/root-context.js b/services/web/frontend/js/shared/context/root-context.js
index e7e0033a11..ea2a8c7071 100644
--- a/services/web/frontend/js/shared/context/root-context.js
+++ b/services/web/frontend/js/shared/context/root-context.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import createSharedContext from 'react2angular-shared-context'
import { ApplicationProvider } from './application-context'
+import { IdeProvider } from './ide-context'
import { EditorProvider } from './editor-context'
import { CompileProvider } from './compile-context'
import { LayoutProvider } from './layout-context'
@@ -13,17 +14,19 @@ export function ContextRoot({ children, ide, settings }) {
return (
-
-
-
- {isAnonymousUser ? (
- children
- ) : (
- {children}
- )}
-
-
-
+
+
+
+
+ {isAnonymousUser ? (
+ children
+ ) : (
+ {children}
+ )}
+
+
+
+
)
}
diff --git a/services/web/frontend/js/shared/context/util/scope-value-hook.js b/services/web/frontend/js/shared/context/util/scope-value-hook.js
index c1e6b8fcbc..3418b4bfc7 100644
--- a/services/web/frontend/js/shared/context/util/scope-value-hook.js
+++ b/services/web/frontend/js/shared/context/util/scope-value-hook.js
@@ -1,17 +1,22 @@
import { useCallback, useEffect, useState } from 'react'
+import PropTypes from 'prop-types'
import _ from 'lodash'
+import { useIdeContext } from '../ide-context'
/**
* Binds a property in an Angular scope making it accessible in a React
* component. The interface is compatible with React.useState(), including
* the option of passing a function to the setter.
*
- * @param {string} path - dot '.' path of a property in `sourceScope`.
- * @param {object} $scope - Angular $scope containing the value to bind.
+ * @param {string} path - dot '.' path of a property in the Angular scope.
* @param {boolean} deep
* @returns {[any, function]} - Binded value and setter function tuple.
*/
-export default function useScopeValue(path, $scope, deep = false) {
+export default function useScopeValue(path, deep = false) {
+ const { $scope } = useIdeContext({
+ $scope: PropTypes.object.isRequired,
+ })
+
const [value, setValue] = useState(() => _.get($scope, path))
useEffect(() => {
diff --git a/services/web/frontend/stories/preview-logs-pane.stories.js b/services/web/frontend/stories/preview-logs-pane.stories.js
index 0ea3701c57..066cbe161b 100644
--- a/services/web/frontend/stories/preview-logs-pane.stories.js
+++ b/services/web/frontend/stories/preview-logs-pane.stories.js
@@ -3,6 +3,7 @@ import PreviewLogsPane from '../js/features/preview/components/preview-logs-pane
import { EditorProvider } from '../js/shared/context/editor-context'
import { ApplicationProvider } from '../js/shared/context/application-context'
import useFetchMock from './hooks/use-fetch-mock'
+import { IdeProvider } from '../js/shared/context/ide-context'
export const TimedOutError = args => {
useFetchMock(fetchMock => {
@@ -25,9 +26,11 @@ export const TimedOutError = args => {
return (
-
-
-
+
+
+
+
+
)
}
@@ -58,9 +61,11 @@ export const TimedOutErrorWithPriorityCompile = args => {
return (
-
-
-
+
+
+
+
+
)
}
diff --git a/services/web/frontend/stories/share-project-modal.stories.js b/services/web/frontend/stories/share-project-modal.stories.js
index 7a595c8a99..d0e9b82fa4 100644
--- a/services/web/frontend/stories/share-project-modal.stories.js
+++ b/services/web/frontend/stories/share-project-modal.stories.js
@@ -1,7 +1,7 @@
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'
+import { withContextRoot } from './utils/with-context-root'
export const LinkSharingOff = args => {
useFetchMock(setupFetchMock)
@@ -11,9 +11,7 @@ export const LinkSharingOff = args => {
publicAccesLevel: 'private',
}
- return renderWithContext(
-
- )
+ return withContextRoot(, { project })
}
export const LinkSharingOn = args => {
@@ -24,9 +22,7 @@ export const LinkSharingOn = args => {
publicAccesLevel: 'tokenBased',
}
- return renderWithContext(
-
- )
+ return withContextRoot(, { project })
}
export const LinkSharingLoading = args => {
@@ -38,9 +34,7 @@ export const LinkSharingLoading = args => {
tokens: undefined,
}
- return renderWithContext(
-
- )
+ return withContextRoot(, { project })
}
export const NonAdminLinkSharingOff = args => {
@@ -49,13 +43,9 @@ export const NonAdminLinkSharingOff = args => {
publicAccesLevel: 'private',
}
- return renderWithContext(
-
- )
+ return withContextRoot(, {
+ project,
+ })
}
export const NonAdminLinkSharingOn = args => {
@@ -64,13 +54,9 @@ export const NonAdminLinkSharingOn = args => {
publicAccesLevel: 'tokenBased',
}
- return renderWithContext(
-
- )
+ return withContextRoot(, {
+ project,
+ })
}
export const RestrictedTokenMember = args => {
@@ -91,9 +77,7 @@ export const RestrictedTokenMember = args => {
publicAccesLevel: 'tokenBased',
}
- return renderWithContext(
-
- )
+ return withContextRoot(, { project })
}
export const LegacyLinkSharingReadAndWrite = args => {
@@ -104,9 +88,7 @@ export const LegacyLinkSharingReadAndWrite = args => {
publicAccesLevel: 'readAndWrite',
}
- return renderWithContext(
-
- )
+ return withContextRoot(, { project })
}
export const LegacyLinkSharingReadOnly = args => {
@@ -117,9 +99,7 @@ export const LegacyLinkSharingReadOnly = args => {
publicAccesLevel: 'readOnly',
}
- return renderWithContext(
-
- )
+ return withContextRoot(, { project })
}
export const LimitedCollaborators = args => {
@@ -133,9 +113,7 @@ export const LimitedCollaborators = args => {
},
}
- return renderWithContext(
-
- )
+ return withContextRoot(, { project })
}
const project = {
@@ -199,18 +177,6 @@ export default {
},
}
-// 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 (
-
- {Story}
-
- )
-}
-
const contacts = [
// user with edited name
{
@@ -282,13 +248,3 @@ function setupFetchMock(fetchMock) {
// send analytics event
.post('express:/event/:key', 200)
}
-
-function ideWithProject(project) {
- return {
- $scope: {
- $watch: () => () => {},
- $applyAsync: () => {},
- project,
- },
- }
-}
diff --git a/services/web/frontend/stories/utils/with-context-root.js b/services/web/frontend/stories/utils/with-context-root.js
new file mode 100644
index 0000000000..9b037f058f
--- /dev/null
+++ b/services/web/frontend/stories/utils/with-context-root.js
@@ -0,0 +1,22 @@
+import React from 'react'
+import { ContextRoot } from '../../js/shared/context/root-context'
+
+// 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.
+export function withContextRoot(Story, scope) {
+ const ide = {
+ ...window._ide,
+ $scope: {
+ ...window._ide.$scope,
+ ...scope,
+ },
+ }
+
+ return (
+
+ {Story}
+
+ )
+}
diff --git a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.js b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.js
index c6fe61b342..9652b7596e 100644
--- a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.js
+++ b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.js
@@ -4,16 +4,17 @@ import React from 'react'
import {
screen,
fireEvent,
+ render,
waitFor,
waitForElementToBeRemoved,
} 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,
+ EditorProviders,
} from '../../../helpers/render-with-context'
import * as locationModule from '../../../../../frontend/js/features/share-project-modal/utils/location'
@@ -73,23 +74,7 @@ describe('', function () {
},
]
- const ideWithProject = project => {
- const scope = { project }
-
- return {
- $scope: {
- $watch: (path, callback) => {
- callback(get(scope, path))
- return () => null
- },
- $applyAsync: () => {},
- ...scope,
- },
- }
- }
-
const modalProps = {
- ide: ideWithProject(project),
show: true,
isAdmin: true,
handleHide: sinon.stub(),
@@ -105,7 +90,9 @@ describe('', function () {
})
it('renders the modal', async function () {
- renderWithEditorContext()
+ renderWithEditorContext(, {
+ scope: { project },
+ })
await screen.findByText('Share Project')
})
@@ -114,7 +101,8 @@ describe('', function () {
const handleHide = sinon.stub()
renderWithEditorContext(
-
+ ,
+ { scope: { project } }
)
const [
@@ -129,12 +117,9 @@ describe('', function () {
})
it('handles access level "private"', async function () {
- renderWithEditorContext(
-
- )
+ renderWithEditorContext(, {
+ scope: { project: { ...project, publicAccesLevel: 'private' } },
+ })
await screen.findByText(
'Link sharing is off, only invited users can view this project.'
@@ -148,12 +133,9 @@ describe('', function () {
})
it('handles access level "tokenBased"', async function () {
- renderWithEditorContext(
-
- )
+ renderWithEditorContext(, {
+ scope: { project: { ...project, publicAccesLevel: 'tokenBased' } },
+ })
await screen.findByText('Link sharing is on')
await screen.findByRole('button', { name: 'Turn off link sharing' })
@@ -165,12 +147,9 @@ describe('', function () {
})
it('handles legacy access level "readAndWrite"', async function () {
- renderWithEditorContext(
-
- )
+ renderWithEditorContext(, {
+ scope: { project: { ...project, publicAccesLevel: 'readAndWrite' } },
+ })
await screen.findByText(
'This project is public and can be edited by anyone with the URL.'
@@ -179,12 +158,9 @@ describe('', function () {
})
it('handles legacy access level "readOnly"', async function () {
- renderWithEditorContext(
-
- )
+ renderWithEditorContext(, {
+ scope: { project: { ...project, publicAccesLevel: 'readOnly' } },
+ })
await screen.findByText(
'This project is public and can be viewed but not edited by anyone with the URL'
@@ -202,16 +178,18 @@ describe('', function () {
]
// render as admin: actions should be present
- const { rerender } = renderWithEditorContext(
-
+ const { rerender } = render(
+
+
+
)
await screen.findByRole('button', { name: 'Turn off link sharing' })
@@ -219,15 +197,17 @@ describe('', function () {
// render as non-admin (non-owner), link sharing on: actions should be missing and message should be present
rerender(
-
+
+
+
)
await screen.findByText(
@@ -242,15 +222,17 @@ describe('', function () {
// render as non-admin (non-owner), link sharing off: actions should be missing and message should be present
rerender(
-
+
+
+
)
await screen.findByText(
@@ -265,13 +247,10 @@ describe('', function () {
})
it('only shows read-only token link to restricted token members', async function () {
- renderWithEditorContext(
- ,
- { isRestrictedTokenMember: true }
- )
+ renderWithEditorContext(, {
+ isRestrictedTokenMember: true,
+ scope: { project: { ...project, publicAccesLevel: 'tokenBased' } },
+ })
// no buttons
expect(screen.queryByRole('button', { name: 'Turn on link sharing' })).to.be
@@ -312,17 +291,16 @@ describe('', function () {
},
]
- renderWithEditorContext(
- , {
+ scope: {
+ project: {
...project,
members,
invites,
publicAccesLevel: 'tokenBased',
- })}
- />
- )
+ },
+ },
+ })
expect(screen.queryAllByText('project-owner@example.com')).to.have.length(1)
expect(screen.queryAllByText('member-author@example.com')).to.have.length(1)
@@ -356,16 +334,15 @@ describe('', function () {
},
]
- renderWithEditorContext(
- , {
+ scope: {
+ project: {
...project,
invites,
publicAccesLevel: 'tokenBased',
- })}
- />
- )
+ },
+ },
+ })
const [, closeButton] = screen.getAllByRole('button', {
name: 'Close',
@@ -391,16 +368,15 @@ describe('', function () {
},
]
- renderWithEditorContext(
- , {
+ scope: {
+ project: {
...project,
invites,
publicAccesLevel: 'tokenBased',
- })}
- />
- )
+ },
+ },
+ })
const [, closeButton] = screen.getAllByRole('button', {
name: 'Close',
@@ -425,16 +401,15 @@ describe('', function () {
},
]
- renderWithEditorContext(
- , {
+ scope: {
+ project: {
...project,
members,
publicAccesLevel: 'tokenBased',
- })}
- />
- )
+ },
+ },
+ })
const [, closeButton] = await screen.getAllByRole('button', {
name: 'Close',
@@ -468,16 +443,15 @@ describe('', function () {
},
]
- renderWithEditorContext(
- , {
+ scope: {
+ project: {
...project,
members,
publicAccesLevel: 'tokenBased',
- })}
- />
- )
+ },
+ },
+ })
expect(screen.queryAllByText('member-viewer@example.com')).to.have.length(1)
@@ -508,16 +482,15 @@ describe('', function () {
},
]
- renderWithEditorContext(
- , {
+ scope: {
+ project: {
...project,
members,
publicAccesLevel: 'tokenBased',
- })}
- />
- )
+ },
+ },
+ })
expect(screen.queryAllByText('member-viewer@example.com')).to.have.length(1)
@@ -551,15 +524,14 @@ describe('', function () {
})
it('sends invites to input email addresses', async function () {
- renderWithEditorContext(
- , {
+ scope: {
+ project: {
...project,
publicAccesLevel: 'tokenBased',
- })}
- />
- )
+ },
+ },
+ })
const [inputElement] = await screen.findAllByLabelText(
'Share with your collaborators'
@@ -641,24 +613,21 @@ describe('', function () {
it('displays a message when the collaborator limit is reached', async function () {
fetchMock.post('/event/project-sharing-paywall-prompt', {})
- renderWithEditorContext(
- , {
+ user: {
+ id: '123abd',
+ allowedFreeTrial: true,
+ },
+ scope: {
+ project: {
...project,
publicAccesLevel: 'tokenBased',
features: {
collaborators: 0,
},
- })}
- />,
- {
- user: {
- id: '123abd',
- allowedFreeTrial: true,
},
- }
- )
+ },
+ })
expect(screen.queryByLabelText('Share with your collaborators')).to.be.null
@@ -668,15 +637,14 @@ describe('', function () {
})
it('handles server error responses', async function () {
- renderWithEditorContext(
- , {
+ scope: {
+ project: {
...project,
publicAccesLevel: 'tokenBased',
- })}
- />
- )
+ },
+ },
+ })
// loading contacts
await waitFor(() => {
@@ -738,25 +706,19 @@ describe('', function () {
const watchCallbacks = {}
- const ideWithProject = project => {
+ const scopeWithProject = project => {
return {
- $scope: {
- $watch: (path, callback, deep) => {
- watchCallbacks[path] = callback
- return () => {}
- },
- $applyAsync: () => {},
- project,
+ $watch: (path, callback) => {
+ watchCallbacks[path] = callback
+ return () => {}
},
+ project,
}
}
- renderWithEditorContext(
-
- )
+ renderWithEditorContext(, {
+ scope: scopeWithProject({ ...project, publicAccesLevel: 'private' }),
+ })
await screen.findByText(
'Link sharing is off, only invited users can view this project.'
@@ -799,7 +761,9 @@ describe('', function () {
})
it('avoids selecting unmatched contact', async function () {
- renderWithEditorContext()
+ renderWithEditorContext(, {
+ scope: { project },
+ })
const [inputElement] = await screen.findAllByLabelText(
'Share with your collaborators'
diff --git a/services/web/test/frontend/helpers/render-with-context.js b/services/web/test/frontend/helpers/render-with-context.js
index f705889dde..229311a954 100644
--- a/services/web/test/frontend/helpers/render-with-context.js
+++ b/services/web/test/frontend/helpers/render-with-context.js
@@ -8,6 +8,8 @@ import { ApplicationProvider } from '../../../frontend/js/shared/context/applica
import { EditorProvider } from '../../../frontend/js/shared/context/editor-context'
import { LayoutProvider } from '../../../frontend/js/shared/context/layout-context'
import { ChatProvider } from '../../../frontend/js/features/chat/context/chat-context'
+import { IdeProvider } from '../../../frontend/js/shared/context/ide-context'
+import { get } from 'lodash'
export function EditorProviders({
user = { id: '123abd' },
@@ -17,6 +19,7 @@ export function EditorProviders({
removeListener: sinon.stub(),
},
isRestrictedTokenMember = false,
+ scope,
children,
}) {
window.user = user || window.user
@@ -24,38 +27,44 @@ export function EditorProviders({
window.project_id = projectId != null ? projectId : window.project_id
window.isRestrictedTokenMember = isRestrictedTokenMember
- window._ide = {
- $scope: {
- project: {
- owner: {
- _id: '124abd',
- },
+ const $scope = {
+ project: {
+ owner: {
+ _id: '124abd',
},
- ui: {
- chatOpen: true,
- pdfLayout: 'flat',
- },
- $watch: () => {},
- toggleHistory: () => {},
},
- socket,
+ ui: {
+ chatOpen: true,
+ pdfLayout: 'flat',
+ },
+ $watch: (path, callback) => {
+ callback(get($scope, path))
+ return () => null
+ },
+ $applyAsync: () => {},
+ toggleHistory: () => {},
+ ...scope,
}
+
+ window._ide = { $scope, socket }
+
return (
-
- {children}
-
+
+
+ {children}
+
+
)
}
export function renderWithEditorContext(component, contextProps) {
- return render(component, {
- // eslint-disable-next-line react/display-name
- wrapper: ({ children }) => (
- {children}
- ),
- })
+ const EditorProvidersWrapper = ({ children }) => (
+ {children}
+ )
+
+ return render(component, { wrapper: EditorProvidersWrapper })
}
export function ChatProviders({ children, ...props }) {
@@ -67,12 +76,11 @@ export function ChatProviders({ children, ...props }) {
}
export function renderWithChatContext(component, props) {
- return render(component, {
- // eslint-disable-next-line react/display-name
- wrapper: ({ children }) => (
- {children}
- ),
- })
+ const ChatProvidersWrapper = ({ children }) => (
+ {children}
+ )
+
+ return render(component, { wrapper: ChatProvidersWrapper })
}
export function cleanUpContext() {