@@ -75,3 +75,5 @@ export default function ProviderList({ entities, reorder = true, first, last, on
);
}
+
+export default ProviderList;
\ No newline at end of file
diff --git a/ui/src/app/metadata/domain/provider/component/ProviderList.test.js b/ui/src/app/metadata/domain/provider/component/ProviderList.test.js
new file mode 100644
index 000000000..c45628109
--- /dev/null
+++ b/ui/src/app/metadata/domain/provider/component/ProviderList.test.js
@@ -0,0 +1,36 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+
+import { ProviderList } from './ProviderList';
+
+jest.mock('../../../../i18n/hooks', () => ({
+ useTranslation: (value) => value
+}));
+
+jest.mock('../../../../dashboard/component/Scroller', () => ({
+ Scroller: ({ children, entities }) =>
{children(entities)}
+}));
+
+jest.mock('../../../../core/components/FormattedDate', () => ({
+ FormattedDate: ({date, time}) => (<>{date}>)
+}));
+
+jest.mock('react-router-dom', () => ({
+ Link: ({children, to}) => (
{children})
+}));
+
+xtest('Provider list', () => {
+ const resourceId = 'foo';
+ const entities = [{
+ resourceId,
+ name: 'foo',
+ '@type': 'foo',
+ createdBy: 'foo',
+ createdDate: 'foo',
+ enabled: 'foo'
+ }];
+
+ render(
);
+
+ expect(screen.getByText('label.order')).toBeInTheDocument();
+});
\ No newline at end of file
diff --git a/ui/src/app/metadata/domain/provider/BaseProviderDefinition.js b/ui/src/app/metadata/domain/provider/definition/BaseProviderDefinition.js
similarity index 97%
rename from ui/src/app/metadata/domain/provider/BaseProviderDefinition.js
rename to ui/src/app/metadata/domain/provider/definition/BaseProviderDefinition.js
index 948a43c39..c801ddb04 100644
--- a/ui/src/app/metadata/domain/provider/BaseProviderDefinition.js
+++ b/ui/src/app/metadata/domain/provider/definition/BaseProviderDefinition.js
@@ -1,6 +1,6 @@
-import { metadataFilterProcessor } from './utility/providerFilterProcessor';
-import { DurationOptions } from '../data';
-import { MetadataFilterTypes } from '../filter';
+import { metadataFilterProcessor } from '../utility/providerFilterProcessor';
+import { DurationOptions } from '../../data';
+import { MetadataFilterTypes } from '../../filter';
export const BaseProviderDefinition = {
schemaPreprocessor: metadataFilterProcessor,
diff --git a/ui/src/app/metadata/domain/provider/BaseProviderDefinition.test.js b/ui/src/app/metadata/domain/provider/definition/BaseProviderDefinition.test.js
similarity index 98%
rename from ui/src/app/metadata/domain/provider/BaseProviderDefinition.test.js
rename to ui/src/app/metadata/domain/provider/definition/BaseProviderDefinition.test.js
index d58cfe9b9..0019675e3 100644
--- a/ui/src/app/metadata/domain/provider/BaseProviderDefinition.test.js
+++ b/ui/src/app/metadata/domain/provider/definition/BaseProviderDefinition.test.js
@@ -1,5 +1,5 @@
import { BaseProviderDefinition } from './BaseProviderDefinition';
-import schema from '../../../../testing/dynamic-http.schema';
+import schema from '../../../../../testing/dynamic-http.schema';
const addErrorMockFn = jest.fn();
const providers = [
diff --git a/ui/src/app/metadata/domain/provider/DynamicHttpMetadataProviderDefinition.js b/ui/src/app/metadata/domain/provider/definition/DynamicHttpMetadataProviderDefinition.js
similarity index 97%
rename from ui/src/app/metadata/domain/provider/DynamicHttpMetadataProviderDefinition.js
rename to ui/src/app/metadata/domain/provider/definition/DynamicHttpMetadataProviderDefinition.js
index 09218a290..87ed3bb31 100644
--- a/ui/src/app/metadata/domain/provider/DynamicHttpMetadataProviderDefinition.js
+++ b/ui/src/app/metadata/domain/provider/definition/DynamicHttpMetadataProviderDefinition.js
@@ -1,8 +1,8 @@
import { BaseProviderDefinition, HttpMetadataResolverAttributesSchema, MetadataFilterPluginsSchema } from './BaseProviderDefinition';
-import API_BASE_PATH from '../../../App.constant';
+import API_BASE_PATH from '../../../../App.constant';
import defaultsDeep from 'lodash/defaultsDeep';
-import { DurationOptions } from '../data';
-import { isValidRegex } from '../../../core/utility/is_valid_regex';
+import { DurationOptions } from '../../data';
+import { isValidRegex } from '../../../../core/utility/is_valid_regex';
export const DynamicHttpMetadataProviderWizard = {
...BaseProviderDefinition,
diff --git a/ui/src/app/metadata/domain/provider/definition/DynamicHttpMetadataProviderDefinition.test.js b/ui/src/app/metadata/domain/provider/definition/DynamicHttpMetadataProviderDefinition.test.js
new file mode 100644
index 000000000..5d8cb6d97
--- /dev/null
+++ b/ui/src/app/metadata/domain/provider/definition/DynamicHttpMetadataProviderDefinition.test.js
@@ -0,0 +1,57 @@
+import { DynamicHttpMetadataProviderWizard } from './DynamicHttpMetadataProviderDefinition';
+import schema from '../../../../../testing/dynamic-http.schema';
+const addErrorMockFn = jest.fn();
+
+const providers = [
+ {
+ resourceId: 1,
+ name: 'foo',
+ xmlId: 'bar'
+ },
+ {
+ resourceId: 2,
+ name: 'baz',
+ xmlId: 'xmlId'
+ }
+];
+
+const e = {
+ name: { addError: addErrorMockFn },
+ metadataRequestURLConstructionScheme: {
+ addError: addErrorMockFn,
+ '@type': {
+ addError: addErrorMockFn
+ },
+ match: {
+ addError: addErrorMockFn
+ }
+ }
+};
+
+describe('validator function', () => {
+ it('should NOT add an error if the regex provided is valid', () => {
+ const validator = DynamicHttpMetadataProviderWizard.validator(providers);
+ const errors = validator({
+ name: 'baz text',
+ metadataRequestURLConstructionScheme: {
+ '@type': 'Regex',
+ match: 'foo'
+ }
+ }, e);
+
+ expect(addErrorMockFn).toHaveBeenCalledTimes(0);
+ });
+
+ it('should add an error if the regex provided is not valid', () => {
+ const validator = DynamicHttpMetadataProviderWizard.validator(providers);
+ const errors = validator({
+ name: 'baz test',
+ metadataRequestURLConstructionScheme: {
+ '@type': 'Regex',
+ match: '*(*&^))'
+ }
+ }, e);
+
+ expect(addErrorMockFn).toHaveBeenCalledTimes(1);
+ });
+});
\ No newline at end of file
diff --git a/ui/src/app/metadata/domain/provider/FileBackedHttpMetadataProviderDefinition.js b/ui/src/app/metadata/domain/provider/definition/FileBackedHttpMetadataProviderDefinition.js
similarity index 99%
rename from ui/src/app/metadata/domain/provider/FileBackedHttpMetadataProviderDefinition.js
rename to ui/src/app/metadata/domain/provider/definition/FileBackedHttpMetadataProviderDefinition.js
index 155ac915f..5d2d8e009 100644
--- a/ui/src/app/metadata/domain/provider/FileBackedHttpMetadataProviderDefinition.js
+++ b/ui/src/app/metadata/domain/provider/definition/FileBackedHttpMetadataProviderDefinition.js
@@ -1,7 +1,7 @@
import defaultsDeep from 'lodash/defaultsDeep';
import { BaseProviderDefinition, HttpMetadataResolverAttributesSchema, MetadataFilterPluginsSchema } from './BaseProviderDefinition';
-import { DurationOptions } from '../data';
+import { DurationOptions } from '../../data';
export const FileBackedHttpMetadataProviderWizard = {
...BaseProviderDefinition,
diff --git a/ui/src/app/metadata/domain/provider/FileSystemMetadataProviderDefinition.js b/ui/src/app/metadata/domain/provider/definition/FileSystemMetadataProviderDefinition.js
similarity index 98%
rename from ui/src/app/metadata/domain/provider/FileSystemMetadataProviderDefinition.js
rename to ui/src/app/metadata/domain/provider/definition/FileSystemMetadataProviderDefinition.js
index 84228dced..8738ffad2 100644
--- a/ui/src/app/metadata/domain/provider/FileSystemMetadataProviderDefinition.js
+++ b/ui/src/app/metadata/domain/provider/definition/FileSystemMetadataProviderDefinition.js
@@ -1,7 +1,7 @@
import defaultsDeep from 'lodash/defaultsDeep';
-import API_BASE_PATH from "../../../App.constant";
+import API_BASE_PATH from "../../../../App.constant";
import { BaseProviderDefinition } from "./BaseProviderDefinition";
-import { DurationOptions } from '../data';
+import { DurationOptions } from '../../data';
export const FileSystemMetadataProviderWizard = {
...BaseProviderDefinition,
diff --git a/ui/src/app/metadata/domain/provider/LocalDynamicMetadataProviderDefinition.js b/ui/src/app/metadata/domain/provider/definition/LocalDynamicMetadataProviderDefinition.js
similarity index 98%
rename from ui/src/app/metadata/domain/provider/LocalDynamicMetadataProviderDefinition.js
rename to ui/src/app/metadata/domain/provider/definition/LocalDynamicMetadataProviderDefinition.js
index 6e4308da4..339c0c606 100644
--- a/ui/src/app/metadata/domain/provider/LocalDynamicMetadataProviderDefinition.js
+++ b/ui/src/app/metadata/domain/provider/definition/LocalDynamicMetadataProviderDefinition.js
@@ -1,7 +1,7 @@
import defaultsDeep from 'lodash/defaultsDeep';
-import API_BASE_PATH from "../../../App.constant";
-import {DurationOptions} from '../data';
+import API_BASE_PATH from "../../../../App.constant";
+import {DurationOptions} from '../../data';
import { BaseProviderDefinition } from "./BaseProviderDefinition";
export const LocalDynamicMetadataProviderWizard = {
diff --git a/ui/src/app/metadata/domain/provider/index.js b/ui/src/app/metadata/domain/provider/index.js
index c39d163fa..05c0e057d 100644
--- a/ui/src/app/metadata/domain/provider/index.js
+++ b/ui/src/app/metadata/domain/provider/index.js
@@ -1,7 +1,7 @@
-import { FileBackedHttpMetadataProviderWizard, FileBackedHttpMetadataProviderEditor } from './FileBackedHttpMetadataProviderDefinition';
-import { DynamicHttpMetadataProviderWizard, DynamicHttpMetadataProviderEditor } from './DynamicHttpMetadataProviderDefinition';
-import { LocalDynamicMetadataProviderWizard, LocalDynamicMetadataProviderEditor } from './LocalDynamicMetadataProviderDefinition';
-import { FileSystemMetadataProviderWizard, FileSystemMetadataProviderEditor } from './FileSystemMetadataProviderDefinition';
+import { FileBackedHttpMetadataProviderWizard, FileBackedHttpMetadataProviderEditor } from './definition/FileBackedHttpMetadataProviderDefinition';
+import { DynamicHttpMetadataProviderWizard, DynamicHttpMetadataProviderEditor } from './definition/DynamicHttpMetadataProviderDefinition';
+import { LocalDynamicMetadataProviderWizard, LocalDynamicMetadataProviderEditor } from './definition/LocalDynamicMetadataProviderDefinition';
+import { FileSystemMetadataProviderWizard, FileSystemMetadataProviderEditor } from './definition/FileSystemMetadataProviderDefinition';
export const MetadataProviderWizardTypes = [
FileBackedHttpMetadataProviderWizard,
diff --git a/ui/src/app/metadata/domain/provider/utility/providerFilterProcessor.test.js b/ui/src/app/metadata/domain/provider/utility/providerFilterProcessor.test.js
new file mode 100644
index 000000000..e2b448dfe
--- /dev/null
+++ b/ui/src/app/metadata/domain/provider/utility/providerFilterProcessor.test.js
@@ -0,0 +1,37 @@
+import { metadataFilterProcessor } from './providerFilterProcessor';
+
+describe('provider model utilities', () => {
+ describe('metadata filter processor function', () => {
+ it('should return null if no schema provided', () => {
+ expect(metadataFilterProcessor(null)).toBe(null);
+ });
+
+ it('should return the schema if no properties are detected', () => {
+ const schema = {};
+ expect(metadataFilterProcessor(schema)).toBe(schema);
+ });
+
+ it('should return the schema if no metadataFilters property exists in the schema', () => {
+ const schema = { properties: { foo: 'bar' } };
+ expect(metadataFilterProcessor(schema)).toBe(schema);
+ });
+
+ it('should turn the filters into an object if provided', () => {
+ const schema = {
+ properties: {
+ metadataFilters: {
+ type: 'array',
+ items: [
+ {
+ $id: 'foo',
+ type: 'string'
+ }
+ ]
+ }
+ }
+ };
+ const processed = metadataFilterProcessor(schema);
+ expect(processed.properties.metadataFilters.properties.foo.type).toBe('string');
+ });
+ });
+});
diff --git a/ui/src/app/metadata/domain/source/SourceDefinition.test.js b/ui/src/app/metadata/domain/source/SourceDefinition.test.js
deleted file mode 100644
index 130cb1110..000000000
--- a/ui/src/app/metadata/domain/source/SourceDefinition.test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { SourceBase } from './SourceDefinition';
-
-describe('SourceDefinition', () => {
- describe('parser', () => {
- it('should remove null values', () => {
- expect(SourceBase.parser({
- foo: null,
- bar: 'baz',
- baz: {
- bar: null
- }
- })).toEqual({bar: 'baz'});
- });
- })
-});
\ No newline at end of file
diff --git a/ui/src/app/metadata/domain/source/SourceDefinition.js b/ui/src/app/metadata/domain/source/definition/SourceDefinition.js
similarity index 99%
rename from ui/src/app/metadata/domain/source/SourceDefinition.js
rename to ui/src/app/metadata/domain/source/definition/SourceDefinition.js
index c2e557c7a..bc11108ee 100644
--- a/ui/src/app/metadata/domain/source/SourceDefinition.js
+++ b/ui/src/app/metadata/domain/source/definition/SourceDefinition.js
@@ -2,8 +2,8 @@ import defaults from 'lodash/defaults';
import merge from 'lodash/merge';
import toNumber from 'lodash/toNumber';
import defaultsDeep from 'lodash/defaultsDeep';
-import API_BASE_PATH from '../../../App.constant';
-import {removeNull} from '../../../core/utility/remove_null';
+import API_BASE_PATH from '../../../../App.constant';
+import {removeNull} from '../../../../core/utility/remove_null';
import { detailedDiff } from 'deep-object-diff';
export const SourceBase = {
diff --git a/ui/src/app/metadata/domain/source/definition/SourceDefinition.test.js b/ui/src/app/metadata/domain/source/definition/SourceDefinition.test.js
new file mode 100644
index 000000000..98001cf0b
--- /dev/null
+++ b/ui/src/app/metadata/domain/source/definition/SourceDefinition.test.js
@@ -0,0 +1,114 @@
+import { SourceBase } from './SourceDefinition';
+
+describe('SourceDefinition', () => {
+ describe('parser', () => {
+ it('should remove null values', () => {
+ expect(SourceBase.parser({
+ foo: null,
+ bar: 'baz',
+ baz: {
+ bar: null
+ }
+ })).toEqual({bar: 'baz'});
+ });
+ });
+
+ describe('warnings', () => {
+ it('should return warnings based on provided data', () => {
+ expect(SourceBase.warnings({
+ relyingPartyOverrides: {
+ signAssertion: false,
+ dontSignResponse: true
+ }
+ })).toEqual({
+ 'relying-party': [
+ 'message.invalid-signing'
+ ]
+ });
+ })
+
+ it('should return no warnings', () => {
+ expect(SourceBase.warnings({
+ relyingPartyOverrides: {
+ signAssertion: true,
+ dontSignResponse: true
+ }
+ })).toEqual({});
+ })
+ });
+
+ describe('bindings', () => {
+ it('should allow one assertion consumer service to be default', () => {
+ expect(SourceBase.bindings(
+ {
+ assertionConsumerServices: [
+ {
+ makeDefault: false
+ },
+ {
+ makeDefault: true
+ }
+ ]
+ },
+ {
+ assertionConsumerServices: [
+ {
+ makeDefault: true
+ },
+ {
+ makeDefault: true
+ }
+ ]
+ }
+ )).toEqual({
+ assertionConsumerServices: [
+ {
+ makeDefault: true
+ },
+ {
+ makeDefault: false
+ }
+ ]
+ });
+ })
+
+ it('should set x509Certificates available', () => {
+ expect(SourceBase.bindings(
+ {},
+ {
+ securityInfo: {
+ x509Certificates: [
+ {}
+ ]
+ }
+ }
+ )).toMatchObject({
+ securityInfo: {
+ x509Certificates: [
+ {}
+ ],
+ x509CertificateAvailable: true
+ }
+ });
+
+ expect(SourceBase.bindings(
+ {},
+ {
+ securityInfo: {
+ x509Certificates: []
+ }
+ }
+ )).toMatchObject({
+ securityInfo: {
+ x509Certificates: [],
+ x509CertificateAvailable: false
+ }
+ });
+
+ expect(SourceBase.bindings(
+ {},
+ {}
+ )).toEqual({});
+ });
+ });
+});
\ No newline at end of file
diff --git a/ui/src/app/metadata/domain/transform.test.js b/ui/src/app/metadata/domain/transform.test.js
new file mode 100644
index 000000000..1ae2c8fa7
--- /dev/null
+++ b/ui/src/app/metadata/domain/transform.test.js
@@ -0,0 +1,19 @@
+import { transformErrors } from './transform';
+
+const errors = [
+ {name: 'const'},
+ {name: 'oneOf'},
+ {name: 'pattern', property: '/email'},
+ {name: 'pattern', property: 'foo'},
+ {name: 'type', message: 'bar'},
+ {name: 'type', message: 'should be string'}
+];
+
+it('should transform error messages', () => {
+ expect(transformErrors(errors)).toEqual([
+ { name: 'pattern', property: '/email', message: 'message.valid-email' },
+ { name: 'pattern', property: 'foo', message: 'message.valid-duration' },
+ { name: 'type', message: 'bar' },
+ { name: 'type', message: 'message.required' }
+ ]);
+});
\ No newline at end of file
diff --git a/ui/src/app/metadata/hooks/api.js b/ui/src/app/metadata/hooks/api.js
index ab835e38e..d0f30ef38 100644
--- a/ui/src/app/metadata/hooks/api.js
+++ b/ui/src/app/metadata/hooks/api.js
@@ -5,17 +5,17 @@ import { useContentionDispatcher, openContentionModalAction } from '../contentio
import {MetadataFilterTypes} from '../domain/filter';
-const lists = {
+export const lists = {
source: 'EntityDescriptors',
provider: 'MetadataResolvers'
};
-const details = {
+export const details = {
source: 'EntityDescriptor',
provider: 'MetadataResolvers'
}
-const schema = {
+export const schema = {
source: 'MetadataSources'
}
@@ -53,19 +53,23 @@ export function useMetadataFilters(id, opts = {
return useFetch(`${API_BASE_PATH}${getMetadataPath('provider')}/${id}/Filters`, opts, onMount);
}
+export const xmlRequestInterceptor = ({ options }) => {
+ options.headers['Accept'] = 'application/xml';
+ return options;
+}
+
export function useMetadataEntityXml(type = 'source', opts = {
interceptors: {
- request: ({options}) => {
- options.headers['Accept'] = 'application/xml';
- return options;
- }
+ request: xmlRequestInterceptor
}
}) {
return useFetch(`${API_BASE_PATH}${getMetadataPath(type)}`, opts);
}
export function useMetadataProviderOrder() {
- return useFetch(`${API_BASE_PATH}/MetadataResolversPositionOrder`);
+ return useFetch(`${API_BASE_PATH}/MetadataResolversPositionOrder`, {
+ cachePolicy: 'no-cache'
+ });
}
export function useMetadataHistory(type, id, opts = {}, i) {
diff --git a/ui/src/app/metadata/hooks/api.test.js b/ui/src/app/metadata/hooks/api.test.js
new file mode 100644
index 000000000..cf6ba8c71
--- /dev/null
+++ b/ui/src/app/metadata/hooks/api.test.js
@@ -0,0 +1,280 @@
+import {
+ getMetadataPath,
+ details,
+ useNonAdminSources,
+ useMetadataEntities,
+ getMetadataListPath,
+ getSchemaPath,
+ lists,
+ schema,
+ useMetadataEntity,
+ useMetadataFilters,
+ useMetadataEntityXml,
+ useMetadataProviderOrder,
+ useMetadataHistory,
+ useMetadataSources,
+ useMetadataProviders,
+ useMetadataProviderTypes,
+ useMetadataAttribute,
+ useMetadataAttributes,
+ useMetadataUpdater,
+ xmlRequestInterceptor,
+ useMetadataFilterTypes
+} from './api';
+
+import useFetch from 'use-http';
+import API_BASE_PATH from '../../App.constant';
+import { MetadataFilterTypes } from '../domain/filter';
+import { useContentionDispatcher } from '../contention/ContentionContext';
+
+jest.mock('use-http');
+jest.mock('../contention/ContentionContext');
+
+describe('api hooks', () => {
+
+ let mockPut;
+ let mockGet;
+
+ beforeEach(() => {
+
+ mockPut = jest.fn().mockResolvedValue({response: { ok: true }});
+ mockGet = jest.fn().mockResolvedValue({ response: { ok: true } });
+
+ useFetch.mockImplementation(() => {
+ return {
+ request: {
+ ok: true
+ },
+ put: mockPut,
+ get: mockGet,
+ error: null,
+ response: {
+ status: 409
+ }
+ };
+ });
+ })
+
+ describe('getMetadataPath', () => {
+ it('should return the correct path', () => {
+ expect(getMetadataPath('source')).toEqual(`/${details['source']}`);
+ });
+ });
+
+ describe('getMetadataListPath', () => {
+ it('should return the correct path', () => {
+ expect(getMetadataListPath('source')).toEqual(`/${lists['source']}`);
+ });
+ });
+
+ describe('getSchemaPath', () => {
+ it('should return the correct path', () => {
+ expect(getSchemaPath('source')).toEqual(`/${schema['source']}`);
+ });
+ });
+
+ describe('useNonAdminSources', () => {
+ it('should call useFetch', () => {
+ const sources = useNonAdminSources();
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataPath('source')}/disabledNonAdmin`, { "cachePolicy": "no-cache" })
+ })
+ });
+
+ describe('useMetadataEntities', () => {
+ it('should call useFetch', () => {
+ const type = 'source';
+ const opts = {};
+ const onMount = [];
+ const sources = useMetadataEntities(type, opts, onMount);
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataListPath(type)}`, opts, onMount)
+ });
+
+ it('should accept options', () => {
+ const type = 'source';
+ const opts = {};
+ const sources = useMetadataEntities(type);
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataListPath(type)}`, opts, undefined)
+ });
+ });
+
+ describe('useMetadataEntity', () => {
+ it('should call useFetch', () => {
+ const type = 'source';
+ const opts = {};
+ const onMount = [];
+ const sources = useMetadataEntity(type, opts, onMount);
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataPath(type)}`, opts)
+ });
+
+ it('should accept options', () => {
+ const type = 'source';
+ const opts = {};
+ const sources = useMetadataEntity(type);
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataPath(type)}`, {
+ ...opts,
+ cachePolicy: 'no-cache'
+ })
+ });
+ });
+
+ describe('useMetadataFilters', () => {
+
+ it('should call useFetch', () => {
+ const type = 'source';
+ const opts = {};
+ const onMount = [];
+ const id = 'foo';
+ const sources = useMetadataFilters(id, opts, onMount);
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataPath('provider')}/${id}/Filters`, opts, onMount)
+ });
+
+ it('should accept options', () => {
+ const type = 'source';
+ const id = 'foo'
+ const opts = {};
+ const sources = useMetadataFilters(id);
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataPath('provider')}/${id}/Filters`, {
+ ...opts,
+ cachePolicy: 'no-cache'
+ }, undefined)
+ });
+ });
+
+ describe('useMetadataEntityXml', () => {
+ it('should call useFetch', () => {
+ const type = 'source';
+ const opts = {};
+ const onMount = [];
+ const sources = useMetadataEntityXml(type, opts, onMount);
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataPath(type)}`, opts)
+ });
+
+ it('should add xml to the headers', () => {
+ const options = {
+ headers: {}
+ };
+ expect(xmlRequestInterceptor({options})).toEqual({
+ headers: {
+ 'Accept': 'application/xml'
+ }
+ })
+ })
+ });
+
+ describe('useMetadataProviderOrder', () => {
+ it('should call useFetch', () => {
+ const entities = useMetadataProviderOrder();
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}/MetadataResolversPositionOrder`, {
+ cachePolicy: 'no-cache'
+ })
+ });
+ });
+
+ describe('useMetadataHistory', () => {
+ it('should call useFetch', () => {
+ const type = 'source';
+ const id = 'foo'
+ const entities = useMetadataHistory(type, id, {
+ cachePolicy: 'no-cache'
+ });
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataPath(type)}/${id}/Versions`, {
+ cachePolicy: 'no-cache'
+ }, undefined)
+ });
+ });
+
+ describe('useMetadataSources', () => {
+ it('should call useFetch', () => {
+ const entities = useMetadataSources({
+ cachePolicy: 'no-cache'
+ });
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataListPath('source')}`, {
+ cachePolicy: 'no-cache'
+ }, undefined)
+ });
+ });
+
+ describe('useMetadataProviders', () => {
+ it('should call useFetch', () => {
+ const entities = useMetadataProviders({
+ cachePolicy: 'no-cache'
+ });
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}${getMetadataListPath('provider')}`, {
+ cachePolicy: 'no-cache'
+ }, undefined)
+ });
+ });
+
+ describe('useMetadataProviderTypes', () => {
+ it('should call useFetch', () => {
+ const entities = useMetadataProviderTypes({
+ cachePolicy: 'no-cache'
+ });
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}/ui/MetadataResolver/types`, {
+ cachePolicy: 'no-cache'
+ }, null)
+ });
+ });
+
+ describe('useMetadataAttributes', () => {
+ it('should call useFetch', () => {
+ const entities = useMetadataAttributes({
+ cachePolicy: 'no-cache'
+ });
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}/custom/entity/attributes`, {
+ cachePolicy: 'no-cache'
+ }, undefined)
+ });
+ });
+
+ describe('useMetadataAttribute', () => {
+ it('should call useFetch', () => {
+ const entities = useMetadataAttribute({
+ cachePolicy: 'no-cache'
+ });
+
+ expect(useFetch).toHaveBeenCalledWith(`${API_BASE_PATH}/custom/entity/attribute`, {
+ cachePolicy: 'no-cache'
+ }, undefined)
+ });
+ });
+
+ describe('useMetadataFilterTypes', () => {
+ it('should return types', () => {
+ expect(useMetadataFilterTypes()).toEqual(MetadataFilterTypes);
+ })
+ })
+
+ describe('useMetadataUpdater', () => {
+
+ beforeEach(() => {
+ useContentionDispatcher.mockImplementation(() => jest.fn());
+ })
+
+ it('should call useFetch', async () => {
+
+ const { update } = useMetadataUpdater('foo', {});
+
+ const promise = update('bar', {});
+
+ expect(useFetch).toHaveBeenCalledWith(`foo`, {
+ cachePolicy: 'no-cache'
+ });
+
+ expect(mockPut).toHaveBeenCalled();
+ });
+ });
+});
\ No newline at end of file
diff --git a/ui/src/app/metadata/hooks/configuration.js b/ui/src/app/metadata/hooks/configuration.js
index dc23b874f..0574359a1 100644
--- a/ui/src/app/metadata/hooks/configuration.js
+++ b/ui/src/app/metadata/hooks/configuration.js
@@ -1,4 +1,4 @@
-import { getConfigurationSections, getLimitedPropertiesFn } from './schema';
+import { getConfigurationSections, getLimitedProperties } from './schema';
export const getLimitedConfigurationsFn = (configurations, limited) => {
return configurations ? ({
@@ -6,7 +6,7 @@ export const getLimitedConfigurationsFn = (configurations, limited) => {
sections: !limited ? configurations.sections :
configurations.sections.map(s => ({
...s,
- properties: getLimitedPropertiesFn(s.properties),
+ properties: getLimitedProperties(s.properties),
}))
}) : configurations;
};
diff --git a/ui/src/app/metadata/hooks/configuration.test.js b/ui/src/app/metadata/hooks/configuration.test.js
new file mode 100644
index 000000000..126a81041
--- /dev/null
+++ b/ui/src/app/metadata/hooks/configuration.test.js
@@ -0,0 +1,28 @@
+import SCHEMA from '../../../testing/dynamic-http.schema';
+import { DynamicHttpMetadataProviderEditor } from '../domain/provider/definition/DynamicHttpMetadataProviderDefinition';
+
+import {
+ useMetadataConfiguration
+} from './configuration';
+
+describe('useMetadataConfiguration hook', () => {
+ it('should return an empty object if any parameters are not supplied', () => {
+ expect(useMetadataConfiguration(null, {}, {})).toEqual({});
+ expect(useMetadataConfiguration({}, null, {})).toEqual({});
+ expect(useMetadataConfiguration({}, {}, null)).toEqual({});
+ });
+
+ it('should return a configuration object', () => {
+ const config = useMetadataConfiguration([], SCHEMA, DynamicHttpMetadataProviderEditor);
+ expect(config.dates.length).toBe(0);
+ expect(config.sections.length).toEqual(4);
+ expect(config.sections[0].differences).toBe(false)
+ });
+
+ it('should return a configuration object limited to differences', () => {
+ const config = useMetadataConfiguration([{ name: 'foo', modifiedDate: '2012-1-1' }, { name: 'bar', modifiedDate: '2012-1-2'}], SCHEMA, DynamicHttpMetadataProviderEditor, true);
+ expect(config.dates.length).toBe(2);
+ expect(config.sections.length).toEqual(4);
+ expect(config.sections[0].differences).toBe(true)
+ });
+});
\ No newline at end of file
diff --git a/ui/src/app/metadata/hooks/schema.test.js b/ui/src/app/metadata/hooks/schema.test.js
index 1679ba221..67b6450db 100644
--- a/ui/src/app/metadata/hooks/schema.test.js
+++ b/ui/src/app/metadata/hooks/schema.test.js
@@ -1,7 +1,7 @@
import React from 'react';
import { useUiSchema } from './schema';
-import { SourceEditor } from '../domain/source/SourceDefinition';
+import { SourceEditor } from '../domain/source/definition/SourceDefinition';
import jsonSchema from '../../../testing/sourceSchema';
import uiSchemaResult from '../../../testing/uiSchema';
@@ -26,6 +26,20 @@ describe('useUiSchema', () => {
const { uiSchema } = useUiSchema(SourceEditor, jsonSchema, 'common')
expect(uiSchema).toEqual(uiSchemaResult);
- })
+ });
+
+ test('should set locked', () => {
+ useIsAdmin.mockResolvedValue(false);
+
+ const { uiSchema } = useUiSchema(SourceEditor, jsonSchema, 'common', true)
+ expect(uiSchema).toBeDefined();
+ });
+
+ test('should change if user is an admin', () => {
+ useIsAdmin.mockResolvedValue(true);
+
+ const { uiSchema } = useUiSchema(SourceEditor, jsonSchema, 'common', true)
+ expect(uiSchema).toBeDefined();
+ });
});
\ No newline at end of file
diff --git a/ui/src/app/metadata/hooks/utility.js b/ui/src/app/metadata/hooks/utility.js
index 653448c25..05546fd8a 100644
--- a/ui/src/app/metadata/hooks/utility.js
+++ b/ui/src/app/metadata/hooks/utility.js
@@ -170,14 +170,14 @@ export const assignValueToProperties = (models, properties, definition, schema)
});
};
-export const getLimitedPropertiesFn = (properties) => {
+export const getLimitedProperties = (properties) => {
return ([
...properties
.filter(p => p.differences)
.map(p => {
const parsed = { ...p };
if (p.properties) {
- parsed.properties = getLimitedPropertiesFn(p.properties);
+ parsed.properties = getLimitedProperties(p.properties);
}
return parsed;
})
diff --git a/ui/src/app/metadata/hooks/utility.test.js b/ui/src/app/metadata/hooks/utility.test.js
index 9faaebec2..36a10d688 100644
--- a/ui/src/app/metadata/hooks/utility.test.js
+++ b/ui/src/app/metadata/hooks/utility.test.js
@@ -1,6 +1,18 @@
-import { getStepProperties, getDefinition, getPropertyItemSchema, getStepProperty } from './utility';
import SCHEMA from '../../../testing/simpleSchema';
+import {
+ getConfigurationSections,
+ getLimitedProperties,
+ assignValueToProperties,
+ getStepProperties,
+ getDefinition,
+ getPropertyItemSchema,
+ getStepProperty
+} from './utility';
+
+import { SCHEMA as formSchema } from '../../../testing/form-schema';
+import { MockMetadataWizard } from '../../../testing/mockMetadataWizard';
+
describe('domain utility functions', () => {
describe('getStepProperties function', () => {
it('should return an empty array of schema or schema.properties is not defined', () => {
@@ -57,5 +69,118 @@ describe('domain utility functions', () => {
expect(property.type).toBe('string');
});
});
+
+ describe('config reducer utilities', () => {
+
+ const model = {
+ name: 'foo',
+ serviceEnabled: true,
+ foo: {
+ bar: 'bar',
+ baz: 'baz'
+ },
+ list: [
+ 'super',
+ 'cool'
+ ]
+ };
+
+ const props = [
+ {
+ id: 'name',
+ items: null,
+ name: 'label.metadata-provider-name-dashboard-display-only',
+ properties: [],
+ type: 'string',
+ value: null,
+ widget: { id: 'string', help: 'message.must-be-unique' }
+ },
+ {
+ id: 'serviceEnabled',
+ items: null,
+ name: 'serviceEnabled',
+ properties: [],
+ type: 'string',
+ value: null,
+ widget: { id: 'select', disabled: true }
+ },
+ {
+ id: 'foo',
+ items: null,
+ name: 'foo',
+ type: 'object',
+ properties: [
+ {
+ id: 'bar',
+ name: 'bar',
+ type: 'string',
+ properties: []
+ },
+ {
+ id: 'baz',
+ name: 'baz',
+ type: 'string',
+ properties: []
+ }
+ ]
+ },
+ {
+ id: 'list',
+ name: 'list',
+ type: 'array',
+ items: {
+ type: 'string'
+ },
+ widget: {
+ id: 'datalist',
+ data: [
+ { key: 'super', label: 'super' },
+ { key: 'cool', label: 'cool' },
+ { key: 'notcool', label: 'notcool' }
+ ]
+ }
+ }
+ ];
+
+ const definition = MockMetadataWizard;
+
+ describe('assignValueToProperties function', () => {
+ it('should assign appropriate values to the given schema properties', () => {
+ const assigned = assignValueToProperties([model], props, definition);
+ expect(assigned[0].value).toEqual(['foo']);
+ expect(assigned[1].value).toEqual([true]);
+ });
+
+ it('should assign differences when passed multiple models', () => {
+ const assigned = assignValueToProperties([model, {
+ ...model,
+ name: 'bar',
+ list: [
+ 'super',
+ 'notcool'
+ ]
+ }], props, definition);
+ expect(assigned[0].differences).toBe(true);
+ });
+ });
+
+ describe('getLimitedPropertiesFn function', () => {
+ it('should filter properties without differences', () => {
+ const assigned = assignValueToProperties([model, {
+ ...model,
+ name: 'bar'
+ }], props, definition);
+ expect(getLimitedProperties(assigned).length).toBe(1);
+ });
+ });
+
+ describe('getConfigurationSections', () => {
+ it('should parse the schema, definition, and model into a MetadataConfiguration', () => {
+ const config = getConfigurationSections([model], definition, formSchema);
+ expect(config.sections).toBeDefined();
+ });
+ });
+ });
+
});
diff --git a/ui/src/app/notifications/component/NotificationItem.js b/ui/src/app/notifications/component/NotificationItem.js
index 4884aa188..73b0d2043 100644
--- a/ui/src/app/notifications/component/NotificationItem.js
+++ b/ui/src/app/notifications/component/NotificationItem.js
@@ -1,21 +1,18 @@
import React from 'react';
import Alert from 'react-bootstrap/Alert';
-import { NotificationContext, removeNotificationAction } from '../hoc/Notifications';
-export function NotificationItem ({ type, body, timeout, id }) {
-
- const { dispatch } = React.useContext(NotificationContext);
+export function NotificationItem ({ type, body, timeout, id, onRemove }) {
React.useEffect(() => {
if (timeout) {
setTimeout(() => {
- dispatch(removeNotificationAction(id));
+ onRemove(id)
}, timeout);
}
- }, [timeout, id, dispatch]);
+ }, [timeout, id, onRemove]);
return (
-
dispatch(removeNotificationAction(id))}>
+ onRemove(id)}>
{body}
)
diff --git a/ui/src/app/notifications/component/NotificationItem.test.js b/ui/src/app/notifications/component/NotificationItem.test.js
new file mode 100644
index 000000000..b06b32984
--- /dev/null
+++ b/ui/src/app/notifications/component/NotificationItem.test.js
@@ -0,0 +1,33 @@
+import React from 'react';
+import { fireEvent, render, screen } from '@testing-library/react';
+
+import { NotificationItem } from './NotificationItem';
+
+jest.mock('../../i18n/hooks', () => ({
+ useTranslation: (value) => value
+}));
+
+describe('Notifcation Item', () => {
+ let context;
+ beforeEach(() => {
+ jest.useFakeTimers();
+ })
+
+ it('should change color based on type', () => {
+ render();
+ const el = screen.getByText('foo');
+ expect(el).toBeInTheDocument();
+ expect(el).toHaveClass('alert-danger')
+ });
+
+ it('should dispatch an event if provided a timeout', () => {
+
+ const mockOnRemove = jest.fn();
+
+ render();
+
+ jest.runAllTimers();
+
+ expect(mockOnRemove).toHaveBeenCalled();
+ });
+})
diff --git a/ui/src/app/notifications/component/NotificationList.js b/ui/src/app/notifications/component/NotificationList.js
index 07d6b03b2..7d621f5c3 100644
--- a/ui/src/app/notifications/component/NotificationList.js
+++ b/ui/src/app/notifications/component/NotificationList.js
@@ -1,16 +1,18 @@
import React from 'react';
-import { NotificationContext } from '../hoc/Notifications';
+import { NotificationContext, removeNotificationAction } from '../hoc/Notifications';
import { NotificationItem } from './NotificationItem';
export function NotificationList () {
- const { state } = React.useContext(NotificationContext);
+ const { state, dispatch } = React.useContext(NotificationContext);
+
+ const onRemove = (id) => dispatch(removeNotificationAction(id));
return (
{state.notifications.map((n) => (
-
-
+
))}
diff --git a/ui/src/app/notifications/component/NotificationList.test.js b/ui/src/app/notifications/component/NotificationList.test.js
new file mode 100644
index 000000000..c65b7a007
--- /dev/null
+++ b/ui/src/app/notifications/component/NotificationList.test.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+
+import { NotificationList } from './NotificationList';
+import { NotificationContext } from '../hoc/Notifications';
+
+jest.mock('../../i18n/hooks', () => ({
+ useTranslation: (value) => value
+}));
+
+describe('Notification List', () => {
+ it('should render notifications', () => {
+ const dispatch = jest.fn();
+ const state = { notifications: [{id: 'foo', body: 'foo', type: 'danger'}] };
+ render(
+
+
+
+ );
+
+ expect(screen.getByText('foo')).toBeInTheDocument();
+ });
+})
diff --git a/ui/src/app/notifications/hoc/Notifications.js b/ui/src/app/notifications/hoc/Notifications.js
index 874a3fb28..8b6383211 100644
--- a/ui/src/app/notifications/hoc/Notifications.js
+++ b/ui/src/app/notifications/hoc/Notifications.js
@@ -41,7 +41,7 @@ export const removeNotificationAction = (id) => {
}
}
-function reducer(state, action) {
+export function reducer(state, action) {
switch (action.type) {
case NotificationActions.ADD_NOTIFICATION:
return {
diff --git a/ui/src/app/notifications/hoc/Notifications.test.js b/ui/src/app/notifications/hoc/Notifications.test.js
new file mode 100644
index 000000000..728378d7e
--- /dev/null
+++ b/ui/src/app/notifications/hoc/Notifications.test.js
@@ -0,0 +1,24 @@
+import { createNotificationAction, reducer, removeNotificationAction } from './Notifications';
+
+describe('Notifications HOC', () => {
+ describe('reducer', () => {
+ it('should add a notification to its state list', () => {
+ const state = reducer({
+ notifications: []
+ }, createNotificationAction('foo'));
+ expect(state.notifications.length).toBe(1);
+ })
+
+ it('should remove a notification to its state list', () => {
+ const state = reducer({
+ notifications: [
+ {
+ id: 'foo'
+ }
+ ]
+ }, removeNotificationAction('foo'));
+
+ expect(state.notifications.length).toBe(0);
+ })
+ });
+});
\ No newline at end of file
diff --git a/ui/src/testing/form-schema.js b/ui/src/testing/form-schema.js
new file mode 100644
index 000000000..01654b15a
--- /dev/null
+++ b/ui/src/testing/form-schema.js
@@ -0,0 +1,129 @@
+export const SCHEMA = {
+ 'title': 'MetadataResolver',
+ 'type': 'object',
+ 'widget': {
+ 'id': 'fieldset'
+ },
+ 'properties': {
+ 'name': {
+ 'title': 'Metadata Provider Name (Dashboard Display Only)',
+ 'description': 'Metadata Provider Name (Dashboard Display Only)',
+ 'type': 'string',
+ 'widget': {
+ 'id': 'string',
+ 'help': 'Must be unique.'
+ }
+ },
+ '@type': {
+ 'title': 'Metadata Provider Type',
+ 'description': 'Metadata Provider Type',
+ 'ui:placeholder': 'Select a metadata provider type',
+ 'type': 'string',
+ 'widget': {
+ 'id': 'select'
+ },
+ 'oneOf': [
+ {
+ 'enum': [
+ 'FileBackedHttpMetadataResolver'
+ ],
+ 'description': 'FileBackedHttpMetadataProvider'
+ }
+ ]
+ },
+ 'list': {
+ 'title': 'label.retained-roles',
+ 'description': 'tooltip.retained-roles',
+ 'type': 'array',
+ 'items': {
+ 'widget': {
+ 'id': 'select'
+ },
+ 'type': 'string',
+ 'oneOf': [
+ {
+ 'enum': [
+ 'SPSSODescriptor'
+ ],
+ 'description': 'value.spdescriptor'
+ },
+ {
+ 'enum': [
+ 'AttributeAuthorityDescriptor'
+ ],
+ 'description': 'value.attr-auth-descriptor'
+ }
+ ]
+ }
+ },
+ 'formatFilterTarget': {
+ 'title': 'label.search-criteria',
+ 'description': 'tooltip.search-criteria',
+ 'type': 'object',
+ 'widget': {
+ 'id': 'filter-target',
+ 'target': 'formatFilterTargetType'
+ },
+ 'properties': {
+ 'formatFilterTargetType': {
+ 'title': '',
+ 'type': 'string',
+ 'default': 'ENTITY',
+ 'oneOf': [
+ {
+ 'enum': [
+ 'ENTITY'
+ ],
+ 'description': 'value.entity-id'
+ },
+ {
+ 'enum': [
+ 'REGEX'
+ ],
+ 'description': 'value.regex'
+ },
+ {
+ 'enum': [
+ 'CONDITION_SCRIPT'
+ ],
+ 'description': 'value.script'
+ }
+ ]
+ },
+ 'value': {
+ 'type': 'array',
+ 'minItems': 1,
+ 'uniqueItems': true,
+ 'items': {
+ 'type': 'string'
+ }
+ }
+ },
+ 'required': [
+ 'value',
+ 'nameIdFormatFilterTargetType'
+ ]
+ }
+ },
+ 'required': [
+ 'name',
+ '@type'
+ ],
+ 'fieldsets': [
+ {
+ 'type': 'section',
+ 'fields': [
+ 'name',
+ '@type'
+ ]
+ }
+ ],
+ 'definitions': {
+ 'description': {
+ 'title': 'Description',
+ 'description': 'A description of the object',
+ 'type': 'string',
+ 'widget': 'string'
+ }
+ }
+};
diff --git a/ui/src/testing/mockMetadataWizard.js b/ui/src/testing/mockMetadataWizard.js
new file mode 100644
index 000000000..38b6e7a2a
--- /dev/null
+++ b/ui/src/testing/mockMetadataWizard.js
@@ -0,0 +1,70 @@
+export const MockMetadataWizard = {
+ label: 'Metadata Source',
+ type: '@MetadataProvider',
+ validatorParams: [],
+ bindings: {},
+ parser(changes, schema) {
+ return changes;
+ },
+ formatter(changes, schema) {
+ return changes;
+ },
+ display(changes, schema) {
+ return changes;
+ },
+ getValidators() {
+ return {};
+ },
+ schema: 'api/ui/MetadataSources',
+ steps: [
+ {
+ index: 1,
+ id: 'common',
+ label: 'label.sp-org-info',
+ fields: [
+ 'name',
+ 'serviceEnabled'
+ ],
+ fieldsets: [
+ {
+ type: 'group',
+ fields: [
+ 'serviceProviderName',
+ 'entityId',
+ 'serviceEnabled',
+ 'organization'
+ ]
+ },
+ {
+ type: 'group',
+ fields: [
+ 'contacts'
+ ]
+ }
+ ]
+ },
+ {
+ index: 2,
+ id: 'next',
+ label: 'something',
+ fields: [
+ 'foo',
+ 'list'
+ ],
+ fieldsets: [
+ {
+ type: 'group',
+ fields: [
+ 'foo'
+ ]
+ },
+ {
+ type: 'group',
+ fields: [
+ 'list'
+ ]
+ }
+ ]
+ }
+ ]
+};
diff --git a/ui/yarn.lock b/ui/yarn.lock
index 36cf32e13..131725ace 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -5034,6 +5034,13 @@ extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
+fast-check@^2.16.0:
+ version "2.16.0"
+ resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.16.0.tgz#352271e6b29d465048ed943c68c14c7a7ce1e4ae"
+ integrity sha512-r1uoJQoLzKUgfAeGzSZ/7dGyvSLG3OGjmWIKZRJpKtY/791di7n/x389F0Bei3Ry8126Z6MKp78Cbt4+9LUp1g==
+ dependencies:
+ pure-rand "^4.1.1"
+
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
@@ -6555,6 +6562,11 @@ jest-environment-node@^26.6.2:
jest-mock "^26.6.2"
jest-util "^26.6.2"
+jest-fast-check@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/jest-fast-check/-/jest-fast-check-1.0.2.tgz#d670b0a5e646777e6cf54b9b9758342e5f021439"
+ integrity sha512-XuPENBGUN2gaTdPxgPJwFsYp0oj+MieRLpBha0flMxfI01zPHgGkZjGSLThimmsU5XFTGhJYZGVnift7UmsSuw==
+
jest-get-type@^26.3.0:
version "26.3.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
@@ -9169,6 +9181,11 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+pure-rand@^4.1.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-4.2.1.tgz#14c08ab1cebce0eb95b987638039742a1006a695"
+ integrity sha512-ESI2eqHP9JlrnTb7H7fgczRUWB6VxMMJ2m9870WCIBhYkBzSGd6gml6WhQVXHK+ZM8k70TqsyI28ixaLPaNz5g==
+
q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
@@ -9400,11 +9417,6 @@ react-infinite-scroll-component@^6.1.0:
dependencies:
throttle-debounce "^2.1.0"
-"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.2:
- version "17.0.2"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
- integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
-
react-is@^16.3.2, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.9.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@@ -9569,24 +9581,6 @@ react-scroll@^1.8.2:
lodash.throttle "^4.1.1"
prop-types "^15.7.2"
-react-shallow-renderer@^16.13.1:
- version "16.14.1"
- resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz#bf0d02df8a519a558fd9b8215442efa5c840e124"
- integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==
- dependencies:
- object-assign "^4.1.1"
- react-is "^16.12.0 || ^17.0.0"
-
-react-test-renderer@^17.0.2:
- version "17.0.2"
- resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.2.tgz#4cd4ae5ef1ad5670fc0ef776e8cc7e1231d9866c"
- integrity sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==
- dependencies:
- object-assign "^4.1.1"
- react-is "^17.0.2"
- react-shallow-renderer "^16.13.1"
- scheduler "^0.20.2"
-
react-transition-group@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"