import React from 'react';
import { mount } from 'enzyme';
import { expect } from 'chai';
import AppRegistry from 'hadron-app-registry';
import { ObjectId } from 'bson';
import app from 'hadron-app';
import {
getNode,
getApi,
getColumn,
getActions,
getColumnApi,
getContext,
notCalledExcept,
} from '../../../test/aggrid-helper';
import CellEditor from './cell-editor';
describe.skip('', function () {
before(function () {
global.hadronApp = app;
global.hadronApp.appRegistry = new AppRegistry();
});
after(function () {
global.hadronApp.appRegistry = new AppRegistry();
});
describe('#render', function () {
let component;
let rowNode;
let value;
const api = getApi();
const column = getColumn('field1', {
headerName: 'field1',
headerComponentParams: { bsonType: 'String' },
});
const actions = getActions();
const columnApi = getColumnApi([]);
const context = getContext([]);
describe('editable element', function () {
before(function (done) {
rowNode = getNode({ field1: 'value' });
value = rowNode.data.hadronDocument.get('field1');
component = mount(
);
done();
});
it('renders the input field', function () {
const wrapper = component.find('.table-view-cell-editor');
(
expect(
wrapper.find('.editable-element-value-wrapper-is-string')
) as any
).to.be.present();
});
it('renders the type cast dropdown', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.table-view-cell-editor-types')).to.be.present();
});
it('renders the add field button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-plus-square-o')).to.be.present();
});
it('renders the remove field button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-trash')).to.be.present();
});
it('does not render other options', function () {
const wrapper = component.find('.table-view-cell-editor');
(
expect(
wrapper.find('.table-view-cell-editor-input-field-inner')
) as any
).to.not.be.present();
expect(wrapper.find('.fa-expand')).to.not.be.present();
});
});
describe('newly added element', function () {
before(function (done) {
rowNode = getNode({});
rowNode.data.hadronDocument.insertEnd('$new', '');
value = rowNode.data.hadronDocument.get('$new');
component = mount(
);
done();
});
it('renders the fieldname input field', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(
wrapper.find('.table-view-cell-editor-input-field-inner')
).to.be.present();
});
it('renders the input field', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(
wrapper.find('.editable-element-value-wrapper-is-string')
).to.be.present();
});
it('renders the type cast dropdown', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.table-view-cell-editor-types')).to.be.present();
});
it('does not render other options', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-plus-square-o')).to.not.be.present();
expect(wrapper.find('.fa-trash')).to.not.be.present();
expect(wrapper.find('.fa-expand')).to.not.be.present();
});
});
describe('empty element', function () {
before(function (done) {
rowNode = getNode({});
value = undefined;
component = mount(
);
done();
});
it('renders the input field', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(
wrapper.find('.editable-element-value-wrapper-is-string')
).to.be.present();
});
it('renders the type cast dropdown', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.table-view-cell-editor-types')).to.be.present();
});
it('renders the add field button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-plus-square-o')).to.be.present();
});
it('does not render other options', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-trash')).to.not.be.present();
expect(
wrapper.find('.table-view-cell-editor-input-field-inner')
).to.not.be.present();
expect(wrapper.find('.fa-expand')).to.not.be.present();
});
});
describe('expandable element', function () {
before(function (done) {
rowNode = getNode({ field1: { subfield1: 'value' } });
value = rowNode.data.hadronDocument.get('field1');
component = mount(
);
done();
});
it('renders the type cast dropdown', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.table-view-cell-editor-types')).to.be.present();
});
it('renders the expand button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-expand')).to.be.present();
});
it('renders the add field button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-plus-square-o')).to.be.present();
});
it('renders the remove field button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-trash')).to.be.present();
});
it('does not render other options', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(
wrapper.find('.table-view-cell-editor-input')
).to.not.be.present();
expect(
wrapper.find('.table-view-cell-editor-input-field-inner')
).to.not.be.present();
});
});
describe('ObjectId', function () {
before(function (done) {
rowNode = getNode({ field1: { _id: new ObjectId() } });
done();
});
describe('top-level', function () {
before(function (done) {
value = rowNode.data.hadronDocument.get('_id');
component = mount(
);
done();
});
it('renders the add field button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-plus-square-o')).to.be.present();
});
it('does not render other options', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(
wrapper.find('.table-view-cell-editor-types')
).to.not.be.present();
expect(
wrapper.find('.table-view-cell-editor-input')
).to.not.be.present();
expect(
wrapper.find('.table-view-cell-editor-input-field-inner')
).to.not.be.present();
expect(wrapper.find('.fa-trash')).to.not.be.present();
expect(wrapper.find('.fa-expand')).to.not.be.present();
});
});
describe('sub-level', function () {
before(function (done) {
value = rowNode.data.hadronDocument.getChild(['field1', '_id']);
context.path = ['field1'];
component = mount(
);
done();
});
it('renders the type cast dropdown', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.table-view-cell-editor-types')).to.be.present();
});
it('renders the add field button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-plus-square-o')).to.be.present();
});
it('renders the remove field button', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.fa-trash')).to.be.present();
});
it('renders other options', function () {
const wrapper = component.find('.table-view-cell-editor');
expect(wrapper.find('.table-view-cell-editor-input')).to.be.present();
expect(
wrapper.find('.table-view-cell-editor-input-field-inner')
).to.not.be.present();
expect(wrapper.find('.fa-expand')).to.not.be.present();
});
});
});
});
describe('#actions', function () {
describe('editable element', function () {
const columnApi = getColumnApi([]);
const context = getContext([]);
const column = getColumn('field1', {
headerName: 'field1',
headerComponentParams: { bsonType: 'String' },
});
describe('handle edit', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({ field1: 'value' });
const value = rowNode.data.hadronDocument.get('field1');
let component;
before(function (done) {
component = mount(
);
const wrapper = component.find('.editable-element-value-is-string');
wrapper.simulate('change', { target: { value: 'new input' } });
expect(
component.find('.editable-element-value-is-string').props().value
).to.equal('new input');
/* Have to call isCancelAfterEnd directly because
* props.api.stopEditing doesn't call it because it's a spy */
component.instance().isCancelAfterEnd();
component.unmount();
done();
});
it('unmounting calls stopEditing', function () {
expect(api.stopEditing.callCount).to.equal(1);
});
it('unmounting calls refreshCells', function () {
expect(api.refreshCells.callCount).to.equal(1);
expect(api.refreshCells.args[0]).to.deep.equal([
{ rowNodes: [rowNode], force: true },
]);
});
it('updates the hadronElement', function () {
expect(value.currentValue).to.equal('new input');
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['stopEditing', 'refreshCells']);
notCalledExcept(actions, []);
});
});
// Enzyme doesn't like the Transition, skipping here as part of this is already
// tested elsewhere. To be revisited when enzyme will be replaced.
describe.skip('handle type change', function () {
let component;
describe('when valid', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({ field1: '100' });
const value = rowNode.data.hadronDocument.get('field1');
before(function (done) {
component = mount(
);
const item = component.find(
'[data-testid="table-view-types-dropdown-select"] Select'
);
expect(item).to.be.present();
item.simulate('mousedown');
const item2 = component.find(
'[data-testid="editable-element-type-Int32"]'
);
expect(item2).to.be.present();
item2.simulate('mousedown');
item.simulate('blur');
component.instance().isCancelAfterEnd();
done();
});
it('updates the hadronElement type', function () {
expect(value.currentType).to.equal('Int32');
});
it('updates the hadronElement value', function () {
expect(value.currentValue.value).to.equal(100);
});
it('does not call api.stopEditing()', function () {
expect(api.stopEditing.callCount).to.equal(0);
});
it('unmounting calls refreshCells', function () {
expect(api.refreshCells.callCount).to.equal(1);
expect(api.refreshCells.args[0]).to.deep.equal([
{ rowNodes: [rowNode], force: true },
]);
});
it('calls elementTypeChanged', function () {
expect(actions.elementTypeChanged.callCount).to.equal(1);
expect(
actions.elementTypeChanged.alwaysCalledWithExactly(
'field1',
'Int32',
'1'
)
).to.equal(true);
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['stopEditing', 'refreshCells']);
notCalledExcept(actions, ['elementTypeChanged']);
});
});
describe('when invalid', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({ field1: 'value' });
const value = rowNode.data.hadronDocument.get('field1');
before(function (done) {
component = mount(
);
const item = component.find('.table-view-cell-editor-input-types');
const item2 = component.find('.editable-element-type-date');
expect(item2).to.be.present();
item2.simulate('mousedown');
item.simulate('blur');
component.instance().isCancelAfterEnd();
done();
});
it('updates the hadronElement type', function () {
expect(value.currentType).to.equal('Date');
});
it('updates the hadronElement value to undefined', function () {
expect(value.currentValue.value).to.equal(undefined);
});
it('does not call api.stopEditing()', function () {
expect(api.stopEditing.callCount).to.equal(0);
});
it('unmounting calls refreshCells', function () {
expect(api.refreshCells.callCount).to.equal(1);
expect(api.refreshCells.args[0]).to.deep.equal([
{ rowNodes: [rowNode], force: true },
]);
});
it('calls elementTypeChanged', function () {
expect(actions.elementTypeChanged.callCount).to.equal(1);
expect(
actions.elementTypeChanged.alwaysCalledWithExactly(
'field1',
'Date',
'1'
)
).to.equal(true);
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['stopEditing', 'refreshCells']);
notCalledExcept(actions, ['elementTypeChanged']);
});
});
});
describe('handle remove', function () {
describe('element not added', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({ field1: 'value' });
const value = rowNode.data.hadronDocument.get('field1');
let component;
before(function (done) {
component = mount(
);
const wrapper = component.find('.fa-trash');
expect(wrapper).to.be.present();
wrapper.simulate('mousedown');
component.instance().isCancelAfterEnd();
done();
});
it('calls elementMarkRemoved action', function () {
expect(actions.elementMarkRemoved.callCount).to.equal(1);
});
it('marks the Element as removed', function () {
expect(value.isRemoved()).to.equal(true);
});
it('calls api.stopEditing()', function () {
expect(api.stopEditing.callCount).to.equal(1);
});
it('unmounting calls refreshCells', function () {
expect(api.refreshCells.callCount).to.equal(1);
expect(api.refreshCells.args[0]).to.deep.equal([
{ rowNodes: [rowNode], force: true },
]);
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['stopEditing', 'refreshCells']);
notCalledExcept(actions, ['elementMarkRemoved']);
});
});
});
describe('element added', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({});
rowNode.data.hadronDocument.insertEnd('field1', 'value');
const value = rowNode.data.hadronDocument.get('field1');
let component;
before(function (done) {
component = mount(
);
const wrapper = component.find('.fa-trash');
expect(wrapper).to.be.present();
wrapper.simulate('mousedown');
component.instance().isCancelAfterEnd();
done();
});
it('calls elementRemoved action', function () {
expect(actions.elementRemoved.callCount).to.equal(1);
});
it('marks the Element as removed', function () {
expect(value.isRemoved()).to.equal(true);
});
it('calls api.stopEditing()', function () {
expect(api.stopEditing.callCount).to.equal(1);
});
it('unmounting calls refreshCells', function () {
expect(api.refreshCells.callCount).to.equal(1);
expect(api.refreshCells.args[0]).to.deep.equal([
{ rowNodes: [rowNode], force: true },
]);
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['stopEditing', 'refreshCells']);
notCalledExcept(actions, ['elementRemoved']);
});
});
});
describe('newly added element', function () {
describe('set field name', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({});
const colId = {};
const column = getColumn('field1', colId);
const columnApi = getColumnApi([]);
const context = getContext([]);
rowNode.data.hadronDocument.insertEnd('$new', '');
const value = rowNode.data.hadronDocument.get('$new');
let component;
before(function (done) {
component = mount(
);
const wrapper = component.find('.editable-element-field');
wrapper.simulate('change', { target: { value: 'fieldname' } });
expect(
component.find('.editable-element-field').props().value
).to.equal('fieldname');
component.instance().isCancelAfterEnd();
done();
});
it('adds a new element to HadronDocument', function () {
expect(value.currentKey).to.equal('fieldname');
expect(
rowNode.data.hadronDocument.get('fieldname').currentValue
).to.equal('');
});
it('renames the column with the fieldname', function () {
expect(colId.headerName).to.equal('fieldname');
});
it('calls elementAdded action', function () {
expect(actions.elementAdded.callCount).to.equal(1);
expect(
actions.elementAdded.alwaysCalledWithExactly(
'fieldname',
'String',
'1'
)
).to.equal(true);
});
it('calls renameColumn', function () {
expect(actions.renameColumn.callCount).to.equal(1);
expect(
actions.renameColumn.alwaysCalledWithExactly('$new', 'fieldname')
).to.equal(true);
});
it('calls refreshHeader', function () {
expect(api.refreshHeader.callCount).to.equal(1);
});
it('unmounting calls refreshCells', function () {
expect(api.refreshCells.callCount).to.equal(1);
expect(api.refreshCells.args[0]).to.deep.equal([
{ rowNodes: [rowNode], force: true },
]);
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['refreshHeader', 'refreshCells']);
notCalledExcept(actions, ['elementAdded', 'renameColumn']);
});
});
describe('set field name to duplicate key', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({});
const colId = {};
const column = getColumn('field1', colId);
const columnApi = getColumnApi([
{
getColDef: () => {
return { colId: 'fieldname' };
},
},
]);
const context = getContext([]);
rowNode.data.hadronDocument.insertEnd('$new', '');
const value = rowNode.data.hadronDocument.get('$new');
let component;
before(function (done) {
component = mount(
);
const wrapper = component.find('.editable-element-field');
wrapper.simulate('change', { target: { value: 'fieldname' } });
expect(
component.find('.editable-element-field-is-duplicate').props().value
).to.equal('fieldname');
component.instance().isCancelAfterEnd();
done();
});
it('removes element from HadronDocument', function () {
expect(rowNode.data.hadronDocument.generateObject()).to.deep.equal({
_id: '1',
});
});
it('calls removeColumn action', function () {
expect(actions.removeColumn.callCount).to.equal(1);
expect(actions.removeColumn.alwaysCalledWithExactly('$new')).to.equal(
true
);
});
it('does not trigger other actions', function () {
notCalledExcept(api, []);
notCalledExcept(actions, ['removeColumn']);
});
});
describe('close without editing', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({});
const colId = {};
const column = getColumn('field1', colId);
const columnApi = getColumnApi([]);
const context = getContext([]);
rowNode.data.hadronDocument.insertEnd('$new', '');
const value = rowNode.data.hadronDocument.get('$new');
let component;
before(function (done) {
component = mount(
);
component.instance().isCancelAfterEnd();
done();
});
it('removes element from HadronDocument', function () {
expect(rowNode.data.hadronDocument.generateObject()).to.deep.equal({
_id: '1',
});
});
it('calls removeColumn action', function () {
expect(actions.removeColumn.callCount).to.equal(1);
expect(actions.removeColumn.alwaysCalledWithExactly('$new'));
});
it('does not trigger other actions', function () {
notCalledExcept(api, []);
notCalledExcept(actions, ['removeColumn']);
});
});
describe('close without editing fieldname', function () {
const api = getApi();
const actions = getActions();
const rowNode = getNode({});
const colId = {};
const column = getColumn('field1', colId);
const columnApi = getColumnApi([]);
const context = getContext([]);
rowNode.data.hadronDocument.insertEnd('$new', '');
const value = rowNode.data.hadronDocument.get('$new');
let component;
before(function (done) {
component = mount(
);
const wrapper = component.find('.editable-element-value-is-string');
wrapper.simulate('change', { target: { value: 'new input' } });
expect(
component.find('.editable-element-value-is-string').props().value
).to.equal('new input');
component.instance().isCancelAfterEnd();
done();
});
it('removes element from HadronDocument', function () {
expect(rowNode.data.hadronDocument.generateObject()).to.deep.equal({
_id: '1',
});
});
it('calls removeColumn action', function () {
expect(actions.removeColumn.callCount).to.equal(1);
expect(actions.removeColumn.alwaysCalledWithExactly('$new')).to.equal(
true
);
});
it('does not trigger other actions', function () {
notCalledExcept(api, []);
notCalledExcept(actions, ['removeColumn']);
});
});
});
describe('empty element', function () {
describe('header exists', function () {
const rowNode = getNode({});
const value = undefined;
const api = getApi();
const actions = getActions();
const column = getColumn('field1', {
headerName: 'field1',
headerComponentParams: { bsonType: 'Date' },
});
const context = getContext([]);
const columnApi = getColumnApi([]);
before(function (done) {
mount(
);
done();
});
it('sets the initial type to what the header has', function () {
expect(
rowNode.data.hadronDocument.get('field1').currentType
).to.equal('Date');
});
it('does not trigger other actions', function () {
notCalledExcept(api, []);
notCalledExcept(actions, []);
});
});
describe('header does not exist', function () {
const rowNode = getNode({});
const value = undefined;
const api = getApi();
const actions = getActions();
const column = getColumn('field1', {
headerName: 'field1',
headerComponentParams: { bsonType: 'mixed' },
});
const context = getContext([]);
const columnApi = getColumnApi([]);
before(function (done) {
mount(
);
done();
});
it('sets the initial type to what the header has', function () {
expect(
rowNode.data.hadronDocument.get('field1').currentType
).to.equal('Undefined');
});
it('does not trigger other actions', function () {
notCalledExcept(api, []);
notCalledExcept(actions, []);
});
});
describe('close without editing', function () {
const rowNode = getNode({});
const value = undefined;
const api = getApi();
const actions = getActions();
const column = getColumn('field1', {
headerName: 'field1',
headerComponentParams: { bsonType: 'String' },
});
const context = getContext([]);
const columnApi = getColumnApi([]);
before(function (done) {
const component = mount(
);
component.instance().isCancelAfterEnd();
done();
});
it('reverts the element', function () {
expect(rowNode.data.hadronDocument.generateObject()).to.deep.equal({
_id: '1',
});
});
it('does not trigger other actions', function () {
notCalledExcept(api, []);
notCalledExcept(actions, []);
});
});
describe('close with editing', function () {
const rowNode = getNode({});
const value = undefined;
const api = getApi();
const actions = getActions();
const column = getColumn('field1', {
headerName: 'field1',
headerComponentParams: { bsonType: 'String' },
});
const context = getContext([]);
const columnApi = getColumnApi([]);
before(function (done) {
const component = mount(
);
const wrapper = component.find('.editable-element-value-is-string');
wrapper.simulate('change', { target: { value: 'new input' } });
expect(
component.find('.editable-element-value-is-string').props().value
).to.equal('new input');
component.instance().isCancelAfterEnd();
done();
});
it('updates the HadronDocument', function () {
expect(
rowNode.data.hadronDocument.get('field1').currentValue
).to.equal('new input');
});
it('calls elementAdded action', function () {
expect(actions.elementAdded.callCount).to.equal(1);
expect(
actions.elementAdded.alwaysCalledWithExactly(
'field1',
'String',
'1'
)
).to.equal(true);
});
it('calls refreshCells', function () {
expect(api.refreshCells.callCount).to.equal(1);
expect(api.refreshCells.args[0]).to.deep.equal([
{ rowNodes: [rowNode], force: true },
]);
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['refreshCells']);
notCalledExcept(actions, ['elementAdded']);
});
});
describe('in a nested element', function () {
const rowNode = getNode({ field: { subfield: {} } });
const value = undefined;
const api = getApi();
const actions = getActions();
const column = getColumn('subsubfield', {
headerName: 'subsubfield',
headerComponentParams: { bsonType: 'String' },
});
const context = getContext(['field', 'subfield']);
const columnApi = getColumnApi([]);
before(function (done) {
const component = mount(
);
const wrapper = component.find('.editable-element-value-is-string');
wrapper.simulate('change', { target: { value: 'new input' } });
expect(
component.find('.editable-element-value-is-string').props().value
).to.equal('new input');
component.instance().isCancelAfterEnd();
done();
});
it('updates the HadronDocument correctly nested', function () {
expect(
rowNode.data.hadronDocument.getChild([
'field',
'subfield',
'subsubfield',
]).currentValue
).to.equal('new input');
});
it('calls elementAdded action', function () {
expect(actions.elementAdded.callCount).to.equal(1);
expect(
actions.elementAdded.alwaysCalledWithExactly(
'subsubfield',
'String',
'1'
)
).to.equal(true);
});
it('calls refreshCells', function () {
expect(api.refreshCells.callCount).to.equal(1);
expect(api.refreshCells.args[0]).to.deep.equal([
{ rowNodes: [rowNode], force: true },
]);
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['refreshCells']);
notCalledExcept(actions, ['elementAdded']);
});
});
});
describe('for an expandable element, clicking on expand', function () {
const rowNode = getNode({ field1: { subfield1: 'value' } });
const value = rowNode.data.hadronDocument.get('field1');
const api = getApi();
const actions = getActions();
const column = getColumn();
const columnApi = getColumnApi([]);
const context = getContext([]);
before(function (done) {
const component = mount(
);
const wrapper = component.find('.fa-expand');
expect(wrapper).to.be.present();
wrapper.simulate('mousedown');
done();
});
it('calls drillDown action', function () {
expect(actions.drillDown.callCount).to.equal(1);
expect(
actions.drillDown.alwaysCalledWithExactly(
rowNode.data.hadronDocument,
value
)
).to.equal(true);
});
it('calls api.stopEditing()', function () {
expect(api.stopEditing.callCount).to.equal(1);
});
it('does not trigger other actions', function () {
notCalledExcept(api, ['stopEditing']);
notCalledExcept(actions, ['drillDown']);
});
});
});
});