blob: 11012e1cab3d3fe2a4004d958e58f0ff21338df7 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
cr.define('pages_settings_test', function() {
/** @enum {string} */
const TestNames = {
ValidPageRanges: 'valid page ranges',
InvalidPageRanges: 'invalid page ranges',
NupChangesPages: 'nup changes pages',
ClearInput: 'clear input',
TabOrder: 'tab order',
ClickingCustomFocusesInput: 'clicking custom focuses input',
InputNotDisabledOnValidityChange: 'input not disabled on validity change',
IgnoreInputKeyEvents: 'ignore input key events',
EnterOnInputTriggersPrint: 'enter on input triggers print',
};
const suiteName = 'PagesSettingsTest';
suite(suiteName, function() {
/** @type {?PrintPreviewPagesSettingsElement} */
let pagesSection = null;
/** @type {!Array<number>} */
const oneToHundred = Array.from({length: 100}, (x, i) => i + 1);
/** @type {string} */
const limitError = 'Out of bounds page reference, limit is ';
/** @override */
setup(function() {
PolymerTest.clearBody();
pagesSection = document.createElement('print-preview-pages-settings');
pagesSection.settings = {
pages: {
value: [1],
unavailableValue: [],
valid: true,
available: true,
key: '',
},
ranges: {
value: [],
unavailableValue: [],
valid: true,
available: true,
key: '',
},
pagesPerSheet: {
value: 1,
unavailableValue: 1,
valid: true,
available: true,
key: '',
},
};
pagesSection.disabled = false;
document.body.appendChild(pagesSection);
});
/**
* Sets up the pages section to use the custom input with the input string
* given by |inputString|, with the document page count set to |pageCount|
* @param {string} inputString
* @param {number} pageCount
* @return {!Promise} Promise that resolves when the input-change event
* has fired.
*/
function setupInput(inputString, pageCount) {
// Set page count.
pagesSection.pageCount = pageCount;
Polymer.dom.flush();
const input = pagesSection.$.pageSettingsCustomInput.inputElement;
const pagesSelect = pagesSection.$$('select');
const isCustomSelected =
pagesSelect.value === pagesSection.pagesValueEnum_.CUSTOM.toString();
const readyForInput = isCustomSelected ?
Promise.resolve() :
test_util.eventToPromise('process-select-change', pagesSection);
// Select custom
if (!isCustomSelected) {
pagesSelect.value = pagesSection.pagesValueEnum_.CUSTOM.toString();
pagesSelect.dispatchEvent(new CustomEvent('change'));
}
return readyForInput.then(() => {
input.focus();
// Set input string
input.value = inputString;
input.dispatchEvent(
new CustomEvent('input', {composed: true, bubbles: true}));
// Validate results
return test_util.eventToPromise('input-change', pagesSection);
});
}
/**
* @param {!Array<number>} expectedPages The expected pages value.
* @param {string} expectedError The expected error message.
* @param {boolean} invalid Whether the pages setting should be invalid.
*/
function validateState(expectedPages, expectedError, invalid) {
const pagesValue = pagesSection.getSettingValue('pages');
assertEquals(expectedPages.length, pagesValue.length);
expectedPages.forEach((page, index) => {
assertEquals(page, pagesValue[index]);
});
assertEquals(!invalid, pagesSection.getSetting('pages').valid);
assertEquals(expectedError !== '', pagesSection.$$('cr-input').invalid);
assertEquals(expectedError, pagesSection.$$('cr-input').errorMessage);
}
// Tests that the page ranges set are valid for different user inputs.
test(assert(TestNames.ValidPageRanges), function() {
const tenToHundred = Array.from({length: 91}, (x, i) => i + 10);
return setupInput('1, 2, 3, 1, 56', 100)
.then(function() {
validateState([1, 2, 3, 56], '', false);
return setupInput('1-3, 6-9, 6-10', 100);
})
.then(function() {
validateState([1, 2, 3, 6, 7, 8, 9, 10], '', false);
return setupInput('10-', 100);
})
.then(function() {
validateState(tenToHundred, '', false);
return setupInput('10-100', 100);
})
.then(function() {
validateState(tenToHundred, '', false);
return setupInput('-', 100);
})
.then(function() {
validateState(oneToHundred, '', false);
// https://crbug.com/806165
return setupInput('1\u30012\u30013\u30011\u300156', 100);
})
.then(function() {
validateState([1, 2, 3, 56], '', false);
return setupInput('1,2,3\u30011\u300156', 100);
})
.then(function() {
validateState([1, 2, 3, 56], '', false);
});
});
// Tests that the correct error messages are shown for different user
// inputs.
test(assert(TestNames.InvalidPageRanges), function() {
const syntaxError = 'Invalid page range, use e.g. 1-5, 8, 11-13';
return setupInput('10-100000', 100)
.then(function() {
validateState(oneToHundred, limitError + '100', true);
return setupInput('1, 100000', 100);
})
.then(function() {
validateState(oneToHundred, limitError + '100', true);
return setupInput('1, 2, 0, 56', 100);
})
.then(function() {
validateState(oneToHundred, syntaxError, true);
return setupInput('-1, 1, 2,, 56', 100);
})
.then(function() {
validateState(oneToHundred, syntaxError, true);
return setupInput('1,2,56-40', 100);
})
.then(function() {
validateState(oneToHundred, syntaxError, true);
return setupInput('101-110', 100);
})
.then(function() {
validateState(oneToHundred, limitError + '100', true);
return setupInput('1\u30012\u30010\u300156', 100);
})
.then(function() {
validateState(oneToHundred, syntaxError, true);
return setupInput('-1,1,2\u3001\u300156', 100);
})
.then(function() {
validateState(oneToHundred, syntaxError, true);
return setupInput('--', 100);
})
.then(function() {
validateState(oneToHundred, syntaxError, true);
return setupInput(' 1 1 ', 100);
})
.then(function() {
validateState(oneToHundred, syntaxError, true);
});
});
// Tests that the pages are set correctly for different values of pages per
// sheet, and that ranges remain fixed (since they are used for generating
// the print preview ticket).
test(assert(TestNames.NupChangesPages), function() {
/**
* @param {string} rangesValue The desired stringified ranges setting
* value.
*/
const validateRanges = function(rangesValue) {
assertEquals(
rangesValue,
JSON.stringify(pagesSection.getSettingValue('ranges')));
};
return setupInput('1, 2, 3, 1, 56', 100)
.then(function() {
const rangesValue =
JSON.stringify(pagesSection.getSettingValue('ranges'));
validateState([1, 2, 3, 56], '', false);
pagesSection.setSetting('pagesPerSheet', 2);
validateRanges(rangesValue);
validateState([1, 2], '', false);
pagesSection.setSetting('pagesPerSheet', 4);
validateRanges(rangesValue);
validateState([1], '', false);
pagesSection.setSetting('pagesPerSheet', 1);
return setupInput('1-3, 6-9, 6-10', 100);
})
.then(function() {
const rangesValue =
JSON.stringify(pagesSection.getSettingValue('ranges'));
validateState([1, 2, 3, 6, 7, 8, 9, 10], '', false);
pagesSection.setSetting('pagesPerSheet', 2);
validateRanges(rangesValue);
validateState([1, 2, 3, 4], '', false);
pagesSection.setSetting('pagesPerSheet', 3);
validateRanges(rangesValue);
validateState([1, 2, 3], '', false);
return setupInput('1-3', 100);
})
.then(function() {
const rangesValue =
JSON.stringify(pagesSection.getSettingValue('ranges'));
validateState([1], '', false);
pagesSection.setSetting('pagesPerSheet', 1);
validateRanges(rangesValue);
validateState([1, 2, 3], '', false);
});
});
// Tests that the clearing a valid input has no effect, clearing an invalid
// input does not show an error message but does not reset the preview, and
// changing focus from an empty input in either case automatically reselects
// the "all" radio button.
test(assert(TestNames.ClearInput), function() {
const input = pagesSection.$.pageSettingsCustomInput.inputElement;
const select = pagesSection.$$('select');
const allValue = pagesSection.pagesValueEnum_.ALL.toString();
const customValue = pagesSection.pagesValueEnum_.CUSTOM.toString();
assertEquals(allValue, select.value);
return setupInput('1-2', 3)
.then(function() {
assertEquals(customValue, select.value);
validateState([1, 2], '', false);
return setupInput('', 3);
})
.then(function() {
assertEquals(customValue, select.value);
validateState([1, 2], '', false);
const whenBlurred = test_util.eventToPromise('blur', input);
input.blur();
return whenBlurred;
})
.then(function() {
// Blurring does not change the state.
assertEquals(customValue, select.value);
validateState([1, 2], '', false);
assertEquals('1-2', input.value);
return setupInput('5', 3);
})
.then(function() {
assertEquals(customValue, select.value);
validateState([1, 2], limitError + '3', true);
return setupInput('', 3);
})
.then(function() {
assertEquals(customValue, select.value);
validateState([1, 2], '', false);
const whenBlurred = test_util.eventToPromise('blur', input);
input.blur();
return whenBlurred;
})
.then(function() {
assertEquals(customValue, select.value);
validateState([1, 2], '', false);
assertEquals('1-2', input.value);
});
});
test(assert(TestNames.ClickingCustomFocusesInput), function() {
const input = pagesSection.$.pageSettingsCustomInput.inputElement;
const radioGroup = pagesSection.$$('cr-radio-group');
assertEquals(pagesSection.pagesValueEnum_.ALL, radioGroup.selected);
// Click the custom input and set a valid value.
return setupInput('1-2', 3)
.then(function() {
// Blur the custom input.
const whenCustomInputBlurred =
test_util.eventToPromise('blur', input);
input.blur();
Polymer.dom.flush();
return whenCustomInputBlurred;
})
.then(function() {
const whenCustomInputFocused =
test_util.eventToPromise('focus', input);
// Clicking the custom radio button should re-focus the input.
pagesSection.$.customRadioButton.click();
return whenCustomInputFocused;
});
});
// Verifies that the input is never disabled when the validity of the
// setting changes.
test(assert(TestNames.InputNotDisabledOnValidityChange), function() {
// In the real UI, the print preview app listens for this event from this
// section and others and sets disabled to true if any change from true to
// false is detected. Imitate this here. Since we are only interacting
// with the pages input, at no point should the input be disabled, as it
// will lose focus.
pagesSection.addEventListener('setting-valid-changed', function(e) {
assertFalse(pagesSection.$.pageSettingsCustomInput.disabled);
pagesSection.set('disabled', !e.detail);
assertFalse(pagesSection.$.pageSettingsCustomInput.disabled);
});
const input = pagesSection.$.pageSettingsCustomInput.inputElement;
// Set a valid input
return setupInput('1', 3)
.then(function() {
validateState([1], '', false);
// Set invalid input
return setupInput('12', 3);
})
.then(function() {
validateState([1], limitError + '3', true);
// Restore valid input
return setupInput('1', 3);
})
.then(function() {
validateState([1], '', false);
// Invalid input again
return setupInput('8', 3);
})
.then(function() {
validateState([1], limitError + '3', true);
// Clear input
return setupInput('', 3);
})
.then(function() {
validateState([1], '', false);
// Set valid input
return setupInput('2', 3);
})
.then(function() {
validateState([2], '', false);
});
});
// Verifies that the enter key event is bubbled to the pages settings
// element, so that it will be bubbled to the print preview app to trigger a
// print.
test(assert(TestNames.EnterOnInputTriggersPrint), function() {
pagesSection.pageCount = 3;
const input = pagesSection.$.pageSettingsCustomInput.inputElement;
const whenPrintReceived =
test_util.eventToPromise('keydown', pagesSection);
// Setup an empty input by clicking on the custom radio button.
const customValue = pagesSection.pagesValueEnum_.CUSTOM.toString();
const pagesSelect = pagesSection.$$('select');
pagesSelect.value = customValue;
pagesSelect.dispatchEvent(new CustomEvent('change'));
const inputFocused = test_util.eventToPromise('focus', input);
return inputFocused
.then(function() {
assertEquals(customValue, pagesSelect.value);
MockInteractions.keyEventOn(input, 'keydown', 13, [], 'Enter');
return whenPrintReceived;
})
.then(function() {
// Keep custom selected, but pages to print should still be all.
assertEquals(customValue, pagesSelect.value);
assertEquals(3, pagesSection.getSetting('pages').value.length);
// Select a custom input of 1.
return setupInput('1', 3);
})
// Re-select custom and print again.
.then(function() {
assertEquals(customValue, pagesSelect.value);
const whenPrintReceived =
test_util.eventToPromise('keydown', pagesSection);
MockInteractions.keyEventOn(input, 'keydown', 13, [], 'Enter');
return whenPrintReceived;
})
.then(function() {
assertEquals(customValue, pagesSelect.value);
});
});
});
return {
suiteName: suiteName,
TestNames: TestNames,
};
});