libreoffice-online/cypress_test/integration_tests/common/helper.js
Tamás Zolnai 815802e6e0 cypress: improve typeIntoDocument() helper method.
First grab the focus to the textarea, otherwise
the force: true flag leads to unexpected behavior.

Change-Id: Ic99bb1b22734733d7bb40b895173e5382c2ba5f4
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/100605
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Tamás Zolnai <tamas.zolnai@collabora.com>
2020-08-12 19:59:35 +02:00

520 lines
14 KiB
JavaScript

/* global cy Cypress expect require */
require('cypress-wait-until');
function loadTestDoc(fileName, subFolder, noFileCopy) {
cy.log('Loading test document - start.');
cy.log('Param - fileName: ' + fileName);
cy.log('Param - subFolder: ' + subFolder);
cy.log('Param - noFileCopy: ' + noFileCopy);
// Get a clean test document
if (noFileCopy !== true) {
if (subFolder === undefined) {
cy.task('copyFile', {
sourceDir: Cypress.env('DATA_FOLDER'),
destDir: Cypress.env('WORKDIR'),
fileName: fileName,
});
} else {
cy.task('copyFile', {
sourceDir: Cypress.env('DATA_FOLDER') + subFolder + '/',
destDir: Cypress.env('WORKDIR') + subFolder + '/',
fileName: fileName,
});
}
}
doIfOnMobile(function() {
cy.viewport('iphone-6');
});
// Open test document
var URI;
if (subFolder === undefined) {
URI = 'http://localhost:'+
Cypress.env('SERVER_PORT') +
'/loleaflet/' +
Cypress.env('WSD_VERSION_HASH') +
'/loleaflet.html?lang=en-US&file_path=file://' +
Cypress.env('WORKDIR') + fileName;
} else {
URI = 'http://localhost:'+
Cypress.env('SERVER_PORT') +
'/loleaflet/' +
Cypress.env('WSD_VERSION_HASH') +
'/loleaflet.html?lang=en-US&file_path=file://' +
Cypress.env('WORKDIR') + subFolder + '/' + fileName;
}
cy.log('Loading: ' + URI);
cy.visit(URI, {
onLoad: function(win) {
win.onerror = cy.onUncaughtException;
}});
// Wait for the document to fully load
cy.get('.leaflet-tile-loaded', {timeout : Cypress.config('defaultCommandTimeout') * 2.0});
// Wait for the sidebar to open.
doIfOnDesktop(function() {
cy.get('#sidebar-panel')
.should('be.visible');
// Check that the document does not take the whole window width.
cy.window()
.then(function(win) {
cy.get('#document-container')
.should(function(doc) {
expect(doc).to.have.lengthOf(1);
expect(doc[0].getBoundingClientRect().right).to.be.lessThan(win.innerWidth * 0.95);
});
});
});
cy.log('Loading test document - end.');
}
// Assert that NO keyboard input is accepted (i.e. keyboard should be HIDDEN).
function assertNoKeyboardInput() {
cy.get('textarea.clipboard')
.should('have.attr', 'data-accept-input', 'false');
}
// Assert that keyboard input is accepted (i.e. keyboard should be VISIBLE).
function assertHaveKeyboardInput() {
cy.get('textarea.clipboard')
.should('have.attr', 'data-accept-input', 'true');
}
// Assert that we have cursor and focus.
function assertCursorAndFocus() {
cy.log('Verifying Cursor and Focus.');
// Active element must be the textarea named clipboard.
cy.document().its('activeElement.className')
.should('be.eq', 'clipboard');
// In edit mode, we should have the blinking cursor.
cy.get('.leaflet-cursor.blinking-cursor')
.should('exist');
cy.get('.leaflet-cursor-container')
.should('exist');
assertHaveKeyboardInput();
cy.log('Cursor and Focus verified.');
}
// Select all text via CTRL+A shortcut.
function selectAllText(assertFocus = true) {
if (assertFocus)
assertCursorAndFocus();
cy.log('Select all text');
// Trigger select all
typeIntoDocument('{ctrl}a');
cy.get('.leaflet-marker-icon')
.should('exist');
}
// Clear all text by selecting all and deleting.
function clearAllText() {
assertCursorAndFocus();
cy.log('Clear all text');
// Trigger select all
typeIntoDocument('{ctrl}a');
cy.get('.leaflet-marker-icon')
.should('exist');
// Then remove
typeIntoDocument('{del}');
cy.get('.leaflet-marker-icon')
.should('not.exist');
}
// Check that the clipboard text matches with the specified text.
function expectTextForClipboard(expectedPlainText) {
doIfInWriter(function() {
cy.get('#copy-paste-container p font')
.should('have.text', expectedPlainText);
});
doIfInCalc(function() {
cy.get('#copy-paste-container pre')
.should('have.text', expectedPlainText);
});
doIfInImpress(function() {
cy.get('#copy-paste-container pre')
.should('have.text', expectedPlainText);
});
}
// Check that the clipboard text matches with the
// passed regular expression.
function matchClipboardText(regexp) {
doIfInWriter(function() {
cy.contains('#copy-paste-container p font', regexp)
.should('exist');
});
doIfInCalc(function() {
cy.contains('#copy-paste-container pre', regexp)
.should('exist');
});
doIfInImpress(function() {
cy.contains('#copy-paste-container pre', regexp)
.should('exist');
});
}
function beforeAll(fileName, subFolder, noFileCopy) {
loadTestDoc(fileName, subFolder, noFileCopy);
}
function afterAll(fileName) {
cy.log('Waiting for closing the document - start.');
cy.log('Param - fileName: ' + fileName);
// Make sure that the document is closed
cy.visit('http://admin:admin@localhost:' +
Cypress.env('SERVER_PORT') +
'/loleaflet/dist/admin/admin.html');
cy.get('#uptime')
.should('not.have.text', '0');
// We have all lines of document infos as one long string.
// We have PID number before the file names, with matching
// also on the PID number we can make sure to match on the
// whole file name, not on a suffix of a file name.
var regex = new RegExp('[0-9]' + fileName);
cy.get('#docview', { timeout: Cypress.config('defaultCommandTimeout') * 2.0 })
.invoke('text')
.should('not.match', regex);
cy.log('Waiting for closing the document - end.');
}
function initAliasToNegative(aliasName) {
cy.log('Initializing alias to a negative value - start.');
cy.log('Param - aliasName: ' + aliasName);
cy.get('#copy-paste-container')
.invoke('offset')
.its('top')
.as(aliasName);
cy.get('@' + aliasName)
.should('be.lessThan', 0);
cy.log('Initializing alias to a negative value - end.');
}
function initAliasToEmptyString(aliasName) {
cy.log('Initializing alias to empty string - start.');
cy.log('Param - aliasName: ' + aliasName);
// Do an empty slice to generate empty string
cy.get('#copy-paste-container')
.invoke('css', 'display')
.invoke('slice', '0', '0')
.as(aliasName);
cy.get('@' + aliasName)
.should('be.equal', '');
cy.log('Initializing alias to empty string - end.');
}
function doIfInCalc(callback) {
cy.get('#document-container')
.then(function(doc) {
if (doc.hasClass('spreadsheet-doctype')) {
callback();
}
});
}
function doIfInImpress(callback) {
cy.get('#document-container')
.then(function(doc) {
if (doc.hasClass('presentation-doctype')) {
callback();
}
});
}
function doIfInWriter(callback) {
cy.get('#document-container')
.then(function(doc) {
if (doc.hasClass('text-doctype')) {
callback();
}
});
}
// Types text into elem with a delay in between characters.
// Sometimes cy.type results in random character insertion,
// this avoids that, which is not clear why it happens.
function typeText(selector, text, delayMs=0) {
for (var i = 0; i < text.length; i++) {
cy.get(selector)
.type(text.charAt(i));
if (delayMs > 0)
cy.wait(delayMs);
}
}
function getLOVersion() {
var versionString = Cypress.env('LO_CORE_VERSION');
if (versionString.includes('Collabora')) {
if (versionString.includes('_6.2.')) {
return 'cp-6-2';
} else if (versionString.includes('_6.4.')) {
return 'cp-6-4';
}
}
return 'master';
}
function imageShouldBeFullWhiteOrNot(selector, fullWhite = true) {
cy.get(selector)
.should(function(images) {
var img = images[0];
// Create an offscreen canvas to check the image's pixels
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
var context = canvas.getContext('2d');
// Ignore a small zone on the edges, to ignore border.
var ignoredPixels = 2;
var pixelData = context.getImageData(ignoredPixels, ignoredPixels,
img.width - 2 * ignoredPixels,
img.height - 2 * ignoredPixels).data;
var allIsWhite = true;
for (var i = 0; i < pixelData.length; ++i) {
allIsWhite = allIsWhite && pixelData[i] == 255;
}
if (fullWhite)
expect(allIsWhite).to.be.true;
else
expect(allIsWhite).to.be.false;
});
}
function waitUntilIdle(selector, content, waitingTime = 1000) {
cy.log('Waiting item to be idle - start.');
cy.log('Param - selector: ' + selector);
cy.log('Param - content: ' + content);
cy.log('Param - waitingTime: ' + waitingTime);
var item;
var waitOnce = 250;
var idleSince = 0;
if (content) {
cy.contains(selector, content, { log: false })
.then(function(itemToIdle) {
item = itemToIdle;
});
cy.waitUntil(function() {
cy.wait(waitOnce, { log: false });
return cy.contains(selector, content, { log: false })
.then(function(itemToIdle) {
if (Cypress.dom.isDetached(item[0])) {
cy.log('Item is detached after ' + (idleSince + waitOnce).toString() + ' ms.');
item = itemToIdle;
idleSince = 0;
} else {
idleSince += waitOnce;
}
return idleSince > waitingTime;
});
});
} else {
cy.get(selector, { log: false })
.then(function(itemToIdle) {
item = itemToIdle;
});
cy.waitUntil(function() {
cy.wait(waitOnce, { log: false });
return cy.get(selector, { log: false })
.then(function(itemToIdle) {
if (Cypress.dom.isDetached(item[0])) {
cy.log('Item is detached after ' + (idleSince + waitOnce).toString() + ' ms.');
item = itemToIdle;
idleSince = 0;
} else {
idleSince += waitOnce;
}
return idleSince > waitingTime;
});
});
}
cy.log('Waiting item to be idle - end.');
}
// This is a workaround for avoid 'item detached from DOM'
// failures caused by GUI flickering.
// GUI flickering might mean bad design, but
// until it's fixed we can use this method.
// Known GUI flickering:
// * mobile wizard
// IMPORTANT: don't use this if there is no
// flickering. Use simple click() instead. This method
// is much slower.
function clickOnIdle(selector, content, waitingTime = 1000) {
cy.log('Clicking on item when idle - start.');
waitUntilIdle(selector, content, waitingTime);
if (content) {
cy.contains(selector, content)
.click();
} else {
cy.get(selector)
.click();
}
cy.log('Clicking on item when idle - end.');
}
// See comments at clickOnIdle() method.
function inputOnIdle(selector, input, waitingTime = 1000) {
cy.log('Type into an input item when idle - start.');
waitUntilIdle(selector, undefined, waitingTime);
cy.get(selector)
.clear()
.type(input)
.type('{enter}');
cy.log('Type into an input item when idle - end.');
}
function doIfOnMobile(callback) {
cy.window()
.then(function(win) {
if (win.navigator.userAgent === 'cypress-mobile') {
callback();
}
});
}
function doIfOnDesktop(callback) {
cy.window()
.then(function(win) {
if (win.navigator.userAgent === 'cypress') {
callback();
}
});
}
function moveCursor(direction) {
cy.log('Moving text cursor - start.');
cy.log('Param - direction: ' + direction);
initAliasToNegative('origCursorPos');
cy.get('.blinking-cursor')
.should('exist');
if (direction === 'up' || direction === 'down') {
cy.get('.blinking-cursor')
.invoke('offset')
.its('top')
.as('origCursorPos');
} else if (direction === 'left' || direction === 'right') {
cy.get('.blinking-cursor')
.invoke('offset')
.its('left')
.as('origCursorPos');
}
cy.get('@origCursorPos')
.should('be.at.least', 0);
var key = '';
if (direction === 'up') {
key = '{uparrow}';
} else if (direction === 'down') {
key = '{downarrow}';
} else if (direction === 'left') {
key = '{leftarrow}';
} else if (direction === 'right') {
key = '{rightarrow}';
}
typeIntoDocument(key);
cy.get('@origCursorPos')
.then(function(origCursorPos) {
cy.get('.blinking-cursor')
.should(function(cursor) {
if (direction === 'up') {
expect(cursor.offset().top).to.be.lessThan(origCursorPos);
} else if (direction === 'down') {
expect(cursor.offset().top).to.be.greaterThan(origCursorPos);
} else if (direction === 'left') {
expect(cursor.offset().left).to.be.lessThan(origCursorPos);
} else if (direction === 'right') {
expect(cursor.offset().left).to.be.greaterThan(origCursorPos);
}
});
});
cy.log('Moving text cursor - end.');
}
function typeIntoDocument(text) {
cy.get('textarea.clipboard')
.focus();
cy.document().its('activeElement.tagName')
.should('be.eq', 'TEXTAREA');
cy.document().its('activeElement.className')
.should('be.eq', 'clipboard');
cy.get('textarea.clipboard')
.type(text, {force: true});
}
module.exports.loadTestDoc = loadTestDoc;
module.exports.assertCursorAndFocus = assertCursorAndFocus;
module.exports.assertNoKeyboardInput = assertNoKeyboardInput;
module.exports.assertHaveKeyboardInput = assertHaveKeyboardInput;
module.exports.selectAllText = selectAllText;
module.exports.clearAllText = clearAllText;
module.exports.expectTextForClipboard = expectTextForClipboard;
module.exports.matchClipboardText = matchClipboardText;
module.exports.afterAll = afterAll;
module.exports.initAliasToNegative = initAliasToNegative;
module.exports.initAliasToEmptyString = initAliasToEmptyString;
module.exports.doIfInCalc = doIfInCalc;
module.exports.doIfInImpress = doIfInImpress;
module.exports.doIfInWriter = doIfInWriter;
module.exports.beforeAll = beforeAll;
module.exports.typeText = typeText;
module.exports.getLOVersion = getLOVersion;
module.exports.imageShouldBeFullWhiteOrNot = imageShouldBeFullWhiteOrNot;
module.exports.clickOnIdle = clickOnIdle;
module.exports.inputOnIdle = inputOnIdle;
module.exports.waitUntilIdle = waitUntilIdle;
module.exports.doIfOnMobile = doIfOnMobile;
module.exports.doIfOnDesktop = doIfOnDesktop;
module.exports.moveCursor = moveCursor;
module.exports.typeIntoDocument = typeIntoDocument;