Skip to content
This repository has been archived by the owner on Jul 17, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1047 from nickgros/context
Browse files Browse the repository at this point in the history
  • Loading branch information
nickgros committed Jun 2, 2021
2 parents d56178d + a53bc80 commit fedf323
Show file tree
Hide file tree
Showing 196 changed files with 3,678 additions and 2,734 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@
"react-hooks/exhaustive-deps": "warn",
"no-extra-semi": "off",
"prefer-const": "warn"
},
"globals": {
"JSX": true
}
}
2 changes: 0 additions & 2 deletions Examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ To use the synapse markdown-it component you must pass it a wiki page id and an
| wikiId: String | wikiId for the synapse page |
| markdown: String | markdown that is to be rendered |
| errorMessageView?: React.FunctionComponent | Should accept and render an error message to the string |
| token?: string | auth token from synapse |

Example 1: Rendering a Synapse Wiki page without any markdown pre-loaded

Expand Down Expand Up @@ -234,7 +233,6 @@ This card can be used in two ways - as a standard row renderer or as a 'Header'
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| sql: string | The sql to be run against Synapse |
| unitDescription: string | Fills in 'Displaying 50 <unitDescription>', NOTE: If not specified then no label will render |
| token?: string | Authentication token |
| limit?: number | Used to constrain the number of cards shown, defaults to Infinity |
| secondaryLabelLimit?: number | Used to constraint the number of secondary labels shown, defaults to three |
| type: string | Type of card to be rendered. |
Expand Down
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ This project helps you integrate your app with the Synapse API backend.

Interested in contributing to this project? See [contributing](./CONTRIBUTING.md).

## Installation with npm
## Installation

We provide multiple ways to add Synapse React Client to your project

### NPM

Run the following command:<br>
`npm install synapse-react-client`
Expand All @@ -28,7 +32,7 @@ If using Typescript then you'll need to create a file called "synapse-react-clie
declare module "synapse-react-client"
```

## Installation without npm or yarn
### Installation without npm or yarn

To see an example index.html page with all the necessary imports view [here](./src/demo/SingleFileBuild/index.html)

Expand Down Expand Up @@ -128,6 +132,27 @@ Note there are a number of CDNs required to finish this functionality-
<script src="https://unpkg.com/markdown-it-br@1.0.0/dist/markdown-it-br.min.js"></script>
```

## Usage

See [`index.ts`](./src/index.tsx) for a comprehensive list of components that can be used.

To function properly, all components must be wrapped in a [SynapseContextProvider](./src/lib/utils/SynapseContext.tsx). To make authenticated requests, you must provide the user's access token as a property to the context provider, among other values. You may maintain this in state, or provide it however you like.

The context provider also maintains a shared cache (via `react-query`). It is recommended to place the provider at the highest possible point in your component tree, and to use the same provider across components if possible.

Example:

```tsx
const myToken = "example-token" // this value may also be undefined, if a user is not signed in
const useUtcTime = true
const inExperimentalMode = false

<SynapseContextProvider synapseContext={{ accessToken: myToken, isInExperimentalMode: inExperimentalMode, utcTime: useUtcTime }} >
<EntityFinder {...entityFinderProps} />
</SynapseContextProvider>

```

## Setting Endpoints

### Configuring endpoint destinations for repo and portal
Expand Down
14 changes: 10 additions & 4 deletions src/__tests__/lib/containers/AccessRequirements.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,22 @@ import SelfSignAccessRequirementComponent from '../../../lib/containers/access_r
import TermsOfUseAccessRequirementComponent from '../../../lib/containers/access_requirement_list/TermsOfUseAccessRequirement'
import ManagedACTAccessRequirementComponent from '../../../lib/containers/access_requirement_list/ManagedACTAccessRequirement'
import ACTAccessRequirementComponent from '../../../lib/containers/access_requirement_list/ACTAccessRequirement'
import { SynapseTestContext } from '../../../mocks/MockSynapseContext'

