Skip to content

Commit

Permalink
Merge pull request Sage-Bionetworks#599 from jay-hodgson/SWC-6614
Browse files Browse the repository at this point in the history
SWC-6614
  • Loading branch information
jay-hodgson authored Dec 8, 2023
2 parents e264439 + 226daba commit 1a74b2a
Show file tree
Hide file tree
Showing 14 changed files with 1,759 additions and 58 deletions.
31 changes: 31 additions & 0 deletions packages/synapse-react-client/src/assets/icons/AddAd.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react'

const AddAd = (props: React.SVGProps<SVGSVGElement>) => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<mask
id="mask0_6722_37828"
style={{ maskType: 'alpha' }}
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="24"
height="24"
>
<rect width="24" height="24" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_6722_37828)">
<path
d="M18 20V17H15V15H18V12H20V15H23V17H20V20H18ZM3 21C2.45 21 1.97917 20.8042 1.5875 20.4125C1.19583 20.0208 1 19.55 1 19V5C1 4.45 1.19583 3.97917 1.5875 3.5875C1.97917 3.19583 2.45 3 3 3H17C17.55 3 18.0208 3.19583 18.4125 3.5875C18.8042 3.97917 19 4.45 19 5V10H17V8H3V19H16V21H3ZM3 6H17V5H3V6Z"
fill="#395979"
/>
</g>
</svg>
)

export default AddAd
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useState } from 'react'
import { TextField, TextFieldProps, Autocomplete } from '@mui/material'
import { useDebouncedEffect } from '../../utils/hooks'

// A debounced input react component

export function DebouncedInput({
initialValue,
onChange,
options,
delay = 250,
...textFieldProps
}: {
initialValue: string
onChange: (value: string) => void
options: string[]
delay?: number
} & Pick<
React.InputHTMLAttributes<TextFieldProps>,
'type' | 'min' | 'max' | 'value' | 'placeholder' | 'className' | 'list'
>) {
const [value, setValue] = useState(initialValue)
useDebouncedEffect(
() => {
onChange(value)
},
[value],
delay,
)

return (
<Autocomplete
disablePortal
isOptionEqualToValue={(option, value) =>
value.length == 0 || option === value
}
options={options}
value={value}
onChange={(event, newValue) => {
setValue(newValue ?? '')
}}
sx={{ marginRight: '10px' }}
renderInput={params => (
<TextField
{...params}
{...textFieldProps}
value={value}
onChange={e => setValue(e.target.value)}
/>
)}
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { render, screen } from '@testing-library/react'
import React from 'react'
import { createWrapper } from '../../testutils/TestingLibraryUtils'
import { MOCK_REPO_ORIGIN } from '../../utils/functions/getEndpoint'
import { ReferenceList } from '@sage-bionetworks/synapse-types'
import { server } from '../../mocks/msw/server'
import { getEntityHandlers } from '../../mocks/msw/handlers/entityHandlers'
import { EntityHeaderTable, EntityHeaderTableProps } from './EntityHeaderTable'

import * as EntityFinderModule from '../EntityFinder/EntityFinderModal'
import mockFileEntityData, {
MOCK_FILE_ENTITY_ID,
MOCK_FILE_NAME,
} from '../../mocks/entity/mockFileEntity'
import mockDatasetData, {
MOCK_DATASET_ENTITY_ID,
MOCK_DATASET_NAME,
} from '../../mocks/entity/mockDataset'
import userEvent from '@testing-library/user-event'

function renderTable(props: EntityHeaderTableProps) {
return render(<EntityHeaderTable {...props} />, {
wrapper: createWrapper(),
})
}

jest.spyOn(EntityFinderModule, 'EntityFinderModal').mockImplementation(() => {
return <div data-testid="EntityFinderModal"></div>
})

describe('EntityHeaderTable tests', () => {
beforeAll(() => {
server.listen()
})
beforeEach(() => {
server.use(...getEntityHandlers(MOCK_REPO_ORIGIN))
})
afterEach(() => server.restoreHandlers())
afterAll(() => server.close())

it('renders table (not editable)', async () => {
const refs: ReferenceList = [
{ targetId: mockFileEntityData.id },
{ targetId: mockDatasetData.id },
]
renderTable({ references: refs, isEditable: false })
expect(await screen.findAllByRole('columnheader')).toHaveLength(3)
expect(await screen.findAllByRole('row')).toHaveLength(3) // 1 header row and 2 data rows
expect(await screen.findByText(MOCK_FILE_NAME)).toBeInTheDocument()
expect(await screen.findByText(MOCK_FILE_ENTITY_ID)).toBeInTheDocument()
expect(await screen.findByText(MOCK_DATASET_NAME)).toBeInTheDocument()
expect(await screen.findByText(MOCK_DATASET_ENTITY_ID)).toBeInTheDocument()
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument()
expect(screen.queryByRole('textbox')).not.toBeInTheDocument()
})

it('renders editable table, with ability to add items', async () => {
const mockOnUpdate = jest.fn()
const refs: ReferenceList = [
{ targetId: mockFileEntityData.id },
{ targetId: mockDatasetData.id },
]
renderTable({ references: refs, isEditable: true, onUpdate: mockOnUpdate })

const textField = await screen.findByRole('textbox')
expect(textField.getAttribute('type')).toBe('text')
await userEvent.click(textField)
await userEvent.paste('syn123, syn456')
const button = await screen.findByRole('button', {
name: 'Add Entities',
})
await userEvent.click(button)

expect(mockOnUpdate).toHaveBeenCalledWith([
{ targetId: MOCK_FILE_ENTITY_ID },
{ targetId: MOCK_DATASET_ENTITY_ID },
{ targetId: 'syn123' },
{ targetId: 'syn456' },
])
})

it('renders editable table, with ability to remove items', async () => {
const mockOnUpdate = jest.fn()
const refs: ReferenceList = [
{ targetId: mockFileEntityData.id },
{ targetId: mockDatasetData.id },
]
const removeEntitiesButtonText = 'Remove Test Entities'
renderTable({
references: refs,
isEditable: true,
onUpdate: mockOnUpdate,
removeSelectedRowsButtonText: removeEntitiesButtonText,
})

const checkBoxes = await screen.findAllByRole('checkbox')
// Click the 'Select All' checkbox
await userEvent.click(checkBoxes[0])
const button = await screen.findByRole('button', {
name: removeEntitiesButtonText,
})
await userEvent.click(button)

expect(mockOnUpdate).toHaveBeenCalledWith([])
})
})
Loading

0 comments on commit 1a74b2a

Please sign in to comment.