import '@testing-library/jest-dom'; import { Provider as MosaicProvider } from '@stoplight/mosaic'; import { render } from '@testing-library/react'; import type { JSONSchema4, JSONSchema7 } from 'json-schema'; import * as React from 'react'; import { describe, expect, it } from 'vitest'; import { SchemaRow } from '../..'; import { buildTree, findNodeWithPath } from './utils'; describe('Property component', () => { function renderSchema(schema: JSONSchema4 | JSONSchema7, nodePath?: readonly string[]) { const tree = buildTree(schema); const node = nodePath ? findNodeWithPath(tree, nodePath) : tree.children[0]; if (node === undefined) { throw new Error('Schema node not found in tree'); } const wrapper = render( , ); return wrapper; } it('should render Types with proper type and subtype', () => { let schema: JSONSchema4 = { type: 'array', items: { type: 'string', }, }; let wrapper = renderSchema(schema).queryAllByTestId('property-type')[0]; expect(wrapper).toMatchInlineSnapshot( ` array[string] `, ); schema = { type: 'object', additionalProperties: { type: 'string', }, }; wrapper = renderSchema(schema).queryAllByTestId('property-type')[0]; expect(wrapper).toMatchInlineSnapshot( ` array[string] `, ); }); it('should handle nullish items', () => { const schema: JSONSchema4 = { type: 'array', items: null as any, }; const wrapper = renderSchema(schema).queryByTestId('property-type'); expect(wrapper).toMatchInlineSnapshot( ` array `, ); }); it('should handle nullish $ref', () => { const schema: JSONSchema4 = { $ref: null as any, }; const wrapper = renderSchema(schema).queryByTestId('property-type-ref'); expect(wrapper).toMatchInlineSnapshot( ` $ref `, ); }); it('should display true schemas', () => { const schema: JSONSchema7 = { type: 'object', properties: { foo: true, }, }; const wrapper = renderSchema(schema, ['properties', 'foo']).queryByTestId('property-type'); expect(wrapper).toMatchInlineSnapshot( ` any `, ); }); it('should display false schemas', () => { const schema: JSONSchema7 = { type: 'object', properties: { foo: false, }, }; const wrapper = renderSchema(schema, ['properties', 'foo']).queryByTestId('property-type'); expect(wrapper).toMatchInlineSnapshot( ` never `, ); }); describe('properties names', () => { it('given an object, should display the names of its properties', () => { const schema: JSONSchema4 = { properties: { foo: { type: 'string', }, }, }; const wrapper = renderSchema(schema, ['properties', 'foo']).queryByTestId('schema-row'); expect(wrapper).toMatchInlineSnapshot( `
foo
string
`, ); }); it('given an object among other types, should still display its properties', () => { const schema: JSONSchema4 = { type: ['string', 'object'], properties: { foo: { type: 'array', items: { type: 'integer', }, }, }, }; const wrapper = renderSchema(schema, ['properties', 'foo']).queryByTestId('schema-row'); expect(wrapper).toMatchInlineSnapshot( `
foo
array[integer]
`, ); }); it('given an array of objects, should display names of those properties', () => { const schema: JSONSchema4 = { type: 'array', items: { properties: { foo: { type: 'string', }, }, }, }; const wrapper = renderSchema(schema, ['items', 'properties', 'foo']).container.firstChild; expect(wrapper).toMatchInlineSnapshot( `
foo
string
`, ); }); it('given an array with a combiner inside, should merge it', () => { const schema: JSONSchema4 = { type: 'array', items: { oneOf: [ { type: 'string', }, { type: 'number', }, ], }, }; const wrapper = renderSchema(schema).container.firstChild; expect(wrapper).toMatchInlineSnapshot( `
`, ); }); it('given an array with a mergeable combiner inside, should merge it', () => { const schema: JSONSchema4 = { type: 'array', items: { oneOf: [ { properties: { foo: {}, bar: {}, baz: {}, }, }, ], type: 'object', }, }; const wrapper = renderSchema(schema).container.firstChild; expect(wrapper).toMatchInlineSnapshot( `
array[object]
foo
any
bar
any
baz
any
`, ); }); it('given an array with an allOf inside and enabled allOf merging, should display the name of properties', () => { const schema: JSONSchema4 = { type: 'object', properties: { 'array-all-objects': { type: 'array', items: { allOf: [ { properties: { foo: { type: 'string', }, }, }, { properties: { bar: { type: 'string', }, }, }, ], type: 'object', }, }, }, }; let wrapper = renderSchema(schema, ['properties', 'array-all-objects', 'items', 'properties', 'foo']).container .firstChild; expect(wrapper).toMatchInlineSnapshot( `
foo
string
`, ); wrapper = renderSchema(schema, ['properties', 'array-all-objects', 'items', 'properties', 'bar']).container .firstChild; expect(wrapper).toMatchInlineSnapshot( `
bar
string
`, ); }); it('given a ref pointing at complex type, should display property name', () => { const schema: JSONSchema4 = { properties: { foo: { $ref: '#/properties/bar', }, bar: { type: 'object', }, }, }; const tree = buildTree(schema); const wrapper = render() .container.firstChild; expect(wrapper).toMatchInlineSnapshot( `
foo
object
`, ); }); }); describe('properties titles', () => { it('given object type, should render title', () => { const schema: JSONSchema4 = { title: 'User', type: 'object', properties: { name: { type: 'string', }, }, }; const wrapper = renderSchema(schema).queryAllByTestId('property-type')[0]; expect(wrapper).toMatchInlineSnapshot( ` User `, ); }); it('given array type with non-array items, should render title', () => { const schema: JSONSchema4 = { type: 'array', items: { title: 'User', type: 'object', properties: { name: { type: 'string', }, }, }, }; const wrapper = renderSchema(schema).queryAllByTestId('property-type')[0]; expect(wrapper).toMatchInlineSnapshot( ` array[User] `, ); }); it('given array with no items, should render title', () => { const schema: JSONSchema4 = { type: 'array', title: 'User', }; const wrapper = renderSchema(schema).queryByTestId('property-type'); expect(wrapper).toMatchInlineSnapshot( ` User `, ); }); it('given array with defined items, should not render title', () => { const schema: JSONSchema4 = { type: 'array', items: [ { title: 'foo', type: 'string', }, { title: 'bar', type: 'number', }, ], }; const wrapper = renderSchema(schema).queryAllByTestId('property-type')[0]; expect(wrapper).toMatchInlineSnapshot( ` array `, ); }); }); describe('format', () => { const schema: JSONSchema4 = require('../../../__fixtures__/formats-schema.json'); it('should render next to a single type', () => { const wrapper = renderSchema(schema, ['properties', 'id']).queryByText('number'); expect(wrapper).toBeInTheDocument(); }); it.each` property | text ${'count'} | ${'integer or null'} ${'date-of-birth'} | ${'number or string or array'} ${'array-of-integers'} | ${'array[integer]'} ${'map-of-ids'} | ${'dictionary[string, integer]'} ${'size'} | ${'number or string'} `('given $property property, should render next to the appropriate type $text', ({ property }) => { const wrapper = renderSchema(schema, ['properties', property]).container.firstChild; expect(wrapper).toMatchSnapshot(); }); it('should render even when the type(s) is/are missing', () => { const wrapper = renderSchema(schema, ['properties', 'notype']).queryByText(''); expect(wrapper).toBeInTheDocument(); }); }); });