Skip to content

Commit

Permalink
fix: fixes #3761 and restores 100% test coverage in utils and validat…
Browse files Browse the repository at this point in the history
…or-ajv8 (#3895)

Fixes #3671 by resolving refs inside of `properties` and array `items` and restoring `100%` unit test coverage for `utils` and `validator-ajv8`
- Updated `package.json` to add `@types/jest` to the global `devDependencies`
- In `@rjsf/utils`, fixed #3671 and restored 100% test coverage as follows:
  - Updated `jest.config.js` to restore test coverage threshold to 100%
  - Updated `resolveAllReferences()` to take a new `recurseList: string[]` parameter that is used to prevent recurse `$ref` processing
    - Return the `schema` directly when it is not an object and also return the original `schema` when the `resolvedSchema` is identical
  - Updated the `resolveReference()` function to call `resolveAllReferences()` and only call `retrieveSchemaInternal()` when the the `updatedSchema` is different than the original
  - Updated the `resolveSchema()` function to always call `resolveReference()` and only return the `updatedSchemas` when something was changed
  - Updated `retrieveSchemaInternal()` to take a new `recurseList: string[] = []` parameter that is passed to `resolveSchema()` and `resolveCondition()`
    - Updated many of the internal functions to take a `recurseList: string[]` parameter that is forwarded to any function that ultimately calls `retrieveSchemaInternal()` or `resolveAllReferences()`
  - Updated the `SchemaParser` to properly pass the `recurseList` array to `retrieveSchemaInternal()` and `resolveAnyOrOneOfSchemas()`
  - Updated the `getClosestMatchingOption()` function to pass an empty array to the `resolveAllReferences()` function for `recurseList`
  - Updated the `computeDefaults()` function to pass an empty array to the `resolveDependencies()` function for `recurseList`
    - Also removed an unnecessary `isObject()` check for `formData` in when dealing with `additionalProperties` since it is always guaranteed to be an object
  - Added/updated tests to ensure that all of the `@rjsf/utils` have 100% test coverage
- In `@rjsf/validator-ajv8` to fix tests due to the #3671 changes and restored 100% test coverage as follows:
  - Updated `jest.config.js` to restore test coverage threshold to 100%
  - Updated the tests for `precompiledValidator` to call `retrieveSchema()` on the precompiled `rootSchema` to avoid errors caused by the `retrieveSchema()` changes
  - Updated `validator.ts` to make the `isValid()` call not check if the `rootSchema` already exists (because it doesn't) since the `finally` always removes it
    - Updated the `validator` tests to restore 100% test coverage
- Updated the `CHANGELOG.md` accordingly while also adding the description for #3870
  • Loading branch information
heath-freenome authored Oct 10, 2023
1 parent 7dd90eb commit 33c9553
Show file tree
Hide file tree
Showing 19 changed files with 419 additions and 90 deletions.
18 changes: 16 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,34 @@ should change the heading of the (upcoming) version to include a major version b

- Updated `ArrayField` to move errors in the errorSchema when the position of array items changes for the insert and copy cases.

## @rjsf/mui
## @rjsf/material-ui

- Removed an unnecessary `Grid` container component in the `ArrayFieldTemplate` component that wrapped the `ArrayFieldItemTemplate`, fixing [#3863](https://github.com/rjsf-team/react-jsonschema-form/issues/3863)
- Fixed an issue where `SelectWidget` switches from controlled to uncontrolled when `enumOptions` does not include a value, fixing [#3844](https://github.com/rjsf-team/react-jsonschema-form/issues/3844)

## @rjsf/material-ui
## @rjsf/mui

- Removed an unnecessary `Grid` container component in the `ArrayFieldTemplate` component that wrapped the `ArrayFieldItemTemplate`, fixing [#3863](https://github.com/rjsf-team/react-jsonschema-form/issues/3863)
- Fixed an issue where `SelectWidget` switches from controlled to uncontrolled when `enumOptions` does not include a value, fixing [#3844](https://github.com/rjsf-team/react-jsonschema-form/issues/3844)

## @rjsf/utils

- Added `getOptionMatchingSimpleDiscriminator()` function
- `getMatchingOption` and `getClosestMatchingOption` now bypass `validator.isValid()` calls when simple discriminator is provided, fixing [#3692](https://github.com/rjsf-team/react-jsonschema-form/issues/3692)
- Fix data type in `FieldTemplateProps['onChange']`
- Updated `retrieveSchema()` to properly resolve references inside of `properties` and array `items` while also dealing with recursive `$ref`s, fixing [#3761](https://github.com/rjsf-team/react-jsonschema-form/issues/3761)
- Updated `schemaParser()` and `getClosestMatchingOption()` to pass the new `recursiveRef` parameter added to internal `retrieveSchema()` APIs
- Added/updated all the necessary tests to restore the `100%` test coverage that was lost when updating to Jest 29
- Updated `getDefaultFormState()` to remove an unnecessary check for `formData` being an object since it is always guaranteed to be one, thereby allowing full testing coverage

## @rjsf/validator-ajv8

- Updated the `validator` and `precompiledValidator` tests to the restore `100%` coverage that was lost when updating to Jest 29
- Updated `isValid()` for the `validator` commenting out an if condition that was preventing `100%` coverage, with a TODO to fix it later

## Dev / docs / playground

- Added the `@types/jest` as a global `devDependency` so that developer tools properly recognize the jest function types

# 5.13.0

Expand Down
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@babel/eslint-parser": "^7.22.15",
"@nrwl/nx-cloud": "^15.3.5",
"@types/estree": "^1.0.1",
"@types/jest": "^29.5.5",
"@types/node": "^18.17.14",
"@types/prettier": "^2.7.3",
"@types/react": "^17.0.65",
Expand Down
3 changes: 1 addition & 2 deletions packages/utils/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ module.exports = {
coveragePathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/test'],
coverageThreshold: {
global: {
// todo: dropped from 100 after jest 29
branches: 98,
branches: 100,
functions: 100,
lines: 100,
statements: 100,
Expand Down
5 changes: 3 additions & 2 deletions packages/utils/src/parser/schemaParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ function parseSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
rootSchema: S,
schema: S
) {
const schemas = retrieveSchemaInternal<T, S, F>(validator, schema, rootSchema, undefined, true);
const recurseRefs: string[] = [];
const schemas = retrieveSchemaInternal<T, S, F>(validator, schema, rootSchema, undefined, true, recurseRefs);
schemas.forEach((schema) => {
const sameSchemaIndex = recurseList.findIndex((item) => isEqual(item, schema));
if (sameSchemaIndex === -1) {
recurseList.push(schema);
const allOptions = resolveAnyOrOneOfSchemas<T, S, F>(validator, schema, rootSchema, true);
const allOptions = resolveAnyOrOneOfSchemas<T, S, F>(validator, schema, rootSchema, true, recurseRefs);
allOptions.forEach((s) => {
if (PROPERTIES_KEY in s && s[PROPERTIES_KEY]) {
forEach(schema[PROPERTIES_KEY], (value) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/utils/src/schema/getClosestMatchingOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export default function getClosestMatchingOption<
): number {
// First resolve any refs in the options
const resolvedOptions = options.map((option) => {
return resolveAllReferences(option, rootSchema);
return resolveAllReferences<S>(option, rootSchema, []);
});

const simpleDiscriminatorMatch = getOptionMatchingSimpleDiscriminator(formData, options, discriminatorField);
Expand Down
19 changes: 8 additions & 11 deletions packages/utils/src/schema/getDefaultFormState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
schemaToCompute = findSchemaDefinition<S>(refName, rootSchema);
}
} else if (DEPENDENCIES_KEY in schema) {
const resolvedSchema = resolveDependencies<T, S, F>(validator, schema, rootSchema, false, formData);
const resolvedSchema = resolveDependencies<T, S, F>(validator, schema, rootSchema, false, [], formData);
schemaToCompute = resolvedSchema[0]; // pick the first element from resolve dependencies
} else if (isFixedItems(schema)) {
defaults = (schema.items! as S[]).map((itemSchema: S, idx: number) =>
Expand Down Expand Up @@ -287,16 +287,13 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
.filter((key) => !schema.properties || !schema.properties[key])
.forEach((key) => keys.add(key));
}
let formDataRequired: string[];
if (isObject(formData)) {
formDataRequired = [];
Object.keys(formData as GenericObjectType)
.filter((key) => !schema.properties || !schema.properties[key])
.forEach((key) => {
keys.add(key);
formDataRequired.push(key);
});
}
const formDataRequired: string[] = [];
Object.keys(formData as GenericObjectType)
.filter((key) => !schema.properties || !schema.properties[key])
.forEach((key) => {
keys.add(key);
formDataRequired.push(key);
});
keys.forEach((key) => {
const computedDefault = computeDefaults(validator, additionalPropertiesSchema as S, {
rootSchema,
Expand Down
Loading

0 comments on commit 33c9553

Please sign in to comment.