Skip to content

Commit 9278ef3

Browse files
[Misc] ARO Mode Update 11.7 (#11539)
(r11.7 → 11.7)
1 parent 5f30e2f commit 9278ef3

File tree

2 files changed

+403
-0
lines changed

2 files changed

+403
-0
lines changed
Lines changed: 391 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,391 @@
1+
import {
2+
getUIMode,
3+
test,
4+
WebViewerInstance,
5+
setupWebViewer,
6+
waitForWVEvent,
7+
evaluateAndWaitForEvent,
8+
} from '../../playwright-utility-setup';
9+
import { expect, Frame, Page } from '@playwright/test';
10+
11+
test.describe('Accessible Mode Tests', () => {
12+
let iframe: Frame | Page;
13+
let instance: WebViewerInstance;
14+
15+
const isAROModeEnabled = async (iframe: Frame | Page) => {
16+
return iframe.evaluate(() => {
17+
return window.instance.Core.documentViewer.getAccessibleReadingOrderManager().isInAccessibleReadingOrderMode();
18+
});
19+
};
20+
21+
test.describe('Loading a XOD file', () => {
22+
test.beforeEach(async ({ page }) => {
23+
const {
24+
iframe: iframeRef,
25+
instance: instanceWebViewer,
26+
} = await setupWebViewer({
27+
page,
28+
samplePath: 'advanced/accessibility',
29+
});
30+
31+
iframe = iframeRef;
32+
instance = instanceWebViewer;
33+
34+
await expect(async () => {
35+
await evaluateAndWaitForEvent(
36+
iframe,
37+
async () => window.instance.Core.documentViewer.loadDocument('/test-files/demo-annotated.xod'),
38+
'AccessibleReadingOrderManager.accessibleReadingOrderModeNoStructure',
39+
);
40+
}).toPass();
41+
42+
const loadingModal = iframe.locator('[data-element="loadingModal"]');
43+
await expect(async () => {
44+
await expect(loadingModal).toHaveCount(0);
45+
}).toPass();
46+
});
47+
48+
// Flaky test: https://app.circleci.com/pipelines/github/XodoDocs/webviewer/123371/workflows/e28c18bd-f750-4335-b6f1-22752562fbcc/jobs/151298/tests
49+
// Jira ticket: https://apryse.atlassian.net/browse/WVR-7712
50+
test.skip('Should tab into the current page from outside of the document', async ({ page, browserName }, testInfo) => {
51+
test.skip(testInfo.project.use.webComponent, 'TODO: This test is failing when using with web component');
52+
test.skip(browserName === 'webkit', 'TODO: investigate why this test is flaky on webkit');
53+
54+
await iframe.evaluate(async () => {
55+
window.instance.Core.documentViewer.setCurrentPage(2);
56+
});
57+
58+
await waitForWVEvent(iframe, 'pageComplete');
59+
60+
let currentPageNumber = await iframe.evaluate(async () => {
61+
return instance.Core.documentViewer.getCurrentPage();
62+
});
63+
expect(currentPageNumber).toBe(2);
64+
65+
await instance('closeElements', ['loadingModal']);
66+
67+
const notesPanelButtonSelector = (getUIMode() === 'default') ? 'notesPanelToggle' : 'toggleNotesButton';
68+
await iframe.locator(`[data-element="${notesPanelButtonSelector}"]`).click();
69+
70+
await page.keyboard.press('Tab');
71+
72+
currentPageNumber = await iframe.evaluate(async () => {
73+
return instance.Core.documentViewer.getCurrentPage();
74+
});
75+
expect(currentPageNumber).toBe(2);
76+
});
77+
78+
test.skip('Should go to the correct page when pressing the document button in accessibility popup', async ({ page, browserName }) => {
79+
test.skip(browserName === 'webkit', 'TODO: investigate why this test is flaky on webkit');
80+
81+
await iframe.evaluate(async () => {
82+
window.instance.Core.documentViewer.setCurrentPage(9);
83+
});
84+
85+
await waitForWVEvent(iframe, 'pageComplete');
86+
87+
let currentPageNumber = await iframe.evaluate(async () => {
88+
return instance.Core.documentViewer.getCurrentPage();
89+
});
90+
expect(currentPageNumber).toBe(9);
91+
92+
await page.locator('#play').click();
93+
94+
// press tab 6 times to get to the accessibility popup
95+
// timeout of 200 used to make test more consistent
96+
await page.keyboard.press('Tab');
97+
// eslint-disable-next-line playwright/no-wait-for-timeout
98+
await page.waitForTimeout(200);
99+
await page.keyboard.press('Tab');
100+
// eslint-disable-next-line playwright/no-wait-for-timeout
101+
await page.waitForTimeout(200);
102+
await page.keyboard.press('Tab');
103+
// eslint-disable-next-line playwright/no-wait-for-timeout
104+
await page.waitForTimeout(200);
105+
await page.keyboard.press('Tab');
106+
// eslint-disable-next-line playwright/no-wait-for-timeout
107+
await page.waitForTimeout(200);
108+
await page.keyboard.press('Tab');
109+
// eslint-disable-next-line playwright/no-wait-for-timeout
110+
await page.waitForTimeout(200);
111+
await page.keyboard.press('Tab');
112+
// eslint-disable-next-line playwright/no-wait-for-timeout
113+
await page.waitForTimeout(200);
114+
115+
await page.keyboard.press('Enter');
116+
// eslint-disable-next-line playwright/no-wait-for-timeout
117+
await page.waitForTimeout(200);
118+
119+
currentPageNumber = await iframe.evaluate(async () => {
120+
return instance.Core.documentViewer.getCurrentPage();
121+
});
122+
expect(currentPageNumber).toBe(9);
123+
});
124+
125+
test('Tabs correctly through pages and links', async ({ page, browserName }, testInfo) => {
126+
test.skip(testInfo.project.use.webComponent, 'TODO: This test is failing when using with web component');
127+
test.skip(browserName === 'firefox' || browserName === 'webkit', 'TODO: investigate why this test fails on webkit and firefox');
128+
129+
// add a link
130+
await evaluateAndWaitForEvent(
131+
iframe,
132+
async () => {
133+
const core = window.instance.Core;
134+
135+
const annot = new core.Annotations.RectangleAnnotation({
136+
PageNumber: 1,
137+
X: 50,
138+
Y: 100,
139+
Width: 150,
140+
Height: 100,
141+
});
142+
143+
core.annotationManager.addAnnotation(annot);
144+
core.annotationManager.redrawAnnotation(annot);
145+
146+
const annotations = core.annotationManager.getAnnotationsList();
147+
const targetAnnotation = annotations[0];
148+
149+
const newLink = new core.Annotations.Link();
150+
newLink.PageNumber = targetAnnotation.PageNumber;
151+
newLink.X = targetAnnotation.X;
152+
newLink.Y = targetAnnotation.Y;
153+
newLink.Width = targetAnnotation.Width;
154+
newLink.Height = targetAnnotation.Height;
155+
156+
newLink.addAction(
157+
'U',
158+
new core.Actions.URI({
159+
uri: 'https://www.apryse.com',
160+
}),
161+
);
162+
163+
core.annotationManager.addAnnotation(newLink);
164+
core.annotationManager.groupAnnotations(targetAnnotation, [newLink]);
165+
core.annotationManager.drawAnnotationsFromList(newLink);
166+
},
167+
'annotManager.annotationsDrawn'
168+
);
169+
170+
await page.locator('#play').click();
171+
172+
// press the document button in the accessibility popup
173+
// timeout of 200 used to make test more consistent
174+
await page.keyboard.press('Tab');
175+
// eslint-disable-next-line playwright/no-wait-for-timeout
176+
await page.waitForTimeout(200);
177+
await page.keyboard.press('Tab');
178+
// eslint-disable-next-line playwright/no-wait-for-timeout
179+
await page.waitForTimeout(200);
180+
await page.keyboard.press('Tab');
181+
// eslint-disable-next-line playwright/no-wait-for-timeout
182+
await page.waitForTimeout(200);
183+
await page.keyboard.press('Tab');
184+
// eslint-disable-next-line playwright/no-wait-for-timeout
185+
await page.waitForTimeout(200);
186+
await page.keyboard.press('Tab');
187+
// eslint-disable-next-line playwright/no-wait-for-timeout
188+
await page.waitForTimeout(200);
189+
await page.keyboard.press('Tab');
190+
// eslint-disable-next-line playwright/no-wait-for-timeout
191+
await page.waitForTimeout(200);
192+
193+
await page.keyboard.press('Enter');
194+
// eslint-disable-next-line playwright/no-wait-for-timeout
195+
await page.waitForTimeout(200);
196+
197+
// should be on page 1
198+
let currentPageNumber = await iframe.evaluate(async () => {
199+
return instance.Core.documentViewer.getCurrentPage();
200+
});
201+
expect(currentPageNumber).toBe(1);
202+
203+
// first tab on page 1 should go to link
204+
await page.keyboard.press('Tab');
205+
// eslint-disable-next-line playwright/no-wait-for-timeout
206+
await page.waitForTimeout(200);
207+
// second tab should go to page 2
208+
await page.keyboard.press('Tab');
209+
// eslint-disable-next-line playwright/no-wait-for-timeout
210+
await page.waitForTimeout(200);
211+
212+
currentPageNumber = await iframe.evaluate(async () => {
213+
return instance.Core.documentViewer.getCurrentPage();
214+
});
215+
expect(currentPageNumber).toBe(2);
216+
});
217+
218+
test('Should be able to toggle a11y mode ON and OFF with the preset button', async () => {
219+
test.skip(getUIMode() !== 'default', 'Test only works in Modular UI');
220+
221+
// Customize header by adding a button to it
222+
await iframe.evaluate(() => {
223+
const toggleA11yModeButton = {
224+
'dataElement': 'toggleAccessibilityModePresetButton',
225+
'type': 'presetButton',
226+
'buttonType': 'toggleAccessibilityModeButton',
227+
};
228+
229+
const mainHeader = window.instance.UI.getModularHeader('default-top-header');
230+
const updatedItems = [...mainHeader.items, toggleA11yModeButton];
231+
mainHeader.setItems(updatedItems);
232+
});
233+
234+
const toggleA11yModeButton = iframe.getByRole('button', { name: /Accessibility Mode/i });
235+
await expect(toggleA11yModeButton).toBeVisible();
236+
expect(await isAROModeEnabled(iframe)).toBe(true);
237+
await toggleA11yModeButton.click();
238+
expect(await isAROModeEnabled(iframe)).toBe(false);
239+
});
240+
241+
test('Should turn the ARO mode on, add the accessible mode content and be able to turn the mode off via UI', async () => {
242+
test.skip(getUIMode() !== 'default', 'Test only works in Modular UI');
243+
expect(await isAROModeEnabled(iframe)).toBe(true);
244+
245+
// ARO mode content should not be added
246+
const a11yContentBoxes = iframe.locator('[data-element^="a11y-reader-content"]');
247+
await expect(a11yContentBoxes).toHaveCount(0);
248+
249+
// Legacy Accessible mode content should be added
250+
const accessibleModeContent = iframe.locator('[id^="pageText"]');
251+
await expect(accessibleModeContent).toHaveCount(2);
252+
253+
254+
await iframe.getByRole('button', { name: /View Controls/i }).click();
255+
await iframe.getByRole('button', { name: /Accessibility Mode/i }).click();
256+
expect(await isAROModeEnabled(iframe)).toBe(false);
257+
258+
// Legacy Accessible mode content should be removed
259+
const accessibleModeContentAfterDisableMode = iframe.locator('[id^="pageText"]');
260+
await expect(accessibleModeContentAfterDisableMode).toHaveCount(0);
261+
});
262+
});
263+
264+
test.describe('Loading a PDF file', () => {
265+
test.beforeEach(async ({ page }) => {
266+
const {
267+
iframe: iframeRef,
268+
} = await setupWebViewer(
269+
{
270+
page,
271+
samplePath: 'advanced/accessibility',
272+
},
273+
);
274+
iframe = iframeRef;
275+
await expect(async () => {
276+
expect(await isAROModeEnabled(iframe)).toBe(true);
277+
}).toPass();
278+
279+
const loadingModal = iframe.locator('[data-element="loadingModal"]');
280+
await expect(async () => {
281+
await expect(loadingModal).toHaveCount(0);
282+
}).toPass();
283+
284+
await expect(async () => {
285+
await evaluateAndWaitForEvent(
286+
iframe,
287+
async () => window.instance.Core.documentViewer.loadDocument('/test-files/pdf-ua/basic-three-page-doc.pdf'),
288+
'AccessibleReadingOrderManager.accessibleReadingOrderModeReady',
289+
);
290+
}).toPass();
291+
});
292+
test('Should activate the Accessible Reading Order Mode without errors and add the appropriate a11y DOM elements', async () => {
293+
const a11yPageContainers = iframe.locator('[data-element^="a11y-reader-container"]');
294+
await expect(a11yPageContainers).toHaveCount(3);
295+
296+
const a11yPage1 = a11yPageContainers.nth(0);
297+
const a11yPage1Elements = a11yPage1.locator('[data-element^="a11y-reader-content"]');
298+
await expect(a11yPage1Elements).toHaveCount(7);
299+
});
300+
301+
// test doesn't pass 150 times
302+
// https://apryse.atlassian.net/browse/WVR-9440
303+
test.skip('Should add the accessibility mode toggle option to the View controls and be able to toggle the mode ON and OFF', async () => {
304+
test.skip(getUIMode() !== 'default', 'Test only works in Modular UI');
305+
expect(await isAROModeEnabled(iframe)).toBe(true);
306+
await iframe.getByRole('button', { name: /View Controls/i }).click();
307+
await iframe.getByRole('button', { name: /Accessibility Mode/i }).click();
308+
expect(await isAROModeEnabled(iframe)).toBe(false);
309+
const a11yPageContainers = iframe.locator('[data-element^="a11y-reader-container"]');
310+
await expect(a11yPageContainers).toHaveCount(0);
311+
await iframe.getByRole('button', { name: /Accessibility Mode/i }).click();
312+
expect(await isAROModeEnabled(iframe)).toBe(true);
313+
const a11yPageContainersAfterEnablingAgain = iframe.locator('[data-element^="a11y-reader-container"]');
314+
await expect(a11yPageContainersAfterEnablingAgain).toHaveCount(3);
315+
});
316+
317+
test('should update the accessibility DOM based on whether the opened file is structured or unstructured', async () => {
318+
// The PDF file loaded is structured so the a11y content should be added
319+
await expect(iframe.locator('[data-element^="a11y-reader-container"]')).toHaveCount(3);
320+
321+
await evaluateAndWaitForEvent(
322+
iframe,
323+
async () => window.instance.Core.documentViewer.loadDocument('/test-files/demo-annotated.pdf'),
324+
'AccessibleReadingOrderManager.accessibleReadingOrderModeNoStructure',
325+
);
326+
327+
// After loading a non-structured file, the a11y content should be removed
328+
await expect(iframe.locator('[data-element^="a11y-reader-container"]')).toHaveCount(0);
329+
// And the legacy accessible content should be added
330+
await expect(iframe.locator('[id^="pageText"]')).toHaveCount(9);
331+
332+
await evaluateAndWaitForEvent(
333+
iframe,
334+
async () => window.instance.Core.documentViewer.loadDocument('/test-files/pdf-ua/PDFUA-Ref-2-02_Invoice.pdf'),
335+
'AccessibleReadingOrderManager.accessibleReadingOrderModeReady'
336+
);
337+
// Opening a structured PDF file again and should add the a11y content and remove the legacy accessible content
338+
await expect(iframe.locator('[data-element^="a11y-reader-container"]')).toHaveCount(1);
339+
await expect(iframe.locator('[id^="pageText"]')).toHaveCount(0);
340+
});
341+
342+
test('should load the legacy accessibility content when the file is incorrectly tagged', async () => {
343+
expect(await isAROModeEnabled(iframe)).toBe(true);
344+
await evaluateAndWaitForEvent(
345+
iframe,
346+
async () => window.instance.Core.documentViewer.loadDocument('/test-files/incorrectly-tagged.pdf'),
347+
'AccessibleReadingOrderManager.accessibleReadingOrderModeNoStructure',
348+
);
349+
350+
const accessibleModeContent = iframe.locator('[id^="pageText"]');
351+
await expect(accessibleModeContent).toHaveCount(3);
352+
});
353+
});
354+
355+
356+
test.describe('Accessible mode and Full API OFF', () => {
357+
test('should log a warning when the user tries to enable accessibility mode using the preset button', async ({ page }) => {
358+
test.skip(getUIMode() !== 'default', 'Test only works in Modular UI');
359+
const { iframe, consoleLogs } = await setupWebViewer({
360+
page,
361+
samplePath: 'viewing/viewing',
362+
});
363+
364+
const isAROModeEnabled = async () => {
365+
return iframe.evaluate(() => {
366+
return window.instance.Core.documentViewer.getAccessibleReadingOrderManager().isInAccessibleReadingOrderMode();
367+
});
368+
};
369+
370+
expect(await isAROModeEnabled()).toBe(false);
371+
372+
await iframe.evaluate(() => {
373+
const toggleA11yModeButton = {
374+
'dataElement': 'toggleAccessibilityModePresetButton',
375+
'type': 'presetButton',
376+
'buttonType': 'toggleAccessibilityModeButton',
377+
};
378+
379+
const mainHeader = window.instance.UI.getModularHeader('default-top-header');
380+
const updatedItems = [...mainHeader.items, toggleA11yModeButton];
381+
mainHeader.setItems(updatedItems);
382+
});
383+
384+
const toggleA11yModeButton = iframe.getByRole('button', { name: /Accessibility Mode/i });
385+
await expect(toggleA11yModeButton).toBeVisible();
386+
await toggleA11yModeButton.click();
387+
expect(await isAROModeEnabled(iframe)).toBe(false);
388+
expect(consoleLogs).toContain('FullAPI is required to use accessibility mode');
389+
});
390+
});
391+
});

0 commit comments

Comments
 (0)