Files
blockly/tests/mocha/icon_test.js
dependabot[bot] bfb5b1dd49 chore(deps): Bump chai from 4.3.10 to 5.1.1 (#8092)
* chore(deps): Bump chai from 4.3.10 to 5.1.1

  Bumps [chai](https://github.com/chaijs/chai) from 4.3.10 to 5.1.1.
  - [Release notes](https://github.com/chaijs/chai/releases)
  - [Changelog](https://github.com/chaijs/chai/blob/main/History.md)
  - [Commits](https://github.com/chaijs/chai/compare/v4.3.10...v5.1.1)

  ---
  updated-dependencies:
  - dependency-name: chai
    dependency-type: direct:development
    update-type: version-update:semver-major
  ...

  Signed-off-by: dependabot[bot] <support@github.com>

* fix(tests): Migrate all usage of chai to ESM (#8216)

* fix(tests): Migrate node tests from CJS to ESM

  This allows us to import (rather than require) chai, fixing failures
  caused by that package dropping suppport for CJS in chai v5.0.0.

* fix(tests): Have mocha tests directly import chai

  Previously they relied on obtaining it from the global scope, but it's
  better if imports are explicit.

* fix(tests): Remove broken load of chai as script

  Chai v5.0.0 no longer supports being loaded as a script, so this did
  nothing but emit an syntax error message on the console.

* fix(tests): Migrate browser tests from CJS to ESM

  This allows us to import (rather than require) chai, fixing failures
  caused by chai no longer supporting CJS.

* chore(tests): format

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Christopher Allen <cpcallen+git@google.com>
2024-06-17 16:48:21 +01:00

370 lines
12 KiB
JavaScript

/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {assert} from '../../node_modules/chai/chai.js';
import {
sharedTestSetup,
sharedTestTeardown,
} from './test_helpers/setup_teardown.js';
import {defineEmptyBlock} from './test_helpers/block_definitions.js';
import {MockIcon, MockSerializableIcon} from './test_helpers/icon_mocks.js';
suite('Icon', function () {
setup(function () {
this.clock = sharedTestSetup.call(this, {fireEventsNow: false}).clock;
defineEmptyBlock();
});
teardown(function () {
sharedTestTeardown.call(this);
});
class MockNonSerializableIcon extends MockIcon {
getType() {
return 'non-serializable icon';
}
}
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;
}
function createHeadlessBlock(workspace) {
return createUninitializedBlock(workspace);
}
suite('Hooks getting properly triggered by the block', function () {
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);
assert.isFalse(
initViewSpy.called,
'Expected initView to not 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);
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);
assert.isFalse(
applyColourSpy.called,
'Expected applyColour to not 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);
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');
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');
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.setDisabledReason(true, 'test reason');
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);
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);
assert.isFalse(
updateEditableSpy.called,
'Expected updateEditable to not 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);
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);
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);
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);
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.stub(icon, 'updateCollapsed');
block.addIcon(icon);
updateCollapsedSpy.resetHistory();
block.setCollapsed(true);
this.clock.runAll();
assert.isTrue(
updateCollapsedSpy.called,
'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);
this.clock.runAll();
assert.isTrue(
updateCollapsedSpy.called,
'Expected updateCollapsed to be called',
);
});
});
});
suite('Serialization', function () {
test('serializable icons are saved', function () {
const block = createHeadlessBlock(createHeadlessWorkspace());
block.addIcon(new MockSerializableIcon());
const json = Blockly.serialization.blocks.save(block);
assert.deepNestedInclude(
json,
{'icons': {'serializable icon': 'some state'}},
'Expected the JSON to include the saved state of the ' +
'serializable icon.',
);
});
test('non-serializable icons are not saved', function () {
const block = createHeadlessBlock(createHeadlessWorkspace());
block.addIcon(new MockNonSerializableIcon());
const json = Blockly.serialization.blocks.save(block);
assert.notProperty(
json,
'icons',
'Expected the JSON to not include any saved state for icons',
);
});
});
suite('Deserialization', function () {
test('registered icons are instantiated and added to the block', function () {
Blockly.icons.registry.register(
'serializable icon',
MockSerializableIcon,
);
const workspace = createHeadlessWorkspace();
const json = {
'type': 'empty_block',
'icons': {
'serializable icon': 'some state',
},
};
const block = Blockly.serialization.blocks.append(json, workspace);
assert.equal(
block.getIcon('serializable icon').state,
'some state',
'Expected the icon to have been properly instantiated and ' +
'deserialized',
);
Blockly.icons.registry.unregister('serializable icon');
});
test('trying to deserialize an unregistered icon throws an error', function () {
const workspace = createHeadlessWorkspace();
const json = {
'type': 'empty_block',
'icons': {
'serializable icon': 'some state',
},
};
assert.throws(
() => {
Blockly.serialization.blocks.append(json, workspace);
},
Blockly.serialization.exceptions.UnregisteredIcon,
'',
'Expected deserializing an unregistered icon to throw',
);
});
});
});