@@ -38,7 +38,14 @@ public class MintlifyRendererNavigationTypeTests : DotNetDocsTestBase
3838 /// Configures test host with a specific template and navigation configuration.
3939 /// This must be called before TestSetup() to ensure the configuration is set before services are built.
4040 /// </summary>
41- private void ConfigureTestWithTemplate ( DocsJsonConfig ? template , DocsNavigationConfig ? navConfig = null )
41+ /// <param name="template">The DocsJsonConfig template to use, or null for no template.</param>
42+ /// <param name="navConfig">Optional navigation configuration to override defaults.</param>
43+ /// <param name="contentOnly">
44+ /// When <see langword="true"/>, sets <c>HasMintlifyTemplate = true</c> on the project context so that
45+ /// <see cref="DocumentationManager.ProcessAsync(System.Collections.Generic.IEnumerable{System.ValueTuple{string,string}})"/>
46+ /// with an empty assembly list still runs the renderer pipeline (content-only mode).
47+ /// </param>
48+ private void ConfigureTestWithTemplate ( DocsJsonConfig ? template , DocsNavigationConfig ? navConfig = null , bool contentOnly = false )
4249 {
4350 _testOutputPath = Path . Combine ( Path . GetTempPath ( ) , $ "MintlifyNavigationTypeTest_{ Guid . NewGuid ( ) } ") ;
4451 Directory . CreateDirectory ( _testOutputPath ) ;
@@ -59,6 +66,10 @@ private void ConfigureTestWithTemplate(DocsJsonConfig? template, DocsNavigationC
5966 {
6067 ctx . DocumentationRootPath = _testOutputPath ;
6168 ctx . ApiReferencePath = string . Empty ;
69+ if ( contentOnly )
70+ {
71+ ctx . HasMintlifyTemplate = true ;
72+ }
6273 } ) ;
6374 } ) ;
6475 } ) ;
@@ -333,6 +344,176 @@ public async Task ApplyNavigationType_WithInvalidType_UsesDefaultBehavior()
333344
334345 #endregion
335346
347+ #region Explicit Template Navigation Section Tests
348+
349+ /// <summary>
350+ /// Regression test: when a template defines explicit Tabs in the Navigation config, the renderer
351+ /// must not auto-generate a parallel pages block from disk discovery (content-only mode).
352+ /// </summary>
353+ [ TestMethod ]
354+ public async Task ExplicitTemplateTabs_ContentOnly_HasTabsAndNoPages ( )
355+ {
356+ // Arrange
357+ ConfigureTestWithTemplate (
358+ new DocsJsonConfig
359+ {
360+ Name = "Test Docs" ,
361+ Theme = "mint" ,
362+ Colors = new ColorsConfig { Primary = "#000000" } ,
363+ Navigation = new NavigationConfig
364+ {
365+ Tabs =
366+ [
367+ new TabConfig { Tab = "Guides" , Href = "/guides" , Pages = [ "guides/index" ] } ,
368+ new TabConfig { Tab = "API Reference" , Href = "/api" , Pages = [ "api/index" ] }
369+ ]
370+ }
371+ } ,
372+ contentOnly : true ) ;
373+
374+ var documentationManager = GetService < DocumentationManager > ( ) ;
375+
376+ // Act
377+ await documentationManager . ProcessAsync ( [ ] ) ;
378+
379+ // Assert
380+ var docsJsonPath = Path . Combine ( _testOutputPath , "docs.json" ) ;
381+ File . Exists ( docsJsonPath ) . Should ( ) . BeTrue ( ) ;
382+
383+ var json = File . ReadAllText ( docsJsonPath ) ;
384+ var config = JsonSerializer . Deserialize < DocsJsonConfig > ( json , MintlifyConstants . JsonSerializerOptions ) ;
385+
386+ config . Should ( ) . NotBeNull ( ) ;
387+ config ! . Navigation . Tabs . Should ( ) . HaveCount ( 2 , "both template-defined tabs should be present" ) ;
388+ config . Navigation . Tabs ! [ 0 ] . Tab . Should ( ) . Be ( "Guides" ) ;
389+ config . Navigation . Tabs ! [ 1 ] . Tab . Should ( ) . Be ( "API Reference" ) ;
390+ config . Navigation . Pages . Should ( ) . BeNull ( "explicit tabs navigation must not produce a spurious pages block" ) ;
391+ }
392+
393+ /// <summary>
394+ /// Regression test: when a template defines explicit Tabs, auto-discovery must not inject a pages block
395+ /// even when a real assembly is also being processed.
396+ /// </summary>
397+ [ TestMethod ]
398+ public async Task ExplicitTemplateTabs_WithAssembly_HasOnlyTabsAndNoPages ( )
399+ {
400+ // Arrange
401+ ConfigureTestWithTemplate ( new DocsJsonConfig
402+ {
403+ Name = "Test API" ,
404+ Theme = "mint" ,
405+ Colors = new ColorsConfig { Primary = "#000000" } ,
406+ Navigation = new NavigationConfig
407+ {
408+ Tabs =
409+ [
410+ new TabConfig { Tab = "Getting Started" , Href = "/start" , Pages = [ "index" ] } ,
411+ new TabConfig { Tab = "API Reference" , Href = "/api" , Pages = [ "api/index" ] }
412+ ]
413+ }
414+ } ) ;
415+
416+ var assemblyPath = typeof ( SimpleClass ) . Assembly . Location ;
417+ var xmlPath = Path . ChangeExtension ( assemblyPath , ".xml" ) ;
418+ var documentationManager = GetService < DocumentationManager > ( ) ;
419+
420+ // Act
421+ await documentationManager . ProcessAsync ( assemblyPath , xmlPath ) ;
422+
423+ // Assert
424+ var docsJsonPath = Path . Combine ( _testOutputPath , "docs.json" ) ;
425+ var json = File . ReadAllText ( docsJsonPath ) ;
426+ var config = JsonSerializer . Deserialize < DocsJsonConfig > ( json , MintlifyConstants . JsonSerializerOptions ) ;
427+
428+ config . Should ( ) . NotBeNull ( ) ;
429+ config ! . Navigation . Tabs . Should ( ) . HaveCount ( 2 , "template-defined tabs should be preserved" ) ;
430+ config . Navigation . Pages . Should ( ) . BeNull ( "auto-discovery must not inject pages alongside explicit tabs even when an assembly is present" ) ;
431+ }
432+
433+ /// <summary>
434+ /// Verifies that a template with explicit Anchors produces anchors and no pages in content-only mode.
435+ /// </summary>
436+ [ TestMethod ]
437+ public async Task ExplicitTemplateAnchors_ContentOnly_HasAnchorsAndNoPages ( )
438+ {
439+ // Arrange
440+ ConfigureTestWithTemplate (
441+ new DocsJsonConfig
442+ {
443+ Name = "Test Docs" ,
444+ Theme = "mint" ,
445+ Colors = new ColorsConfig { Primary = "#000000" } ,
446+ Navigation = new NavigationConfig
447+ {
448+ Anchors =
449+ [
450+ new AnchorConfig { Anchor = "Documentation" , Href = "/docs" , Icon = "book" , Pages = [ ] } ,
451+ new AnchorConfig { Anchor = "API" , Href = "/api" , Icon = "code" , Pages = [ ] }
452+ ]
453+ }
454+ } ,
455+ contentOnly : true ) ;
456+
457+ var documentationManager = GetService < DocumentationManager > ( ) ;
458+
459+ // Act
460+ await documentationManager . ProcessAsync ( [ ] ) ;
461+
462+ // Assert
463+ var docsJsonPath = Path . Combine ( _testOutputPath , "docs.json" ) ;
464+ var json = File . ReadAllText ( docsJsonPath ) ;
465+ var config = JsonSerializer . Deserialize < DocsJsonConfig > ( json , MintlifyConstants . JsonSerializerOptions ) ;
466+
467+ config . Should ( ) . NotBeNull ( ) ;
468+ config ! . Navigation . Anchors . Should ( ) . HaveCount ( 2 , "both template-defined anchors should be present" ) ;
469+ config . Navigation . Anchors ! [ 0 ] . Anchor . Should ( ) . Be ( "Documentation" ) ;
470+ config . Navigation . Anchors ! [ 1 ] . Anchor . Should ( ) . Be ( "API" ) ;
471+ config . Navigation . Pages . Should ( ) . BeNull ( "explicit anchors navigation must not produce a spurious pages block" ) ;
472+ }
473+
474+ /// <summary>
475+ /// Verifies that a template with explicit Products produces products and no pages in content-only mode.
476+ /// </summary>
477+ [ TestMethod ]
478+ public async Task ExplicitTemplateProducts_ContentOnly_HasProductsAndNoPages ( )
479+ {
480+ // Arrange
481+ ConfigureTestWithTemplate (
482+ new DocsJsonConfig
483+ {
484+ Name = "Test Platform" ,
485+ Theme = "mint" ,
486+ Colors = new ColorsConfig { Primary = "#000000" } ,
487+ Navigation = new NavigationConfig
488+ {
489+ Products =
490+ [
491+ new ProductConfig { Product = "Core SDK" , Href = "/core" , Pages = [ "core/index" ] } ,
492+ new ProductConfig { Product = "Extensions" , Href = "/ext" , Pages = [ "ext/index" ] }
493+ ]
494+ }
495+ } ,
496+ contentOnly : true ) ;
497+
498+ var documentationManager = GetService < DocumentationManager > ( ) ;
499+
500+ // Act
501+ await documentationManager . ProcessAsync ( [ ] ) ;
502+
503+ // Assert
504+ var docsJsonPath = Path . Combine ( _testOutputPath , "docs.json" ) ;
505+ var json = File . ReadAllText ( docsJsonPath ) ;
506+ var config = JsonSerializer . Deserialize < DocsJsonConfig > ( json , MintlifyConstants . JsonSerializerOptions ) ;
507+
508+ config . Should ( ) . NotBeNull ( ) ;
509+ config ! . Navigation . Products . Should ( ) . HaveCount ( 2 , "both template-defined products should be present" ) ;
510+ config . Navigation . Products ! [ 0 ] . Product . Should ( ) . Be ( "Core SDK" ) ;
511+ config . Navigation . Products ! [ 1 ] . Product . Should ( ) . Be ( "Extensions" ) ;
512+ config . Navigation . Pages . Should ( ) . BeNull ( "explicit products navigation must not produce a spurious pages block" ) ;
513+ }
514+
515+ #endregion
516+
336517 }
337518
338519}
0 commit comments