@@ -13,6 +13,29 @@ export type TestData = WeakMap<vscode.TestItem, BehaveTestData>;
1313export class TestFile {
1414 public didResolve = false ;
1515
16+ private addDuplicateScenarioDiagnostics ( featureUri : vscode . Uri , scenarioRanges : Map < string , vscode . Range [ ] > ) {
17+ const existingDiagnostics = config . diagnostics . get ( featureUri ) || [ ] ;
18+ const newDiagnostics = [ ...existingDiagnostics ] ;
19+
20+ for ( const [ scenarioName , ranges ] of scenarioRanges ) {
21+ if ( ranges . length > 1 ) {
22+ diagLog ( `Duplicate scenario detected: "${ scenarioName } "` ) ;
23+
24+ for ( const range of ranges ) {
25+ const diagnostic = new vscode . Diagnostic (
26+ range ,
27+ `Duplicate scenario name: "${ scenarioName } ". Each scenario in a feature file must have a unique name.` ,
28+ vscode . DiagnosticSeverity . Error
29+ ) ;
30+ diagnostic . code = "duplicate-scenario" ;
31+ diagnostic . source = "behave-vsc" ;
32+ newDiagnostics . push ( diagnostic ) ;
33+ }
34+ }
35+ }
36+ config . diagnostics . set ( featureUri , newDiagnostics ) ;
37+ }
38+
1639 public async createScenarioTestItemsFromFeatureFileContent ( wkspSettings : WorkspaceSettings , content : string , testData : TestData ,
1740 controller : vscode . TestController , item : vscode . TestItem , caller : string ) {
1841 if ( ! item . uri )
@@ -31,8 +54,14 @@ export class TestFile {
3154
3255 const thisGeneration = generationCounter ++ ;
3356 const ancestors : { item : vscode . TestItem , children : vscode . TestItem [ ] } [ ] = [ ] ;
57+ const scenarioRanges = new Map < string , vscode . Range [ ] > ( ) ;
3458 this . didResolve = true ;
3559
60+ // Clear any existing diagnostics for this file
61+ const existingDiagnostics = config . diagnostics . get ( featureUri ) || [ ] ;
62+ const nonDuplicateDiagnostics = existingDiagnostics . filter ( d => d . code !== "duplicate-scenario" ) ;
63+ config . diagnostics . set ( featureUri , nonDuplicateDiagnostics ) ;
64+
3665 const ascend = ( depth : number ) => {
3766 while ( ancestors . length > depth ) {
3867 const finished = ancestors . pop ( ) ;
@@ -42,13 +71,9 @@ export class TestFile {
4271 finished . item . children . replace ( finished . children ) ;
4372 }
4473 catch ( e : unknown ) {
45- let err = ( e as Error ) . toString ( ) ;
74+ const err = ( e as Error ) . toString ( ) ;
4675 if ( err . includes ( "duplicate test item" ) ) {
47- const n = err . lastIndexOf ( '/' ) ;
48- const scen = err . substring ( n ) ;
49- err = err . replace ( scen , `. Duplicate scenario name: "${ scen . slice ( 1 ) } ".` ) ;
50- // don't throw here, show it and carry on
51- config . logger . showError ( err , wkspSettings . uri ) ;
76+ this . addDuplicateScenarioDiagnostics ( featureUri , scenarioRanges ) ;
5277 }
5378 else
5479 throw e ;
@@ -59,6 +84,11 @@ export class TestFile {
5984 const onScenarioLine = ( range : vscode . Range , scenarioName : string , isOutline : boolean ) => {
6085 const parent = ancestors [ ancestors . length - 1 ] ;
6186
87+ // Track scenario name and range for duplicate detection
88+ const ranges = scenarioRanges . get ( scenarioName ) || [ ] ;
89+ ranges . push ( range ) ;
90+ scenarioRanges . set ( scenarioName , ranges ) ;
91+
6292 const data = new Scenario ( featureFilename , featureFileWkspRelativePath , featureName , scenarioName , thisGeneration , isOutline ) ;
6393 const id = `${ uriId ( featureUri ) } /${ data . getLabel ( ) } ` ;
6494 const tcase = controller . createTestItem ( id , data . getLabel ( ) , featureUri ) ;
0 commit comments