@@ -42,9 +42,12 @@ export class ServiceSpecConfigPage extends BasePage {
4242
4343 constructor ( page : Page , testInfo : TestInfo , eyes : any , specName : string ) {
4444 super ( page , testInfo , eyes , specName ) ;
45+ const specFileName = specName . includes ( "/" )
46+ ? specName . split ( "/" ) . pop ( ) !
47+ : specName ;
4548 this . specTree = page . locator ( "#spec-tree" ) ;
4649 this . specSection = page . locator (
47- `xpath=//div[contains(@id,"${ specName } ") and @data-mode="spec"]` ,
50+ `xpath=//div[contains(@id,"${ specFileName } ") and @data-mode="spec"]` ,
4851 ) ;
4952 this . specBtn = page . locator ( 'li.tab[data-type="spec"]' ) . first ( ) ;
5053 this . editBtn = this . specSection . getByText ( / E d i t s p e c m a t i c .y a m l / i) ;
@@ -57,10 +60,10 @@ export class ServiceSpecConfigPage extends BasePage {
5760 this . contractTestTab = page . locator ( 'li.tab[data-type="test"]' ) . first ( ) ;
5861 this . alertMsg = page . locator ( ".alert-msg p" ) ;
5962 this . validationErrorBtn = page
60- . locator ( `[id*="${ this . specName } "]` )
63+ . locator ( `[id*="${ specFileName } "]` )
6164 . locator ( "button.bcc-errors-btn" ) ;
6265 this . errorContent = page
63- . locator ( `[id*="${ this . specName } "]` )
66+ . locator ( `[id*="${ specFileName } "]` )
6467 . locator ( ".bcc-errors-content" ) ;
6568
6669 this . bccTestButton = this . specSection . locator ( "#bcc-test-btn" ) ;
@@ -384,14 +387,23 @@ export class ServiceSpecConfigPage extends BasePage {
384387 }
385388
386389 async toggleBccErrorSection ( shouldExpand : boolean ) {
387- const isExpanded = await this . bccErrorToggle . getAttribute ( "aria-expanded" ) ;
390+ // Use the content element's CSS class as the source of truth for the
391+ // current expanded state. aria-expanded on the toggle button can drift
392+ // out of sync with the actual visual state when scenarios run back-to-back
393+ // without a page reload.
394+ const classes = ( await this . bccErrorContent . getAttribute ( "class" ) ) ?? "" ;
395+ const isCurrentlyExpanded = classes . includes ( "show" ) ;
388396
389397 if (
390- ( shouldExpand && isExpanded === "false" ) ||
391- ( ! shouldExpand && isExpanded === "true" )
398+ ( shouldExpand && ! isCurrentlyExpanded ) ||
399+ ( ! shouldExpand && isCurrentlyExpanded )
392400 ) {
393401 await this . bccErrorToggle . click ( ) ;
394- await takeAndAttachScreenshot ( this . page , "expanding-error-setion" ) ;
402+ await takeAndAttachScreenshot (
403+ this . page ,
404+ "expanding-error-section" ,
405+ this . eyes ,
406+ ) ;
395407 }
396408
397409 if ( shouldExpand ) {
@@ -510,4 +522,82 @@ export class ServiceSpecConfigPage extends BasePage {
510522 await expect ( saveAlert ) . toBeHidden ( { timeout : 5000 } ) ;
511523 } ) ;
512524 }
525+
526+ async verifyCompatibilityScenario (
527+ scenario : {
528+ oldText : string ;
529+ newText : string ;
530+ expectedMessage : string | RegExp ;
531+ } ,
532+ reload : boolean = true ,
533+ ) {
534+ await test . step ( `Scenario: ${ scenario . oldText } -> ${ scenario . newText } ` , async ( ) => {
535+ if ( scenario . newText === "" ) {
536+ await this . deleteSpecLinesInEditor ( scenario . oldText , 1 ) ;
537+ } else {
538+ await this . editSpecInEditor ( scenario . oldText , scenario . newText ) ;
539+ }
540+
541+ await this . runBackwardCompatibilityTest ( ) ;
542+
543+ const actualMessage = await this . getAlertMessageText ( ) ;
544+ expect ( actualMessage ) . toContain ( scenario . expectedMessage ) ;
545+
546+ await this . dismissAlert ( ) ;
547+
548+ if ( reload ) {
549+ await this . page . reload ( ) ;
550+ await this . openSpecTab ( ) ;
551+ }
552+ } ) ;
553+ }
554+
555+ async verifyIncompatibilityScenario (
556+ scenario : {
557+ oldText : string ;
558+ newText : string ;
559+ lineCount : number ;
560+ expectedErrorCount : number ;
561+ expectedDetail : string ;
562+ } ,
563+ reload : boolean = true ,
564+ ) {
565+ // 1. Preconditions: Get back to a clean state (skipped when batching without reload)
566+ if ( reload ) {
567+ await test . step ( "Preconditions for the test" , async ( ) => {
568+ await this . page . reload ( ) ;
569+ await this . navigateToSpec ( this . specName ! ) ;
570+ } ) ;
571+ }
572+
573+ await test . step ( `Incompatibility Check for: ${ scenario . oldText } ` , async ( ) => {
574+ if ( scenario . lineCount > 0 ) {
575+ await this . deleteSpecLinesInEditor (
576+ scenario . oldText ,
577+ scenario . lineCount ,
578+ ) ;
579+ } else if ( scenario . newText !== "" ) {
580+ await this . editSpecInEditor ( scenario . oldText , scenario . newText ) ;
581+ }
582+
583+ await this . runBackwardCompatibilityTest ( ) ;
584+
585+ const toastText = await this . getAlertMessageText ( ) ;
586+ expect . soft ( toastText ) . toContain ( "Backward compatibility test failed" ) ;
587+ await this . dismissAlert ( ) ;
588+
589+ await this . toggleBccErrorSection ( true ) ;
590+ const { summary, details } = await this . getBccErrorDetails ( ) ;
591+
592+ // Check for error count and details
593+ expect . soft ( summary ) . toContain ( `${ scenario . expectedErrorCount } error` ) ;
594+ const hasMatch = details . some ( ( d ) => d . includes ( scenario . expectedDetail ) ) ;
595+ expect
596+ . soft (
597+ hasMatch ,
598+ `Expected error detail not found: ${ scenario . expectedDetail } ` ,
599+ )
600+ . toBe ( true ) ;
601+ } ) ;
602+ }
513603}
0 commit comments