From acd96aa2c5e19a2b9e24f2e3d8714dca0e2ee340 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 17 May 2019 15:19:14 -0700 Subject: [PATCH] Added Field Value Tests (#2459) * Added field value tests. * Fixed field image src param. * Fixed falsy values with label fields. * Fixed falsy values with text input fields. * Fixed some angle field tests. * Fixed other text input when editing tests. * Fixed colour tests. * Cleaned up some number and variable field tests. * Added angle field > 360 degrees tests. * Fixed variable validator tests. * Split setValue tests into sub-suites. * Fixed angle >360 tests * Changed var declarations to property declarations. --- core/field_checkbox.js | 7 +- core/field_colour.js | 9 +- core/field_date.js | 12 +- core/field_image.js | 21 +- core/field_label.js | 8 +- core/field_label_serializable.js | 4 +- core/field_textinput.js | 8 +- tests/mocha/field_angle_test.js | 248 ++++++++++++++ tests/mocha/field_checkbox_test.js | 173 ++++++++++ tests/mocha/field_colour_test.js | 210 ++++++++++++ tests/mocha/field_date_test.js | 179 ++++++++++ tests/mocha/field_dropdown_test.js | 193 +++++++++++ tests/mocha/field_image_test.js | 169 +++++++++ tests/mocha/field_label_serializable_test.js | 170 +++++++++ tests/mocha/field_label_test.js | 167 +++++++++ tests/mocha/field_number_test.js | 342 +++++++++++++++++++ tests/mocha/field_textinput_test.js | 213 ++++++++++++ tests/mocha/field_variable_test.js | 183 ++++++++-- tests/mocha/index.html | 12 + tests/mocha/test_helpers.js | 2 +- 20 files changed, 2274 insertions(+), 56 deletions(-) create mode 100644 tests/mocha/field_angle_test.js create mode 100644 tests/mocha/field_checkbox_test.js create mode 100644 tests/mocha/field_colour_test.js create mode 100644 tests/mocha/field_date_test.js create mode 100644 tests/mocha/field_dropdown_test.js create mode 100644 tests/mocha/field_image_test.js create mode 100644 tests/mocha/field_label_serializable_test.js create mode 100644 tests/mocha/field_label_test.js create mode 100644 tests/mocha/field_number_test.js create mode 100644 tests/mocha/field_textinput_test.js diff --git a/core/field_checkbox.js b/core/field_checkbox.js index b37217068..f096b1e9a 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -32,7 +32,8 @@ goog.require('Blockly.utils'); /** * Class for a checkbox field. - * @param {string} state The initial state of the field ('TRUE' or 'FALSE'). + * @param {string=} opt_state The initial state of the field ('TRUE' or + * 'FALSE'), defaults to 'FALSE'. * @param {Function=} opt_validator A function that is executed when a new * option is selected. Its sole argument is the new checkbox state. If * it returns a value, this becomes the new checkbox state, unless the @@ -40,10 +41,10 @@ goog.require('Blockly.utils'); * @extends {Blockly.Field} * @constructor */ -Blockly.FieldCheckbox = function(state, opt_validator) { +Blockly.FieldCheckbox = function(opt_state, opt_validator) { Blockly.FieldCheckbox.superClass_.constructor.call(this, '', opt_validator); // Set the initial state. - this.setValue(state); + this.setValue(opt_state); }; goog.inherits(Blockly.FieldCheckbox, Blockly.Field); diff --git a/core/field_colour.js b/core/field_colour.js index a6a501efa..d0796acf0 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -34,7 +34,8 @@ goog.require('goog.math.Size'); /** * Class for a colour input field. - * @param {string} colour The initial colour in '#rrggbb' format. + * @param {string=} opt_colour The initial colour in '#rrggbb' format, defaults + * to the first value in the default colour array. * @param {Function=} opt_validator A function that is executed when a new * colour is selected. Its sole argument is the new colour value. Its * return value becomes the selected colour, unless it is undefined, in @@ -43,8 +44,10 @@ goog.require('goog.math.Size'); * @extends {Blockly.Field} * @constructor */ -Blockly.FieldColour = function(colour, opt_validator) { - Blockly.FieldColour.superClass_.constructor.call(this, colour, opt_validator); +Blockly.FieldColour = function(opt_colour, opt_validator) { + opt_colour = opt_colour || Blockly.FieldColour.COLOURS[0]; + Blockly.FieldColour.superClass_.constructor + .call(this, opt_colour, opt_validator); this.setText(Blockly.Field.NBSP + Blockly.Field.NBSP + Blockly.Field.NBSP); }; goog.inherits(Blockly.FieldColour, Blockly.Field); diff --git a/core/field_date.js b/core/field_date.js index de80d026b..7cbe31a16 100644 --- a/core/field_date.js +++ b/core/field_date.js @@ -40,7 +40,7 @@ goog.require('goog.ui.DatePicker'); /** * Class for a date input field. - * @param {string} date The initial date. + * @param {string=} opt_date The initial date, defaults to the current day. * @param {Function=} opt_validator A function that is executed when a new * date is selected. Its sole argument is the new date value. Its * return value becomes the selected date, unless it is undefined, in @@ -49,12 +49,12 @@ goog.require('goog.ui.DatePicker'); * @extends {Blockly.Field} * @constructor */ -Blockly.FieldDate = function(date, opt_validator) { - if (!date) { - date = new goog.date.Date().toIsoString(true); +Blockly.FieldDate = function(opt_date, opt_validator) { + if (!opt_date) { + opt_date = new goog.date.Date().toIsoString(true); } - Blockly.FieldDate.superClass_.constructor.call(this, date, opt_validator); - this.setValue(date); + Blockly.FieldDate.superClass_.constructor.call(this, opt_date, opt_validator); + this.setValue(opt_date); }; goog.inherits(Blockly.FieldDate, Blockly.Field); diff --git a/core/field_image.js b/core/field_image.js index dfebb2d2c..dda922364 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -34,9 +34,9 @@ goog.require('goog.math.Size'); /** * Class for an image on a block. - * @param {string} src The URL of the image. - * @param {number} width Width of the image. - * @param {number} height Height of the image. + * @param {string=} src The URL of the image, defaults to an empty string. + * @param {!(string|number)} width Width of the image. + * @param {!(string|number)} height Height of the image. * @param {string=} opt_alt Optional alt text for when block is collapsed. * @param {Function=} opt_onClick Optional function to be called when the image * is clicked. If opt_onClick is defined, opt_alt must also be defined. @@ -48,15 +48,26 @@ Blockly.FieldImage = function(src, width, height, opt_alt, opt_onClick, opt_flipRtl) { this.sourceBlock_ = null; + + if (isNaN(height) || isNaN(width)) { + throw Error('Height and width values of an image field must cast to' + + ' numbers.'); + } + // Ensure height and width are numbers. Strings are bad at math. this.height_ = Number(height); this.width_ = Number(width); + if (this.height_ <= 0 || this.width_ <= 0) { + throw Error('Height and width values of an image field must be greater' + + ' than 0.'); + } this.size_ = new goog.math.Size(this.width_, this.height_ + 2 * Blockly.BlockSvg.INLINE_PADDING_Y); + this.flipRtl_ = opt_flipRtl; this.tooltip_ = ''; - this.setValue(src); - this.setText(opt_alt); + this.setValue(src || ''); + this.setText(opt_alt || ''); if (typeof opt_onClick == 'function') { this.clickHandler_ = opt_onClick; diff --git a/core/field_label.js b/core/field_label.js index cecf2b8c0..2db51c03a 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -36,7 +36,8 @@ goog.require('goog.math.Size'); /** * Class for a non-editable, non-serializable text field. - * @param {string} text The initial content of the field. + * @param {string=} text The initial content of the field, defaults to an + * empty string. * @param {string=} opt_class Optional CSS class for the field's text. * @extends {Blockly.Field} * @constructor @@ -44,7 +45,10 @@ goog.require('goog.math.Size'); Blockly.FieldLabel = function(text, opt_class) { this.size_ = new goog.math.Size(0, 17.5); this.class_ = opt_class; - this.setValue(text); + if (text === null || text === undefined) { + text = ''; + } + this.setValue(String(text)); this.tooltip_ = ''; }; goog.inherits(Blockly.FieldLabel, Blockly.Field); diff --git a/core/field_label_serializable.js b/core/field_label_serializable.js index 182ecbbd4..b8f579f7f 100644 --- a/core/field_label_serializable.js +++ b/core/field_label_serializable.js @@ -33,8 +33,8 @@ goog.require('Blockly.utils'); /** * Class for a non-editable, serializable text field. - * @param {string} text The initial content of the field. - * @param {string} opt_class Optional CSS class for the field's text. + * @param {!string} text The initial content of the field. + * @param {string=} opt_class Optional CSS class for the field's text. * @extends {Blockly.FieldLabel} * @constructor * diff --git a/core/field_textinput.js b/core/field_textinput.js index 3fd38c028..088a28109 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -37,7 +37,8 @@ goog.require('goog.math.Coordinate'); /** * Class for an editable text field. - * @param {string} text The initial content of the field. + * @param {string=} text The initial content of the field, defaults to an + * empty string. * @param {Function=} opt_validator An optional function that is called * to validate any constraints on what the user entered. Takes the new * text as an argument and returns either the accepted text, a replacement @@ -46,7 +47,10 @@ goog.require('goog.math.Coordinate'); * @constructor */ Blockly.FieldTextInput = function(text, opt_validator) { - Blockly.FieldTextInput.superClass_.constructor.call(this, text, + if (text === null || text === undefined) { + text = ''; + } + Blockly.FieldTextInput.superClass_.constructor.call(this, String(text), opt_validator); }; goog.inherits(Blockly.FieldTextInput, Blockly.Field); diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js new file mode 100644 index 000000000..de468e48f --- /dev/null +++ b/tests/mocha/field_angle_test.js @@ -0,0 +1,248 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Angle Fields', function() { + function assertValue(angleField, expectedValue, opt_expectedText) { + var actualValue = angleField.getValue(); + var actualText = angleField.getText(); + opt_expectedText = opt_expectedText || String(expectedValue); + assertEquals(String(actualValue), String(expectedValue)); + assertEquals(parseFloat(actualValue), expectedValue); + assertEquals(actualText, opt_expectedText); + } + function assertValueDefault(angleField) { + assertValue(angleField, 0); + } + suite('Constructor', function() { + test('Empty', function() { + var angleField = new Blockly.FieldAngle(); + assertValueDefault(angleField); + }); + test('Null', function() { + var angleField = new Blockly.FieldAngle(null); + assertValueDefault(angleField); + }); + test('Undefined', function() { + var angleField = new Blockly.FieldAngle(undefined); + assertValueDefault(angleField); + }); + test('Non-Parsable String', function() { + var angleField = new Blockly.FieldAngle('bad'); + assertValueDefault(angleField); + }); + test('NaN', function() { + var angleField = new Blockly.FieldAngle(NaN); + assertValueDefault(angleField); + }); + test('Integer', function() { + var angleField = new Blockly.FieldAngle(1); + assertValue(angleField, 1); + }); + test('Float', function() { + var angleField = new Blockly.FieldAngle(1.5); + assertValue(angleField, 1.5); + }); + test('Integer String', function() { + var angleField = new Blockly.FieldAngle('1'); + assertValue(angleField, 1); + }); + test('Float String', function() { + var angleField = new Blockly.FieldAngle('1.5'); + assertValue(angleField, 1.5); + }); + test('> 360°', function() { + var angleField = new Blockly.FieldAngle(362); + assertValue(angleField, 2); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var angleField = Blockly.FieldAngle.fromJson({}); + assertValueDefault(angleField); + }); + test('Null', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:null }); + assertValueDefault(angleField); + }); + test('Undefined', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:undefined }); + assertValueDefault(angleField); + }); + test('Non-Parsable String', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:'bad' }); + assertValueDefault(angleField); + }); + test('NaN', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:NaN }); + assertValueDefault(angleField); + }); + test('Integer', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:1 }); + assertValue(angleField, 1); + }); + test('Float', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:1.5 }); + assertValue(angleField, 1.5); + }); + test('Integer String', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:'1' }); + assertValue(angleField, 1); + }); + test('Float String', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:'1.5' }); + assertValue(angleField, 1.5); + }); + test('> 360°', function() { + var angleField = Blockly.FieldAngle.fromJson({ angle:362 }); + assertValue(angleField, 2); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.angleField = new Blockly.FieldAngle(); + }); + test('Null', function() { + this.angleField.setValue(null); + assertValueDefault(this.angleField); + }); + test('Undefined', function() { + this.angleField.setValue(undefined); + assertValueDefault(this.angleField); + }); + test.skip('Non-Parsable String', function() { + this.angleField.setValue('bad'); + assertValueDefault(this.angleField); + }); + test('NaN', function() { + this.angleField.setValue(NaN); + assertValueDefault(this.angleField); + }); + test('Integer', function() { + this.angleField.setValue(2); + assertValue(this.angleField, 2); + }); + test('Float', function() { + this.angleField.setValue(2.5); + assertValue(this.angleField, 2.5); + }); + test('Integer String', function() { + this.angleField.setValue('2'); + assertValue(this.angleField, 2); + }); + test('Float', function() { + this.angleField.setValue('2.5'); + assertValue(this.angleField, 2.5); + }); + test('>360°', function() { + this.angleField.setValue(362); + assertValue(this.angleField, 2); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.angleField = new Blockly.FieldAngle(1); + }); + test('Null', function() { + this.angleField.setValue(null); + assertValue(this.angleField, 1); + }); + test.skip('Undefined', function() { + this.angleField.setValue(undefined); + assertValue(this.angleField, 1); + }); + test.skip('Non-Parsable String', function() { + this.angleField.setValue('bad'); + assertValue(this.angleField, 1); + }); + test.skip('NaN', function() { + this.angleField.setValue(NaN); + assertValue(this.angleField, 1); + }); + test('Integer', function() { + this.angleField.setValue(2); + assertValue(this.angleField, 2); + }); + test('Float', function() { + this.angleField.setValue(2.5); + assertValue(this.angleField, 2.5); + }); + test('Integer String', function() { + this.angleField.setValue('2'); + assertValue(this.angleField, 2); + }); + test('Float', function() { + this.angleField.setValue('2.5'); + assertValue(this.angleField, 2.5); + }); + test('>360°', function() { + this.angleField.setValue(362); + assertValue(this.angleField, 2); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.angleField = new Blockly.FieldAngle(1); + Blockly.FieldTextInput.htmlInput_ = Object.create(null); + Blockly.FieldTextInput.htmlInput_.oldValue_ = '1'; + Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 1; + }); + teardown(function() { + Blockly.FieldTextInput.htmlInput_ = null; + }); + suite('Null Validator', function() { + setup(function() { + this.angleField.setValidator(function() { + return null; + }); + }); + test('When Editing', function() { + this.angleField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '2'; + this.angleField.onHtmlInputChange_(null); + assertValue(this.angleField, 1, '2'); + this.angleField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.angleField.setValue(2); + assertValue(this.angleField, 1); + }); + }); + suite('Force Mult of 30 Validator', function() { + setup(function() { + this.angleField.setValidator(function(newValue) { + return Math.round(newValue / 30) * 30; + }); + }); + test('When Editing', function() { + this.angleField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '25'; + this.angleField.onHtmlInputChange_(null); + assertValue(this.angleField, 30, '25'); + this.angleField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.angleField.setValue(25); + assertValue(this.angleField, 30); + }); + }); + }); +}); diff --git a/tests/mocha/field_checkbox_test.js b/tests/mocha/field_checkbox_test.js new file mode 100644 index 000000000..0c909df82 --- /dev/null +++ b/tests/mocha/field_checkbox_test.js @@ -0,0 +1,173 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite.skip('Checkbox Fields', function() { + function assertValue(checkboxField, expectedValue, expectedText) { + var actualValue = checkboxField.getValue(); + var actualText = checkboxField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedText); + } + function assertValueDefault(checkboxField) { + assertValue(checkboxField, 'FALSE', 'false'); + } + suite('Constructor', function() { + test('Null', function() { + var checkboxField = new Blockly.FieldCheckbox(null); + assertValueDefault(checkboxField); + }); + test('Undefined', function() { + var checkboxField = new Blockly.FieldCheckbox(undefined); + assertValueDefault(checkboxField); + }); + test('Non-Parsable String', function() { + var checkboxField = new Blockly.FieldCheckbox('bad'); + assertValueDefault(checkboxField); + }); + test('True', function() { + var checkboxField = new Blockly.FieldCheckbox(true); + assertValue(checkboxField, 'TRUE', 'true'); + }); + test('False', function() { + var checkboxField = new Blockly.FieldCheckbox(false); + assertValue(checkboxField, 'FALSE', 'false'); + }); + test('String TRUE', function() { + var checkboxField = new Blockly.FieldCheckbox('TRUE'); + assertValue(checkboxField, 'TRUE', 'true'); + }); + test('String FALSE', function() { + var checkboxField = new Blockly.FieldCheckbox('FALSE'); + assertValue(checkboxField, 'FALSE', 'false'); + }); + }); + suite('fromJson', function() { + test('Null', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: null}); + assertValueDefault(checkboxField); + }); + test('Undefined', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: undefined}); + assertValueDefault(checkboxField); + }); + test('Non-Parsable String', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: 'bad'}); + assertValueDefault(checkboxField); + }); + test('True', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: true}); + assertValue(checkboxField, 'TRUE', 'true'); + }); + test('False', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: false}); + assertValue(checkboxField, 'FALSE', 'false'); + }); + test('String TRUE', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: 'TRUE'}); + assertValue(checkboxField, 'TRUE', 'true'); + }); + test('String FALSE', function() { + var checkboxField = Blockly.FieldCheckbox.fromJson({ checked: 'FALSE'}); + assertValue(checkboxField, 'FALSE', 'false'); + }); + }); + suite('setValue', function() { + suite('True -> New Value', function() { + setup(function() { + this.checkboxField = new Blockly.FieldCheckbox('TRUE'); + }); + test('Null', function() { + this.checkboxField.setValue(null); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + test('Undefined', function() { + this.checkboxField.setValue(undefined); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + test('Non-Parsable String', function() { + this.checkboxField.setValue('bad'); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + test('False', function() { + this.checkboxField.setValue('FALSE'); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + }); + suite('False -> New Value', function() { + setup(function() { + this.checkboxField = new Blockly.FieldCheckbox('FALSE'); + }); + test('Null', function() { + this.checkboxField.setValue(null); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + test('Undefined', function() { + this.checkboxField.setValue(undefined); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + test('Non-Parsable String', function() { + this.checkboxField.setValue('bad'); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + test('True', function() { + this.checkboxField.setValue('TRUE'); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + }); + }); + suite('Validators', function() { + setup(function() { + this.checkboxField = new Blockly.FieldCheckbox(true); + }); + suite('Null Validator', function() { + setup(function() { + this.checkboxField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.checkboxField.setValue('FALSE'); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + }); + suite('Always True Validator', function() { + setup(function() { + this.checkboxField.setValidator(function() { + return 'TRUE'; + }); + }); + test('New Value', function() { + this.checkboxField.setValue('FALSE'); + assertValue(this.checkboxField, 'TRUE', 'true'); + }); + }); + suite('Always False Validator', function() { + setup(function() { + this.checkboxField.setValidator(function() { + return 'FALSE'; + }); + }); + test('New Value', function() { + this.checkboxField.setValue('TRUE'); + assertValue(this.checkboxField, 'FALSE', 'false'); + }); + }); + }); +}); diff --git a/tests/mocha/field_colour_test.js b/tests/mocha/field_colour_test.js new file mode 100644 index 000000000..2979bf0ca --- /dev/null +++ b/tests/mocha/field_colour_test.js @@ -0,0 +1,210 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Colour Fields', function() { + function assertValue(colourField, expectedValue, expectedText) { + var actualValue = colourField.getValue(); + var actualText = colourField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedText); + } + function assertValueDefault(colourField) { + var expectedValue = Blockly.FieldColour.COLOURS[0]; + var expectedText = expectedValue; + var m = expectedValue.match(/^#(.)\1(.)\2(.)\3$/); + if (m) { + expectedText = '#' + m[1] + m[2] + m[3]; + } + assertValue(colourField, expectedValue, expectedText); + } + + setup(function() { + this.previousColours = Blockly.FieldColour.COLOURS; + Blockly.FieldColour.Colours = [ + '#ffffff', '#ff0000', '#00ff00', '#0000ff', '#ffffff' + ]; + }); + teardown(function() { + Blockly.FieldColour.Colours = this.previousColours; + }); + suite('Constructor', function() { + test('Empty', function() { + var colourField = new Blockly.FieldColour(); + assertValueDefault(colourField); + }); + test('Null', function() { + var colourField = new Blockly.FieldColour(null); + assertValueDefault(colourField); + }); + test('Undefined', function() { + var colourField = new Blockly.FieldColour(undefined); + assertValueDefault(colourField); + }); + test.skip('Non-Parsable String', function() { + var colourField = new Blockly.FieldColour('bad'); + assertValueDefault(colourField); + }); + test.skip('#AAAAAA', function() { + var colourField = new Blockly.FieldColour('#AAAAAA'); + assertValue(colourField, '#aaaaaa', '#aaa'); + }); + test('#aaaaaa', function() { + var colourField = new Blockly.FieldColour('#aaaaaa'); + assertValue(colourField, '#aaaaaa', '#aaa'); + }); + test.skip('#AAAA00', function() { + var colourField = new Blockly.FieldColour('#AAAA00'); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('#aaaa00', function() { + var colourField = new Blockly.FieldColour('#aaaa00'); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test.skip('#BCBCBC', function() { + var colourField = new Blockly.FieldColour('#BCBCBC'); + assertValue(colourField, '#bcbcbc', '#bcbcbc'); + }); + test('#bcbcbc', function() { + var colourField = new Blockly.FieldColour('#bcbcbc'); + assertValue(colourField, '#bcbcbc', '#bcbcbc'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var colourField = new Blockly.FieldColour.fromJson({}); + assertValueDefault(colourField); + }); + test('Null', function() { + var colourField = new Blockly.FieldColour.fromJson({ colour:null }); + assertValueDefault(colourField); + }); + test('Undefined', function() { + var colourField = new Blockly.FieldColour.fromJson({ colour:undefined }); + assertValueDefault(colourField); + }); + test.skip('Non-Parsable String', function() { + var colourField = new Blockly.FieldColour.fromJson({ colour:'bad' }); + assertValueDefault(colourField); + }); + test.skip('#AAAAAA', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#AAAAAA' }); + assertValue(colourField, '#aaaaaa', '#aaa'); + }); + test('#aaaaaa', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#aaaaaa' }); + assertValue(colourField, '#aaaaaa', '#aaa'); + }); + test.skip('#AAAA00', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#AAAA00' }); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test('#aaaa00', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#aaaa00' }); + assertValue(colourField, '#aaaa00', '#aa0'); + }); + test.skip('#BCBCBC', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#BCBCBC' }); + assertValue(colourField, '#bcbcbc', '#bcbcbc'); + }); + test('#bcbcbc', function() { + var colourField = Blockly.FieldColour.fromJson({ colour: '#bcbcbc' }); + assertValue(colourField, '#bcbcbc', '#bcbcbc'); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.colourField = new Blockly.FieldColour(); + }); + test.skip('Null', function() { + this.colourField.setValue(null); + assertValueDefault(this.colourField); + }); + test.skip('Undefined', function() { + this.colourField.setValue(undefined); + assertValueDefault(this.colourField); + }); + test.skip('Non-Parsable String', function() { + this.colourField.setValue('bad'); + assertValueDefault(this.colourField); + }); + test('#000000', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#000000', '#000'); + }); + test('#bcbcbc', function() { + this.colourField.setValue('#bcbcbc'); + assertValue(this.colourField, '#bcbcbc', '#bcbcbc'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.colourField = new Blockly.FieldColour('#aaaaaa'); + }); + test.skip('Null', function() { + this.colourField.setValue(null); + assertValue(this.colourField, '#aaaaaa', '#aaa'); + }); + test.skip('Undefined', function() { + this.colourField.setValue(undefined); + assertValue(this.colourField, '#aaaaaa', '#aaa'); + }); + test.skip('Non-Parsable String', function() { + this.colourField.setValue('bad'); + assertValue(this.colourField, '#aaaaaa', '#aaa'); + }); + test('#000000', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#000000', '#000'); + }); + test('#bcbcbc', function() { + this.colourField.setValue('#bcbcbc'); + assertValue(this.colourField, '#bcbcbc', '#bcbcbc'); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.colourField = new Blockly.FieldColour('#aaaaaa'); + }); + suite('Null Validator', function() { + setup(function() { + this.colourField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#aaaaaa', '#aaa'); + }); + }); + suite('Force Full Red Validator', function() { + setup(function() { + this.colourField.setValidator(function(newValue) { + return '#ff' + newValue.substr(3, 4); + }); + }); + test('New Value', function() { + this.colourField.setValue('#000000'); + assertValue(this.colourField, '#ff0000', '#f00'); + }); + }); + }); +}); diff --git a/tests/mocha/field_date_test.js b/tests/mocha/field_date_test.js new file mode 100644 index 000000000..cc95b36ba --- /dev/null +++ b/tests/mocha/field_date_test.js @@ -0,0 +1,179 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Date Fields', function() { + function assertValue(dateField, expectedValue) { + var actualValue = dateField.getValue(); + var actualText = dateField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedValue); + } + function assertValueDefault(dateField) { + var today = new goog.date.Date().toIsoString(true); + assertValue(dateField, today); + } + suite('Constructor', function() { + test('Empty', function() { + var dateField = new Blockly.FieldDate(); + assertValueDefault(dateField); + }); + test('Null', function() { + var dateField = new Blockly.FieldDate(null); + assertValueDefault(dateField); + }); + test('Undefined', function() { + var dateField = new Blockly.FieldDate(undefined); + assertValueDefault(dateField); + }); + test.skip('Non-Parsable String', function() { + var dateField = new Blockly.FieldDate('bad'); + assertValueDefault(dateField); + }); + test('2020-02-20', function() { + var dateField = new Blockly.FieldDate('2020-02-20'); + assertValue(dateField, '2020-02-20'); + }); + test.skip('Invalid Date - Month(2020-13-20)', function() { + var dateField = new Blockly.FieldDate('2020-13-20'); + assertValueDefault(dateField); + }); + test.skip('Invalid Date - Day(2020-02-32)', function() { + var dateField = new Blockly.FieldDate('2020-02-32'); + assertValueDefault(dateField); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var dateField = Blockly.FieldDate.fromJson({}); + assertValueDefault(dateField); + }); + test('Null', function() { + var dateField = Blockly.FieldDate.fromJson({ date: null }); + assertValueDefault(dateField); + }); + test('Undefined', function() { + var dateField = Blockly.FieldDate.fromJson({ date: undefined }); + assertValueDefault(dateField); + }); + test.skip('Non-Parsable String', function() { + var dateField = Blockly.FieldDate.fromJson({ date: 'bad' }); + assertValueDefault(dateField); + }); + test('2020-02-20', function() { + var dateField = Blockly.FieldDate.fromJson({ date: '2020-02-20' }); + assertValue(dateField, '2020-02-20'); + }); + test.skip('Invalid Date - Month(2020-13-20)', function() { + var dateField = Blockly.FieldDate.fromJson({ date: '2020-13-20' }); + assertValueDefault(dateField); + }); + test.skip('Invalid Date - Day(2020-02-32)', function() { + var dateField = Blockly.FieldDate.fromJson({ date: '2020-02-32' }); + assertValueDefault(dateField); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.dateField = new Blockly.FieldDate(); + }); + test.skip('Null', function() { + this.dateField.setValue(null); + assertValueDefault(this.dateField); + }); + test.skip('Undefined', function() { + this.dateField.setValue(undefined); + assertValueDefault(this.dateField); + }); + test.skip('Non-Parsable String', function() { + this.dateField.setValue('bad'); + assertValueDefault(this.dateField); + }); + test.skip('Invalid Date - Month(2020-13-20)', function() { + this.dateField.setValue('2020-13-20'); + assertValueDefault(this.dateField); + }); + test.skip('Invalid Date - Day(2020-02-32)', function() { + this.dateField.setValue('2020-02-32'); + assertValueDefault(this.dateField); + }); + test('3030-03-30', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '3030-03-30'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.dateField = new Blockly.FieldDate('2020-02-20'); + }); + test.skip('Null', function() { + this.dateField.setValue(null); + assertValue(this.dateField, '2020-02-20'); + }); + test.skip('Undefined', function() { + this.dateField.setValue(undefined); + assertValue(this.dateField, '2020-02-20'); + }); + test.skip('Non-Parsable String', function() { + this.dateField.setValue('bad'); + assertValue(this.dateField, '2020-02-20'); + }); + test.skip('Invalid Date - Month(2020-13-20)', function() { + this.dateField.setValue('2020-13-20'); + assertValue(this.dateField, '2020-02-20'); + }); + test.skip('Invalid Date - Day(2020-02-32)', function() { + this.dateField.setValue('2020-02-32'); + assertValue(this.dateField, '2020-02-20'); + }); + test('3030-03-30', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '3030-03-30'); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.dateField = new Blockly.FieldDate('2020-02-20'); + }); + suite('Null Validator', function() { + setup(function() { + this.dateField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '2020-02-20'); + }); + }); + suite('Force Day 20s Validator', function() { + setup(function() { + this.dateField.setValidator(function(newValue) { + return newValue.substr(0, 8) + '2' + newValue.substr(9, 1); + }); + }); + test('New Value', function() { + this.dateField.setValue('3030-03-30'); + assertValue(this.dateField, '3030-03-20'); + }); + }); + }); +}); diff --git a/tests/mocha/field_dropdown_test.js b/tests/mocha/field_dropdown_test.js new file mode 100644 index 000000000..23c5f8016 --- /dev/null +++ b/tests/mocha/field_dropdown_test.js @@ -0,0 +1,193 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Dropdown Fields', function() { + function assertValue(dropdownField, expectedValue, expectedText) { + var actualValue = dropdownField.getValue(); + var actualText = dropdownField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedText); + } + suite('Constructor', function() { + test('Empty', function() { + chai.assert.throws(function() { + new Blockly.FieldDropdown(); + }); + }); + test('Null', function() { + chai.assert.throws(function() { + new Blockly.FieldDropdown(null); + }); + }); + test('Undefined', function() { + chai.assert.throws(function() { + new Blockly.FieldDropdown(undefined); + }); + }); + test('Array Items not Arrays', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + new Blockly.FieldDropdown([1, 2, 3]); + }); + }); + test('Array Items with Invalid IDs', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + new Blockly.FieldDropdown([['1', 1], ['2', 2], ['3', 3]]); + }); + }); + test('Array Items with Invalid Content', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + new Blockly.FieldDropdown([[1, '1'], [2, '2'], [3, '3']]); + }); + }); + test('Text Dropdown', function() { + var dropdownField = new Blockly.FieldDropdown( + [['a', 'A'], ['b', 'B'], ['c', 'C']]); + assertValue(dropdownField, 'A', 'a'); + }); + test('Image Dropdown', function() { + var dropdownField = new Blockly.FieldDropdown([ + [{ src:'scrA', alt:'a' }, 'A'], + [{ src:'scrB', alt:'b' }, 'B'], + [{ src:'scrC', alt:'c' }, 'C']]); + assertValue(dropdownField, 'A', 'a'); + }); + test('Dynamic Dropdown Text', function() { + var dynamicDropdownFunc = function() { + return [['a', 'A'], ['b', 'B'], ['c', 'C']]; + }; + var dropdownField = new Blockly.FieldDropdown(dynamicDropdownFunc); + assertValue(dropdownField, 'A', 'a'); + }); + test('Dynamic Dropdown Image', function() { + var dynamicDropdownFunc = function() { + return [ + [{ src:'scrA', alt:'a' }, 'A'], + [{ src:'scrB', alt:'b' }, 'B'], + [{ src:'scrC', alt:'c' }, 'C'] + ]; + }; + var dropdownField = new Blockly.FieldDropdown(dynamicDropdownFunc); + assertValue(dropdownField, 'A', 'a'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson({}); + }); + }); + test('Null', function() { + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson({ options: null }); + }); + }); + test('Undefined', function() { + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson({ options: undefined }); + }); + }); + test('Array Items not Arrays', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson({ options: [1, 2, 3] }); + }); + }); + test('Array Items with Invalid IDs', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson( + { options:[['1', 1], ['2', 2], ['3', 3]] }); + }); + }); + test('Array Items with Invalid Content', function() { + console.log('You should see three console warnings after this message.'); + chai.assert.throws(function() { + Blockly.FieldDropdown.fromJson( + { options:[[1, '1'], [2, '2'], [3, '3']] }); + }); + }); + test('Text Dropdown', function() { + var dropdownField = Blockly.FieldDropdown.fromJson( + { options:[['a', 'A'], ['b', 'B'], ['c', 'C']] }); + assertValue(dropdownField, 'A', 'a'); + }); + test('Image Dropdown', function() { + var dropdownField = Blockly.FieldDropdown.fromJson({ options:[ + [{ src:'scrA', alt:'a' }, 'A'], + [{ src:'scrB', alt:'b' }, 'B'], + [{ src:'scrC', alt:'c' }, 'C']] }); + assertValue(dropdownField, 'A', 'a'); + }); + }); + suite('setValue', function() { + setup(function() { + this.dropdownField = new Blockly.FieldDropdown( + [['a', 'A'], ['b', 'B'], ['c', 'C']]); + }); + test('Null', function() { + this.dropdownField.setValue(null); + assertValue(this.dropdownField, 'A', 'a'); + }); + test.skip('Undefined', function() { + this.dropdownField.setValue(undefined); + assertValue(this.dropdownField, 'A', 'a'); + }); + test.skip('Invalid ID', function() { + this.dropdownField.setValue('bad'); + assertValue(this.dropdownField, 'A', 'a'); + }); + test('Valid ID', function() { + this.dropdownField.setValue('B'); + assertValue(this.dropdownField, 'B', 'b'); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.dropdownField = new Blockly.FieldDropdown([ + ["1a","1A"], ["1b","1B"], ["1c","1C"], + ["2a","2A"], ["2b","2B"], ["2c","2C"]]); + }); + suite('Null Validator', function() { + setup(function() { + this.dropdownField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.dropdownField.setValue('1B'); + assertValue(this.dropdownField, '1A', '1a'); + }); + }); + suite('Force 1s Validator', function() { + setup(function() { + this.dropdownField.setValidator(function(newValue) { + return '1' + newValue.charAt(1); + }); + }); + test('New Value', function() { + this.dropdownField.setValue('2B'); + assertValue(this.dropdownField, '1B', '1b'); + }); + }); + }); +}); diff --git a/tests/mocha/field_image_test.js b/tests/mocha/field_image_test.js new file mode 100644 index 000000000..eb968882c --- /dev/null +++ b/tests/mocha/field_image_test.js @@ -0,0 +1,169 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Image Fields', function() { + function assertValue(imageField, expectedValue, expectedText) { + var actualValue = imageField.getValue(); + var actualText = imageField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedText); + } + function assertValueDefault(imageField) { + assertValue(imageField, '', ''); + } + suite('Constructor', function() { + test('Empty', function() { + chai.assert.throws(function() { + new Blockly.FieldImage(); + }); + }); + test('Null Src', function() { + var imageField = new Blockly.FieldImage(null, 1, 1); + assertValueDefault(imageField); + }); + test('Undefined Src', function() { + var imageField = new Blockly.FieldImage(undefined, 1, 1); + assertValueDefault(imageField); + }); + test('Null Size', function() { + chai.assert.throws(function() { + new Blockly.FieldImage('src', null, null); + }); + }); + test('Undefined Size', function() { + chai.assert.throws(function() { + new Blockly.FieldImage('src', undefined, undefined); + }); + }); + test('Zero Size', function() { + chai.assert.throws(function() { + new Blockly.FieldImage('src', 0, 0); + }); + }); + test('Non-Parsable String for Size', function() { + chai.assert.throws(function() { + new Blockly.FieldImage('src', 'bad', 'bad'); + }); + }); + // Note: passing invalid an src path doesn't need to throw errors + // because the developer can see they did it incorrectly when they view + // the block. + test('With Alt', function() { + var imageField = new Blockly.FieldImage('src', 1, 1, 'alt'); + assertValue(imageField, 'src', 'alt'); + }); + test('Without Alt', function() { + var imageField = new Blockly.FieldImage('src', 1, 1); + assertValue(imageField, 'src', ''); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + chai.assert.throws(function() { + Blockly.FieldImage.fromJson({}); + }); + }); + test('Null Src', function() { + var imageField = Blockly.FieldImage.fromJson({ + src: null, + width: 1, + height: 1 + }); + assertValueDefault(imageField); + }); + test('Undefined Src', function() { + var imageField = Blockly.FieldImage.fromJson({ + src: undefined, + width: 1, + height: 1 + }); + assertValueDefault(imageField); + }); + test('Null Size', function() { + chai.assert.throws(function() { + Blockly.FieldImage.fromJson({ + src: 'src', + width: null, + height: null + }); + }); + }); + test('Undefined Size', function() { + chai.assert.throws(function() { + Blockly.FieldImage.fromJson({ + src: 'src', + width: undefined, + height: undefined + }); + }); + }); + test('Non-Parsable String for Size', function() { + chai.assert.throws(function() { + Blockly.FieldImage.fromJson({ + src: 'src', + width: 'bad', + height: 'bad' + }); + }); + }); + test('With Alt', function() { + var imageField = Blockly.FieldImage.fromJson({ + src: 'src', + width: 1, + height: 1, + alt: 'alt' + }); + assertValue(imageField, 'src', 'alt'); + }); + test('Without Alt', function() { + var imageField = Blockly.FieldImage.fromJson({ + src: 'src', + width: 1, + height: 1 + }); + assertValue(imageField, 'src', ''); + }); + }); + suite('setValue', function() { + setup(function() { + this.imageField = new Blockly.FieldImage('src', 1, 1, 'alt'); + }); + test('Null', function() { + this.imageField.setValue(null); + assertValue(this.imageField, 'src', 'alt'); + }); + test.skip('Undefined', function() { + this.imageField.setValue(undefined); + assertValue(this.imageField, 'src', 'alt'); + }); + test('New Src, New Alt', function() { + this.imageField.setValue('newSrc'); + assertValue(this.imageField, 'newSrc', 'alt'); + this.imageField.setText('newAlt'); + assertValue(this.imageField, 'newSrc', 'newAlt'); + }); + test('New Alt, New Src', function() { + this.imageField.setText('newAlt'); + assertValue(this.imageField, 'src', 'newAlt'); + this.imageField.setValue('newSrc'); + assertValue(this.imageField, 'newSrc', 'newAlt'); + }); + }); +}); diff --git a/tests/mocha/field_label_serializable_test.js b/tests/mocha/field_label_serializable_test.js new file mode 100644 index 000000000..e59fd329c --- /dev/null +++ b/tests/mocha/field_label_serializable_test.js @@ -0,0 +1,170 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Label Serializable Fields', function() { + function assertValue(labelField, expectedValue) { + var actualValue = labelField.getValue(); + var actualText = labelField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedValue); + } + function assertValueDefault(labelField) { + assertValue(labelField, ''); + } + suite('Constructor', function() { + test('Empty', function() { + var labelField = new Blockly.FieldLabelSerializable(); + assertValueDefault(labelField); + }); + test('Null', function() { + var labelField = new Blockly.FieldLabelSerializable(null); + assertValueDefault(labelField); + }); + test('Undefined', function() { + var labelField = new Blockly.FieldLabelSerializable(undefined); + assertValueDefault(labelField); + }); + test('String', function() { + var labelField = new Blockly.FieldLabelSerializable('value'); + assertValue(labelField, 'value'); + }); + test('Number (Truthy)', function() { + var labelField = new Blockly.FieldLabelSerializable(1); + assertValue(labelField, '1'); + }); + test('Number (Falsy)', function() { + var labelField = new Blockly.FieldLabelSerializable(0); + assertValue(labelField, '0'); + }); + test('Boolean True', function() { + var labelField = new Blockly.FieldLabelSerializable(true); + assertValue(labelField, 'true'); + }); + test('Boolean False', function() { + var labelField = new Blockly.FieldLabelSerializable(false); + assertValue(labelField, 'false'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var labelField = new Blockly.FieldLabelSerializable.fromJson({}); + assertValueDefault(labelField); + }); + test('Null', function() { + var labelField = new Blockly.FieldLabelSerializable + .fromJson({ text:null }); + assertValueDefault(labelField); + }); + test('Undefined', function() { + var labelField = new Blockly.FieldLabelSerializable + .fromJson({ text:undefined }); + assertValueDefault(labelField); + }); + test('String', function() { + var labelField = Blockly.FieldLabelSerializable + .fromJson({ text:'value' }); + assertValue(labelField, 'value'); + }); + test('Number (Truthy)', function() { + var labelField = Blockly.FieldLabelSerializable.fromJson({ text:1 }); + assertValue(labelField, '1'); + }); + test('Number (Falsy)', function() { + var labelField = Blockly.FieldLabelSerializable.fromJson({ text:0 }); + assertValue(labelField, '0'); + }); + test('Boolean True', function() { + var labelField = Blockly.FieldLabelSerializable.fromJson({ text:true }); + assertValue(labelField, 'true'); + }); + test('Boolean False', function() { + var labelField = Blockly.FieldLabelSerializable.fromJson({ text:false }); + assertValue(labelField, 'false'); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.labelField = new Blockly.FieldLabelSerializable(); + }); + test('Null', function() { + this.labelField.setValue(null); + assertValueDefault(this.labelField); + }); + test.skip('Undefined', function() { + this.labelField.setValue(undefined); + assertValueDefault(this.labelField); + }); + test('New String', function() { + this.labelField.setValue('newValue'); + assertValue(this.labelField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.labelField.setValue(1); + assertValue(this.labelField, '1'); + }); + test.skip('Number (Falsy)', function() { + this.labelField.setValue(0); + assertValue(this.labelField, '0'); + }); + test('Boolean True', function() { + this.labelField.setValue(true); + assertValue(this.labelField, 'true'); + }); + test.skip('Boolean False', function() { + this.labelField.setValue(false); + assertValue(this.labelField, 'false'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.labelField = new Blockly.FieldLabelSerializable('value'); + }); + test('Null', function() { + this.labelField.setValue(null); + assertValue(this.labelField, 'value'); + }); + test.skip('Undefined', function() { + this.labelField.setValue(undefined); + assertValue(this.labelField, 'value'); + }); + test('New String', function() { + this.labelField.setValue('newValue'); + assertValue(this.labelField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.labelField.setValue(1); + assertValue(this.labelField, '1'); + }); + test('Number (Falsy)', function() { + this.labelField.setValue(0); + assertValue(this.labelField, '0'); + }); + test('Boolean True', function() { + this.labelField.setValue(true); + assertValue(this.labelField, 'true'); + }); + test('Boolean False', function() { + this.labelField.setValue(false); + assertValue(this.labelField, 'false'); + }); + }); + }); +}); diff --git a/tests/mocha/field_label_test.js b/tests/mocha/field_label_test.js new file mode 100644 index 000000000..1974da55e --- /dev/null +++ b/tests/mocha/field_label_test.js @@ -0,0 +1,167 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Label Fields', function() { + function assertValue(labelField, expectedValue) { + var actualValue = labelField.getValue(); + var actualText = labelField.getText(); + assertEquals(actualValue, expectedValue); + assertEquals(actualText, expectedValue); + } + function assertValueDefault(labelField) { + assertValue(labelField, ''); + } + suite('Constructor', function() { + test('Empty', function() { + var labelField = new Blockly.FieldLabel(); + assertValueDefault(labelField); + }); + test('Null', function() { + var labelField = new Blockly.FieldLabel(null); + assertValueDefault(labelField); + }); + test('Undefined', function() { + var labelField = new Blockly.FieldLabel(undefined); + assertValueDefault(labelField); + }); + test('String', function() { + var labelField = new Blockly.FieldLabel('value'); + assertValue(labelField, 'value'); + }); + test('Number (Truthy)', function() { + var labelField = new Blockly.FieldLabel(1); + assertValue(labelField, '1'); + }); + test('Number (Falsy)', function() { + var labelField = new Blockly.FieldLabel(0); + assertValue(labelField, '0'); + }); + test('Boolean True', function() { + var labelField = new Blockly.FieldLabel(true); + assertValue(labelField, 'true'); + }); + test('Boolean False', function() { + var labelField = new Blockly.FieldLabel(false); + assertValue(labelField, 'false'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var labelField = new Blockly.FieldLabel.fromJson({}); + assertValueDefault(labelField); + }); + test('Null', function() { + var labelField = new Blockly.FieldLabel.fromJson({ text:null }); + assertValueDefault(labelField); + }); + test('Undefined', function() { + var labelField = new Blockly.FieldLabel.fromJson({ text:undefined }); + assertValueDefault(labelField); + }); + test('String', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:'value' }); + assertValue(labelField, 'value'); + }); + test('Number (Truthy)', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:1 }); + assertValue(labelField, '1'); + }); + test('Number (Falsy)', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:0 }); + assertValue(labelField, '0'); + }); + test('Boolean True', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:true }); + assertValue(labelField, 'true'); + }); + test('Boolean False', function() { + var labelField = Blockly.FieldLabel.fromJson({ text:false }); + assertValue(labelField, 'false'); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.labelField = new Blockly.FieldLabel(); + }); + test('Null', function() { + this.labelField.setValue(null); + assertValueDefault(this.labelField); + }); + test.skip('Undefined', function() { + this.labelField.setValue(undefined); + assertValueDefault(this.labelField); + }); + test('New String', function() { + this.labelField.setValue('newValue'); + assertValue(this.labelField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.labelField.setValue(1); + assertValue(this.labelField, '1'); + }); + test.skip('Number (Falsy)', function() { + this.labelField.setValue(0); + assertValue(this.labelField, '0'); + }); + test('Boolean True', function() { + this.labelField.setValue(true); + assertValue(this.labelField, 'true'); + }); + test.skip('Boolean False', function() { + this.labelField.setValue(false); + assertValue(this.labelField, 'false'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.labelField = new Blockly.FieldLabel('value'); + }); + test('Null', function() { + this.labelField.setValue(null); + assertValue(this.labelField, 'value'); + }); + test.skip('Undefined', function() { + this.labelField.setValue(undefined); + assertValue(this.labelField, 'value'); + }); + test('New String', function() { + this.labelField.setValue('newValue'); + assertValue(this.labelField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.labelField.setValue(1); + assertValue(this.labelField, '1'); + }); + test('Number (Falsy)', function() { + this.labelField.setValue(0); + assertValue(this.labelField, '0'); + }); + test('Boolean True', function() { + this.labelField.setValue(true); + assertValue(this.labelField, 'true'); + }); + test('Boolean False', function() { + this.labelField.setValue(false); + assertValue(this.labelField, 'false'); + }); + }); + }); +}); diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js new file mode 100644 index 000000000..f0c1d1db0 --- /dev/null +++ b/tests/mocha/field_number_test.js @@ -0,0 +1,342 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Number Fields', function() { + function assertValue(numberField, expectedValue, opt_expectedText) { + var actualValue = numberField.getValue(); + var actualText = numberField.getText(); + opt_expectedText = opt_expectedText || String(expectedValue); + assertEquals(String(actualValue), String(expectedValue)); + assertEquals(parseFloat(actualValue), expectedValue); + assertEquals(actualText, opt_expectedText); + } + function assertValueDefault(numberFieldField) { + assertValue(numberFieldField, 0); + } + function assertNumberField(numberField, expectedMin, expectedMax, + expectedPrecision, expectedValue) { + assertValue(numberField, expectedValue); + assertEquals(numberField.min_, expectedMin); + assertEquals(numberField.max_, expectedMax); + assertEquals(numberField.precision_, expectedPrecision); + } + function assertNumberFieldDefault(numberField) { + assertNumberField(numberField, -Infinity, Infinity, 0, 0); + } + function createNumberFieldSameValuesConstructor(value) { + return new Blockly.FieldNumber(value, value, value, value); + } + function createNumberFieldSameValuesJson(value) { + return Blockly.FieldNumber.fromJson( + { 'value': value, min: value, max: value, precision: value }); + } + function assertNumberFieldSameValues(numberField, value) { + assertNumberField(numberField, value, value, value, value); + } + suite('Constructor', function() { + test('Empty', function() { + var numberField = new Blockly.FieldNumber(); + assertNumberFieldDefault(numberField); + }); + test('Null', function() { + var numberField = createNumberFieldSameValuesConstructor(null); + assertNumberFieldDefault(numberField); + }); + test('Undefined', function() { + var numberField = createNumberFieldSameValuesConstructor(undefined); + assertNumberFieldDefault(numberField); + }); + test('Non-Parsable String', function() { + var numberField = createNumberFieldSameValuesConstructor('bad'); + assertNumberFieldDefault(numberField); + }); + test('NaN', function() { + var numberField = createNumberFieldSameValuesConstructor(NaN); + assertNumberFieldDefault(numberField); + }); + test('Integer', function() { + var numberField = createNumberFieldSameValuesConstructor(1); + assertNumberFieldSameValues(numberField, 1); + }); + test('Float', function() { + var numberField = createNumberFieldSameValuesConstructor(1.5); + assertNumberFieldSameValues(numberField, 1.5); + }); + test('Integer String', function() { + var numberField = createNumberFieldSameValuesConstructor('1'); + assertNumberFieldSameValues(numberField, 1); + }); + test('Float String', function() { + var numberField = createNumberFieldSameValuesConstructor('1.5'); + assertNumberFieldSameValues(numberField, 1.5); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var numberField = Blockly.FieldNumber.fromJson({}); + assertNumberFieldDefault(numberField); + }); + test('Null', function() { + var numberField = createNumberFieldSameValuesJson(null); + assertNumberFieldDefault(numberField); + }); + test('Undefined', function() { + var numberField = createNumberFieldSameValuesJson(undefined); + assertNumberFieldDefault(numberField); + }); + test('Non-Parsable String', function() { + var numberField = createNumberFieldSameValuesJson('bad'); + assertNumberFieldDefault(numberField); + }); + test('NaN', function() { + var numberField = createNumberFieldSameValuesJson(NaN); + assertNumberFieldDefault(numberField); + }); + test('Integer', function() { + var numberField = createNumberFieldSameValuesJson(1); + assertNumberFieldSameValues(numberField, 1); + }); + test('Float', function() { + var numberField = createNumberFieldSameValuesJson(1.5); + assertNumberFieldSameValues(numberField, 1.5); + }); + test('Integer String', function() { + var numberField = createNumberFieldSameValuesJson('1'); + assertNumberFieldSameValues(numberField, 1); + }); + test('Float String', function() { + var numberField = createNumberFieldSameValuesJson('1.5'); + assertNumberFieldSameValues(numberField, 1.5); + }); + }); + suite('setValue', function() { + suite('Value Types', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.numberField = new Blockly.FieldNumber(); + }); + test('Null', function() { + this.numberField.setValue(null); + assertValueDefault(this.numberField); + }); + test.skip('Undefined', function() { + this.numberField.setValue(undefined); + assertValueDefault(this.numberField); + }); + test.skip('Non-Parsable String', function() { + this.numberField.setValue('bad'); + assertValueDefault(this.numberField); + }); + test.skip('NaN', function() { + this.numberField.setValue(NaN); + assertValueDefault(this.numberField); + }); + test('Integer', function() { + this.numberField.setValue(2); + assertValue(this.numberField, 2); + }); + test('Float', function() { + this.numberField.setValue(2.5); + assertValue(this.numberField, 2.5); + }); + test('Integer String', function() { + this.numberField.setValue('2'); + assertValue(this.numberField, 2); + }); + test('Float String', function() { + this.numberField.setValue('2.5'); + assertValue(this.numberField, 2.5); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.numberField = new Blockly.FieldNumber(1); + }); + test('Null', function() { + this.numberField.setValue(null); + assertValue(this.numberField, 1); + }); + test.skip('Undefined', function() { + this.numberField.setValue(undefined); + assertValue(this.numberField, 1); + }); + test.skip('Non-Parsable String', function() { + this.numberField.setValue('bad'); + assertValue(this.numberField, 1); + }); + test.skip('NaN', function() { + this.numberField.setValue(NaN); + assertValue(this.numberField, 1); + }); + test('Integer', function() { + this.numberField.setValue(2); + assertValue(this.numberField, 2); + }); + test('Float', function() { + this.numberField.setValue(2.5); + assertValue(this.numberField, 2.5); + }); + test('Integer String', function() { + this.numberField.setValue('2'); + assertValue(this.numberField, 2); + }); + test('Float String', function() { + this.numberField.setValue('2.5'); + assertValue(this.numberField, 2.5); + }); + }); + }); + suite('Constraints', function() { + suite('Precision', function() { + test('Float', function() { + var numberField = new Blockly.FieldNumber(); + numberField.setValue(123.456); + assertValue(numberField, 123.456); + }); + test('0.01', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: .01 }); + numberField.setValue(123.456); + assertValue(numberField, 123.46); + }); + test('0.5', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: .5 }); + numberField.setValue(123.456); + assertValue(numberField, 123.5); + }); + test('1', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: 1 }); + numberField.setValue(123.456); + assertValue(numberField, 123); + }); + test.skip('1.5', function() { + var numberField = new Blockly.FieldNumber + .fromJson({ precision: 1.5 }); + numberField.setValue(123.456); + assertValue(numberField, 123); + }); + }); + suite('Min', function() { + test('-10', function() { + var numberField = new Blockly.FieldNumber.fromJson({ min: -10 }); + numberField.setValue(-20); + assertValue(numberField, -10); + numberField.setValue(0); + assertValue(numberField, 0); + numberField.setValue(20); + assertValue(numberField, 20); + }); + test('0', function() { + var numberField = new Blockly.FieldNumber.fromJson({ min: 0 }); + numberField.setValue(-20); + assertValue(numberField, 0); + numberField.setValue(0); + assertValue(numberField, 0); + numberField.setValue(20); + assertValue(numberField, 20); + }); + test('+10', function() { + var numberField = new Blockly.FieldNumber.fromJson({ min: 10 }); + numberField.setValue(-20); + assertValue(numberField, 10); + numberField.setValue(0); + assertValue(numberField, 10); + numberField.setValue(20); + assertValue(numberField, 20); + }); + }); + suite('Max', function() { + test('-10', function() { + var numberField = new Blockly.FieldNumber.fromJson({ max: -10 }); + numberField.setValue(-20); + assertValue(numberField, -20); + numberField.setValue(0); + assertValue(numberField, -10); + numberField.setValue(20); + assertValue(numberField, -10); + }); + test('0', function() { + var numberField = new Blockly.FieldNumber.fromJson({ max: 0 }); + numberField.setValue(-20); + assertValue(numberField, -20); + numberField.setValue(0); + assertValue(numberField, 0); + numberField.setValue(20); + assertValue(numberField, 0); + }); + test('+10', function() { + var numberField = new Blockly.FieldNumber.fromJson({ max: 10 }); + numberField.setValue(-20); + assertValue(numberField, -20); + numberField.setValue(0); + assertValue(numberField, 0); + numberField.setValue(20); + assertValue(numberField, 10); + }); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.numberFieldField = new Blockly.FieldNumber(1); + Blockly.FieldTextInput.htmlInput_ = Object.create(null); + Blockly.FieldTextInput.htmlInput_.oldValue_ = '1'; + Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 1; + }); + suite('Null Validator', function() { + setup(function() { + this.numberFieldField.setValidator(function() { + return null; + }); + }); + test('When Editing', function() { + this.numberFieldField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '2'; + this.numberFieldField.onHtmlInputChange_(null); + assertValue(this.numberFieldField, 1, '2'); + this.numberFieldField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.numberFieldField.setValue(2); + assertValue(this.numberFieldField, 1); + }); + }); + suite('Force End with 6 Validator', function() { + setup(function() { + this.numberFieldField.setValidator(function(newValue) { + return String(newValue).replace(/.$/, "6"); + }); + }); + test('When Editing', function() { + this.numberFieldField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = '25'; + this.numberFieldField.onHtmlInputChange_(null); + assertValue(this.numberFieldField, 26, '25'); + this.numberFieldField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.numberFieldField.setValue(25); + assertValue(this.numberFieldField, 26); + }); + }); + }); +}); diff --git a/tests/mocha/field_textinput_test.js b/tests/mocha/field_textinput_test.js new file mode 100644 index 000000000..2a1b72b06 --- /dev/null +++ b/tests/mocha/field_textinput_test.js @@ -0,0 +1,213 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +suite ('Text Input Fields', function() { + function assertValue(textInputField, expectedValue, opt_expectedText) { + var actualValue = textInputField.getValue(); + var actualText = textInputField.getText(); + opt_expectedText = opt_expectedText || expectedValue; + assertEquals(actualValue, expectedValue); + assertEquals(actualText, opt_expectedText); + } + function assertValueDefault(textInputField) { + assertValue(textInputField, ''); + } + suite('Constructor', function() { + test('Empty', function() { + var textInputField = new Blockly.FieldTextInput(); + assertValueDefault(textInputField); + }); + test('Null', function() { + var textInputField = new Blockly.FieldTextInput(null); + assertValueDefault(textInputField); + }); + test('Undefined', function() { + var textInputField = new Blockly.FieldTextInput(undefined); + assertValueDefault(textInputField); + }); + test('String', function() { + var textInputField = new Blockly.FieldTextInput('value'); + assertValue(textInputField, 'value'); + }); + test('Number (Truthy)', function() { + var textInputField = new Blockly.FieldTextInput(1); + assertValue(textInputField, '1'); + }); + test('Number (Falsy)', function() { + var textInputField = new Blockly.FieldTextInput(0); + assertValue(textInputField, '0'); + }); + test('Boolean True', function() { + var textInputField = new Blockly.FieldTextInput(true); + assertValue(textInputField, 'true'); + }); + test('Boolean False', function() { + var textInputField = new Blockly.FieldTextInput(false); + assertValue(textInputField, 'false'); + }); + }); + suite('fromJson', function() { + test('Empty', function() { + var textInputField = new Blockly.FieldTextInput.fromJson({}); + assertValueDefault(textInputField); + }); + test('Null', function() { + var textInputField = new Blockly.FieldTextInput.fromJson({ text: null}); + assertValueDefault(textInputField); + }); + test('Undefined', function() { + var textInputField = new Blockly.FieldTextInput + .fromJson({ text: undefined}); + assertValueDefault(textInputField); + }); + test('String', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:'value' }); + assertValue(textInputField, 'value'); + }); + test('Number (Truthy)', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:1 }); + assertValue(textInputField, '1'); + }); + test('Number (Falsy)', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:0 }); + assertValue(textInputField, '0'); + }); + test('Boolean True', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:true }); + assertValue(textInputField, 'true'); + }); + test('Boolean False', function() { + var textInputField = Blockly.FieldTextInput.fromJson({ text:false }); + assertValue(textInputField, 'false'); + }); + }); + suite('setValue', function() { + suite('Empty -> New Value', function() { + setup(function() { + this.textInputField = new Blockly.FieldTextInput(); + }); + test('Null', function() { + this.textInputField.setValue(null); + assertValueDefault(this.textInputField); + }); + test.skip('Undefined', function() { + this.textInputField.setValue(undefined); + assertValueDefault(this.textInputField); + }); + test('New String', function() { + this.textInputField.setValue('newValue'); + assertValue(this.textInputField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.textInputField.setValue(1); + assertValue(this.textInputField, '1'); + }); + test.skip('Number (Falsy)', function() { + this.textInputField.setValue(0); + assertValue(this.textInputField, '0'); + }); + test('Boolean True', function() { + this.textInputField.setValue(true); + assertValue(this.textInputField, 'true'); + }); + test.skip('Boolean False', function() { + this.textInputField.setValue(false); + assertValue(this.textInputField, 'false'); + }); + }); + suite('Value -> New Value', function() { + setup(function() { + this.textInputField = new Blockly.FieldTextInput('value'); + }); + test('Null', function() { + this.textInputField.setValue(null); + assertValue(this.textInputField, 'value'); + }); + test.skip('Undefined', function() { + this.textInputField.setValue(undefined); + assertValue(this.textInputField, 'value'); + }); + test('New String', function() { + this.textInputField.setValue('newValue'); + assertValue(this.textInputField, 'newValue'); + }); + test('Number (Truthy)', function() { + this.textInputField.setValue(1); + assertValue(this.textInputField, '1'); + }); + test('Number (Falsy)', function() { + this.textInputField.setValue(0); + assertValue(this.textInputField, '0'); + }); + test('Boolean True', function() { + this.textInputField.setValue(true); + assertValue(this.textInputField, 'true'); + }); + test('Boolean False', function() { + this.textInputField.setValue(false); + assertValue(this.textInputField, 'false'); + }); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.textInputField = new Blockly.FieldTextInput('value'); + Blockly.FieldTextInput.htmlInput_ = Object.create(null); + Blockly.FieldTextInput.htmlInput_.oldValue_ = 'value'; + Blockly.FieldTextInput.htmlInput_.untypedDefaultValue_ = 'value'; + }); + suite('Null Validator', function() { + setup(function() { + this.textInputField.setValidator(function() { + return null; + }); + }); + test('When Editing', function() { + this.textInputField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = 'newValue'; + this.textInputField.onHtmlInputChange_(null); + assertValue(this.textInputField, 'value', 'newValue'); + this.textInputField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.textInputField.setValue('newValue'); + assertValue(this.textInputField, 'value'); + }); + }); + suite('Remove \'a\' Validator', function() { + setup(function() { + this.textInputField.setValidator(function(newValue) { + return newValue.replace(/a/g, ''); + }); + }); + test('When Editing', function() { + this.textInputField.isBeingEdited_ = true; + Blockly.FieldTextInput.htmlInput_.value = 'bbbaaa'; + this.textInputField.onHtmlInputChange_(null); + assertValue(this.textInputField, 'bbb', 'bbbaaa'); + this.textInputField.isBeingEdited_ = false; + }); + test('When Not Editing', function() { + this.textInputField.setValue('bbbaaa'); + assertValue(this.textInputField, 'bbb'); + }); + }); + }); +}); diff --git a/tests/mocha/field_variable_test.js b/tests/mocha/field_variable_test.js index da8338c38..8e7026eb6 100644 --- a/tests/mocha/field_variable_test.js +++ b/tests/mocha/field_variable_test.js @@ -1,5 +1,27 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2019 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ suite('Variable Fields', function() { + var FAKE_VARIABLE_NAME = 'yertle'; + var FAKE_ID = 'turtle'; + function getMockBlock(workspace) { return { 'workspace': workspace, @@ -8,54 +30,49 @@ suite('Variable Fields', function() { } }; } - function fieldVariable_createAndInitField(workspace) { - var fieldVariable = new Blockly.FieldVariable('name1'); + function initField(fieldVariable, workspace) { var mockBlock = getMockBlock(workspace); fieldVariable.setSourceBlock(mockBlock); // No view to initialize, but still need to init the model. fieldVariable.initModel(); return fieldVariable; } + function createAndInitFieldConstructor(workspace, variableName) { + return initField(new Blockly.FieldVariable(variableName), workspace); + } + function createAndInitFieldJson(workspace, variableName) { + return initField(Blockly.FieldVariable.fromJson( + { variable:variableName }), workspace); + } + function assertValue(variableField, expectedName, opt_expectedId) { + var actualName = variableField.getText(); + var actualId = variableField.getValue(); + opt_expectedId = opt_expectedId || FAKE_ID; + assertEquals(actualName, expectedName); + assertEquals(actualId, opt_expectedId); + } + function assertValueDefault(variableField) { + assertValue(variableField, FAKE_VARIABLE_NAME, FAKE_ID); + } setup(function() { this.workspace = new Blockly.Workspace(); + + sinon.stub(Blockly.utils, 'genUid') + .returns(FAKE_ID); + sinon.stub(Blockly.Variables, 'generateUniqueName') + .returns(FAKE_VARIABLE_NAME); }); teardown(function() { this.workspace.dispose(); - }); - - test('Constructor', function() { - var fieldVariable = new Blockly.FieldVariable('name1'); - // The field does not have a variable until after init() is called. - assertEquals('', fieldVariable.getText()); - assertNull(fieldVariable.getValue()); - }); - - test('Set value by ID', function() { - this.workspace.createVariable('name2', null, 'id2'); - - var fieldVariable = fieldVariable_createAndInitField(this.workspace); - var oldId = fieldVariable.getValue(); - - fieldVariable.setValue('id2'); - // Setting value by ID gives us the right text as well. - assertEquals('name2', fieldVariable.getText()); - assertEquals('id2', fieldVariable.getValue()); - chai.assert.notEqual(oldId, fieldVariable.getValue()); - }); - - test('Set value: variable does not exist', function() { - var fieldVariable = fieldVariable_createAndInitField(this.workspace); - chai.assert.throws(function() { - fieldVariable.setValue('id1'); - }); + sinon.restore(); }); test('Dropdown contains variables', function() { // Expect that the dropdown options will contain the variables that exist this.workspace.createVariable('name1', '', 'id1'); this.workspace.createVariable('name2', '', 'id2'); - var fieldVariable = fieldVariable_createAndInitField(this.workspace); + var fieldVariable = createAndInitFieldConstructor(this.workspace, 'name1'); // Expect that variables created after field creation will show up too. this.workspace.createVariable('name3', '', 'id3'); @@ -68,9 +85,112 @@ suite('Variable Fields', function() { isEqualArrays(result_options[0], ['name1', 'id1']); isEqualArrays(result_options[1], ['name2', 'id2']); isEqualArrays(result_options[2], ['name3', 'id3']); - }); + suite('Constructor', function() { + test('Null', function() { + var variableField = createAndInitFieldConstructor(this.workspace, null); + assertValueDefault(variableField); + }); + test('Undefined', function() { + var variableField = createAndInitFieldConstructor( + this.workspace, undefined); + assertValueDefault(variableField); + }); + test('No Value Before InitModel', function() { + var fieldVariable = new Blockly.FieldVariable('name1'); + assertEquals('', fieldVariable.getText()); + assertNull(fieldVariable.getValue()); + }); + test('Given Variable Name', function() { + var fieldVariable = createAndInitFieldConstructor( + this.workspace, 'name1'); + assertValue(fieldVariable, 'name1'); + }); + }); + suite('fromJson', function() { + test('Null', function() { + var variableField = createAndInitFieldJson(this.workspace, null); + assertValueDefault(variableField); + }); + test('Undefined', function() { + var variableField = createAndInitFieldJson(this.workspace, undefined); + assertValueDefault(variableField); + }); + test('No Value Before InitModel', function() { + var variableField = new Blockly.FieldVariable('name1'); + assertEquals('', variableField.getText()); + assertNull(variableField.getValue()); + }); + test('Given Variable Name', function() { + var variableField = createAndInitFieldJson(this.workspace, 'name1'); + assertValue(variableField, 'name1'); + }); + }); + suite('setValue', function() { + test.skip('Null', function() { + var variableField = createAndInitFieldConstructor( + this.workspace, 'name1'); + variableField.setValue(null); + assertValue(variableField, 'name1'); + }); + test.skip('Undefined', function() { + var variableField = createAndInitFieldConstructor( + this.workspace, 'name1'); + variableField.setValue(undefined); + assertValue(variableField, 'name1'); + }); + test('New Variable ID', function() { + this.workspace.createVariable('name2', null, 'id2'); + var variableField = createAndInitFieldConstructor( + this.workspace, 'name1'); + var oldId = variableField.getValue(); + + variableField.setValue('id2'); + // Setting value by ID gives us the right text as well. + assertEquals('name2', variableField.getText()); + assertEquals('id2', variableField.getValue()); + chai.assert.notEqual(oldId, variableField.getValue()); + }); + test.skip('Variable Does not Exist', function() { + var variableField = createAndInitFieldConstructor( + this.workspace, 'name1'); + variableField.setValue('id1'); + assertValue(variableField, 'name1'); + }); + }); + suite.skip('Validators', function() { + setup(function() { + this.workspace.createVariable('name1', null, 'id1'); + this.workspace.createVariable('name2', null, 'id2'); + this.workspace.createVariable('name3', null, 'id3'); + this.variableField = createAndInitFieldConstructor(this.workspace, 'name1'); + }); + suite('Null Validator', function() { + setup(function() { + this.variableField.setValidator(function() { + return null; + }); + }); + test('New Value', function() { + this.variableField.setValue('id2'); + assertValue(this.variableField, 'name1', 'id1'); + }); + }); + suite('Force \'id\' ID Validator', function() { + setup(function() { + this.variableField.setValidator(function(newValue) { + return 'id' + newValue.charAt(newValue.length - 1); + }); + }); + test('New Value', function() { + // Must create the var so that the field doesn't throw an error. + this.workspace.createVariable('thing2', null, 'other2'); + this.variableField.setValue('other2'); + assertValue(this.variableField, 'name2', 'id2'); + }); + }); + }); suite('Get variable types', function() { setup(function() { this.workspace.createVariable('name1', 'type1'); @@ -121,7 +241,6 @@ suite('Variable Fields', function() { }); }); }); - suite('Default types', function() { test('Default type exists', function() { var fieldVariable = new Blockly.FieldVariable(null, null, ['b'], 'b'); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index f65647865..48c0c2e51 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -19,11 +19,23 @@ ui: 'tdd' }); + + + + + + + + + + + + diff --git a/tests/mocha/test_helpers.js b/tests/mocha/test_helpers.js index deea338e8..fc6b1e795 100644 --- a/tests/mocha/test_helpers.js +++ b/tests/mocha/test_helpers.js @@ -104,5 +104,5 @@ function assertNotUndefined() { _validateArguments(1, arguments); var commentArg = _commentArg(1, arguments); var val = _nonCommentArg(1, 1, arguments); - chai.assert.isNotUndefined(val, commentArg); + chai.assert.isDefined(val, commentArg); }