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

Commit

Permalink
Upgrade to rjsf-v5
Browse files Browse the repository at this point in the history
Tests still failing.
  • Loading branch information
nickgros committed Oct 11, 2022
1 parent f087bb4 commit 5882268
Show file tree
Hide file tree
Showing 34 changed files with 663 additions and 405 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@
"@popperjs/core": "^2.10.2",
"@react-google-maps/api": "^2.13.1",
"@react-hook/resize-observer": "^1.2.6",
"@rjsf/core": "^4.2.3",
"@rjsf/core": "^5.0.0-beta.11",
"@rjsf/utils": "^5.0.0-beta.11",
"@rjsf/validator-ajv6": "^5.0.0-beta.11",
"@sage-bionetworks/react-base-table": "^1.13.2",
"@sage-bionetworks/rjsf-core": "^3.1.4",
"@types/ua-parser-js": "^0.7.36",
"@upsetjs/react": "^1.6.2",
"animate.css": "^4.1.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { utils } from '@sage-bionetworks/rjsf-core'
import { getDefaultRegistry } from '@rjsf/core'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import React from 'react'
Expand All @@ -8,7 +8,7 @@ import {
guessPropertyType,
PropertyType,
transformDataFromPropertyType,
} from '../../../../../lib/containers/entity/annotations/AdditionalPropertiesSchemaField'
} from '../../../../../lib/containers/entity/SchemaDrivenAnnotationEditor/field/AdditionalPropertiesSchemaField'

