diff --git a/tests/browser/test/.mocharc.js b/tests/browser/test/.mocharc.js index 27fa880fbf8..58d3bf55eb4 100644 --- a/tests/browser/test/.mocharc.js +++ b/tests/browser/test/.mocharc.js @@ -2,4 +2,5 @@ module.exports = { ui: 'tdd', + require: 'tests/browser/test/hooks.js', }; diff --git a/tests/browser/test/basic_block_factory_test.js b/tests/browser/test/basic_block_factory_test.js index 84069f5df15..026f2565950 100644 --- a/tests/browser/test/basic_block_factory_test.js +++ b/tests/browser/test/basic_block_factory_test.js @@ -11,21 +11,20 @@ const chai = require('chai'); const {testSetup, testFileLocations} = require('./test_setup'); -let browser; suite('Testing Connecting Blocks', 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.BLOCK_FACTORY); + this.browser = await testSetup(testFileLocations.BLOCK_FACTORY); }); test('Testing Block Drag', async function () { - const startingBlock = await browser.$( + const startingBlock = await this.browser.$( '#blockly > div > svg.blocklySvg > g > g.blocklyBlockCanvas > g:nth-child(2)', ); - const blocklyCanvas = await browser.$( + const blocklyCanvas = await this.browser.$( '#blockly > div > svg.blocklySvg > g > g.blocklyBlockCanvas', ); const firstPostion = await blocklyCanvas.getAttribute('transform'); @@ -34,8 +33,12 @@ suite('Testing Connecting Blocks', function (done) { chai.assert.notEqual(firstPostion, secondPosition); }); - // Teardown entire suite after test are done running suiteTeardown(async function () { - await browser.deleteSession(); + await this.browser.execute(() => { + // If you leave blocks on the workspace, the block factory pops up an alert asking + // if you really want to lose your work when you try to load a new page. + // Clearing blocks resolves this and is easier than waiting for the alert. + Blockly.getMainWorkspace().clear(); + }); }); }); diff --git a/tests/browser/test/basic_block_test.js b/tests/browser/test/basic_block_test.js index 31fea8fd958..7d594c50ede 100644 --- a/tests/browser/test/basic_block_test.js +++ b/tests/browser/test/basic_block_test.js @@ -18,8 +18,6 @@ const { } = 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 @@ -27,20 +25,15 @@ suite('Basic block tests', function (done) { // Setup Selenium for all of the tests suiteSetup(async function () { - browser = await testSetup( + this.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 dragNthBlockFromFlyout(browser, 'Align', 0, 250, 50 * i); - chai.assert.equal((await getAllBlocks(browser)).length, i); + await dragNthBlockFromFlyout(this.browser, 'Align', 0, 250, 50 * i); + chai.assert.equal((await getAllBlocks(this.browser)).length, i); } }); - - // Teardown entire suite after test are done running - suiteTeardown(async function () { - await browser.deleteSession(); - }); }); diff --git a/tests/browser/test/basic_playground_test.js b/tests/browser/test/basic_playground_test.js index e3a746f2186..8bed7dd6c99 100644 --- a/tests/browser/test/basic_playground_test.js +++ b/tests/browser/test/basic_playground_test.js @@ -37,25 +37,24 @@ async function getCommentText(browser, blockId) { }, blockId); } -let browser; suite('Testing Connecting Blocks', function () { // 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); + this.browser = await testSetup(testFileLocations.PLAYGROUND); }); test('Testing Block Flyout', async function () { - const logicButton = await browser.$('#blockly-0'); + const logicButton = await this.browser.$('#blockly-0'); logicButton.click(); - const ifDoBlock = await browser.$( + const ifDoBlock = await this.browser.$( '#blocklyDiv > div > svg:nth-child(7) > g > g.blocklyBlockCanvas > g:nth-child(3)', ); await ifDoBlock.dragAndDrop({x: 20, y: 20}); - await new Promise((resolve) => setTimeout(resolve, 2000)); // 2 sec - const blockOnWorkspace = await browser.execute(() => { + await new Promise((resolve) => setTimeout(resolve, 200)); + const blockOnWorkspace = await this.browser.execute(() => { const newBlock = Blockly.getMainWorkspace().getAllBlocks(false)[0]; if (newBlock.id) { return true; @@ -66,11 +65,6 @@ suite('Testing Connecting Blocks', function () { chai.assert.isTrue(blockOnWorkspace); }); - - // Teardown entire suite after test are done running - suiteTeardown(async function () { - await browser.deleteSession(); - }); }); /** @@ -83,45 +77,40 @@ suite('Right Clicking on Blocks', function () { // Setup Selenium for all of the tests suiteSetup(async function () { - browser = await testSetup(testFileLocations.PLAYGROUND); - this.block = await dragNthBlockFromFlyout(browser, 'Loops', 0, 20, 20); + this.browser = await testSetup(testFileLocations.PLAYGROUND); + this.block = await dragNthBlockFromFlyout(this.browser, 'Loops', 0, 20, 20); this.blockId = this.block.id; }); test('clicking the collapse option collapses the block', async function () { - await contextMenuSelect(browser, this.block, 'Collapse Block'); - chai.assert.isTrue(await getIsCollapsed(browser, this.blockId)); + await contextMenuSelect(this.browser, this.block, 'Collapse Block'); + chai.assert.isTrue(await getIsCollapsed(this.browser, this.blockId)); }); // Assumes that test('clicking the expand option expands the block', async function () { - await contextMenuSelect(browser, this.block, 'Expand Block'); - chai.assert.isFalse(await getIsCollapsed(browser, this.blockId)); + await contextMenuSelect(this.browser, this.block, 'Expand Block'); + chai.assert.isFalse(await getIsCollapsed(this.browser, this.blockId)); }); test('clicking the disable option disables the block', async function () { - await contextMenuSelect(browser, this.block, 'Disable Block'); - chai.assert.isTrue(await getIsDisabled(browser, this.blockId)); + await contextMenuSelect(this.browser, this.block, 'Disable Block'); + chai.assert.isTrue(await getIsDisabled(this.browser, this.blockId)); }); test('clicking the enable option enables the block', async function () { - await contextMenuSelect(browser, this.block, 'Enable Block'); - chai.assert.isFalse(await getIsDisabled(browser, this.block.id)); + await contextMenuSelect(this.browser, this.block, 'Enable Block'); + chai.assert.isFalse(await getIsDisabled(this.browser, this.block.id)); }); test('clicking the add comment option adds a comment to the block', async function () { - await contextMenuSelect(browser, this.block, 'Add Comment'); - chai.assert.equal(await getCommentText(browser, this.block.id), ''); + await contextMenuSelect(this.browser, this.block, 'Add Comment'); + chai.assert.equal(await getCommentText(this.browser, this.block.id), ''); }); test('clicking the remove comment option removes a comment from the block', async function () { - await contextMenuSelect(browser, this.block, 'Remove Comment'); - chai.assert.isNull(await getCommentText(browser, this.block.id)); - }); - - // Teardown entire suite after test are done running - suiteTeardown(async function () { - await browser.deleteSession(); + await contextMenuSelect(this.browser, this.block, 'Remove Comment'); + chai.assert.isNull(await getCommentText(this.browser, this.block.id)); }); }); @@ -131,11 +120,11 @@ suite('Disabling', function () { this.timeout(0); suiteSetup(async function () { - browser = await testSetup(testFileLocations.PLAYGROUND); + this.browser = await testSetup(testFileLocations.PLAYGROUND); }); setup(async function () { - await browser.refresh(); + await this.browser.refresh(); }); test( @@ -143,24 +132,24 @@ suite('Disabling', function () { 'parent is diabled', async function () { const parent = await dragBlockTypeFromFlyout( - browser, + this.browser, 'Logic', 'controls_if', 10, 10, ); const child = await dragBlockTypeFromFlyout( - browser, + this.browser, 'Logic', 'logic_boolean', 110, 110, ); - await connect(browser, child, 'OUTPUT', parent, 'IF0'); + await connect(this.browser, child, 'OUTPUT', parent, 'IF0'); - await contextMenuSelect(browser, parent, 'Disable Block'); + await contextMenuSelect(this.browser, parent, 'Disable Block'); - chai.assert.isTrue(await getIsDisabled(browser, child.id)); + chai.assert.isTrue(await getIsDisabled(this.browser, child.id)); }, ); @@ -169,24 +158,24 @@ suite('Disabling', function () { 'parent is disabled', async function () { const parent = await dragBlockTypeFromFlyout( - browser, + this.browser, 'Logic', 'controls_if', 10, 10, ); const child = await dragBlockTypeFromFlyout( - browser, + this.browser, 'Logic', 'controls_if', 110, 110, ); - await connect(browser, child, 'PREVIOUS', parent, 'DO0'); + await connect(this.browser, child, 'PREVIOUS', parent, 'DO0'); - await contextMenuSelect(browser, parent, 'Disable Block'); + await contextMenuSelect(this.browser, parent, 'Disable Block'); - chai.assert.isTrue(await getIsDisabled(browser, child.id)); + chai.assert.isTrue(await getIsDisabled(this.browser, child.id)); }, ); @@ -195,28 +184,24 @@ suite('Disabling', function () { 'parent is disabled', async function () { const parent = await dragBlockTypeFromFlyout( - browser, + this.browser, 'Logic', 'controls_if', 10, 10, ); const child = await dragBlockTypeFromFlyout( - browser, + this.browser, 'Logic', 'controls_if', 110, 110, ); - await connect(browser, child, 'PREVIOUS', parent, 'NEXT'); + await connect(this.browser, child, 'PREVIOUS', parent, 'NEXT'); - await contextMenuSelect(browser, parent, 'Disable Block'); + await contextMenuSelect(this.browser, parent, 'Disable Block'); - chai.assert.isFalse(await getIsDisabled(browser, child.id)); + chai.assert.isFalse(await getIsDisabled(this.browser, child.id)); }, ); - - suiteTeardown(async function () { - await browser.deleteSession(); - }); }); diff --git a/tests/browser/test/block_undo_test.js b/tests/browser/test/block_undo_test.js index 2f057d26f76..94f5a6f71ca 100644 --- a/tests/browser/test/block_undo_test.js +++ b/tests/browser/test/block_undo_test.js @@ -18,32 +18,26 @@ const { screenDirection, } = require('./test_setup'); -let browser; suite('Testing undo block movement', 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); + this.browser = await testSetup(testFileLocations.PLAYGROUND); }); test('Undoing Block Movement LTR', async function () { - await testUndoBlock(screenDirection.LTR); + await testUndoBlock(this.browser, screenDirection.LTR); }); test('Undoing Block Movement RTL', async function () { - await switchRTL(browser); - await testUndoBlock(screenDirection.RTL); - }); - - // Teardown entire suite after test are done running - suiteTeardown(async function () { - await browser.deleteSession(); + await switchRTL(this.browser); + await testUndoBlock(this.browser, screenDirection.RTL); }); }); -async function testUndoBlock(delta) { +async function testUndoBlock(browser, delta) { // Drag out first function const defReturnBlock = await dragBlockTypeFromFlyout( browser, diff --git a/tests/browser/test/extensive_test.js b/tests/browser/test/extensive_test.js index ed218a6321d..2dfb5dc8875 100644 --- a/tests/browser/test/extensive_test.js +++ b/tests/browser/test/extensive_test.js @@ -16,51 +16,45 @@ const { } = require('./test_setup'); const {Key} = require('webdriverio'); -let browser; suite('This tests loading Large Configuration and Deletion', 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); + this.browser = await testSetup(testFileLocations.PLAYGROUND); }); test('This test loading from JSON results in the correct number of blocks', async function () { - const blockNum = await testingJSONLoad(); + const blockNum = await testingJSONLoad(this.browser); chai.assert.equal(blockNum, 13); }); test('This test deleting block results in the correct number of blocks', async function () { const fourthRepeatDo = await getBlockElementById( - browser, + this.browser, 'E8bF[-r:B~cabGLP#QYd', ); await fourthRepeatDo.click({x: -100, y: -40}); - await browser.keys([Key.Delete]); - await browser.pause(100); - const blockNum = await browser.execute(() => { + await this.browser.keys([Key.Delete]); + await this.browser.pause(100); + const blockNum = await this.browser.execute(() => { return Blockly.getMainWorkspace().getAllBlocks(false).length; }); chai.assert.equal(blockNum, 10); }); test('This test undoing delete block results in the correct number of blocks', async function () { - await browser.keys([Key.Ctrl, 'z']); - await browser.pause(100); - const blockNum = await browser.execute(() => { + await this.browser.keys([Key.Ctrl, 'z']); + await this.browser.pause(100); + const blockNum = await this.browser.execute(() => { return Blockly.getMainWorkspace().getAllBlocks(false).length; }); chai.assert.equal(blockNum, 13); }); - - // Teardown entire suite after test are done running - suiteTeardown(async function () { - await browser.deleteSession(); - }); }); -async function testingJSONLoad() { +async function testingJSONLoad(browser) { return await browser.execute(() => { const myWorkspace = Blockly.getMainWorkspace(); const state = { diff --git a/tests/browser/test/field_edits_test.js b/tests/browser/test/field_edits_test.js index a507d860ea8..52e6ca60dcb 100644 --- a/tests/browser/test/field_edits_test.js +++ b/tests/browser/test/field_edits_test.js @@ -19,32 +19,26 @@ const { } = require('./test_setup'); const {Key} = require('webdriverio'); -let browser; suite('Testing Field Edits', 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); + this.browser = await testSetup(testFileLocations.PLAYGROUND); }); test('Testing Field Edits LTR', async function () { - await testFieldEdits(screenDirection.LTR); + await testFieldEdits(this.browser, screenDirection.LTR); }); test('Testing Field Edits RTL', async function () { - switchRTL(browser); - await testFieldEdits(screenDirection.RTL); - }); - - // Teardown entire suite after test are done running - suiteTeardown(async function () { - await browser.deleteSession(); + switchRTL(this.browser); + await testFieldEdits(this.browser, screenDirection.RTL); }); }); -async function testFieldEdits(delta) { +async function testFieldEdits(browser, delta) { const mathNumber = await dragBlockTypeFromFlyout( browser, 'Math', @@ -52,7 +46,7 @@ async function testFieldEdits(delta) { 50 * delta, 20, ); - await browser.pause(2000); + await browser.pause(200); // Click on the field to change the value const numeric = await getSelectedBlockElement(browser); @@ -63,7 +57,7 @@ async function testFieldEdits(delta) { // Click on the workspace const workspace = await browser.$('#blocklyDiv > div > svg.blocklySvg > g'); await workspace.click(); - await browser.pause(2000); + await browser.pause(200); // Get value of the number const numericText = await browser .$( diff --git a/tests/browser/test/hooks.js b/tests/browser/test/hooks.js new file mode 100644 index 00000000000..a7f08ed564e --- /dev/null +++ b/tests/browser/test/hooks.js @@ -0,0 +1,25 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Hooks to run before the first test and after the last test. + * These create a shared chromedriver instance, so we don't have to fire up + * a new one for every suite. + */ +const {driverSetup, driverTeardown} = require('./test_setup'); + +const mochaHooks = { + async beforeAll() { + // Set a long timeout for startup. + this.timeout(10000); + return await driverSetup(); + }, + async afterAll() { + return await driverTeardown(); + }, +}; + +module.exports = {mochaHooks}; diff --git a/tests/browser/test/procedure_test.js b/tests/browser/test/procedure_test.js index 8438fba21de..2e9fac69cb0 100644 --- a/tests/browser/test/procedure_test.js +++ b/tests/browser/test/procedure_test.js @@ -18,91 +18,90 @@ const { connect, } = require('./test_setup'); -let browser; - suite('Testing Connecting Blocks', 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.CODE_DEMO); + this.browser = await testSetup(testFileLocations.CODE_DEMO); }); test('Testing Procedure', async function () { // Drag out first function let proceduresDefReturn = await getBlockTypeFromCategory( - browser, + this.browser, 'Functions', 'procedures_defreturn', ); await proceduresDefReturn.dragAndDrop({x: 50, y: 20}); - const doSomething = await getSelectedBlockElement(browser); + const doSomething = await getSelectedBlockElement(this.browser); // Drag out second function. proceduresDefReturn = await getBlockTypeFromCategory( - browser, + this.browser, 'Functions', 'procedures_defreturn', ); await proceduresDefReturn.dragAndDrop({x: 300, y: 200}); - const doSomething2 = await getSelectedBlockElement(browser); + const doSomething2 = await getSelectedBlockElement(this.browser); // Drag out numeric const mathNumeric = await getBlockTypeFromCategory( - browser, + this.browser, 'Math', 'math_number', ); await mathNumeric.dragAndDrop({x: 50, y: 20}); - const numeric = await getSelectedBlockElement(browser); + const numeric = await getSelectedBlockElement(this.browser); // Connect numeric to first procedure - await connect(browser, numeric, 'OUTPUT', doSomething, 'RETURN'); + await connect(this.browser, numeric, 'OUTPUT', doSomething, 'RETURN'); // Drag out doSomething caller from flyout. const doSomethingFlyout = await getNthBlockOfCategory( - browser, + this.browser, 'Functions', 3, ); await doSomethingFlyout.dragAndDrop({x: 50, y: 20}); - const doSomethingCaller = await getSelectedBlockElement(browser); + const doSomethingCaller = await getSelectedBlockElement(this.browser); // Connect the doSomething caller to doSomething2 - await connect(browser, doSomethingCaller, 'OUTPUT', doSomething2, 'RETURN'); + await connect( + this.browser, + doSomethingCaller, + 'OUTPUT', + doSomething2, + 'RETURN', + ); // Drag out print from flyout. const printFlyout = await getBlockTypeFromCategory( - browser, + this.browser, 'Text', 'text_print', ); await printFlyout.dragAndDrop({x: 50, y: 20}); - const print = await getSelectedBlockElement(browser); + const print = await getSelectedBlockElement(this.browser); // Drag out doSomething2 caller from flyout. const doSomething2Flyout = await getNthBlockOfCategory( - browser, + this.browser, 'Functions', 4, ); await doSomething2Flyout.dragAndDrop({x: 130, y: 20}); - const doSomething2Caller = await getSelectedBlockElement(browser); + const doSomething2Caller = await getSelectedBlockElement(this.browser); // Connect doSomething2 caller with print. - await connect(browser, doSomething2Caller, 'OUTPUT', print, 'TEXT'); + await connect(this.browser, doSomething2Caller, 'OUTPUT', print, 'TEXT'); // Click run button and verify the number is 123 - const runButton = await browser.$('#runButton'); + const runButton = await this.browser.$('#runButton'); runButton.click(); - await browser.pause(200); - const alertText = await browser.getAlertText(); // get the alert text + await this.browser.pause(200); + const alertText = await this.browser.getAlertText(); // get the alert text chai.assert.equal(alertText, '123'); }); - - // Teardown entire suite after test are done running - suiteTeardown(async function () { - await browser.deleteSession(); - }); }); diff --git a/tests/browser/test/test_setup.js b/tests/browser/test/test_setup.js index cfc051371cf..87af399748e 100644 --- a/tests/browser/test/test_setup.js +++ b/tests/browser/test/test_setup.js @@ -20,8 +20,14 @@ const webdriverio = require('webdriverio'); const path = require('path'); const {posixPath} = require('../../../scripts/helpers'); -let browser; -async function testSetup(url) { +let driver = null; + +/** + * Start up the test page. This should only be done once, to avoid + * constantly popping browser windows open and closed. + * @return A Promsie that resolves to a webdriverIO browser that tests can manipulate. + */ +async function driverSetup() { const options = { capabilities: { 'browserName': 'chrome', @@ -48,10 +54,31 @@ async function testSetup(url) { } // Use Selenium to bring up the page console.log('Starting webdriverio...'); - browser = await webdriverio.remote(options); - console.log('Loading URL: ' + url); - await browser.url(url); - return browser; + driver = await webdriverio.remote(options); + return driver; +} + +/** + * End the webdriverIO session. + * @return A Promise that resolves after the actions have been completed. + */ +async function driverTeardown() { + await driver.deleteSession(); + driver = null; + return; +} + +/** + * Navigate to the correct URL for the test, using the shared driver. + * @param {string} url The URL to open for the test. + * @return A Promsie that resolves to a webdriverIO browser that tests can manipulate. + */ +async function testSetup(url) { + if (!driver) { + await driverSetup(); + } + await driver.url(url); + return driver; } const testFileLocations = { @@ -382,6 +409,8 @@ async function getAllBlocks(browser) { module.exports = { testSetup, testFileLocations, + driverSetup, + driverTeardown, getSelectedBlockElement, getSelectedBlockId, getBlockElementById,