This is an automated email from the ASF dual-hosted git repository. sushuang pushed a commit to branch fix/contain-label-name in repository https://gitbox.apache.org/repos/asf/echarts.git
commit 0cae1137200b078d64e439169ef81b9a74e3d623 Author: 100pah <[email protected]> AuthorDate: Sun Apr 6 18:53:36 2025 +0800 (test) Sync test facilities update manually. --- test/lib/reset.css | 52 +++- test/lib/testHelper.js | 547 ++++++++++++++++++++++++++++++-------- test/runTest/cli.js | 2 +- test/runTest/recorder/recorder.js | 2 +- 4 files changed, 478 insertions(+), 125 deletions(-) diff --git a/test/lib/reset.css b/test/lib/reset.css index d12d7fa16..d17312f5a 100644 --- a/test/lib/reset.css +++ b/test/lib/reset.css @@ -51,38 +51,74 @@ body > .main { padding-left: 2px; padding-right: 2px; } -.test-buttons button { + +.test-inputs button { margin: 10px 5px; } -.test-buttons-slider { +.test-inputs-fix-height { + position: relative; + overflow: scroll; + box-shadow: inset -3px -3px 3px rgba(0, 0, 0, 0.3); +} +.test-inputs-style-compact button { + margin-top: 2px; + margin-bottom: 2px; +} +.test-inputs-slider { white-space: nowrap; display: inline-block; margin: 10px 5px; font-size: 14px; + padding: 0; +} +.test-inputs-style-compact .test-inputs-slider { + margin-top: 2px; + margin-bottom: 2px; +} +.test-inputs-slider-input { + width: 129px; + height: 16px; +} +.test-inputs-style-compact .test-inputs-slider-input { + width: 90px; } -.test-buttons-slider span { +.test-inputs-slider-sub { + margin-left: -10px; +} +.test-inputs-slider span { vertical-align: middle; margin: 0 3px; } -.test-buttons-slider input { +.test-inputs-slider-disabled span { + color: #aaa; +} +.test-inputs-slider input { vertical-align: middle; margin: 0 3px; } -.test-buttons-select { +.test-inputs-select { white-space: nowrap; display: inline-block; font-size: 14px; margin: 10px 5px; margin-right: 10px; } -.test-buttons-select span { +.test-inputs-style-compact .test-inputs-select { + margin-top: 2px; + margin-bottom: 2px; +} +.test-inputs-select span { vertical-align: middle; margin: 0 3px; } -.test-buttons-select input { +.test-inputs-select select { vertical-align: middle; - margin: 0 3px; + margin: 0; + padding: 0; + font-size: 13.3333px; + height: 19px; } + .test-chart-block { position: relative; } diff --git a/test/lib/testHelper.js b/test/lib/testHelper.js index 16d990d40..ae58e64ff 100644 --- a/test/lib/testHelper.js +++ b/test/lib/testHelper.js @@ -72,18 +72,28 @@ * @param {boolean} [opt.lazyUpdate] * @param {boolean} [opt.notMerge] * @param {boolean} [opt.autoResize=true] - * @param {Array.<Object>|Object|Function} [opt.buttons] They are the same: `opt.button`, `opt.inputs`, `opt.input` + * @param {string} [opt.inputsStyle='normal'] Optional, can be 'normal', 'compact'. + * Can be either `inputsStyle` or `buttonsStyle`. + * @param {number} [opt.inputsHeight] Default not fix height. If specified, a scroll + * bar will be displayed if overflow the height. In visual test, once a height changed + * by adding something, the subsequent position will be changed, leading to test failures. + * Fixing the height helps avoid this. + * Can be either `inputsHeight` or `buttonsHeight`. + * @param {Array.<Object>|Object|Function} [opt.inputs] + * They are the same: `opt.buttons` `opt.button`, `opt.inputs`, `opt.input` * It can be a function that return buttons configuration, like: - * buttons: chart => { return [{text: 'xxx', onclick: fn}, ...]; } + * inputs: chart => { return [{text: 'xxx', onclick: fn}, ...]; } * Item can be these types: * [{ - * // A button(default). + * // A button (default). * text: 'xxx', * // They are the same: `onclick`, `click` (capital insensitive) * onclick: fn * }, { - * // A range slider (HTML <input type="range">). Can also be `type: 'slider'`. - * type: 'range', + * // A range slider (HTML <input type="range">). + * type: 'range', // Or 'slider' + * id: 'some_id', // Optional. Can be used in `getState` and `setState`. + * stateGroup: 'some_state_group', // Optional. Can be used in `getState` and `setState`. * text: 'xxx', // Optional * min: 0, // Optional * max: 100, // Optional @@ -96,13 +106,30 @@ * }, { * // A select (HTML <select>...</select>). * type: 'select', // Or `selection` - * options: ['a', 'b', 'c'], // Or [{text: 'a', value: 123}, ...]. - * // Can be any type, like `true`, `123`, etc. - * // They are the same: `options: []`, `values: []`, `items: []`. + * id: 'some_id', // Optional. Can be used in `getState` and `setState`. + * stateGroup: 'some_state_group', // Optional. Can be used in `getState` and `setState`. + * // Either `values` or `options` can be used. + * // Items in `values` or `options[i].value` can be any type, like `true`, `123`, etc. + * values: ['a', 'b', 'c'], + * options: [ + * {text: 'a', value: 123}, + * {value: {some: {some: 456}}}, // `text` can be omitted and auto generated by `value`. + * {text: 'c', input: ...}, // `input` can be used as shown below. + * ... + * ], + * // `options[i]` can nest other input type, currently only support `type: range`: + * options: [ + * {value: undefined}, + * {text: 'c', input: { + * type: 'range', + * // ... Other properties of `range` input except `onchange` and `text`. + * // When this option is not selected, the range input will be disabled. + * }} + * ], * valueIndex: 0, // Optional. The initial value index. By default, the first option. - * value: 'c', // Optional. The initial value. By default, the first option. - * // Can be any type, like `true`, `123`, etc. - * // But can only be JS primitive type, as `===` is used internally. + * value: 'cval', // Optional. The initial value. By default, the first option. + * // Can be any type, like `true`, `123`, etc. + * // But can only be JS primitive type, as `===` is used internally. * text: 'xxx', // Optional. * // They are the same: `oninput` `input` * // `onchange` `change` @@ -116,6 +143,14 @@ * }, * // ... * ] + * The value of the inputs can be update by: + * chart.__testHelper.setState({'some_id_1': 'value1', 'some_id_2': 'value2'}); + * // Only set state from input that has 'some_state_group_1'. + * chart.__testHelper.setState({...}, 'some_state_group_1'); + * // Get: {some_id_1: 'value1', some_id_2: 'value2'} + * chart.__testHelper.getState(); + * // Only get state from input that has 'some_state_group_1'. + * chart.__testHelper.getState('some_state_group_1'); * @param {boolean} [opt.recordCanvas] 'test/lib/canteen.js' is required. * @param {boolean} [opt.recordVideo] * @param {string} [opt.renderer] 'canvas' or 'svg' @@ -132,7 +167,7 @@ var title = document.createElement('div'); var left = document.createElement('div'); var chartContainer = document.createElement('div'); - var buttonsContainer = document.createElement('div'); + var inputsContainer = document.createElement('div'); var dataTableContainer = document.createElement('div'); var infoContainer = document.createElement('div'); var recordCanvasContainer = document.createElement('div'); @@ -140,16 +175,31 @@ title.setAttribute('title', dom.getAttribute('id')); + var inputsHeight = testHelper.retrieveValue(opt.inputsHeight, opt.buttonsHeight, null); + if (inputsHeight != null) { + inputsHeight = parseFloat(inputsHeight); + } + title.className = 'test-title'; dom.className = 'test-chart-block'; left.className = 'test-chart-block-left'; chartContainer.className = 'test-chart'; - buttonsContainer.className = 'test-buttons'; dataTableContainer.className = 'test-data-table'; infoContainer.className = 'test-info'; recordCanvasContainer.className = 'record-canvas'; recordVideoContainer.className = 'record-video'; + inputsContainer.className = [ + 'test-inputs', + 'test-inputs-style-' + (opt.inputsStyle || opt.buttonsStyle || 'normal'), + (inputsHeight != null ? 'test-inputs-fix-height' : '') + ].join(' '); + if (inputsHeight != null) { + inputsContainer.style.cssText = [ + 'height:' + inputsHeight + 'px', + ].join(';') + ';'; + } + if (opt.info) { dom.className += ' test-chart-block-has-right'; infoContainer.className += ' test-chart-block-right'; @@ -157,7 +207,7 @@ left.appendChild(recordCanvasContainer); left.appendChild(recordVideoContainer); - left.appendChild(buttonsContainer); + left.appendChild(inputsContainer); left.appendChild(dataTableContainer); left.appendChild(chartContainer); dom.appendChild(infoContainer); @@ -192,7 +242,10 @@ dataTableContainer.innerHTML = tableHTML.join(''); } - chart && initButtons(chart, opt, buttonsContainer, errMsgPrefix) + var inputsResult; + if (chart) { + inputsResult = initInputs(chart, opt, inputsContainer, errMsgPrefix); + } if (opt.info) { updateInfo(opt.info, opt.infoKey); @@ -209,13 +262,15 @@ } chart.__testHelper = { - updateInfo: updateInfo + updateInfo: updateInfo, + setState: inputsResult && inputsResult.setState, + getState: inputsResult && inputsResult.getState }; return chart; }; - function initButtons(chart, opt, buttonsContainer, errMsgPrefix) { + function initInputs(chart, opt, inputsContainer, errMsgPrefix) { var NAMES_ON_INPUT_CHANGE = makeFlexibleNames([ 'input', 'on-input', 'on-change', 'select', 'on-select' ]); @@ -229,73 +284,152 @@ 'br', 'line-break', 'break', 'wrap', 'new-line', 'end-of-line', 'carriage-return', 'line-feed', 'line-separator', 'next-line' ]); + // key: id, value: {setState, getState} + var _inputsDict = {}; + + init(); + + return {setState: setState, getState: getState}; - var buttons = testHelper.retrieveValue(opt.buttons, opt.button, opt.input, opt.inputs); - if (typeof buttons === 'function') { - buttons = buttons(chart); + + function init() { + var inputsDefineList = retrieveInputDefineList(); + + for (var i = 0; i < inputsDefineList.length; i++) { + var singleCreated = createInputByDefine(inputsDefineList[i]); + if (!singleCreated) { + continue; + } + for (var j = 0; j < singleCreated.elList.length; j++) { + inputsContainer.appendChild(singleCreated.elList[j]); + } + var id = retrieveId(inputsDefineList[i], 'id'); + var stateGroup = retrieveId(inputsDefineList[i], 'stateGroup'); + if (stateGroup != null) { + if (id == null) { + id = generateId('test_inputs_'); + } + singleCreated.stateGroup = stateGroup; + } + if (id != null) { + if (_inputsDict[singleCreated.id]) { + throw new Error(errMsgPrefix + 'Duplicate input id: ' + singleCreated.id); + } + singleCreated.id = id; + _inputsDict[singleCreated.id] = singleCreated; + } + } } - if (!(buttons instanceof Array)) { - buttons = buttons ? [buttons] : []; + + function setState(state, stateGroup) { + for (var id in state) { + if (state.hasOwnProperty(id)) { + if (_inputsDict[id] == null) { + throw new Error(errMsgPrefix + 'No input with id: ' + id); + } + if (!stateGroup || _inputsDict[id].stateGroup === stateGroup) { + _inputsDict[id].setState(state[id]); + } + } + } } - if (!buttons.length) { - return; + + function getState(stateGroup) { + var result = {}; + for (var id in _inputsDict) { + if (_inputsDict.hasOwnProperty(id) + && (!stateGroup || _inputsDict[id].stateGroup === stateGroup) + ) { + result[id] = _inputsDict[id].getState(); + } + } + return result; } - for (var i = 0; i < buttons.length; i++) { - processBtnDefine(buttons[i]); + function retrieveInputDefineList() { + var defineList = testHelper.retrieveValue(opt.buttons, opt.button, opt.input, opt.inputs); + if (typeof defineList === 'function') { + defineList = defineList(chart); + } + if (!(defineList instanceof Array)) { + defineList = defineList ? [defineList] : []; + } + return defineList; } - function getBtnTextHTML(btnDefine, defaultText) { - return testHelper.encodeHTML(testHelper.retrieveValue(btnDefine.name, btnDefine.text, defaultText)); + function getBtnTextHTML(inputDefine, defaultText) { + return testHelper.encodeHTML(testHelper.retrieveValue(inputDefine.name, inputDefine.text, defaultText)); } - function getBtnDefineAttr(btnDefine, attr, defaultValue) { - return btnDefine[attr] != null ? btnDefine[attr] : defaultValue; + function getBtnDefineAttr(inputDefine, attr, defaultValue) { + return inputDefine[attr] != null ? inputDefine[attr] : defaultValue; } - function getBtnEventListener(btnDefine, names) { + function getBtnEventListener(inputDefine, names) { for (var idx = 0; idx < names.length; idx++) { - if (btnDefine[names[idx]]) { - return btnDefine[names[idx]]; + if (inputDefine[names[idx]]) { + return inputDefine[names[idx]]; + } + } + } + + function retrieveId(inputDefine, idPropName) { + if (inputDefine && inputDefine[idPropName] != null) { + var type = getType(inputDefine[idPropName]); + if (type !== 'string' && type != 'number') { + throw new Error(errMsgPrefix + 'id must be string or number.'); } + return inputDefine[idPropName] + ''; } } - function processBtnDefine(btnDefine) { - if (!btnDefine) { + function createInputByDefine(inputDefine) { + if (!inputDefine) { return; } - var inputType = btnDefine.hasOwnProperty('type') ? btnDefine.type : 'button'; + var inputType = inputDefine.hasOwnProperty('type') ? inputDefine.type : 'button'; if (arrayIndexOf(NAMES_TYPE_RANGE, inputType) >= 0) { - createRangeInput(btnDefine, buttonsContainer); + var rangeInputCreated = createRangeInput(inputDefine); + return { + elList: [rangeInputCreated.el], + getState: rangeInputCreated.getState, + setState: rangeInputCreated.setState + }; } else if (arrayIndexOf(NAMES_TYPE_SELECT, inputType) >= 0) { - createSelectInput(btnDefine, buttonsContainer); + return createSelectInput(inputDefine); } else if (arrayIndexOf(NAMES_TYPE_BR, inputType) >= 0) { - createBr(btnDefine, buttonsContainer); + return { + elList: [createBr(inputDefine)] + }; } else if (arrayIndexOf(NAMES_TYPE_BUTTON, inputType) >= 0) { - createButtonInput(btnDefine, buttonsContainer); + return { + elList: [createButtonInput(inputDefine)] + }; } else { throw new Error(errMsgPrefix + 'Unsupported button type: ' + inputType); } } - function createRangeInput(btnDefine, buttonsContainer) { + function createRangeInput(inputDefine, internallyForceDef) { var sliderWrapperEl = document.createElement('span'); - sliderWrapperEl.className = 'test-buttons-slider'; - buttonsContainer.appendChild(sliderWrapperEl); + resetWrapperCSS(false); var sliderTextEl = document.createElement('span'); - sliderTextEl.className = 'test-buttons-slider-text'; - sliderTextEl.innerHTML = getBtnTextHTML(btnDefine, ''); + sliderTextEl.className = 'test-inputs-slider-text'; + sliderTextEl.innerHTML = internallyForceDef + ? getBtnTextHTML(internallyForceDef, '') + : getBtnTextHTML(inputDefine, ''); sliderWrapperEl.appendChild(sliderTextEl); var sliderInputEl = document.createElement('input'); - sliderInputEl.className = 'test-buttons-slider-input'; + sliderInputEl.className = 'test-inputs-slider-input'; sliderInputEl.setAttribute('type', 'range'); - var sliderListener = getBtnEventListener(btnDefine, NAMES_ON_INPUT_CHANGE); + var sliderListener = internallyForceDef + ? getBtnEventListener(internallyForceDef, NAMES_ON_INPUT_CHANGE) + : getBtnEventListener(inputDefine, NAMES_ON_INPUT_CHANGE); if (!sliderListener) { throw new Error(errMsgPrefix + 'No listener (either ' + NAMES_ON_INPUT_CHANGE.join(', ') + ') specified for slider.'); } @@ -304,105 +438,271 @@ var target = {value: this.value}; sliderListener.call(target, {target: target}); }); - sliderInputEl.setAttribute('min', getBtnDefineAttr(btnDefine, 'min', 0)); - sliderInputEl.setAttribute('max', getBtnDefineAttr(btnDefine, 'max', 100)); - sliderInputEl.setAttribute('value', getBtnDefineAttr(btnDefine, 'value', 30)); - sliderInputEl.setAttribute('step', getBtnDefineAttr(btnDefine, 'step', 1)); + sliderInputEl.setAttribute('min', getBtnDefineAttr(inputDefine, 'min', 0)); + sliderInputEl.setAttribute('max', getBtnDefineAttr(inputDefine, 'max', 100)); + sliderInputEl.setAttribute('value', getBtnDefineAttr(inputDefine, 'value', 30)); + sliderInputEl.setAttribute('step', getBtnDefineAttr(inputDefine, 'step', 1)); sliderWrapperEl.appendChild(sliderInputEl); var sliderValueEl = document.createElement('span'); - sliderValueEl.className = 'test-buttons-slider-value'; + sliderValueEl.className = 'test-inputs-slider-value'; function updateSliderValueEl() { var val = sliderInputEl.value; + updateText(val); + } + function updateText(val) { sliderValueEl.innerHTML = testHelper.encodeHTML(val); } updateSliderValueEl(); sliderWrapperEl.appendChild(sliderValueEl); + + function resetWrapperCSS(disabled) { + sliderWrapperEl.className = 'test-inputs-slider' + + (internallyForceDef ? ' test-inputs-slider-sub' : '') + + (disabled ? ' test-inputs-slider-disabled' : ''); + } + + return { + el: sliderWrapperEl, + setState: function (state) { + if (state == null || !isFinite(+state.value)) { + throw new Error(errMsgPrefix + 'Invalid state: ' + printObject(state) + ' for range'); + } + sliderInputEl.value = state.value; + updateText(state.value); + }, + getState: function () { + return {value: +sliderInputEl.value}; + }, + disable: function (disabled) { + sliderInputEl.disabled = disabled; + resetWrapperCSS(disabled); + } + }; } - function createSelectInput(btnDefine, buttonsContainer) { - var selectWrapperEl = document.createElement('span'); - selectWrapperEl.className = 'test-buttons-select'; - buttonsContainer.appendChild(selectWrapperEl); + function createSelectInput(inputDefine) { + var selectCtx = { + _optionList: [], + _selectEl: null, + _optionIdxToSubInput: [], + _elList: [] + }; + + createElementsForSelect(); + + var _selectListener = getBtnEventListener(inputDefine, NAMES_ON_INPUT_CHANGE); + if (!_selectListener) { + throw new Error(errMsgPrefix + 'No listener (either ' + NAMES_ON_INPUT_CHANGE.join(', ') + ') specified for select.'); + } + + initOptionsForSelect(inputDefine); + + selectCtx._selectEl.addEventListener('change', function () { + var optionIdx = getOptionIndex(selectCtx._selectEl); + disableSubInputs(optionIdx); + handleSelectChange(getValueByOptionIndex(optionIdx)); + }); + + setInitValue(inputDefine); + + return { + elList: selectCtx._elList, + getState: getStateForSelect, + setState: setStateForSelect + }; - var textEl = document.createElement('span'); - textEl.className = 'test-buttons-select-text'; - textEl.innerHTML = getBtnTextHTML(btnDefine, ''); - selectWrapperEl.appendChild(textEl); + function createElementsForSelect() { + var selectWrapperEl = document.createElement('span'); + selectWrapperEl.className = 'test-inputs-select'; - var selectEl = document.createElement('select'); - selectEl.className = 'test-buttons-select-input'; - selectWrapperEl.appendChild(selectEl); + var textEl = document.createElement('span'); + textEl.className = 'test-inputs-select-text'; + textEl.innerHTML = getBtnTextHTML(inputDefine, ''); + selectWrapperEl.appendChild(textEl); - var optionDefList = testHelper.retrieveValue(btnDefine.options, btnDefine.values, btnDefine.items, []); - optionDefList = optionDefList.slice(); - if (!optionDefList.length) { - throw new Error(errMsgPrefix + 'No options specified for select.'); + var selectEl = document.createElement('select'); + selectEl.className = 'test-inputs-select-select'; + selectWrapperEl.appendChild(selectEl); + + selectCtx._elList.push(selectWrapperEl); + selectCtx._selectEl = selectEl; } - for (var idx = 0; idx < optionDefList.length; idx++) { - var optionDef = optionDefList[idx]; + + function initOptionsForSelect(inputDefine) { // optionDef can be {text, value} or just value // (value can be null/undefined/array/object/... everything). // Convinient but might cause ambiguity when a value happens to be {text, value}, but rarely happen. - if (isObject(optionDef) && optionDef.hasOwnProperty('text') && optionDef.hasOwnProperty('value')) { - optionDef = {text: optionDef.text, value: optionDef.value}; + if (inputDefine.options) { + for (var optionIdx = 0; optionIdx < inputDefine.options.length; optionIdx++) { + var optionDef = inputDefine.options[optionIdx]; + if ( + !isObject(optionDef) + || ( + !optionDef.hasOwnProperty('value') + && !isObject(optionDef.input) + ) + ) { + throw new Error( + 'Can only be {type: "select", options: {value: any, text?: string, input?: SubInput}[]}' + ); + } + var text = getType(optionDef.text) === 'string' + ? optionDef.text + : makeTextByValue(optionDef); + selectCtx._optionList.push({ + value: optionDef.value, + input: optionDef.input, + text: text + }); + } } - else { - optionDef = { - text: printObject(optionDef, { - arrayLineBreak: false, objectLineBreak: false, indent: 0, lineBreak: '' - }), - value: optionDef - }; + else if (inputDefine.values) { + for (var optionIdx = 0; optionIdx < inputDefine.values.length; optionIdx++) { + var value = inputDefine.values[optionIdx]; + selectCtx._optionList.push({ + value: value, + text: makeTextByValue({value: value}) + }); + } } - optionDefList[idx] = optionDef; - var optionEl = document.createElement('option'); - optionEl.innerHTML = testHelper.encodeHTML(optionDef.text); - // HTML select.value is always string. But it would be more convenient to - // convert it to user's raw input value type. - optionEl.value = idx; - selectEl.appendChild(optionEl); - } - if (btnDefine.hasOwnProperty('valueIndex')) { - var valueIndex = btnDefine.valueIndex; - if (valueIndex < 0 || valueIndex >= optionDefList.length) { - throw new Error(errMsgPrefix + 'Invalid valueIndex: ' + valueIndex); + if (!selectCtx._optionList.length) { + throw new Error(errMsgPrefix + 'No options specified for select.'); } - selectEl.value = optionDefList[valueIndex].value; - } - else if (btnDefine.hasOwnProperty('value')) { - var found = false; - for (var idx = 0; idx < optionDefList.length; idx++) { - if (optionDefList[idx].value === btnDefine.value) { - selectEl.value = idx; - found = true; + + for (var optionIdx = 0; optionIdx < selectCtx._optionList.length; optionIdx++) { + var optionDef = selectCtx._optionList[optionIdx]; + selectCtx._optionList[optionIdx] = optionDef; + var optionEl = document.createElement('option'); + optionEl.innerHTML = testHelper.encodeHTML(optionDef.text); + // HTML select.value is always string. But it would be more convenient to + // convert it to user's raw input value type. + // (The input raw value can be null/undefined/array/object/... everything). + optionEl.value = optionIdx; + selectCtx._selectEl.appendChild(optionEl); + + if (optionDef.input) { + if (arrayIndexOf(NAMES_TYPE_RANGE, optionDef.input.type) < 0) { + throw new Error(errMsgPrefix + 'Sub input only supported for range input.'); + } + var createdRangeInput = createRangeInput(optionDef.input, { + text: '', + onchange: function () { + handleSelectChange(this.value) + } + }); + selectCtx._elList.push(createdRangeInput.el); + selectCtx._optionIdxToSubInput[optionIdx] = createdRangeInput; } } - if (!found) { - throw new Error(errMsgPrefix + 'Value not found in select options: ' + btnDefine.value); + } + + function getStateForSelect() { + var subInputState = {}; + for (var optionIdx = 0; optionIdx < selectCtx._optionIdxToSubInput.length; optionIdx++) { + if (selectCtx._optionIdxToSubInput[optionIdx]) { + subInputState[optionIdx] = selectCtx._optionIdxToSubInput[optionIdx].getState(); + } } + return { + valueIndex: getOptionIndex(selectCtx._selectEl), + subInputState: subInputState + }; } - var selectListener = getBtnEventListener(btnDefine, NAMES_ON_INPUT_CHANGE); - if (!selectListener) { - throw new Error(errMsgPrefix + 'No listener (either ' + NAMES_ON_INPUT_CHANGE.join(', ') + ') specified for select.'); + + function setStateForSelect(state) { + if (state == null + || getType(state.valueIndex) !== 'number' + || !isObject(state.subInputState) + ) { + throw new Error(errMsgPrefix + 'Invalid state: ' + printObject(state) + ' for select'); + } + resetOptionIndex(state.valueIndex); + for (var optionIdx in state.subInputState) { + if (state.subInputState.hasOwnProperty(optionIdx)) { + var subInput = selectCtx._optionIdxToSubInput[optionIdx]; + if (subInput) { + subInput.setState(state.subInputState[optionIdx]); + } + } + } + } + + function setInitValue(inputDefine) { + var initOptionIdx = 0; + if (inputDefine.hasOwnProperty('valueIndex')) { + var valueIndex = inputDefine.valueIndex; + if (valueIndex < 0 || valueIndex >= selectCtx._optionList.length) { + throw new Error(errMsgPrefix + 'Invalid valueIndex: ' + valueIndex); + } + selectCtx._selectEl.value = selectCtx._optionList[valueIndex].value; + initOptionIdx = valueIndex; + } + else if (inputDefine.hasOwnProperty('value')) { + var found = false; + for (var idx = 0; idx < selectCtx._optionList.length; idx++) { + if (!selectCtx._optionList[idx].input && selectCtx._optionList[idx].value === inputDefine.value) { + found = true; + initOptionIdx = idx; + } + } + if (!found) { + throw new Error(errMsgPrefix + 'Value not found in select options: ' + inputDefine.value); + } + } + resetOptionIndex(initOptionIdx); + } + + function resetOptionIndex(optionIdx) { + disableSubInputs(optionIdx); + selectCtx._selectEl.value = optionIdx; + } + + function getOptionIndex(optionIndexHost) { + return +optionIndexHost.value; + } + + function getValueByOptionIndex(optionIdx) { + return selectCtx._optionList[optionIdx].input + ? selectCtx._optionIdxToSubInput[optionIdx].getState().value + : selectCtx._optionList[optionIdx].value; + } + + function handleSelectChange(value) { + var target = {value: value}; + _selectListener.call(target, {target: target}); + } + + function disableSubInputs(currOptionIdx) { + for (var i = 0; i < selectCtx._optionIdxToSubInput.length; i++) { + var subInput = selectCtx._optionIdxToSubInput[i]; + if (subInput) { + subInput.disable(i !== currOptionIdx); + } + } + } + + function makeTextByValue(optionDef) { + if (optionDef.hasOwnProperty('value')) { + return printObject(optionDef.value, { + arrayLineBreak: false, objectLineBreak: false, indent: 0, lineBreak: '' + }); + } + else if (optionDef.input) { + return 'range input'; + } } - selectEl.addEventListener('change', function () { - var idx = this.value; - var target = {value: optionDefList[idx].value}; - selectListener.call(target, {target: target}); - }); } - function createBr(btnDefine, buttonsContainer) { - var brEl = document.createElement('br'); - buttonsContainer.appendChild(brEl); + function createBr(inputDefine) { + return document.createElement('br'); } - function createButtonInput(btnDefine, buttonsContainer) { + function createButtonInput(inputDefine) { var btn = document.createElement('button'); - btn.innerHTML = getBtnTextHTML(btnDefine, 'button'); - btn.addEventListener('click', getBtnEventListener(btnDefine, NAMES_ON_CLICK)); - buttonsContainer.appendChild(btn); + btn.innerHTML = getBtnTextHTML(inputDefine, 'button'); + btn.addEventListener('click', getBtnEventListener(inputDefine, NAMES_ON_CLICK)); + return btn; } } @@ -1325,6 +1625,23 @@ return names; } + function objectNoOtherNotNullUndefinedPropExcept(obj, exceptProps) { + if (!obj) { + return false; + } + for (var key in obj) { + if (obj.hasOwnProperty(key) && arrayIndexOf(exceptProps, key) < 0 && obj[key] != null) { + return false; + } + } + return true; + } + + var _idBase = 1; + function generateId(prefix) { + return prefix + '' + (_idBase++); + } + function VideoRecorder(chart) { this.start = startRecording; this.stop = stopRecording; diff --git a/test/runTest/cli.js b/test/runTest/cli.js index 0448f6821..cd9360ce3 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -413,7 +413,7 @@ async function runTest(browser, testOpt, runtimeCode, expectedSource, expectedVe } else { // Only run once - await runTestPage(browser, testOpt, 'local', runtimeCode, true); + await runTestPage(browser, testOpt, expectedSource, 'local', runtimeCode, true); } } diff --git a/test/runTest/recorder/recorder.js b/test/runTest/recorder/recorder.js index 66f18dee7..e4289563e 100644 --- a/test/runTest/recorder/recorder.js +++ b/test/runTest/recorder/recorder.js @@ -40,7 +40,7 @@ function getUniqueSelector(el) { let selector = ''; if (el.id) { // id has highest priority. - return el.id; + return '#' + el.id; } else { selector = el.tagName.toLowerCase(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
