diff --git a/tests/mocha/icon_test.js b/tests/mocha/icon_test.js new file mode 100644 index 000000000..e0b83fa83 --- /dev/null +++ b/tests/mocha/icon_test.js @@ -0,0 +1,316 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +goog.declareModuleId('Blockly.test.icon'); + +import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js'; +import {defineEmptyBlock} from './test_helpers/block_definitions.js'; + +suite.skip('Icon', function() { + setup(function() { + this.clock = sharedTestSetup.call(this, {fireEventsNow: false}).clock; + defineEmptyBlock(); + }); + + teardown(function() { + sharedTestTeardown.call(this); + }); + + suite('Hooks getting properly triggered by the block', function() { + class MockIcon { + initView() {} + + applyColour() {} + + updateEditable() {} + + updateCollapsed() {} + } + + function createHeadlessWorkspace() { + return new Blockly.Workspace(); + } + + function createWorkspaceSvg() { + const workspace = new Blockly.WorkspaceSvg(new Blockly.Options({})); + workspace.createDom(); + return workspace; + } + + function createUninitializedBlock(workspace) { + return workspace.newBlock('empty_block'); + } + + function createInitializedBlock(workspace) { + const block = workspace.newBlock('empty_block'); + block.initSvg(); + block.render(); + return block; + } + + suite('Triggering view initialization', function() { + test('initView is not called by headless blocks', function() { + const workspace = createHeadlessWorkspace(); + const block = createUninitializedBlock(workspace); + const icon = new MockIcon(); + const initViewSpy = sinon.spy(icon, 'initView'); + + block.addIcon(icon); + + chai.assert.isFalse( + initViewSpy.called, 'Expected initView to not be called'); + }); + + test('initView is called by headful blocks during initSvg', function() { + const workspace = createWorkspaceSvg(); + const block = createUninitializedBlock(workspace); + const icon = new MockIcon(); + const initViewSpy = sinon.spy(icon, 'initView'); + + block.addIcon(icon); + chai.assert.isFalse( + initViewSpy.called, + 'Expected initView to not be called before initing svg'); + block.initSvg(); + chai.assert.isTrue( + initViewSpy.calledOnce, 'Expected initView to be called'); + }); + + test( + 'initView is called by headful blocks that are currently ' + + 'rendered when the icon is added', + function() { + const workspace = new Blockly.WorkspaceSvg(new Blockly.Options({})); + workspace.createDom(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const initViewSpy = sinon.spy(icon, 'initView'); + + block.addIcon(icon); + chai.assert.isTrue( + initViewSpy.calledOnce, 'Expected initView to be called'); + }); + }); + + suite('Triggering applying colors', function() { + test('applyColour is not called by headless blocks', function() { + const workspace = createHeadlessWorkspace(); + const block = createUninitializedBlock(workspace); + const icon = new MockIcon(); + const applyColourSpy = sinon.spy(icon, 'applyColour'); + + block.addIcon(icon); + + chai.assert.isFalse( + applyColourSpy.called, 'Expected applyColour to not be called'); + }); + + test('applyColour is called by headful blocks during initSvg', function() { + const workspace = createWorkspaceSvg(); + const block = createUninitializedBlock(workspace); + const icon = new MockIcon(); + const applyColourSpy = sinon.spy(icon, 'applyColour'); + + block.addIcon(icon); + chai.assert.isFalse( + applyColourSpy.called, + 'Expected applyCOlour to not be called before initing svg'); + block.initSvg(); + chai.assert.isTrue( + applyColourSpy.calledOnce, 'Expected applyColour to be called'); + }); + + test( + 'applyColour is called by headful blocks that are currently ' + + 'rendered when the icon is added', + function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const applyColourSpy = sinon.spy(icon, 'applyColour'); + + block.addIcon(icon); + chai.assert.isTrue( + applyColourSpy.calledOnce, 'Expected applyColour to be called'); + }); + + test("applyColour is called when the block's color changes", function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const applyColourSpy = sinon.spy(icon, 'applyColour'); + + block.addIcon(icon); + applyColourSpy.resetHistory(); + block.setColour('#cccccc'); + chai.assert.isTrue( + applyColourSpy.calledOnce, 'Expected applyColour to be called'); + }); + + test("applyColour is called when the block's style changes", function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const applyColourSpy = sinon.spy(icon, 'applyColour'); + + block.addIcon(icon); + applyColourSpy.resetHistory(); + block.setStyle('logic_block'); + chai.assert.isTrue( + applyColourSpy.calledOnce, 'Expected applyColour to be called'); + }); + + test('applyColour is called when the block is disabled', function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const applyColourSpy = sinon.spy(icon, 'applyColour'); + + block.addIcon(icon); + applyColourSpy.resetHistory(); + block.setDisabled(true); + chai.assert.isTrue( + applyColourSpy.calledOnce, 'Expected applyColour to be called'); + }); + + test('applyColour is called when the block becomes a shadow', function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const applyColourSpy = sinon.spy(icon, 'applyColour'); + + block.addIcon(icon); + applyColourSpy.resetHistory(); + block.setShadow(true); + chai.assert.isTrue( + applyColourSpy.calledOnce, 'Expected applyColour to be called'); + }); + }); + + suite('Triggering updating editability', function() { + test('updateEditable is not called by headless blocks', function() { + const workspace = createHeadlessWorkspace(); + const block = createUninitializedBlock(workspace); + const icon = new MockIcon(); + const updateEditableSpy = sinon.spy(icon, 'updateEditable'); + + block.addIcon(icon); + + chai.assert.isFalse( + updateEditableSpy.called, + 'Expected updateEditable to not be called'); + }); + + test('updateEditable is called by headful blocks during initSvg', + function() { + const workspace = createWorkspaceSvg(); + const block = createUninitializedBlock(workspace); + const icon = new MockIcon(); + const updateEditableSpy = sinon.spy(icon, 'updateEditable'); + + block.addIcon(icon); + chai.assert.isFalse( + updateEditableSpy.called, + 'Expected updateEditable to not be called before initing svg'); + block.initSvg(); + chai.assert.isTrue( + updateEditableSpy.calledOnce, 'Expected updateEditable to be called'); + }); + + test( + 'updateEditable is called by headful blocks that are currently ' + + 'rendered when the icon is added', + function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const updateEditableSpy = sinon.spy(icon, 'updateEditable'); + + block.addIcon(icon); + chai.assert.isTrue( + updateEditableSpy.calledOnce, + 'Expected updateEditable to be called'); + }); + + test( + 'updateEditable is called when the block is made ineditable', + function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const updateEditableSpy = sinon.spy(icon, 'updateEditable'); + + block.addIcon(icon); + updateEditableSpy.resetHistory(); + block.setEditable(false); + chai.assert.isTrue( + updateEditableSpy.calledOnce, 'Expected updateEditable to be called'); + }); + + test( + 'updateEditable is called when the block is made editable', + function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const updateEditableSpy = sinon.spy(icon, 'updateEditable'); + + block.addIcon(icon); + block.setEditable(false); + updateEditableSpy.resetHistory(); + block.setEditable(true); + chai.assert.isTrue( + updateEditableSpy.calledOnce, 'Expected updateEditable to be called'); + }); + }); + + suite('Triggering updating collapsed-ness', function() { + test('updateCollapsed is not called by headless blocks', function() { + const workspace = createHeadlessWorkspace(); + const block = createUninitializedBlock(workspace); + const icon = new MockIcon(); + const updateCollapsedSpy = sinon.spy(icon, 'updateCollapsed'); + + block.addIcon(icon); + block.setCollapsed(true); + block.setCollapsed(false); + + chai.assert.isFalse( + updateCollapsedSpy.called, + 'Expected updateCollapsed to not be called'); + }); + + test('updateCollapsed is called when the block is collapsed', function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const updateCollapsedSpy = sinon.spy(icon, 'updateCollapsed'); + block.addIcon(icon); + + block.setCollapsed(true); + + chai.assert.isTrue( + updateCollapsedSpy.calledOnce, + 'Expected updateCollapsed to be called'); + }); + + test('updateCollapsed is called when the block is expanded', function() { + const workspace = createWorkspaceSvg(); + const block = createInitializedBlock(workspace); + const icon = new MockIcon(); + const updateCollapsedSpy = sinon.spy(icon, 'updateCollapsed'); + block.addIcon(icon); + + block.setCollapsed(true); + block.setCollapsed(false); + + chai.assert.isTrue( + updateCollapsedSpy.calledTwice, + 'Expected updateCollapsed to be called twice'); + }); + }); + }); +}); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index 4583a311b..108c895aa 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -98,6 +98,7 @@ 'Blockly.test.flyout', 'Blockly.test.generator', 'Blockly.test.gesture', + 'Blockly.test.icon', 'Blockly.test.input', 'Blockly.test.insertionMarker', 'Blockly.test.insertionMarkerManager', diff --git a/tests/mocha/test_helpers/block_definitions.js b/tests/mocha/test_helpers/block_definitions.js index 8fa937dd7..4b0b79900 100644 --- a/tests/mocha/test_helpers/block_definitions.js +++ b/tests/mocha/test_helpers/block_definitions.js @@ -7,6 +7,15 @@ goog.declareModuleId('Blockly.test.helpers.blockDefinitions'); +export function defineEmptyBlock(name = 'empty_block') { + Blockly.defineBlocksWithJsonArray([ + { + "type": name, + "message0": "", + }, + ]); +} + export function defineStackBlock(name = 'stack_block') { Blockly.defineBlocksWithJsonArray([{ "type": name,