@@ -336,6 +336,7 @@ describe('Localization', () => {
336336 await waitForFormReady ( page )
337337 await changeLocale ( page , defaultLocale )
338338 await page . locator ( '#field-title' ) . fill ( englishTitle )
339+ await page . locator ( 'button.tabs-field__tab-button' , { hasText : 'Main Nav' } ) . click ( )
339340 await page . locator ( '#field-nav__layout .blocks-field__drawer-toggler' ) . click ( )
340341 await page . locator ( 'button[title="Text"]' ) . click ( )
341342 await page . locator ( '#field-nav__layout__0__text' ) . waitFor ( { state : 'visible' } )
@@ -894,7 +895,7 @@ describe('Localization', () => {
894895 await changeLocale ( page , defaultLocale )
895896 await fillValues ( { title : 'English Title' } )
896897 await saveDocAndAssert ( page )
897- const id = await page . locator ( '.id-label' ) . innerText ( )
898+ const id = await page . locator ( '.id-label' ) . getAttribute ( 'title' )
898899
899900 await changeLocale ( page , spanishLocale )
900901 await fillValues ( { title : 'Spanish Title' } )
@@ -925,11 +926,11 @@ describe('Localization', () => {
925926 // Close all toasts to prevent them from interfering with subsequent tests. E.g. the following could happen
926927 await closeAllToasts ( page )
927928
928- await expect . poll ( ( ) => page . url ( ) ) . not . toContain ( id )
929929 await page . waitForURL ( ( url ) => ! url . toString ( ) . includes ( id ) )
930930
931931 // Wait for page to be ready after duplicate redirect
932932 await expect ( page . locator ( '.localizer button.popup-button' ) ) . toBeVisible ( )
933+ await waitForFormReady ( page )
933934 await changeLocale ( page , defaultLocale )
934935 await expect ( page . locator ( '#field-title' ) ) . toHaveValue ( 'English Title' )
935936 await changeLocale ( page , spanishLocale )
@@ -1029,6 +1030,63 @@ describe('Localization', () => {
10291030 } )
10301031 } )
10311032
1033+ describe ( 'unique localized field validation errors' , ( ) => {
1034+ test ( 'should show correct field name in toast and highlight seoTitle inside tabs on duplicate unique value' , async ( ) => {
1035+ await page . goto ( urlWithRequiredLocalizedFields . create )
1036+ await waitForFormReady ( page )
1037+ await changeLocale ( page , defaultLocale )
1038+
1039+ const uniqueSeoTitle = `seo-e2e-unique-${ Date . now ( ) } `
1040+
1041+ await payload . create ( {
1042+ collection : withRequiredLocalizedFields ,
1043+ data : {
1044+ title : 'Existing doc title' ,
1045+ seoTitle : uniqueSeoTitle ,
1046+ nav : {
1047+ layout : [
1048+ {
1049+ blockType : 'text' ,
1050+ text : 'existing block' ,
1051+ } ,
1052+ ] ,
1053+ } ,
1054+ } ,
1055+ locale : defaultLocale ,
1056+ } )
1057+
1058+ // seoTitle is in the SEO tab (active by default) — fill it first
1059+ await page . locator ( '#field-seoTitle' ) . fill ( uniqueSeoTitle )
1060+ await page . locator ( '#field-title' ) . fill ( 'Second doc title' )
1061+
1062+ await page . locator ( 'button.tabs-field__tab-button' , { hasText : 'Main Nav' } ) . click ( )
1063+ await page . locator ( '#field-nav__layout .blocks-field__drawer-toggler' ) . click ( )
1064+ await page . locator ( 'button[title="Text"]' ) . click ( )
1065+ await page . locator ( '#field-nav__layout__0__text' ) . waitFor ( { state : 'visible' } )
1066+ await page . locator ( '#field-nav__layout__0__text' ) . fill ( 'test block' )
1067+
1068+ // Switch back to SEO tab so the field error tooltip is visible after save
1069+ await page . locator ( 'button.tabs-field__tab-button' , { hasText : 'SEO' } ) . click ( )
1070+
1071+ await saveDocAndAssert ( page , '#action-save' , 'error' , { disableDismissAllToasts : true } )
1072+
1073+ // 1. Toast error message should reference 'seoTitle', not 'seoTitle.en'
1074+ const errorToast = page . locator ( '.payload-toast-container .toast-error' )
1075+ await expect ( errorToast ) . toBeVisible ( )
1076+ await expect ( errorToast . locator ( '[data-testid="field-error"]' ) ) . toHaveText ( 'seoTitle' )
1077+
1078+ await closeAllToasts ( page )
1079+
1080+ // 2. SEO tab button should be highlighted with an error pill
1081+ const seoTabButton = page . locator ( 'button.tabs-field__tab-button' , { hasText : 'SEO' } )
1082+ await expect ( seoTabButton ) . toHaveClass ( / t a b s - f i e l d _ _ t a b - b u t t o n - - h a s - e r r o r / )
1083+ await expect ( seoTabButton . locator ( '.error-pill' ) ) . toBeVisible ( )
1084+
1085+ // 3. The seoTitle field itself should be in error state
1086+ await expect ( page . locator ( '.field-type.text:has(#field-seoTitle)' ) ) . toHaveClass ( / \b e r r o r \b / )
1087+ } )
1088+ } )
1089+
10321090 describe ( 'A11y' , ( ) => {
10331091 test . fixme ( 'Locale picker should have no accessibility violations' , async ( { } , testInfo ) => {
10341092 await page . goto ( url . list )
0 commit comments