Files
blockly/tests/mocha/toolbox_test.js
Neil Fraser 42fde0f81b chore: Reduce delta on ports to blockly-samples (#6886)
* Reduce usage of obsolete .keyCode property.
* Rename private properties/methods which violate eslint rules.
* Use arrays of bound events rather than individual properties.
* Improve typing info.
* Also fix O(n^2) recursive performance issue in theme's getComponentStyle function.
* And replace String(...) with '${...}' (smaller, faster).
* .toString() is considered harmful.
2023-03-15 13:28:57 -07:00

681 lines
27 KiB
JavaScript

/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.toolbox');
import {defineStackBlock} from './test_helpers/block_definitions.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
import {getBasicToolbox, getCategoryJSON, getChildItem, getCollapsibleItem, getDeeplyNestedJSON, getInjectedToolbox, getNonCollapsibleItem, getSeparator, getSimpleJson, getXmlArray} from './test_helpers/toolbox_definitions.js';
suite('Toolbox', function() {
setup(function() {
sharedTestSetup.call(this);
defineStackBlock();
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('init', function() {
setup(function() {
this.toolbox = getInjectedToolbox();
});
teardown(function() {
this.toolbox.dispose();
});
test('Init called -> HtmlDiv is created', function() {
chai.assert.isDefined(this.toolbox.HtmlDiv);
});
test('Init called -> HtmlDiv is inserted before parent node', function() {
const toolboxDiv = Blockly.common.getMainWorkspace().getInjectionDiv().childNodes[0];
chai.assert.equal(toolboxDiv.className,
'blocklyToolboxDiv blocklyNonSelectable');
});
test('Init called -> Toolbox is subscribed to background and foreground colour', function() {
const themeManager = this.toolbox.workspace_.getThemeManager();
const themeManagerSpy = sinon.spy(themeManager, 'subscribe');
const componentManager = this.toolbox.workspace_.getComponentManager();
sinon.stub(componentManager, 'addComponent');
this.toolbox.init();
sinon.assert.calledWith(themeManagerSpy, this.toolbox.HtmlDiv,
'toolboxBackgroundColour', 'background-color');
sinon.assert.calledWith(themeManagerSpy, this.toolbox.HtmlDiv,
'toolboxForegroundColour', 'color');
});
test('Init called -> Render is called', function() {
const renderSpy = sinon.spy(this.toolbox, 'render');
const componentManager = this.toolbox.workspace_.getComponentManager();
sinon.stub(componentManager, 'addComponent');
this.toolbox.init();
sinon.assert.calledOnce(renderSpy);
});
test('Init called -> Flyout is initialized', function() {
const componentManager = this.toolbox.workspace_.getComponentManager();
sinon.stub(componentManager, 'addComponent');
this.toolbox.init();
chai.assert.isDefined(this.toolbox.flyout_);
});
});
suite('render', function() {
setup(function() {
this.toolbox = getInjectedToolbox();
});
teardown(function() {
this.toolbox.dispose();
});
test('Render called with valid toolboxDef -> Contents are created', function() {
const positionStub = sinon.stub(this.toolbox, 'position');
this.toolbox.render({'contents': [
{'kind': 'category', 'contents': []},
{'kind': 'category', 'contents': []},
]});
chai.assert.lengthOf(this.toolbox.contents_, 2);
sinon.assert.called(positionStub);
});
// TODO: Uncomment once implemented.
test.skip('Toolbox definition with both blocks and categories -> Should throw an error', function() {
const toolbox = this.toolbox;
const badToolboxDef = [
{
"kind": "block",
},
{
"kind": "category",
},
];
chai.assert.throws(function() {
toolbox.render({'contents': badToolboxDef});
}, 'Toolbox cannot have both blocks and categories in the root level.');
});
// TODO: Uncomment once implemented.
test.skip('Expanded set to true for a non collapsible toolbox item -> Should open flyout', function() {
this.toolbox.render(this.toolboxXml);
const selectedNode = this.toolbox.tree_.children_[0];
chai.assert.isTrue(selectedNode.selected_);
});
test('JSON toolbox definition -> Should create toolbox with contents', function() {
const jsonDef = {'contents': [
{
"kind": "category",
"contents": [
{
"kind": "block",
"blockxml": '<block xmlns="http://www.w3.org/1999/xhtml" type="basic_block"><field name="TEXT">FirstCategory-FirstBlock</field></block>',
},
{
"kind": "label",
"text": "Input/Output:",
"web-class": "ioLabel",
},
{
"kind": "button",
"text": "insert",
"callbackkey": "insertConnectionStacks",
"web-class": "ioLabel",
},
{
"kind": "sep",
"gap": "7",
},
],
},
]};
this.toolbox.render(jsonDef);
chai.assert.lengthOf(this.toolbox.contents_, 1);
});
test('multiple icon classes can be applied', function() {
const jsonDef = {'contents': [
{
"kind": "category",
"cssConfig": {
"icon": "customIcon customIconEvents",
},
"contents": [
{
"kind": "block",
"blockxml": '<block xmlns="http://www.w3.org/1999/xhtml" type="basic_block"><field name="TEXT">FirstCategory-FirstBlock</field></block>',
},
],
},
]};
chai.assert.doesNotThrow(() => {
this.toolbox.render(jsonDef);
});
chai.assert.lengthOf(this.toolbox.contents_, 1);
});
});
suite('onClick_', function() {
setup(function() {
this.toolbox = getInjectedToolbox();
});
teardown(function() {
this.toolbox.dispose();
});
test('Toolbox clicked -> Should close flyout', function() {
const hideChaffStub = sinon.stub(
Blockly.WorkspaceSvg.prototype, "hideChaff");
const evt = new PointerEvent('pointerdown', {});
this.toolbox.HtmlDiv.dispatchEvent(evt);
sinon.assert.calledOnce(hideChaffStub);
});
test('Category clicked -> Should select category', function() {
const categoryXml = document.getElementsByClassName('blocklyTreeRow')[0];
const evt = {
'target': categoryXml,
};
const item = this.toolbox.contentMap_[categoryXml.getAttribute('id')];
const setSelectedSpy = sinon.spy(this.toolbox, 'setSelectedItem');
const onClickSpy = sinon.spy(item, 'onClick');
this.toolbox.onClick_(evt);
sinon.assert.calledOnce(setSelectedSpy);
sinon.assert.calledOnce(onClickSpy);
});
});
suite('onKeyDown_', function() {
setup(function() {
this.toolbox = getInjectedToolbox();
});
teardown(function() {
this.toolbox.dispose();
});
function createKeyDownMock(key) {
return {
'key': key,
'preventDefault': function() {},
};
}
function testCorrectFunctionCalled(toolbox, key, funcName) {
const event = createKeyDownMock(key);
const preventDefaultEvent = sinon.stub(event, 'preventDefault');
const selectMethodStub = sinon.stub(toolbox, funcName);
selectMethodStub.returns(true);
toolbox.onKeyDown_(event);
sinon.assert.called(selectMethodStub);
sinon.assert.called(preventDefaultEvent);
}
test('Down button is pushed -> Should call selectNext_', function() {
testCorrectFunctionCalled(this.toolbox, 'ArrowDown', 'selectNext_', true);
});
test('Up button is pushed -> Should call selectPrevious_', function() {
testCorrectFunctionCalled(this.toolbox, 'ArrowUp', 'selectPrevious_', true);
});
test('Left button is pushed -> Should call selectParent_', function() {
testCorrectFunctionCalled(this.toolbox, 'ArrowLeft', 'selectParent_', true);
});
test('Right button is pushed -> Should call selectChild_', function() {
testCorrectFunctionCalled(this.toolbox, 'ArrowRight', 'selectChild_', true);
});
test('Enter button is pushed -> Should toggle expanded', function() {
this.toolbox.selectedItem_ = getCollapsibleItem(this.toolbox);
const toggleExpandedStub = sinon.stub(this.toolbox.selectedItem_, 'toggleExpanded');
const event = createKeyDownMock('Enter');
const preventDefaultEvent = sinon.stub(event, 'preventDefault');
this.toolbox.onKeyDown_(event);
sinon.assert.called(toggleExpandedStub);
sinon.assert.called(preventDefaultEvent);
});
test('Enter button is pushed when no item is selected -> Should not call prevent default', function() {
this.toolbox.selectedItem_ = null;
const event = createKeyDownMock('Enter');
const preventDefaultEvent = sinon.stub(event, 'preventDefault');
this.toolbox.onKeyDown_(event);
sinon.assert.notCalled(preventDefaultEvent);
});
});
suite('Select Methods', function() {
setup(function() {
this.toolbox = getInjectedToolbox();
});
teardown(function() {
this.toolbox.dispose();
});
suite('selectChild_', function() {
test('No item is selected -> Should not handle event', function() {
this.toolbox.selectedItem_ = null;
const handled = this.toolbox.selectChild_();
chai.assert.isFalse(handled);
});
test('Selected item is not collapsible -> Should not handle event', function() {
this.toolbox.selectedItem_ = getNonCollapsibleItem(this.toolbox);
const handled = this.toolbox.selectChild_();
chai.assert.isFalse(handled);
});
test('Selected item is collapsible -> Should expand', function() {
const collapsibleItem = getCollapsibleItem(this.toolbox);
this.toolbox.selectedItem_ = collapsibleItem;
const handled = this.toolbox.selectChild_();
chai.assert.isTrue(handled);
chai.assert.isTrue(collapsibleItem.isExpanded());
chai.assert.equal(this.toolbox.selectedItem_, collapsibleItem);
});
test('Selected item is expanded -> Should select child', function() {
const collapsibleItem = getCollapsibleItem(this.toolbox);
collapsibleItem.expanded_ = true;
const selectNextStub = sinon.stub(this.toolbox, 'selectNext_');
this.toolbox.selectedItem_ = collapsibleItem;
const handled = this.toolbox.selectChild_();
chai.assert.isTrue(handled);
sinon.assert.called(selectNextStub);
});
});
suite('selectParent_', function() {
test('No item selected -> Should not handle event', function() {
this.toolbox.selectedItem_ = null;
const handled = this.toolbox.selectParent_();
chai.assert.isFalse(handled);
});
test('Selected item is expanded -> Should collapse', function() {
const collapsibleItem = getCollapsibleItem(this.toolbox);
collapsibleItem.expanded_ = true;
this.toolbox.selectedItem_ = collapsibleItem;
const handled = this.toolbox.selectParent_();
chai.assert.isTrue(handled);
chai.assert.isFalse(collapsibleItem.isExpanded());
chai.assert.equal(this.toolbox.selectedItem_, collapsibleItem);
});
test('Selected item is not expanded -> Should get parent', function() {
const childItem = getChildItem(this.toolbox);
this.toolbox.selectedItem_ = childItem;
const handled = this.toolbox.selectParent_();
chai.assert.isTrue(handled);
chai.assert.equal(this.toolbox.selectedItem_, childItem.getParent());
});
});
suite('selectNext_', function() {
test('No item is selected -> Should not handle event', function() {
this.toolbox.selectedItem_ = null;
const handled = this.toolbox.selectNext_();
chai.assert.isFalse(handled);
});
test('Next item is selectable -> Should select next item', function() {
const item = this.toolbox.contents_[0];
this.toolbox.selectedItem_ = item;
const handled = this.toolbox.selectNext_();
chai.assert.isTrue(handled);
chai.assert.equal(this.toolbox.selectedItem_, this.toolbox.contents_[1]);
});
test('Selected item is last item -> Should not handle event', function() {
const item = this.toolbox.contents_[this.toolbox.contents_.length - 1];
this.toolbox.selectedItem_ = item;
const handled = this.toolbox.selectNext_();
chai.assert.isFalse(handled);
chai.assert.equal(this.toolbox.selectedItem_, item);
});
test('Selected item is collapsed -> Should skip over its children', function() {
const item = getCollapsibleItem(this.toolbox);
const childItem = item.flyoutItems_[0];
item.expanded_ = false;
this.toolbox.selectedItem_ = item;
const handled = this.toolbox.selectNext_();
chai.assert.isTrue(handled);
chai.assert.notEqual(this.toolbox.selectedItem_, childItem);
});
});
suite('selectPrevious', function() {
test('No item is selected -> Should not handle event', function() {
this.toolbox.selectedItem_ = null;
const handled = this.toolbox.selectPrevious_();
chai.assert.isFalse(handled);
});
test('Selected item is first item -> Should not handle event', function() {
const item = this.toolbox.contents_[0];
this.toolbox.selectedItem_ = item;
const handled = this.toolbox.selectPrevious_();
chai.assert.isFalse(handled);
chai.assert.equal(this.toolbox.selectedItem_, item);
});
test('Previous item is selectable -> Should select previous item', function() {
const item = this.toolbox.contents_[1];
const prevItem = this.toolbox.contents_[0];
this.toolbox.selectedItem_ = item;
const handled = this.toolbox.selectPrevious_();
chai.assert.isTrue(handled);
chai.assert.equal(this.toolbox.selectedItem_, prevItem);
});
test('Previous item is collapsed -> Should skip over children of the previous item', function() {
const childItem = getChildItem(this.toolbox);
const parentItem = childItem.getParent();
const parentIdx = this.toolbox.contents_.indexOf(parentItem);
// Gets the item after the parent.
const item = this.toolbox.contents_[parentIdx + 1];
this.toolbox.selectedItem_ = item;
const handled = this.toolbox.selectPrevious_();
chai.assert.isTrue(handled);
chai.assert.notEqual(this.toolbox.selectedItem_, childItem);
});
});
});
suite('setSelectedItem', function() {
setup(function() {
this.toolbox = getInjectedToolbox();
});
teardown(function() {
this.toolbox.dispose();
});
function setupSetSelected(toolbox, oldItem, newItem) {
toolbox.selectedItem_ = oldItem;
const newItemStub = sinon.stub(newItem, 'setSelected');
toolbox.setSelectedItem(newItem);
return newItemStub;
}
test('Selected item and new item are null -> Should not update the flyout', function() {
this.selectedItem_ = null;
this.toolbox.setSelectedItem(null);
const updateFlyoutStub = sinon.stub(this.toolbox, 'updateFlyout_');
sinon.assert.notCalled(updateFlyoutStub);
});
test('New item is not selectable -> Should not update the flyout', function() {
const separator = getSeparator(this.toolbox);
this.toolbox.setSelectedItem(separator);
const updateFlyoutStub = sinon.stub(this.toolbox, 'updateFlyout_');
sinon.assert.notCalled(updateFlyoutStub);
});
test('Select an item with no children -> Should select item', function() {
const oldItem = getCollapsibleItem(this.toolbox);
const oldItemStub = sinon.stub(oldItem, 'setSelected');
const newItem = getNonCollapsibleItem(this.toolbox);
const newItemStub = setupSetSelected(this.toolbox, oldItem, newItem);
sinon.assert.calledWith(oldItemStub, false);
sinon.assert.calledWith(newItemStub, true);
});
test('Select previously selected item with no children -> Should deselect', function() {
const newItem = getNonCollapsibleItem(this.toolbox);
const newItemStub = setupSetSelected(this.toolbox, newItem, newItem);
sinon.assert.calledWith(newItemStub, false);
});
test('Select collapsible item -> Should select item', function() {
const newItem = getCollapsibleItem(this.toolbox);
const newItemStub = setupSetSelected(this.toolbox, null, newItem);
sinon.assert.calledWith(newItemStub, true);
});
test('Select previously selected collapsible item -> Should not deselect', function() {
const newItem = getCollapsibleItem(this.toolbox);
const newItemStub = setupSetSelected(this.toolbox, newItem, newItem);
sinon.assert.notCalled(newItemStub);
});
});
suite('updateFlyout_', function() {
setup(function() {
this.toolbox = getInjectedToolbox();
});
teardown(function() {
this.toolbox.dispose();
});
function testHideFlyout(toolbox, oldItem, newItem) {
const updateFlyoutStub = sinon.stub(toolbox.flyout_, 'hide');
toolbox.updateFlyout_(oldItem, newItem);
sinon.assert.called(updateFlyoutStub);
}
test('Select previously selected item -> Should close flyout', function() {
const newItem = getNonCollapsibleItem(this.toolbox);
testHideFlyout(this.toolbox, newItem, newItem);
});
test('No new item -> Should close flyout', function() {
testHideFlyout(this.toolbox, null, null);
});
test('Old item but no new item -> Should close flyout', function() {
const oldItem = getNonCollapsibleItem(this.toolbox);
testHideFlyout(this.toolbox, oldItem, null);
});
test('Select collapsible item -> Should close flyout', function() {
const newItem = getCollapsibleItem(this.toolbox);
testHideFlyout(this.toolbox, null, newItem);
});
test('Select selectable item -> Should open flyout', function() {
const showFlyoutstub = sinon.stub(this.toolbox.flyout_, 'show');
const scrollToStartFlyout = sinon.stub(this.toolbox.flyout_, 'scrollToStart');
const newItem = getNonCollapsibleItem(this.toolbox);
this.toolbox.updateFlyout_(null, newItem);
sinon.assert.called(showFlyoutstub);
sinon.assert.called(scrollToStartFlyout);
});
});
suite('position', function() {
setup(function() {
this.toolbox = getBasicToolbox();
const metricsStub = sinon.stub(this.toolbox.workspace_, 'getMetrics');
metricsStub.returns({});
});
function checkHorizontalToolbox(toolbox) {
chai.assert.equal(toolbox.HtmlDiv.style.left, '0px', 'Check left position');
chai.assert.equal(toolbox.HtmlDiv.style.height, 'auto', 'Check height');
chai.assert.equal(toolbox.HtmlDiv.style.width, '100%', 'Check width');
chai.assert.equal(toolbox.height_, toolbox.HtmlDiv.offsetHeight, 'Check height');
}
function checkVerticalToolbox(toolbox) {
chai.assert.equal(toolbox.HtmlDiv.style.height, '100%', 'Check height');
chai.assert.equal(toolbox.width_, toolbox.HtmlDiv.offsetWidth, 'Check width');
}
test('HtmlDiv is not created -> Should not resize', function() {
const toolbox = this.toolbox;
toolbox.HtmlDiv = null;
toolbox.horizontalLayout_ = true;
toolbox.position();
chai.assert.equal(toolbox.height_, 0);
});
test('Horizontal toolbox at top -> Should anchor horizontal toolbox to top', function() {
const toolbox = this.toolbox;
toolbox.toolboxPosition = Blockly.utils.toolbox.Position.TOP;
toolbox.horizontalLayout_ = true;
toolbox.position();
checkHorizontalToolbox(toolbox);
chai.assert.equal(toolbox.HtmlDiv.style.top, '0px', 'Check top');
});
test('Horizontal toolbox at bottom -> Should anchor horizontal toolbox to bottom', function() {
const toolbox = this.toolbox;
toolbox.toolboxPosition = Blockly.utils.toolbox.Position.BOTTOM;
toolbox.horizontalLayout_ = true;
toolbox.position();
checkHorizontalToolbox(toolbox);
chai.assert.equal(toolbox.HtmlDiv.style.bottom, '0px', 'Check bottom');
});
test('Vertical toolbox at right -> Should anchor to right', function() {
const toolbox = this.toolbox;
toolbox.toolboxPosition = Blockly.utils.toolbox.Position.RIGHT;
toolbox.horizontalLayout_ = false;
toolbox.position();
chai.assert.equal(toolbox.HtmlDiv.style.right, '0px', 'Check right');
checkVerticalToolbox(toolbox);
});
test('Vertical toolbox at left -> Should anchor to left', function() {
const toolbox = this.toolbox;
toolbox.toolboxPosition = Blockly.utils.toolbox.Position.LEFT;
toolbox.horizontalLayout_ = false;
toolbox.position();
chai.assert.equal(toolbox.HtmlDiv.style.left, '0px', 'Check left');
checkVerticalToolbox(toolbox);
});
});
suite('parseMethods', function() {
setup(function() {
this.categoryToolboxJSON = getCategoryJSON();
this.simpleToolboxJSON = getSimpleJson();
});
function checkValue(actual, expected, value) {
const actualVal = actual[value];
const expectedVal = expected[value];
chai.assert.equal(actualVal.toUpperCase(), expectedVal.toUpperCase(), 'Checking value for: ' + value);
}
function checkContents(actualContents, expectedContents) {
chai.assert.equal(actualContents.length, expectedContents.length);
for (let i = 0; i < actualContents.length; i++) {
// TODO: Check the values as well as all the keys.
chai.assert.containsAllKeys(actualContents[i], Object.keys(expectedContents[i]));
}
}
function checkCategory(actual, expected) {
checkValue(actual, expected, 'kind');
checkValue(actual, expected, 'name');
chai.assert.deepEqual(actual['cssconfig'], expected['cssconfig']);
checkContents(actual.contents, expected.contents);
}
function checkCategoryToolbox(actual, expected) {
const actualContents = actual['contents'];
const expectedContents = expected['contents'];
chai.assert.equal(actualContents.length, expectedContents.length);
for (let i = 0; i < expected.length; i++) {
checkCategory(actualContents[i], expected[i]);
}
}
function checkSimpleToolbox(actual, expected) {
checkContents(actual['contents'], expected['contents']);
}
suite('parseToolbox', function() {
test('Category Toolbox: JSON', function() {
const toolboxDef = Blockly.utils.toolbox.convertToolboxDefToJson(this.categoryToolboxJSON);
chai.assert.isNotNull(toolboxDef);
checkCategoryToolbox(toolboxDef, this.categoryToolboxJSON);
});
test('Simple Toolbox: JSON', function() {
const toolboxDef = Blockly.utils.toolbox.convertToolboxDefToJson(this.simpleToolboxJSON);
chai.assert.isNotNull(toolboxDef);
checkSimpleToolbox(toolboxDef, this.simpleToolboxJSON);
});
test('Category Toolbox: xml', function() {
const toolboxXml = document.getElementById('toolbox-categories');
const toolboxDef = Blockly.utils.toolbox.convertToolboxDefToJson(toolboxXml);
chai.assert.isNotNull(toolboxDef);
checkCategoryToolbox(toolboxDef, this.categoryToolboxJSON);
});
test('Simple Toolbox: xml', function() {
const toolboxXml = document.getElementById('toolbox-simple');
const toolboxDef = Blockly.utils.toolbox.convertToolboxDefToJson(toolboxXml);
chai.assert.isNotNull(toolboxDef);
checkSimpleToolbox(toolboxDef, this.simpleToolboxJSON);
});
test('Simple Toolbox: string', function() {
let toolbox = '<xml>';
toolbox += ' <block type="controls_if"></block>';
toolbox += ' <block type="controls_whileUntil"></block>';
toolbox += '</xml>';
const toolboxJson = {
'contents': [
{
'kind': 'block',
'type': 'controls_if',
},
{
'kind': 'block',
'type': 'controls_if',
},
],
};
const toolboxDef = Blockly.utils.toolbox.convertToolboxDefToJson(toolbox);
chai.assert.isNotNull(toolboxDef);
checkSimpleToolbox(toolboxDef, toolboxJson);
});
test('Category Toolbox: string', function() {
let toolbox = '<xml>';
toolbox += ' <category name="a"></category>';
toolbox += ' <category name="b"></category>';
toolbox += '</xml>';
const toolboxJson = {
'contents': [
{
'kind': 'category',
'name': 'a',
},
{
'kind': 'category',
'name': 'b',
},
],
};
const toolboxDef = Blockly.utils.toolbox.convertToolboxDefToJson(toolbox);
chai.assert.isNotNull(toolboxDef);
checkSimpleToolbox(toolboxDef, toolboxJson);
});
});
suite('parseFlyout', function() {
test('Array of Nodes', function() {
const xmlList = getXmlArray();
const flyoutDef = Blockly.utils.toolbox.convertFlyoutDefToJsonArray(xmlList);
checkContents(flyoutDef, this.simpleToolboxJSON['contents']);
});
test('NodeList', function() {
const nodeList = document.getElementById('toolbox-simple').childNodes;
const flyoutDef = Blockly.utils.toolbox.convertFlyoutDefToJsonArray(nodeList);
checkContents(flyoutDef, this.simpleToolboxJSON['contents']);
});
test('List of json', function() {
const jsonList = this.simpleToolboxJSON['contents'];
const flyoutDef = Blockly.utils.toolbox.convertFlyoutDefToJsonArray(jsonList);
checkContents(flyoutDef, this.simpleToolboxJSON['contents']);
});
test('Json', function() {
const flyoutDef = Blockly.utils.toolbox.convertFlyoutDefToJsonArray(this.simpleToolboxJSON);
checkContents(flyoutDef, this.simpleToolboxJSON['contents']);
});
});
});
suite('Nested Categories', function() {
setup(function() {
this.toolbox = getInjectedToolbox();
});
teardown(function() {
this.toolbox.dispose();
});
test('Child categories visible if all ancestors expanded', function() {
this.toolbox.render(getDeeplyNestedJSON());
const outerCategory = this.toolbox.contents_[0];
const middleCategory = this.toolbox.contents_[1];
const innerCategory = this.toolbox.contents_[2];
outerCategory.toggleExpanded();
middleCategory.toggleExpanded();
innerCategory.show();
chai.assert.isTrue(innerCategory.isVisible(),
'All ancestors are expanded, so category should be visible');
});
test('Child categories not visible if any ancestor not expanded', function() {
this.toolbox.render(getDeeplyNestedJSON());
const middleCategory = this.toolbox.contents_[1];
const innerCategory = this.toolbox.contents_[2];
// Don't expand the outermost category
// Even though the direct parent of inner is expanded, it shouldn't be visible
// because all ancestor categories need to be visible, not just parent
middleCategory.toggleExpanded();
innerCategory.show();
chai.assert.isFalse(innerCategory.isVisible(),
'Not all ancestors are expanded, so category should not be visible');
});
});
});