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 : / A c c e s s i b i l i t y M o d e / 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 : / V i e w C o n t r o l s / i } ) . click ( ) ;
255+ await iframe . getByRole ( 'button' , { name : / A c c e s s i b i l i t y M o d e / 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 : / V i e w C o n t r o l s / i } ) . click ( ) ;
307+ await iframe . getByRole ( 'button' , { name : / A c c e s s i b i l i t y M o d e / 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 : / A c c e s s i b i l i t y M o d e / 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 : / A c c e s s i b i l i t y M o d e / 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