Browse Source

Merge pull request #3633 from overleaf/msm-react-context-validation

Added PropTypes validation to react context

GitOrigin-RevId: 86950bdacf366035d1cfd923c7e7674d543b380f
Miguel Serrano 5 years ago
parent
commit
77c35e3715

+ 3 - 1
services/web/frontend/js/features/outline/components/outline-pane.js

@@ -19,7 +19,9 @@ function OutlinePane({
 }) {
   const { t } = useTranslation()
 
-  const { projectId } = useEditorContext()
+  const { projectId } = useEditorContext({
+    projectId: PropTypes.string.isRequired
+  })
 
   const storageKey = `file_outline.expanded.${projectId}`
   const [expanded, setExpanded] = useState(() => {

+ 7 - 2
services/web/frontend/js/features/preview/components/preview-error.js

@@ -8,10 +8,15 @@ import { useEditorContext } from '../../../shared/context/editor-context'
 import { startFreeTrial } from '../../../main/account-upgrade'
 
 function PreviewError({ name }) {
-  const { isProjectOwner } = useEditorContext()
+  const { isProjectOwner } = useEditorContext({
+    isProjectOwner: PropTypes.bool
+  })
   const {
     exposedSettings: { enableSubscriptions }
-  } = useApplicationContext()
+  } = useApplicationContext({
+    exposedSettings: PropTypes.shape({ enableSubscriptions: PropTypes.bool })
+      .isRequired
+  })
 
   const { t } = useTranslation()
   let errorTitle

+ 20 - 3
services/web/frontend/js/shared/context/application-context.js

@@ -4,6 +4,17 @@ import ExposedSettings from '../../main/exposed-settings'
 
 export const ApplicationContext = createContext()
 
+ApplicationContext.Provider.propTypes = {
+  value: PropTypes.shape({
+    user: PropTypes.shape({
+      id: PropTypes.string.isRequired
+    }),
+    exposedSettings: PropTypes.shape({
+      enableSubscriptions: PropTypes.bool
+    })
+  })
+}
+
 export function ApplicationProvider({ children }) {
   const applicationContextValue = {
     user: window.user,
@@ -20,7 +31,13 @@ ApplicationProvider.propTypes = {
   children: PropTypes.any
 }
 
-export function useApplicationContext() {
-  const applicationContext = useContext(ApplicationContext)
-  return applicationContext
+export function useApplicationContext(propTypes) {
+  const data = useContext(ApplicationContext)
+  PropTypes.checkPropTypes(
+    propTypes,
+    data,
+    'data',
+    'ApplicationContext.Provider'
+  )
+  return data
 }

+ 17 - 3
services/web/frontend/js/shared/context/editor-context.js

@@ -4,6 +4,19 @@ import usePersistedState from '../../infrastructure/persisted-state-hook'
 
 export const EditorContext = createContext()
 
+EditorContext.Provider.propTypes = {
+  value: PropTypes.shape({
+    cobranding: PropTypes.shape({
+      logoImgUrl: PropTypes.string.isRequired,
+      brandVariationName: PropTypes.string.isRequired,
+      brandVariationHomeUrl: PropTypes.string.isRequired
+    }),
+    loading: PropTypes.bool,
+    projectId: PropTypes.string.isRequired,
+    isProjectOwner: PropTypes.bool
+  })
+}
+
 export function EditorProvider({
   children,
   loading,
@@ -70,7 +83,8 @@ EditorProvider.propTypes = {
   setChatIsOpenAngular: PropTypes.func.isRequired
 }
 
-export function useEditorContext() {
-  const editorContext = useContext(EditorContext)
-  return editorContext
+export function useEditorContext(propTypes) {
+  const data = useContext(EditorContext)
+  PropTypes.checkPropTypes(propTypes, data, 'data', 'EditorContext.Provider')
+  return data
 }

+ 1 - 1
services/web/test/frontend/helpers/render-with-context.js

@@ -7,7 +7,7 @@ import { ChatProvider } from '../../../frontend/js/features/chat/context/chat-co
 
 export function renderWithEditorContext(
   children,
-  { user = { id: '123abd' }, projectId } = {}
+  { user = { id: '123abd' }, projectId = 'project123' } = {}
 ) {
   window.user = user || window.user
   window.project_id = projectId != null ? projectId : window.project_id