Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion browser/src/app/LayoutingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class LayoutingService {
null;
private _layoutTasks: Array<LayoutingTask> = [];
private _layoutTaskFlush: ReturnType<typeof setTimeout> | null = null;
private _drainCallbacks: Array<LayoutingTask> = [];

// get something around 25 fps as minimum (35ms + some overflow = ~40ms)
private MAX_TASK_DURATION_MS = 35;
Expand All @@ -36,6 +37,11 @@ class LayoutingService {
return this._layoutTasks.length > 0;
}

public onDrain(callback: LayoutingTask): void {
this._drainCallbacks.push(callback);
this._scheduleLayouting();
}

public runTheTopTask(): boolean {
const task = this._layoutTasks.shift();
if (!task) return false;
Expand Down Expand Up @@ -71,7 +77,10 @@ class LayoutingService {

private _flushLayoutingQueue(): void {
this._layoutTaskFlush = null;
if (!this.hasTasksPending()) return;
if (!this.hasTasksPending()) {
this._runDrainCallbacks();
return;
}

this._requestedFrame = window.requestAnimationFrame(() => {
this._requestedFrame = null;
Expand All @@ -83,9 +92,22 @@ class LayoutingService {
return;
}
}
this._runDrainCallbacks();
});
}

private _runDrainCallbacks(): void {
const callbacks = this._drainCallbacks;
this._drainCallbacks = [];
for (const cb of callbacks) {
try {
cb();
} catch (ex) {
console.error('Drain callback exception: ' + ex);
}
}
}

private _scheduleLayouting(): void {
if (this._layoutTaskFlush) return;
this._setupTimer();
Expand Down
15 changes: 7 additions & 8 deletions browser/src/control/Control.JSDialogBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -2548,15 +2548,14 @@ window.L.Control.JSDialogBuilder = window.L.Control.extend({
control.setAttribute('tabIndex', '0');

if (control && window.L.Browser.cypressTest && window.app.a11yValidator) {
// setupA11yLabelForLabelableElement uses two layouting task depth,
// so use three here to do this test after those have added the labels
// Various things use multiple layouting task depths, like
// setupA11yLabelForLabelableElement which uses a layouting
// depth of two, to add a11y properties. We want this task to
// happen after those tasks so schedule a layout task and
// fun the checkWidget when all layout tasks have completed.
app.layoutingService.appendLayoutingTask(() => {
app.layoutingService.appendLayoutingTask(() => {
app.layoutingService.appendLayoutingTask(() => {
app.layoutingService.appendLayoutingTask(() => {
window.app.a11yValidator.checkWidget(data.type, control);
});
});
app.layoutingService.onDrain(() => {
window.app.a11yValidator.checkWidget(data.type, control);
});
});
}
Expand Down
46 changes: 23 additions & 23 deletions cypress_test/integration_tests/desktop/writer/a11y_dialog_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,14 @@ describe(['tagdesktop'], 'Accessibility Writer Tests', function () {
cy.log(`Skipping missing-context dialog: ${command}`);
return;
}
// not jsdialog enabled
if (command == '.uno:ChapterNumberingDialog') {
cy.log(`Skipping non-jsdialog dialog: ${command}`);
return;
}
// don't pass yet
if (command == '.uno:FormatColumns' ||
command == '.uno:InsertBreak' ||
command == '.uno:InsertFrame' ||
if (command == '.uno:InsertFrame' ||
command == '.uno:InsertIndexesEntry' ||
command == '.uno:InsertMultiIndex' ||
command == '.uno:LineNumberingDialog' ||
command == '.uno:PageDialog' ||
command == '.uno:ParagraphDialog' ||
command == '.uno:SpellingAndGrammarDialog' ||
command == '.uno:TableNumberFormatDialog' ||
command == '.uno:Watermark') {
command == '.uno:SpellingAndGrammarDialog') {
cy.log(`Skipping buggy dialog: ${command}`);
return;
}
Expand All @@ -96,13 +89,10 @@ describe(['tagdesktop'], 'Accessibility Writer Tests', function () {

// ContentControlProperties dialog
cy.then(() => {
win.app.map.sendUnoCommand('.uno:InsertCheckboxContentControl');
});
helper.typeIntoDocument('{rightarrow}');
cy.then(() => {
win.app.map.sendUnoCommand('.uno:InsertDropdownContentControl');
win.app.map.sendUnoCommand('.uno:ContentControlProperties');
});
handleDialog(1);
handleDialog(1, '.uno:ContentControlProperties');

// Text ReadOnly info dialog
helper.clearAllText();
Expand All @@ -129,7 +119,7 @@ describe(['tagdesktop'], 'Accessibility Writer Tests', function () {
}
});

cy.spy(win.app.socket, '_onMessage').as('onMessage');
cy.spy(win.app.socket, '_onMessage').as('onMessage').log(false);

// add to the cypress queue to be run after the dialogs are processed
// and errors checked
Expand Down Expand Up @@ -171,7 +161,6 @@ describe(['tagdesktop'], 'Accessibility Writer Tests', function () {

function handleDialog(level, command) {
getActiveDialog(level)
.should('exist')
.then(() => {
// Open 'options' subdialogs
if (command == '.uno:EditRegion' ||
Expand All @@ -181,6 +170,9 @@ describe(['tagdesktop'], 'Accessibility Writer Tests', function () {
} else if (command == '.uno:InsertIndexesEntry') {
cy.cGet('#new-button').click();
handleDialog(level + 1);
} else if (command == '.uno:ContentControlProperties') {
cy.cGet('#add-button').click();
handleDialog(level + 1);
}

handleTabsInDialog(level);
Expand All @@ -190,8 +182,8 @@ describe(['tagdesktop'], 'Accessibility Writer Tests', function () {

function getActiveDialog(level) {
return cy.cGet('.ui-dialog[role="dialog"]')
.should('have.length.at.least', level)
.last();
.should('have.length', level)
.then($dialogs => cy.wrap($dialogs.last()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the difference here .then(...) vs .last()?

I stopped to use then for getters if there is no reason behind (we were failing on that in the past).
It's meant to be used for one-time "actions" (no auto-retry is provided).
https://docs.cypress.io/api/commands/should#Differences

}

function handleTabsInDialog(level) {
Expand Down Expand Up @@ -279,9 +271,17 @@ describe(['tagdesktop'], 'Accessibility Writer Tests', function () {
}

function closeActiveDialog(level) {
getActiveDialog(level).within(() => {
cy.get('.ui-dialog-titlebar-close').click({ force: true });
});
// Closing the dialog via the titlebar directly can be fragile.
// So find the jsdialog ancestor, because it has a unique id,
// and use that id to make a selector and a get via that is
// retryable by cypress.
getActiveDialog(level)
.parents('.jsdialog-window')
.invoke('attr', 'id')
.then(dialogId => {
cy.cGet(`#${CSS.escape(dialogId)} .ui-dialog-titlebar-close`)
.click();
});

cy.cGet('.ui-dialog[role="dialog"]').should('have.length', level - 1);
}
Expand Down
Loading