describe('Access Requirement List works as expect', () => {
let container: HTMLElement
let wrapper: ReactWrapper<any, Readonly<{}>, React.Component<{}, {}, any>>

async function init(props: AccessRequirementListProps) {
await act(async () => {
wrapper = await mount(<AccessRequirementList {...props} />)
container = await render(<AccessRequirementList {...props} />)
wrapper = await mount(<AccessRequirementList {...props} />, {
wrappingComponent: SynapseTestContext,
})
container = await render(
<SynapseTestContext>
<AccessRequirementList {...props} />
</SynapseTestContext>,
)
})
}

Expand Down Expand Up @@ -92,8 +99,7 @@ describe('Access Requirement List works as expect', () => {
]

const props = {
entityID: '_',
token: '_',
entityId: '_',
accessRequirementFromProps: accessRequirements,
onHide: jest.fn(),
}
Expand Down
22 changes: 12 additions & 10 deletions src/__tests__/lib/containers/CardContainer.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { shallow } from 'enzyme'
import { mount, shallow } from 'enzyme'
import * as React from 'react'
import { SynapseConstants } from '../../../lib'
import CardContainer, {
Expand All @@ -9,10 +9,13 @@ import {
QueryBundleRequest,
QueryResultBundle,
} from '../../../lib/utils/synapseTypes/'
import { SynapseTestContext } from '../../../mocks/MockSynapseContext'
import syn16787123Json from '../../../mocks/syn16787123.json'

const createShallowComponent = (props: CardContainerProps) => {
const wrapper = shallow(<CardContainer {...props} />)
const mountComponent = (props: CardContainerProps) => {
const wrapper = mount(<CardContainer {...props} />, {
wrappingComponent: SynapseTestContext,
})
const instance = wrapper.instance()
return { wrapper, instance }
}
Expand Down Expand Up @@ -52,13 +55,13 @@ describe('it performs all functionality', () => {
}

it('renders without crashing', () => {
const tree = createShallowComponent(props)
const tree = mountComponent(props)
expect(tree).toBeDefined()
})

it('Renders total and RowContainer correctly with a faceted view', () => {
// inject filter prop
const { wrapper } = createShallowComponent({
const { wrapper } = mountComponent({
...props,
facet: 'projectStatus',
})
Expand All @@ -69,12 +72,12 @@ describe('it performs all functionality', () => {

it('Renders with a title', () => {
const title = 'HelloWorld'
const { wrapper } = createShallowComponent({ ...props, title })
const { wrapper } = mountComponent({ ...props, title })
expect(wrapper.find('h2.SRC-card-overview-title').text()).toEqual(title)
})

it('handleViewMore works', () => {
const { wrapper } = createShallowComponent(props)
const { wrapper } = mountComponent(props)
// go through calling handle view more
wrapper.find('Button').simulate('click')
expect(getLastQueryRequest).toHaveBeenCalled()
Expand All @@ -86,7 +89,7 @@ describe('it performs all functionality', () => {
...props,
hasMoreData: false,
}
const { wrapper } = createShallowComponent(propsWithHasMoreDataFalse)
const { wrapper } = mountComponent(propsWithHasMoreDataFalse)
expect(wrapper.find('Button')).toHaveLength(0)
})

Expand All @@ -95,8 +98,7 @@ describe('it performs all functionality', () => {
...props,
limit: 3,
}
const { wrapper } = createShallowComponent(propsWithHasMoreDataFalse)
const { wrapper } = mountComponent(propsWithHasMoreDataFalse)
expect(wrapper.find('Button')).toHaveLength(1)
})

})
28 changes: 16 additions & 12 deletions src/__tests__/lib/containers/DirectDownload.test.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
import { mount } from 'enzyme'
import * as React from 'react'
import DirectDownload, { DirectFileDownloadProps } from '../../../lib/containers/DirectDownload'
import DirectDownload, {
DirectFileDownloadProps,
} from '../../../lib/containers/DirectDownload'
import { act } from '@testing-library/react'
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils';
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils'
import { SynapseTestContext } from '../../../mocks/MockSynapseContext'

describe('DirectDownload: basic functionality', () => {

const props:DirectFileDownloadProps = {
token: '123',
const props: DirectFileDownloadProps = {
associatedObjectId: 'abc',
entityVersionNumber: '345'
entityVersionNumber: '345',
}

it('render direct download component without crashing', async () => {
const wrapper = mount(<DirectDownload {...props} />)
mockAllIsIntersecting(true);
const wrapper = mount(<DirectDownload {...props} />, {
wrappingComponent: SynapseTestContext,
})
mockAllIsIntersecting(true)
expect(wrapper).toBeDefined()
})

it('file handle fetch failure should display nothing', async () => {
await act(async () => {
const wrapper = await mount(<DirectDownload {...props} />)
mockAllIsIntersecting(true);
const wrapper = await mount(<DirectDownload {...props} />, {
wrappingComponent: SynapseTestContext,
})
mockAllIsIntersecting(true)
expect(wrapper.children()).toEqual({})
})
})

})
})
13 changes: 9 additions & 4 deletions src/__tests__/lib/containers/DownloadConfirmation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {
} from '../../../lib/containers/download_list/DownloadConfirmation'
import { resolveAllPending } from '../../../lib/testutils/EnzymeHelpers'
import { Alert } from 'react-bootstrap'
import {
MOCK_CONTEXT_VALUE,
SynapseTestContext,
} from '../../../mocks/MockSynapseContext'

let getQueryTableResultsFn: Function
let addFilesToDownloadRequestFn: Function
Expand Down Expand Up @@ -75,7 +79,9 @@ const addFilesToDownloadListResponse: AddFilesToDownloadListResponse = {

const createMountedComponent = (props: DownloadConfirmationProps) => {
const wrapper = mount<React.FunctionComponent<DownloadConfirmationProps>>(
<DownloadConfirmation {...props} />,
<SynapseTestContext>
<DownloadConfirmation {...props} />
</SynapseTestContext>,
)

return { wrapper }
Expand All @@ -93,7 +99,6 @@ describe('it performs the expected functionality', () => {

const props: DownloadConfirmationProps = {
fnClose: mockClose,
token: '12345',
getLastQueryRequest: () => queryBundleRequest,
}

Expand Down Expand Up @@ -122,7 +127,7 @@ describe('it performs the expected functionality', () => {
await resolveAllPending(wrapper)
expect(getQueryTableResultsFn).toHaveBeenCalledWith(
mockGetQueryTableRequest,
props.token,
MOCK_CONTEXT_VALUE.accessToken,
)
expect(getQueryTableResultsFn).toHaveBeenCalledTimes(1)
expect(wrapper.find('button')).toHaveLength(2)
Expand All @@ -137,7 +142,7 @@ describe('it performs the expected functionality', () => {
wrapper.find('button.btn-primary').simulate('click')
expect(addFilesToDownloadRequestFn).toHaveBeenCalledWith(
addFilesToDownloadListRequest,
props.token,
MOCK_CONTEXT_VALUE.accessToken,
)
expect(wrapper.text()).toBe('Adding Files To List')
expect(wrapper.find('button')).toHaveLength(0)
Expand Down
7 changes: 4 additions & 3 deletions src/__tests__/lib/containers/EntityForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import EntityForm, { EntityFormProps } from '../../../lib/containers/EntityForm'
import { mockUserProfileData } from '../../../mocks/mock_user_profile'
import { mockFileEntity } from '../../../mocks/mock_file_entity'
import reactJsonschemaForm from 'react-jsonschema-form'
import { SynapseTestContext } from '../../../mocks/MockSynapseContext'

const createShallowComponent = (props: EntityFormProps) => {
const wrapper = mount(<EntityForm {...props} />)
const wrapper = mount(<EntityForm {...props} />, {
wrappingComponent: SynapseTestContext,
})
const instance = wrapper.instance() as EntityForm
return { wrapper, instance }
}
Expand All @@ -22,15 +25,13 @@ describe('it basic tests', () => {
Promise.resolve({ id: targetFolderId }),
)
SynapseClient.getEntity = jest.fn(() => Promise.resolve(mockFileEntity))
const token: string = '123444'
const parentContainerId: string = 'syn20355732'
const formSchemaEntityId: string = 'syn20184776'
const formUiSchemaEntityId: string = 'syn20184771'
const initFormData: boolean = false
const synIdCallback = jest.fn()
const props: EntityFormProps = {
parentContainerId,
token,
formSchemaEntityId,
formUiSchemaEntityId,
initFormData,
Expand Down
33 changes: 20 additions & 13 deletions src/__tests__/lib/containers/EntityIdList.test.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
import * as React from 'react'
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils'
import EntityIdList, { EntityIdListProps } from '../../../lib/containers/EntityIdList'
import EntityIdList, {
EntityIdListProps,
} from '../../../lib/containers/EntityIdList'
import { mount } from 'enzyme'
import { act } from 'react-dom/test-utils'
import { SynapseTestContext } from '../../../mocks/MockSynapseContext'

describe('EntityIdList: basic functionality', () => {

const props:EntityIdListProps = {
token: '123',
entityIdList: ['syn123', 'syn345']
const props: EntityIdListProps = {
entityIdList: ['syn123', 'syn345'],
}

it('render direct download component without crashing', async () => {
const wrapper = mount(<EntityIdList {...props} />)
mockAllIsIntersecting(true);
const wrapper = mount(<EntityIdList {...props} />, {
wrappingComponent: SynapseTestContext,
})
mockAllIsIntersecting(true)
expect(wrapper).toBeDefined()
})

it('test', async () => {
const setEntityNameList = jest.fn()
const handleStateChange = jest.spyOn(React, "useState")
handleStateChange.mockImplementation(entityNameList => [entityNameList, setEntityNameList]);
const handleStateChange = jest.spyOn(React, 'useState')
handleStateChange.mockImplementation(entityNameList => [
entityNameList,
setEntityNameList,
])
act(() => {
mount(<EntityIdList {...props} />)
mockAllIsIntersecting(true);
mount(<EntityIdList {...props} />, {
wrappingComponent: SynapseTestContext,
})
mockAllIsIntersecting(true)
})
expect(handleStateChange).toBeCalled()
})

})
})
17 changes: 15 additions & 2 deletions src/__tests__/lib/containers/Facets.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,20 @@ import { QueryResultBundle } from '../../../lib/utils/synapseTypes/'
import TotalQueryResults from '../../../lib/containers/TotalQueryResults'
import { SELECT_ALL } from '../../../lib/containers/table/SynapseTableConstants'
import { cloneDeep } from 'lodash-es'
import { SynapseTestContext } from '../../../mocks/MockSynapseContext'
import { resolveAllPending } from '../../../lib/testutils/EnzymeHelpers'

const createMountedComponent = (props: QueryWrapperChildProps) => {
const wrapper = mount(<Facets {...props} />)
const wrapper = mount(
React.createElement(
componentProps => (
<SynapseTestContext>
<Facets {...componentProps} />
</SynapseTestContext>
),
props,
),
)
const instance = wrapper.instance() as Facets
return { wrapper, instance }
}
Expand Down Expand Up @@ -149,14 +160,16 @@ describe('it performs basic functionality', () => {
Ideally, this wouldn't be necessary, however its a tricky scenario because its an async process
that has to get mocked, we essentially freeze the state during which the backend is fetching data.
*/
await wrapper.setProps({
wrapper.setProps({
isLoading: true,
lastFacetSelection: {
columnName: facet,
facetValue: 'Cutaneous Neurofibroma',
selector: SELECT_SINGLE_FACET,
},
})

await resolveAllPending(wrapper)
// end mocking QueryWrapper behvaior
expect(wrapper.find(`input.${FACET_NOT_SELECTED_CLASS}`)).toHaveLength(10)
expect(wrapper.find(`input.${FACET_SELECTED_CLASS}`)).toHaveLength(1)
Expand Down

0 comments on commit fedf323

Please sign in to comment.