@@ -491,6 +491,136 @@ test('toHaveAccessibleDescription', async ({ page }) => {
491
491
await expect ( page . locator ( 'div' ) ) . toHaveAccessibleDescription ( 'foo bar baz' ) ;
492
492
} ) ;
493
493
494
+ test ( 'toHaveAccessibleErrorMessage' , async ( { page } ) => {
495
+ await page . setContent ( `
496
+ <form>
497
+ <input role="textbox" aria-invalid="true" aria-errormessage="error-message" />
498
+ <div id="error-message">Hello</div>
499
+ <div id="irrelevant-error">This should not be considered.</div>
500
+ </form>
501
+ ` ) ;
502
+
503
+ const locator = page . locator ( 'input[role="textbox"]' ) ;
504
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( 'Hello' ) ;
505
+ await expect ( locator ) . not . toHaveAccessibleErrorMessage ( 'hello' ) ;
506
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( 'hello' , { ignoreCase : true } ) ;
507
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( / e l l \w / ) ;
508
+ await expect ( locator ) . not . toHaveAccessibleErrorMessage ( / h e l l o / ) ;
509
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( / h e l l o / , { ignoreCase : true } ) ;
510
+ await expect ( locator ) . not . toHaveAccessibleErrorMessage ( 'This should not be considered.' ) ;
511
+ } ) ;
512
+
513
+ test ( 'toHaveAccessibleErrorMessage should handle multiple aria-errormessage references' , async ( { page } ) => {
514
+ await page . setContent ( `
515
+ <form>
516
+ <input role="textbox" aria-invalid="true" aria-errormessage="error1 error2" />
517
+ <div id="error1">First error message.</div>
518
+ <div id="error2">Second error message.</div>
519
+ <div id="irrelevant-error">This should not be considered.</div>
520
+ </form>
521
+ ` ) ;
522
+
523
+ const locator = page . locator ( 'input[role="textbox"]' ) ;
524
+
525
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( 'First error message. Second error message.' ) ;
526
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( / f i r s t e r r o r m e s s a g e ./ i) ;
527
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( / s e c o n d e r r o r m e s s a g e ./ i) ;
528
+ await expect ( locator ) . not . toHaveAccessibleErrorMessage ( / T h i s s h o u l d n o t b e c o n s i d e r e d ./ i) ;
529
+ } ) ;
530
+
531
+ test . describe ( 'toHaveAccessibleErrorMessage should handle aria-invalid attribute' , ( ) => {
532
+ const errorMessageText = 'Error message' ;
533
+
534
+ async function setupPage ( page , ariaInvalidValue : string | null ) {
535
+ const ariaInvalidAttr = ariaInvalidValue === null ? '' : `aria-invalid="${ ariaInvalidValue } "` ;
536
+ await page . setContent ( `
537
+ <form>
538
+ <input id="node" role="textbox" ${ ariaInvalidAttr } aria-errormessage="error-msg" />
539
+ <div id="error-msg">${ errorMessageText } </div>
540
+ </form>
541
+ ` ) ;
542
+ return page . locator ( '#node' ) ;
543
+ }
544
+
545
+ test . describe ( 'evaluated in false' , ( ) => {
546
+ test ( 'no aria-invalid attribute' , async ( { page } ) => {
547
+ const locator = await setupPage ( page , null ) ;
548
+ await expect ( locator ) . not . toHaveAccessibleErrorMessage ( errorMessageText ) ;
549
+ } ) ;
550
+ test ( 'aria-invalid="false"' , async ( { page } ) => {
551
+ const locator = await setupPage ( page , 'false' ) ;
552
+ await expect ( locator ) . not . toHaveAccessibleErrorMessage ( errorMessageText ) ;
553
+ } ) ;
554
+ test ( 'aria-invalid="" (empty string)' , async ( { page } ) => {
555
+ const locator = await setupPage ( page , '' ) ;
556
+ await expect ( locator ) . not . toHaveAccessibleErrorMessage ( errorMessageText ) ;
557
+ } ) ;
558
+ } ) ;
559
+ test . describe ( 'evaluated in true' , ( ) => {
560
+ test ( 'aria-invalid="true"' , async ( { page } ) => {
561
+ const locator = await setupPage ( page , 'true' ) ;
562
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( errorMessageText ) ;
563
+ } ) ;
564
+ test ( 'aria-invalid="foo" (unrecognized value)' , async ( { page } ) => {
565
+ const locator = await setupPage ( page , 'foo' ) ;
566
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( errorMessageText ) ;
567
+ } ) ;
568
+ } ) ;
569
+ } ) ;
570
+
571
+ test . describe ( 'toHaveAccessibleErrorMessage should handle validity state with aria-invalid' , ( ) => {
572
+ const errorMessageText = 'Error message' ;
573
+
574
+ test ( 'should show error message when validity is false and aria-invalid is true' , async ( { page } ) => {
575
+ await page . setContent ( `
576
+ <form>
577
+ <input id="node" role="textbox" type="number" min="1" max="100" aria-invalid="true" aria-errormessage="error-msg" />
578
+ <div id="error-msg">${ errorMessageText } </div>
579
+ </form>
580
+ ` ) ;
581
+ const locator = page . locator ( '#node' ) ;
582
+ await locator . fill ( '101' ) ;
583
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( errorMessageText ) ;
584
+ } ) ;
585
+
586
+ test ( 'should show error message when validity is true and aria-invalid is true' , async ( { page } ) => {
587
+ await page . setContent ( `
588
+ <form>
589
+ <input id="node" role="textbox" type="number" min="1" max="100" aria-invalid="true" aria-errormessage="error-msg" />
590
+ <div id="error-msg">${ errorMessageText } </div>
591
+ </form>
592
+ ` ) ;
593
+ const locator = page . locator ( '#node' ) ;
594
+ await locator . fill ( '99' ) ;
595
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( errorMessageText ) ;
596
+ } ) ;
597
+
598
+ test ( 'should show error message when validity is false and aria-invalid is false' , async ( { page } ) => {
599
+ await page . setContent ( `
600
+ <form>
601
+ <input id="node" role="textbox" type="number" min="1" max="100" aria-invalid="false" aria-errormessage="error-msg" />
602
+ <div id="error-msg">${ errorMessageText } </div>
603
+ </form>
604
+ ` ) ;
605
+ const locator = page . locator ( '#node' ) ;
606
+ await locator . fill ( '101' ) ;
607
+ await expect ( locator ) . toHaveAccessibleErrorMessage ( errorMessageText ) ;
608
+ } ) ;
609
+
610
+ test ( 'should not show error message when validity is true and aria-invalid is false' , async ( { page } ) => {
611
+ await page . setContent ( `
612
+ <form>
613
+ <input id="node" role="textbox" type="number" min="1" max="100" aria-invalid="false" aria-errormessage="error-msg" />
614
+ <div id="error-msg">${ errorMessageText } </div>
615
+ </form>
616
+ ` ) ;
617
+ const locator = page . locator ( '#node' ) ;
618
+ await locator . fill ( '99' ) ;
619
+ await expect ( locator ) . not . toHaveAccessibleErrorMessage ( errorMessageText ) ;
620
+ } ) ;
621
+ } ) ;
622
+
623
+
494
624
test ( 'toHaveRole' , async ( { page } ) => {
495
625
await page . setContent ( `<div role="button">Button!</div>` ) ;
496
626
await expect ( page . locator ( 'div' ) ) . toHaveRole ( 'button' ) ;
0 commit comments