describe('AdditionalPropertiesSchemaField unit tests', () => {
describe('guessPropertyType tests', () => {
Expand Down Expand Up @@ -126,7 +126,7 @@ describe('AdditionalPropertiesSchemaField unit tests', () => {
uiSchema={{}}
idSchema={{ $id: 'root' }}
formData={initialData}
registry={utils.getDefaultRegistry()}
registry={getDefaultRegistry()}
onChange={jest.fn()}
/>,
)
Expand Down Expand Up @@ -161,7 +161,7 @@ describe('AdditionalPropertiesSchemaField unit tests', () => {
uiSchema={{}}
idSchema={{ $id: 'root' }}
formData={initialData}
registry={utils.getDefaultRegistry()}
registry={getDefaultRegistry()}
onChange={jest.fn()}
/>,
)
Expand Down Expand Up @@ -209,7 +209,7 @@ describe('AdditionalPropertiesSchemaField unit tests', () => {
uiSchema={{}}
idSchema={{ $id: 'root' }}
formData={initialData}
registry={utils.getDefaultRegistry()}
registry={getDefaultRegistry()}
onChange={jest.fn()}
/>,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { AjvError } from '@rjsf/core'
import { RJSFValidationError } from '@rjsf/utils'
import {
dropNullishArrayValues,
getFriendlyPropertyName,
transformErrors,
} from '../../../../../lib/containers/entity/annotations/AnnotationEditorUtils'
} from '../../../../../lib/containers/entity/SchemaDrivenAnnotationEditor/AnnotationEditorUtils'

describe('AnnotationEditorUtils tests', () => {
describe('dropNullishArrayValues', () => {
Expand Down Expand Up @@ -53,7 +53,7 @@ describe('AnnotationEditorUtils tests', () => {

describe('transformErrors', () => {
it('combines errors caused by an enumeration defined using anyOf', () => {
const errors: AjvError[] = [
const errors: RJSFValidationError[] = [
{
name: 'type',
property: '.study[0]',
Expand Down Expand Up @@ -100,7 +100,7 @@ describe('AnnotationEditorUtils tests', () => {
})

it('returns a custom message when using a key that collides with a reserved property', () => {
const errors: AjvError[] = [
const errors: RJSFValidationError[] = [
{
name: 'not',
property: "['name']",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
act,
queryByAttribute,
render,
screen,
Expand All @@ -10,10 +11,11 @@ import selectEvent from 'react-select-event'
import {
SchemaDrivenAnnotationEditor,
SchemaDrivenAnnotationEditorProps,
} from '../../../../../lib/containers/entity/annotations/SchemaDrivenAnnotationEditor'
} from '../../../../../lib/containers/entity/SchemaDrivenAnnotationEditor/SchemaDrivenAnnotationEditor'
import { displayToast } from '../../../../../lib/containers/ToastMessage'
import { createWrapper } from '../../../../../lib/testutils/TestingLibraryUtils'
import {
ASYNCHRONOUS_JOB_TOKEN,
ENTITY_JSON,
ENTITY_SCHEMA_BINDING,
SCHEMA_VALIDATION_GET,
Expand All @@ -24,6 +26,7 @@ import {
getEndpoint,
} from '../../../../../lib/utils/functions/getEndpoint'
import { SynapseContextType } from '../../../../../lib/utils/SynapseContext'
import { AsynchronousJobStatus } from '../../../../../lib/utils/synapseTypes'
import mockFileEntity from '../../../../../mocks/entity/mockFileEntity'
import {
mockSchemaBinding,
Expand Down Expand Up @@ -81,7 +84,7 @@ async function clickSaveAndConfirm() {

// These tests are unstable, so we'll skip them until we can fix them
// The component is in experimental mode only, so not a big deal for now
describe.skip('SchemaDrivenAnnotationEditor tests', () => {
describe('SchemaDrivenAnnotationEditor tests', () => {
// Handle the msw lifecycle:
beforeAll(() => server.listen())
afterEach(() => {
Expand Down Expand Up @@ -191,6 +194,17 @@ describe.skip('SchemaDrivenAnnotationEditor tests', () => {
return res(ctx.status(201), ctx.json({ token: mockAsyncTokenId }))
},
),
rest.get(
`${getEndpoint(
BackendDestinationEnum.REPO_ENDPOINT,
)}${ASYNCHRONOUS_JOB_TOKEN(mockAsyncTokenId)}`,
async (req, res, ctx) => {
const response: AsynchronousJobStatus = {
responseBody: { validationSchema: mockValidationSchema },
}
return res(ctx.status(200), ctx.json(response))
},
),
rest.get(
`${getEndpoint(
BackendDestinationEnum.REPO_ENDPOINT,
Expand Down Expand Up @@ -256,7 +270,10 @@ describe.skip('SchemaDrivenAnnotationEditor tests', () => {
expect(screen.queryByLabelText('state*')).not.toBeInTheDocument()

// Behavior under test: select "USA" and "state" field appears
await selectEvent.select(countryField, 'USA')
await userEvent.click(countryField)
await act(async () => {
await selectEvent.select(countryField, 'USA')
})
await screen.findByLabelText('state*')
})

Expand Down Expand Up @@ -432,9 +449,8 @@ describe.skip('SchemaDrivenAnnotationEditor tests', () => {
)
})

// Skipped due to unstable execution on TravisCI.
// Next two tests are the same as the previous two tests, but with an array.
it.skip('Converts data in a schema-defined array to an additionalProperty array when removed from the schema', async () => {
it('Converts data in a schema-defined array to an additionalProperty array when removed from the schema', async () => {
// Converting an array of strings to an additional property array shouldn't change the data, because they are both arrays.
server.use(
stringArrayAnnotationsHandler,
Expand Down Expand Up @@ -568,9 +584,11 @@ describe.skip('SchemaDrivenAnnotationEditor tests', () => {
expect(showStringArrayField.value).toBe('true')

// Verify that the field for the first value in the array is visible
expect(
queryByAttribute('id', component.container, 'root_stringArray_0'),
).not.toBeNull()
await waitFor(() => {
expect(
queryByAttribute('id', component.container, 'root_stringArray_0'),
).not.toBeNull()
})

// Save the form
await clickSaveAndConfirm()
Expand Down
2 changes: 2 additions & 0 deletions src/lib/containers/EntityForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// Will give you the Synapse ID of the FileEntity that contains the user form data.
import * as React from 'react'
import Form from '@rjsf/core'
import validator from '@rjsf/validator-ajv8'
import { SynapseClient } from '../utils'
import {
EntityId,
Expand Down Expand Up @@ -323,6 +324,7 @@ export default class EntityForm extends React.Component<
this.state.formUiSchema &&
!this.state.error && (
<Form
validator={validator}
formData={this.state.formData}
schema={this.state.formSchema}
uiSchema={this.state.formUiSchema}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/containers/ModalDownload.FormSchema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UiSchema } from '@rjsf/core'
import { UiSchema } from '@rjsf/utils'
import { JSONSchema7 } from 'json-schema'

export const writeHeaderOption = 'First line is the columns names.'
Expand Down
4 changes: 3 additions & 1 deletion src/lib/containers/ModalDownload.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react'
import validator from '@rjsf/validator-ajv6'
import { Button, Modal } from 'react-bootstrap'
import Form, { IChangeEvent } from '@rjsf/core'
import { SynapseClient } from '../utils'
Expand All @@ -24,7 +25,7 @@ export type ModalDownloadState = {
isLoading: boolean
step: number
data?: DownloadFromTableResult
formData: {}
formData: Record<string, unknown>
}

export type ModalDownloadProps = {
Expand Down Expand Up @@ -149,6 +150,7 @@ export default class ModalDownload extends React.Component<
<IconSvg options={{ icon: 'close' }} />
</button>
<Form
validator={validator}
schema={formSchemaArray[this.state.step]}
uiSchema={formSchemaUIArray[this.state.step]}
onChange={this.handleChange}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/containers/QuerySortSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
EnumOption,
findValueOption,
Control,
} from './entity/annotations/CustomSelectWidget'
} from './entity/SchemaDrivenAnnotationEditor/widget/SelectWidget'

export type QuerySortSelectorProps = {
sortConfig: SortConfiguration
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AjvError } from '@sage-bionetworks/rjsf-core'
import { RJSFValidationError } from '@rjsf/utils'
import { flatMap, groupBy, isEmpty } from 'lodash-es'
import { entityJsonKeys } from '../../../utils/synapseTypes'

Expand Down Expand Up @@ -31,18 +31,20 @@ export function dropNullishArrayValues(
* @param error
* @returns
*/
export function getFriendlyPropertyName(error: AjvError) {
if (error.property.startsWith('[')) {
export function getFriendlyPropertyName(error: RJSFValidationError) {
if (error.property?.startsWith('[')) {
// Additional properties are surrounded by brackets and quotations, so let's remove them
return error.property.substring(2, error.property.length - 2)
} else if (error.property.startsWith('.')) {
} else if (error.property?.startsWith('.')) {
return error.property.substring(1)
} else {
return error.property
}
}

export function transformErrors(errors: AjvError[]): AjvError[] {
export function transformErrors(
errors: RJSFValidationError[],
): RJSFValidationError[] {
// Transform the errors in the following ways:
// - Simplify the set of errors when failing to select an enumeration defined with an anyOf (SWC-5724)
// - Show a custom error message when using a property that collides with an internal entity property (SWC-5678)
Expand Down Expand Up @@ -86,7 +88,7 @@ export function transformErrors(errors: AjvError[]): AjvError[] {
// Custom error message if the custom annotation key collides with an internal entity property
errors = errors.map(error => {
const propertyName = getFriendlyPropertyName(error)
if (entityJsonKeys.includes(propertyName)) {
if (propertyName && entityJsonKeys.includes(propertyName)) {
error.message = `"${propertyName}" is a reserved internal key and cannot be used.`
}
return error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ const Template: ComponentStory<typeof SchemaDrivenAnnotationEditor> = args => (
</div>
)

export const NoSchema = Template.bind({})
NoSchema.args = {
entityId: 'syn28579706',
}

export const ComplexSchema = Template.bind({})
ComplexSchema.args = {
schemaId: 'nkauer-ad.main',
Expand Down
Loading

0 comments on commit 5882268

Please sign in to comment.