test: Basic Blocks: verify drag blocks works properly (#7291)

* refactor(tests): Have testSetup accept a URL

  Have testSetup accept a URL.  Make testFileLocations a dictionary
  whose values are URLs, and change the spellings of the keys to
  be CONSTANT_CASE.

  This allows tests to specify their own URL, or to add a query or
  fragment.

* feat(tests): Add getAllBlocks helper

* test: Verify drag blocks works properly

* chore(tests): Reformat comments

  Manually reformat comments to comply with styleguide.
This commit is contained in:
Christopher Allen
2023-07-14 15:51:38 +01:00
committed by GitHub
parent 8355351898
commit 82a775a982
8 changed files with 130 additions and 52 deletions

View File

@@ -18,7 +18,7 @@ suite('Testing Connecting Blocks', function (done) {
// Setup Selenium for all of the tests
suiteSetup(async function () {
browser = await testSetup(testFileLocations.blockfactory);
browser = await testSetup(testFileLocations.BLOCK_FACTORY);
});
test('Testing Block Drag', async function () {

View File

@@ -0,0 +1,55 @@
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Node.js script to run Automated tests in Chrome, via
* webdriver, of basic Blockly block functionality.
*/
const chai = require('chai');
const {
testSetup,
testFileLocations,
getAllBlocks,
getSelectedBlockElement,
switchRTL,
dragBlockTypeFromFlyout,
screenDirection,
} = require('./test_setup');
const {Key} = require('webdriverio');
let browser;
suite('Basic block tests', function (done) {
// Setting timeout to unlimited as the webdriver takes a longer time
// to run than most mocha test
this.timeout(0);
// Setup Selenium for all of the tests
suiteSetup(async function () {
browser = await testSetup(
testFileLocations.PLAYGROUND + '?toolbox=test-blocks'
);
});
test('Drag three blocks into the workspace', async function () {
for (let i = 1; i <= 3; i++) {
await dragBlockTypeFromFlyout(
browser,
'Basic',
'test_basic_empty',
250,
50 * i
);
chai.assert.equal((await getAllBlocks(browser)).length, i);
}
});
// Teardown entire suite after test are done running
suiteTeardown(async function () {
await browser.deleteSession();
});
});

View File

@@ -41,7 +41,7 @@ suite('Testing Connecting Blocks', function (done) {
// Setup Selenium for all of the tests
suiteSetup(async function () {
browser = await testSetup(testFileLocations.playground);
browser = await testSetup(testFileLocations.PLAYGROUND);
});
test('Testing Block Flyout', async function () {
@@ -80,7 +80,7 @@ suite('Right Clicking on Blocks', function (done) {
// Setup Selenium for all of the tests
suiteSetup(async function () {
browser = await testSetup(testFileLocations.playground);
browser = await testSetup(testFileLocations.PLAYGROUND);
this.block = await dragNthBlockFromFlyout(browser, 'Loops', 0, 20, 20);
this.blockId = this.block.id;
});

View File

@@ -25,7 +25,7 @@ suite('Testing undo block movement', function (done) {
// Setup Selenium for all of the tests
suiteSetup(async function () {
browser = await testSetup(testFileLocations.playground);
browser = await testSetup(testFileLocations.PLAYGROUND);
});
test('Undoing Block Movement LTR', async function () {

View File

@@ -23,7 +23,7 @@ suite('This tests loading Large Configuration and Deletion', function (done) {
// Setup Selenium for all of the tests
suiteSetup(async function () {
browser = await testSetup(testFileLocations.playground);
browser = await testSetup(testFileLocations.PLAYGROUND);
});
test('This test loading from JSON results in the correct number of blocks', async function () {

View File

@@ -26,7 +26,7 @@ suite('Testing Field Edits', function (done) {
// Setup Selenium for all of the tests
suiteSetup(async function () {
browser = await testSetup(testFileLocations.playground);
browser = await testSetup(testFileLocations.PLAYGROUND);
});
test('Testing Field Edits LTR', async function () {

View File

@@ -26,7 +26,7 @@ suite('Testing Connecting Blocks', function (done) {
// Setup Selenium for all of the tests
suiteSetup(async function () {
browser = await testSetup(testFileLocations.code);
browser = await testSetup(testFileLocations.CODE_DEMO);
});
test('Testing Procedure', async function () {

View File

@@ -5,8 +5,11 @@
*/
/**
* @fileoverview Node.js script to run automated functional tests in Chrome, via webdriver.
* @fileoverview Node.js script to run automated functional tests in
* Chrome, via webdriver.
*
* This file is to be used in the suiteSetup for any automated fuctional test.
*
* Note: In this file many functions return browser elements that can
* be clicked or otherwise interacted with through Selenium WebDriver. These
* elements are not the raw HTML and SVG elements on the page; they are
@@ -18,8 +21,7 @@ const path = require('path');
const {posixPath} = require('../../../scripts/helpers');
let browser;
async function testSetup(testFile) {
let url;
async function testSetup(url) {
const options = {
capabilities: {
'browserName': 'chrome',
@@ -45,25 +47,6 @@ async function testSetup(testFile) {
options.capabilities['goog:chromeOptions'].args.push('--disable-gpu');
}
// Use Selenium to bring up the page
if (testFile == testFileLocations.blockfactory) {
url =
'file://' +
posixPath(
path.join(__dirname, '..', '..', '..', 'demos', 'blockfactory')
) +
'/index.html';
} else if (testFile == testFileLocations.code) {
url =
'file://' +
posixPath(path.join(__dirname, '..', '..', '..', 'demos', 'code')) +
'/index.html';
} else {
url =
'file://' +
posixPath(path.join(__dirname, '..', '..')) +
'/playground.html';
}
console.log(url);
console.log('Starting webdriverio...');
browser = await webdriverio.remote(options);
console.log('Loading URL: ' + url);
@@ -72,13 +55,23 @@ async function testSetup(testFile) {
}
const testFileLocations = {
blockfactory: 0,
code: 1,
playground: 2,
BLOCK_FACTORY:
'file://' +
posixPath(path.join(__dirname, '..', '..', '..', 'demos', 'blockfactory')) +
'/index.html',
CODE_DEMO:
'file://' +
posixPath(path.join(__dirname, '..', '..', '..', 'demos', 'code')) +
'/index.html',
PLAYGROUND:
'file://' +
posixPath(path.join(__dirname, '..', '..')) +
'/playground.html',
};
/**
* Enum for both LTR and RTL use cases.
*
* @readonly
* @enum {number}
*/
@@ -146,8 +139,8 @@ async function getCategory(browser, categoryName) {
* @param browser The active WebdriverIO Browser object.
* @param categoryName The name of the toolbox category to search.
* @param n Which block to select, 0-indexed from the top of the category.
* @return A Promise that resolves to the root element of the nth block in the
* given category.
* @return A Promise that resolves to the root element of the nth
* block in the given category.
*/
async function getNthBlockOfCategory(browser, categoryName, n) {
const category = await getCategory(browser, categoryName);
@@ -163,8 +156,8 @@ async function getNthBlockOfCategory(browser, categoryName, n) {
* @param browser The active WebdriverIO Browser object.
* @param categoryName The name of the toolbox category to search.
* @param blockType The type of the block to search for.
* @return A Promise that resolves to the root element of the first block with the
* given type in the given category.
* @return A Promise that resolves to the root element of the first
* block with the given type in the given category.
*/
async function getBlockTypeFromCategory(browser, categoryName, blockType) {
const category = await getCategory(browser, categoryName);
@@ -203,10 +196,11 @@ async function getBlockTypeFromWorkspace(browser, blockType, position) {
/**
* @param browser The active WebdriverIO Browser object.
* @param id The ID of the block the connection is on.
* @param connectionName Which connection to return. An input name
* to get a value or statement connection, and otherwise the type of the connection.
* @return A Promise that resolves to the location of the specific connection in screen
* coordinates.
* @param connectionName Which connection to return. An input name to
* get a value or statement connection, and otherwise the type of
* the connection.
* @return A Promise that resolves to the location of the specific
* connection in screen coordinates.
*/
async function getLocationOfBlockConnection(browser, id, connectionName) {
return await browser.execute(
@@ -233,6 +227,7 @@ async function getLocationOfBlockConnection(browser, id, connectionName) {
block.getRelativeToSurfaceXY(),
connection.getOffsetInBlock()
);
console.log(Blockly);
return Blockly.utils.svgMath.wsToScreenCoordinates(
Blockly.getMainWorkspace(),
loc
@@ -245,6 +240,7 @@ async function getLocationOfBlockConnection(browser, id, connectionName) {
/**
* Drags a block toward another block so that the specified connections attach.
*
* @param browser The active WebdriverIO Browser object.
* @param draggedBlock The block to drag.
* @param draggedConnection The active connection on the block being dragged.
@@ -279,6 +275,7 @@ async function connect(
/**
* Switch the playground to RTL mode.
*
* @param browser The active WebdriverIO Browser object.
* @return A Promise that resolves when the actions are completed.
*/
@@ -290,14 +287,16 @@ async function switchRTL(browser) {
/**
* Drag the specified block from the flyout and return the root element
* of the block.
*
* @param browser The active WebdriverIO Browser object.
* @param categoryName The name of the toolbox category to search.
* @param n Which block to select, indexed from the top of the category.
* @param x The x-distance to drag, as a delta from the block's initial location
* on screen.
* @param y The y-distance to drag, as a delta from the block's initial location
* on screen.
* @return A Promise that resolves to the root element of the newly created block.
* @param x The x-distance to drag, as a delta from the block's
* initial location on screen.
* @param y The y-distance to drag, as a delta from the block's
* initial location on screen.
* @return A Promise that resolves to the root element of the newly
* created block.
*/
async function dragNthBlockFromFlyout(browser, categoryName, n, x, y) {
const flyoutBlock = await getNthBlockOfCategory(browser, categoryName, n);
@@ -308,14 +307,16 @@ async function dragNthBlockFromFlyout(browser, categoryName, n, x, y) {
/**
* Drag the specified block from the flyout and return the root element
* of the block.
*
* @param browser The active WebdriverIO Browser object.
* @param categoryName The name of the toolbox category to search.
* @param type The type of the block to search for.
* @param x The x-distance to drag, as a delta from the block's initial location
* on screen.
* @param y The y-distance to drag, as a delta from the block's initial location
* on screen.
* @return A Promise that resolves to the root element of the newly created block.
* @param x The x-distance to drag, as a delta from the block's
* initial location on screen.
* @param y The y-distance to drag, as a delta from the block's
* initial location on screen.
* @return A Promise that resolves to the root element of the newly
* created block.
*/
async function dragBlockTypeFromFlyout(browser, categoryName, type, x, y) {
const flyoutBlock = await getBlockTypeFromCategory(
@@ -328,8 +329,9 @@ async function dragBlockTypeFromFlyout(browser, categoryName, type, x, y) {
}
/**
* Right-click on the specified block, then click on the specified context menu
* item.
* Right-click on the specified block, then click on the specified
* context menu item.
*
* @param browser The active WebdriverIO Browser object.
* @param block The block to click, as an interactable element.
* @param itemText The display text of the context menu item to click.
@@ -343,6 +345,26 @@ async function contextMenuSelect(browser, block, itemText) {
await browser.pause(200);
}
/**
* Get all blocks on the main workspace. Because the blocks have circular
* references that can't be JSON-encoded they can't be returned directly, so
* extract relevant properties only.
*
* @param browser The active WebdriverIO Browser object.
* @return A Promise that resolves to an array of blocks on the main workspace.
*/
async function getAllBlocks(browser) {
return browser.execute(() => {
// return Blockly.getMainWorkspace().getAllBlocks(false);
return Blockly.getMainWorkspace()
.getAllBlocks(false)
.map((block) => ({
type: block.type,
id: block.id,
}));
});
}
module.exports = {
testSetup,
testFileLocations,
@@ -359,4 +381,5 @@ module.exports = {
dragBlockTypeFromFlyout,
screenDirection,
getBlockTypeFromWorkspace,
getAllBlocks,
};