import { TreeListParentNode, TreeState } from '@stoplight/tree-list';
import { shallow } from 'enzyme';
import 'jest-enzyme';
import { JSONSchema4 } from 'json-schema';
import * as React from 'react';
import { SchemaTree } from '../../tree';
import { metadataStore } from '../../tree/metadata';
import { walk } from '../../tree/utils/walk';
import { SchemaTreeListNode } from '../../types';
import { Property, Types } from '../shared';
describe('Property component', () => {
it('should render Types with proper type and subtype', () => {
const treeNode: SchemaTreeListNode = {
id: 'foo',
name: '',
parent: null,
};
const schema: JSONSchema4 = {
type: 'array',
items: {
type: 'string',
},
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.find(Types)).toExist();
expect(wrapper.find(Types)).toHaveProp('type', 'array');
expect(wrapper.find(Types)).toHaveProp('subtype', 'string');
});
it('should handle nullish items', () => {
const treeNode: SchemaTreeListNode = {
id: 'foo',
name: '',
parent: null,
};
const schema: JSONSchema4 = {
type: 'array',
items: null as any,
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper).not.toBeEmptyRender();
});
it('should handle nullish $ref', () => {
const treeNode: SchemaTreeListNode = {
id: 'foo',
name: '',
parent: null,
};
const schema: JSONSchema4 = {
$ref: null as any,
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper).not.toBeEmptyRender();
});
describe('properties counter', () => {
test('given an object among other types, should still display the counter', () => {
const treeNode: SchemaTreeListNode = {
id: 'foo',
name: '',
parent: null,
};
const schema: JSONSchema4 = {
type: ['string', 'object'],
properties: {
foo: {
type: 'array',
items: {
type: 'integer',
},
},
},
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.findWhere(el => /^{\d\}$/.test(el.text())).first()).toHaveText('{1}');
});
it('given missing properties property, should not display the counter', () => {
const treeNode: SchemaTreeListNode = {
id: 'foo',
name: '',
parent: null,
};
const schema: JSONSchema4 = {
type: 'object',
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.findWhere(el => /^{\d\}$/.test(el.text()))).not.toExist();
});
it('given nullish properties property, should not display the counter', () => {
const treeNode: SchemaTreeListNode = {
id: 'foo',
name: '',
parent: null,
};
const schema: JSONSchema4 = {
type: 'object',
properties: null as any,
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.findWhere(el => /^{\d\}$/.test(el.text()))).not.toExist();
});
it('given object properties property, should display the counter', () => {
const treeNode: SchemaTreeListNode = {
id: 'foo',
name: '',
parent: null,
};
const schema: JSONSchema4 = {
type: 'object',
properties: {},
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.findWhere(el => /^{\d\}$/.test(el.text())).first()).toHaveText('{0}');
});
});
describe('properties names', () => {
test('given an object, should display names its properties', () => {
const schema: JSONSchema4 = {
properties: {
foo: {
type: 'string',
},
},
};
const tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: false,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});
tree.populate();
const wrapper = shallow();
expect(wrapper.find('div').first()).toHaveText('foo');
});
test('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 tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: false,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});
tree.populate();
const wrapper = shallow();
expect(wrapper.find('div').first()).toHaveText('foo');
});
test('given an array of objects, should display names of those properties', () => {
const schema: JSONSchema4 = {
type: 'array',
items: {
properties: {
foo: {
type: 'string',
},
},
},
};
const tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: false,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});
tree.populate();
const wrapper = shallow();
expect(wrapper.find('div').first()).toHaveText('foo');
});
test('given an array with a combiner inside, should just render the type of combiner', () => {
const schema: JSONSchema4 = {
type: 'array',
items: {
oneOf: [
{
properties: {},
},
],
type: 'object',
},
};
const tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: false,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});
tree.populate();
const wrapper = shallow();
expect(wrapper).toHaveHTML('oneOf');
});
test('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',
},
},
},
};
const tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: true,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});
tree.populate();
expect(shallow()).toHaveHTML(
'
foo
string',
);
expect(shallow()).toHaveHTML(
'bar
string',
);
});
test('given a ref pointing at primitive type, should not display property name', () => {
const schema: JSONSchema4 = {
properties: {
foo: {
$ref: '#/properties/bar',
},
bar: {
type: 'string',
},
},
};
const tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: false,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});
tree.populate();
tree.unwrap(Array.from(tree)[1] as TreeListParentNode);
const wrapper = shallow();
expect(wrapper.find('div').first()).not.toExist();
});
test('given a ref pointing at complex type, should not display property name', () => {
const schema: JSONSchema4 = {
properties: {
foo: {
$ref: '#/properties/bar',
},
bar: {
type: 'object',
},
},
};
const tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: false,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});
tree.populate();
tree.unwrap(Array.from(tree)[1] as TreeListParentNode);
const wrapper = shallow();
expect(wrapper.find('div').first()).not.toExist();
});
});
describe('properties titles', () => {
let treeNode: SchemaTreeListNode;
beforeEach(() => {
treeNode = {
id: 'foo',
name: '',
parent: null,
};
});
it('given object type, should render title', () => {
const schema: JSONSchema4 = {
title: 'User',
type: 'object',
properties: {
name: {
type: 'string',
},
},
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.find(Types)).toExist();
expect(wrapper.find(Types)).toHaveProp('type', 'object');
expect(wrapper.find(Types)).toHaveProp('subtype', void 0);
expect(wrapper.find(Types)).toHaveProp('title', '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',
},
},
},
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.find(Types)).toExist();
expect(wrapper.find(Types)).toHaveProp('type', 'array');
expect(wrapper.find(Types)).toHaveProp('subtype', 'object');
expect(wrapper.find(Types)).toHaveProp('title', 'User');
});
it('given array with no items, should render title', () => {
const schema: JSONSchema4 = {
type: 'array',
title: 'User',
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.find(Types)).toExist();
expect(wrapper.find(Types)).toHaveProp('type', 'array');
expect(wrapper.find(Types)).toHaveProp('subtype', void 0);
expect(wrapper.find(Types)).toHaveProp('title', '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',
},
],
};
metadataStore.set(treeNode, {
schemaNode: walk(schema).next().value.node,
path: [],
schema,
});
const wrapper = shallow();
expect(wrapper.find(Types)).toExist();
expect(wrapper.find(Types)).toHaveProp('type', 'array');
expect(wrapper.find(Types)).toHaveProp('subtype', void 0);
expect(wrapper.find(Types)).toHaveProp('title', void 0);
});
});
test("no title for combiner's children", () => {
const schema: JSONSchema4 = {
type: 'object',
title: 'Account',
allOf: [
{
type: 'object',
properties: {
type: {
type: 'string',
enum: ['admin', 'editor'],
},
enabled: {
type: 'boolean',
description: 'Is this account enabled',
},
},
required: ['type'],
},
],
oneOf: [
{
type: 'object',
title: 'Admin',
properties: {
root: {
type: 'boolean',
},
group: {
type: 'string',
},
expirationDate: {
type: 'string',
},
},
},
{
type: 'object',
title: 'Editor',
properties: {
supervisor: {
type: 'string',
},
key: {
type: 'string',
},
},
},
],
};
const tree = new SchemaTree(schema, new TreeState(), {
expandedDepth: Infinity,
mergeAllOf: true,
resolveRef: void 0,
shouldResolveEagerly: false,
onPopulate: void 0,
});
tree.populate();
const wrapper = shallow();
expect(wrapper.children().first()).toEqual(wrapper.find(Types));
});
});