import React from 'react';
import { render, screen, within } from '@testing-library/react';
import { expect } from 'chai';
import AppRegistry from 'hadron-app-registry';
import userEvent from '@testing-library/user-event';
import {
parseSchema,
type PrimitiveSchemaType,
type SchemaType,
} from 'mongodb-schema';
import { BSON, Decimal128 } from 'bson';
import configureActions from '../actions';
import Field, { shouldShowUnboundArrayInsight } from './field';
describe('Field', function () {
let container: HTMLElement;
let testAppRegistry: AppRegistry;
beforeEach(function () {
testAppRegistry = new AppRegistry();
testAppRegistry.registerStore('Query.Store', {
getState() {
return {
queryBar: {
fields: {
filter: {
value: {},
string: '',
valid: true,
},
},
},
};
},
subscribe() {
return () => {};
},
} as any);
});
describe('basic field name', function () {
beforeEach(function () {
const types: PrimitiveSchemaType[] = [
{
name: 'Decimal128',
path: ['testFieldName'],
probability: 0.7,
count: 3,
bsonType: 'Decimal128',
values: [
new Decimal128('123'),
new Decimal128('345'),
new Decimal128('999'),
],
},
{
name: 'String',
path: ['testFieldName'],
probability: 0.3,
count: 3,
bsonType: 'String',
values: ['testa', 'testb', 'testc'],
},
];
render(
);
container = screen.getByTestId('schema-field');
});
it('renders the field name', function () {
const fieldName = within(container).getByText('testFieldName');
expect(fieldName).to.be.visible;
});
it('renders the various field types', function () {
expect(within(container).getByText('String')).to.be.visible;
expect(within(container).getByText('Decimal128')).to.be.visible;
expect(within(container).queryByText('Int32')).to.not.exist;
});
});
describe('document field with nested fields', function () {
beforeEach(function () {
const types: SchemaType[] = [
{
name: 'Document',
path: ['documentField'],
probability: 0.7,
count: 1,
bsonType: 'Document',
fields: [
{
name: 'nestedFieldName',
path: ['documentField', 'nestedFieldName'],
probability: 1, // Always exists
count: 2,
hasDuplicates: false,
type: ['String'],
types: [
{
name: 'String',
path: ['documentField', 'nestedFieldName'],
probability: 1,
count: 2,
bsonType: 'String',
values: ['test11', 'test22'],
},
],
},
],
},
{
name: 'String',
path: ['documentField'],
probability: 0.3,
count: 1,
bsonType: 'String',
values: ['testa'],
},
];
render(
);
container = screen.getByTestId('schema-field');
});
it('renders the field name', function () {
const fieldName = within(container).getByText('documentField');
expect(fieldName).to.be.visible;
});
it('renders the field type', function () {
expect(within(container).getByText('Document')).to.be.visible;
});
it('does not render the nested fields', function () {
expect(within(container).queryByText('nestedFieldName')).to.not.exist;
});
it('renders the nested fields when the field is clicked', function () {
const fieldNameButton = within(container).getByText('documentField');
userEvent.click(fieldNameButton, undefined, {
skipPointerEventsCheck: true,
});
expect(within(container).queryByText('nestedFieldName')).to.be.visible;
});
});
describe('array field with various types', function () {
const types: SchemaType[] = [
{
name: 'Array',
path: ['arrayField'],
probability: 0.7,
count: 2,
bsonType: 'Array',
lengths: [2, 2],
averageLength: 2,
totalCount: 4,
types: [
{
name: 'String',
path: ['arrayField'],
probability: 0.6,
count: 2,
bsonType: 'String',
values: ['test11', 'test22'],
},
{
name: 'Decimal128',
path: ['arrayField'],
probability: 0.4,
count: 2,
bsonType: 'Decimal128',
values: [new Decimal128('555'), new Decimal128('777')],
},
],
},
{
name: 'Date',
path: ['arrayField'],
probability: 0.3,
count: 1,
bsonType: 'Date',
},
];
beforeEach(function () {
render(
);
container = screen.getByTestId('schema-field');
});
it('renders the field name', function () {
expect(within(container).getByText('arrayField')).to.be.visible;
});
it('renders the field type', function () {
expect(within(container).getByText('Array')).to.be.visible;
});
it('renders the various types found in the array', function () {
expect(within(container).getByText('String')).to.be.visible;
expect(within(container).getByText('Decimal128')).to.be.visible;
expect(within(container).queryByText('Int32')).to.not.exist;
});
});
});
describe('shouldShowUnboundArrayInsight', function () {
async function getTypesForValue(val: any) {
return (await parseSchema([{ a: val }])).fields[0].types;
}
it('should return true when document matches criteria', async function () {
const schemas = await Promise.all(
[{ a: 1 }, new BSON.ObjectId(), 'a'].map((val) => {
return getTypesForValue([val]);
})
);
for (const schemaType of schemas) {
expect(shouldShowUnboundArrayInsight(schemaType, 1)).to.eq(true);
}
});
it("should return false when document doesn't match criteria", async function () {
const tooSmall = await getTypesForValue([1, 2, 3]);
expect(shouldShowUnboundArrayInsight(tooSmall, 5)).to.eq(false);
const wrongType = await getTypesForValue([1.2]);
expect(shouldShowUnboundArrayInsight(wrongType, 1)).to.eq(false);
const notArray = await getTypesForValue(true);
expect(shouldShowUnboundArrayInsight(notArray, 1)).to.eq(false);
});
});