diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html
index bf3cf3aba..feb2d2e93 100644
--- a/tests/jsunit/index.html
+++ b/tests/jsunit/index.html
@@ -19,7 +19,6 @@
-
diff --git a/tests/jsunit/widget_div_test.js b/tests/jsunit/widget_div_test.js
deleted file mode 100644
index db15dbe37..000000000
--- a/tests/jsunit/widget_div_test.js
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * @license
- * Copyright 2017 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-'use strict';
-
-
-function widgetdiv_testHelper_makeBBox(left, top, width, height) {
- return {
- left: left,
- right: left + width,
- top: top,
- bottom: top + height
- };
-}
-
-function widgetdiv_testHelper_makeSize(width, height) {
- return {
- width: width,
- height: height
- };
-}
-
-var widgetDiv_test_viewport = widgetdiv_testHelper_makeBBox(0, 0, 1000, 1000);
-var widgetDiv_test_widgetSize = widgetdiv_testHelper_makeSize(100, 100);
-
-// Anchor is always 90 px wide and 90 px tall for this test.
-var widgetDiv_test_anchorSize = 90;
-
-function widgetdiv_testHelper_makeAnchor(left, top) {
- return {
- left: left,
- right: left + widgetDiv_test_anchorSize,
- top: top,
- bottom: top + widgetDiv_test_anchorSize
- };
-}
-
-function test_widgetDiv_topConflict() {
- var anchorTop = 50;
- // Anchor placed close to the top.
- var anchorBBox = widgetdiv_testHelper_makeAnchor(500, anchorTop);
-
- // The widget div should be placed just below the anchor.
- var calculated = Blockly.WidgetDiv.calculateY_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize);
- assertEquals(anchorTop + widgetDiv_test_anchorSize, calculated);
-}
-
-function test_widgetDiv_bottomConflict() {
- var anchorTop = 900;
- // Anchor placed close to the bottom.
- var anchorBBox = widgetdiv_testHelper_makeAnchor(500, anchorTop);
-
- // The widget div should be placed just above the anchor.
- var calculated = Blockly.WidgetDiv.calculateY_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize);
- assertEquals(anchorTop - widgetDiv_test_widgetSize.height, calculated);
-}
-
-function test_widgetDiv_noYConflict() {
- var anchorTop = 500;
- // Anchor placed in the middle.
- var anchorBBox = widgetdiv_testHelper_makeAnchor(500, anchorTop);
-
- // The widget div should be placed just below the anchor.
- var calculated = Blockly.WidgetDiv.calculateY_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize);
- assertEquals(anchorTop + widgetDiv_test_anchorSize, calculated);
-}
-
-
-function test_widgetDiv_leftConflict_LTR() {
- var anchorLeft = 50;
- // Anchor placed close to the left side.
- var anchorBBox = widgetdiv_testHelper_makeAnchor(anchorLeft, 500);
-
- // The widget div should be placed at the anchor.
- var calculated = Blockly.WidgetDiv.calculateX_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize, false /* rtl */);
- assertEquals(anchorLeft, calculated);
-}
-
-function test_widgetDiv_rightConflict_LTR() {
- var anchorLeft = 950;
- // Anchor placed close to the right side.
- var anchorBBox = widgetdiv_testHelper_makeAnchor(anchorLeft, 500);
-
- // The widget div should be placed as far right as possible--at the edge of
- // the screen.
- var calculated = Blockly.WidgetDiv.calculateX_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize, false /* rtl */);
- assertEquals(1000 - widgetDiv_test_widgetSize.width, calculated);
-}
-
-function test_widgetDiv_noXConflict_LTR() {
- var anchorLeft = 500;
- // Anchor in the middle
- var anchorBBox = widgetdiv_testHelper_makeAnchor(anchorLeft, 500);
- // The widget div should be placed just at the left side of the anchor.
- var calculated = Blockly.WidgetDiv.calculateX_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize, false /* rtl */);
- assertEquals(anchorLeft, calculated);
-}
-
-function test_widgetDiv_leftConflict_RTL() {
- var anchorLeft = 10;
- // Anchor placed close to the left side.
- var anchorBBox = widgetdiv_testHelper_makeAnchor(anchorLeft, 500);
- // The widget div should be placed as far left as possible--at the edge of
- // the screen.
- var calculated = Blockly.WidgetDiv.calculateX_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize, true /* rtl */);
- assertEquals(0, calculated);
-}
-
-function test_widgetDiv_rightConflict_RTL() {
- var anchorLeft = 950;
- // Anchor placed close to the right side.
- var anchorBBox = widgetdiv_testHelper_makeAnchor(anchorLeft, 500);
-
- // The widget div should be placed as far right as possible--at the edge of
- // the screen.
- var calculated = Blockly.WidgetDiv.calculateX_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize, true /* rtl */);
- assertEquals(1000 - widgetDiv_test_widgetSize.width, calculated);
-}
-
-function test_widgetDiv_noXConflict_RTL() {
- var anchorLeft = 500;
- // anchor placed in the middle
- var anchorBBox = widgetdiv_testHelper_makeAnchor(anchorLeft, 500);
- // The widget div should be placed at the right side of the anchor.
- var calculated = Blockly.WidgetDiv.calculateX_(widgetDiv_test_viewport,
- anchorBBox, widgetDiv_test_widgetSize, true /* rtl */);
- assertEquals(anchorBBox.right - widgetDiv_test_widgetSize.width, calculated);
-}
diff --git a/tests/mocha/index.html b/tests/mocha/index.html
index 65a64d1a9..c3f0e03c9 100644
--- a/tests/mocha/index.html
+++ b/tests/mocha/index.html
@@ -62,6 +62,7 @@
+
diff --git a/tests/mocha/widget_div_test.js b/tests/mocha/widget_div_test.js
new file mode 100644
index 000000000..bc90ad960
--- /dev/null
+++ b/tests/mocha/widget_div_test.js
@@ -0,0 +1,161 @@
+/**
+ * @license
+ * Copyright 2020 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+suite('WidgetDiv', function() {
+
+ suite('positionWithAnchor', function() {
+ function makeBBox(left, top, width, height) {
+ return {
+ left: left,
+ right: left + width,
+ top: top,
+ bottom: top + height,
+ width: width,
+ height: height
+ };
+ }
+
+ setup(function() {
+ Blockly.WidgetDiv.createDom();
+ this.viewportBBox = makeBBox(0, 0, 1000, 1003);
+ this.widgetSize = {
+ width: 100,
+ height: 102
+ };
+ this.anchorSize = {
+ width: 90,
+ height: 91
+ };
+
+ this.testWidgetPosition = function(
+ anchorBBox, rtl, expectedX, expectedY, expectedHeight) {
+ Blockly.WidgetDiv.positionWithAnchor(
+ this.viewportBBox, anchorBBox, this.widgetSize, rtl);
+ var style = Blockly.WidgetDiv.DIV.style;
+ chai.assert.equal(style.left, expectedX + 'px', 'Left');
+ chai.assert.equal(style.top, expectedY + 'px', 'Top');
+ chai.assert.equal(style.height, expectedHeight + 'px', 'Height');
+ };
+ });
+
+ suite('LTR', function() {
+ test('noConflict', function() {
+ // Anchor placed in the middle.
+ var anchorBBox =
+ makeBBox(500, 500, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed just below at the left side of the
+ // anchor.
+ var expectedX = anchorBBox.left;
+ var expectedY = anchorBBox.top + this.anchorSize.height;
+ this.testWidgetPosition(
+ anchorBBox, false, expectedX, expectedY, this.widgetSize.height);
+ });
+
+ test('topConflict', function() {
+ // Anchor close to the top.
+ var anchorBBox =
+ makeBBox(500, 50, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed just below the anchor.
+ var expectedX = anchorBBox.left;
+ var expectedY = anchorBBox.top + this.anchorSize.height;
+ this.testWidgetPosition(
+ anchorBBox, false, expectedX, expectedY, this.widgetSize.height);
+ });
+
+ test('bottomConflict', function() {
+ // Anchor placed close to the bottom.
+ var anchorBBox =
+ makeBBox(500, 900, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed just above the anchor.
+ var expectedX = anchorBBox.left;
+ var expectedY = anchorBBox.top - this.widgetSize.height;
+ this.testWidgetPosition(
+ anchorBBox, false, expectedX, expectedY, this.widgetSize.height);
+ });
+
+ test('leftConflict', function() {
+ // Anchor placed close to the left side.
+ var anchorBBox =
+ makeBBox(50, 500, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed at the anchor.
+ var expectedX = anchorBBox.left;
+ var expectedY = anchorBBox.top + this.anchorSize.height;
+ this.testWidgetPosition(
+ anchorBBox, false, expectedX, expectedY, this.widgetSize.height);
+ });
+
+ test('rightConflict', function() {
+ // Anchor placed close to the right side.
+ var anchorBBox =
+ makeBBox(950, 500, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed as far right as possible--at the edge of
+ // the screen.
+ var expectedX = this.viewportBBox.width - this.widgetSize.width;
+ var expectedY = anchorBBox.top + this.anchorSize.height;
+ this.testWidgetPosition(
+ anchorBBox, false, expectedX, expectedY, this.widgetSize.height);
+ });
+ });
+ suite('RTL', function() {
+ test('noConflict', function() {
+ // Anchor placed in the middle
+ var anchorBBox =
+ makeBBox(500, 500, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed at the right side of the anchor.
+ var expectedX = anchorBBox.right - this.widgetSize.width;
+ var expectedY = anchorBBox.top + this.anchorSize.height;
+ this.testWidgetPosition(
+ anchorBBox, true, expectedX, expectedY, this.widgetSize.height);
+ });
+
+ test('topConflict', function() {
+ // Anchor close to the top.
+ var anchorBBox =
+ makeBBox(500, 50, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed just below the anchor.
+ var expectedX = anchorBBox.right - this.widgetSize.width;
+ var expectedY = anchorBBox.top + this.anchorSize.height;
+ this.testWidgetPosition(
+ anchorBBox, true, expectedX, expectedY, this.widgetSize.height);
+ });
+
+ test('bottomConflict', function() {
+ // Anchor placed close to the bottom.
+ var anchorBBox =
+ makeBBox(500, 900, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed just above the anchor.
+ var expectedX = anchorBBox.right - this.widgetSize.width;
+ var expectedY = anchorBBox.top - this.widgetSize.height;
+ this.testWidgetPosition(
+ anchorBBox, true, expectedX, expectedY, this.widgetSize.height);
+ });
+
+ test('leftConflict', function() {
+ // Anchor placed close to the left side.
+ var anchorBBox =
+ makeBBox(10, 500, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed as far left as possible--at the edge of
+ // the screen.
+ var expectedX = 0;
+ var expectedY = anchorBBox.top + this.anchorSize.height;
+ this.testWidgetPosition(
+ anchorBBox, true, expectedX, expectedY, this.widgetSize.height);
+ });
+
+ test('rightConflict', function() {
+ // Anchor placed close to the right side.
+ var anchorBBox =
+ makeBBox(950, 500, this.anchorSize.width, this.anchorSize.height);
+ // The widget div should be placed as far right as possible--at the edge of
+ // the screen.
+ var expectedX = this.viewportBBox.width - this.widgetSize.width;
+ var expectedY = anchorBBox.top + this.anchorSize.height;
+ this.testWidgetPosition(
+ anchorBBox, true, expectedX, expectedY, this.widgetSize.height);
+ });
+ });
+ });
+});