Files
blockly/tests/browser/test/toolbox_drag_test.mjs
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

208 lines
6.4 KiB
JavaScript

/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Tests for the dragging out of the toolbox and flyout.
*/
import * as chai from 'chai';
import {
testSetup,
testFileLocations,
getCategory,
scrollFlyout,
screenDirection,
PAUSE_TIME,
} from './test_setup.mjs';
// Categories in the basic toolbox.
const basicCategories = [
'Logic',
'Loops',
'Math',
'Text',
'Lists',
'Colour',
'Variables',
'Functions',
];
// Categories in the test blocks toolbox.
const testCategories = [
'Align',
'Basic',
// Skip connections because it's an accordion that is already open.
// 'Connections',
'Row',
'Stack',
'Statement',
'Drag',
// Skip fields because it's an accordion that is already open.
// 'Fields',
'Defaults',
'Numbers',
'Angles',
'Drop-downs',
// Note: images has a block that has a bad image source, but still builds and renders
// just fine.
'Images',
'Emoji! o((*^ᴗ^*))o',
'Validators',
'Mutators',
'Style',
'Serialization',
];
/**
* Check whether an element is fully inside the bounds of the Blockly div. You can use this
* to determine whether a block on the workspace or flyout is inside the Blockly div.
* This does not check whether there are other Blockly elements (such as a toolbox or
* flyout) on top of the element. A partially visible block is considered out of bounds.
* @param browser The active WebdriverIO Browser object.
* @param element The element to look for.
* @returns A Promise resolving to true if the element is in bounds and false otherwise.
*/
async function elementInBounds(browser, element) {
return await browser.execute((elem) => {
const rect = elem.getBoundingClientRect();
const blocklyDiv = document.getElementById('blocklyDiv');
const blocklyRect = blocklyDiv.getBoundingClientRect();
const vertInView =
rect.top >= blocklyRect.top && rect.bottom <= blocklyRect.bottom;
const horInView =
rect.left >= blocklyRect.left && rect.right <= blocklyRect.right;
return vertInView && horInView;
}, element);
}
/**
* Get how many top-level blocks there are in the specified category.
* @param browser The active WebdriverIO Browser object.
* @param categoryName The name of the category to inspect.
* @returns A Promise resolving to the number of top-level blocks in the specified
* category's flyout.
*/
async function getBlockCount(browser, categoryName) {
const category = await getCategory(browser, categoryName);
await category.click();
await browser.pause(PAUSE_TIME);
const blockCount = await browser.execute(() => {
return Blockly.getMainWorkspace()
.getFlyout()
.getWorkspace()
.getTopBlocks(false).length;
});
// Unicode escape to close flyout.
await browser.keys(['\uE00C']);
await browser.pause(PAUSE_TIME);
return blockCount;
}
/**
* Check whether the block at the given index in the flyout is disabled.
* @param browser The active WebdriverIO Browser object.
* @param i The index of the block in the currently open flyout.
* @returns A Promise resolving to true if the ith block in the flyout is
* disabled, and false otherwise.
*/
async function isBlockDisabled(browser, i) {
return await browser.execute((n) => {
return !Blockly.getMainWorkspace()
.getFlyout()
.getWorkspace()
.getTopBlocks()
[n].isEnabled();
}, i);
}
/**
* Loop over a list of categories and click on each one to open it.
* @param browser The WebdriverIO Browser instance for this test.
* @param categoryList An array of category names, as strings.
* @param directionMultiplier 1 for LTR and -1 for RTL.
* @returns A Promise that resolves when all actions have finished.
*/
async function openCategories(browser, categoryList, directionMultiplier) {
let failureCount = 0;
for (const categoryName of categoryList) {
const blockCount = await getBlockCount(browser, categoryName);
try {
for (let i = 0; i < blockCount; i++) {
const category = await getCategory(browser, categoryName);
await category.click();
if (await isBlockDisabled(browser, i)) {
// Unicode escape to close flyout.
await browser.keys(['\uE00C']);
await browser.pause(PAUSE_TIME);
continue;
}
const flyoutBlock = await browser.$(
`.blocklyFlyout .blocklyBlockCanvas > g:nth-child(${3 + i * 2})`,
);
while (!(await elementInBounds(browser, flyoutBlock))) {
await scrollFlyout(browser, 0, 50);
}
await flyoutBlock.dragAndDrop({x: directionMultiplier * 50, y: 0});
await browser.pause(PAUSE_TIME);
// Should be one top level block on the workspace.
const topBlockCount = await browser.execute(() => {
return Blockly.getMainWorkspace().getTopBlocks(false).length;
});
if (topBlockCount != 1) {
failureCount++;
console.log(`fail: block ${i} in category ${categoryName}`);
}
// Clean up between blocks so they can't interact with each other.
await browser.execute(() => {
Blockly.getMainWorkspace().clear();
});
await browser.pause(PAUSE_TIME);
}
} catch (e) {
failureCount++;
throw e;
}
}
chai.assert.equal(failureCount, 0);
}
suite('Open toolbox categories', function () {
this.timeout(0);
test('opening every toolbox category in the category toolbox in LTR', async function () {
this.browser = await testSetup(testFileLocations.PLAYGROUND);
await openCategories(this.browser, basicCategories, screenDirection.LTR);
});
test('opening every toolbox category in the category toolbox in RTL', async function () {
this.browser = await testSetup(testFileLocations.PLAYGROUND_RTL);
await openCategories(this.browser, basicCategories, screenDirection.RTL);
});
test('opening every toolbox category in the test toolbox in LTR', async function () {
this.browser = await testSetup(
testFileLocations.PLAYGROUND + '?toolbox=test-blocks',
);
await openCategories(this.browser, testCategories, screenDirection.LTR);
});
test('opening every toolbox category in the test toolbox in RTL', async function () {
this.browser = await testSetup(
testFileLocations.PLAYGROUND + '?toolbox=test-blocks&dir=rtl',
);
await openCategories(this.browser, testCategories, screenDirection.RTL);
});
});