Skip to content

docs: restructure, deduplicate, and clean up documentation#5019

Merged
thomhurst merged 9 commits intomainfrom
docs/restructure-and-cleanup
Feb 26, 2026
Merged

docs: restructure, deduplicate, and clean up documentation#5019
thomhurst merged 9 commits intomainfrom
docs/restructure-and-cleanup

Conversation

@thomhurst
Copy link
Owner

Summary

  • Restructure directories and sidebar: Consolidate 7 old directories (test-lifecycle/, test-authoring/, parallelism/, advanced/, customization-extensibility/, extensions/, experimental/) into 3 new ones (writing-tests/, extending/, merged into execution/). Flatten sidebar from 5 levels of nesting to max 3. Promote Assertions to top-level. Remove emoji from sidebar labels.
  • Fix code bugs: Add missing await on assertions, remove shell heredoc artifact, fix syntax errors, fix 6 types of API inconsistencies (IAsyncInitializableIAsyncInitializer, OutputWriterOutput, HookType.TestTest, wrong ITestExecutor signature, TestDetails.TestNameMetadata.TestName), remove phantom TUnitCacheTestResults MSBuild properties, fix non-existent ConcurrentDictionary.GetOrAddAsync().
  • Merge 9 stub pages (under 150 words each) into their logical parents. Delete redundant combined-data-source-summary.md and examples/intro.md placeholder.
  • Deduplicate: Extract code coverage into single page (was copy-pasted 4x across migration guides), consolidate SharedType and hook parameter docs.
  • Normalize tone: Remove all first-person voice, marketing copy, emoji from headings. Trim ~1,170 lines of padding (filler math examples, repeated container patterns, fabricated API types).
  • Expand 8 thin pages with real content and working code examples.

100 files changed, +1,168 −2,547 lines. Docs site builds cleanly with zero broken links.

Test plan

  • npm run build in docs/ passes with no broken links
  • Spot-check sidebar navigation in local dev server
  • Verify redirects work for any bookmarked old URLs (may need Docusaurus redirects plugin)

…ss all docs

- Add missing `await` before assertions in nested-data-sources.md
- Remove shell heredoc artifact from method-data-source.md
- Fix syntax error (missing paren) in assertions/getting-started.md
- Fix missing bracket in comparison/attributes.md
- Normalize hook syntax to short form [After(Test)] across 8 files
- Fix TestDetails.TestName to Metadata.TestName in user-facing examples
- Fix IAsyncInitializable to IAsyncInitializer in aot-compatibility.md
- Fix OutputWriter.WriteLine to Output.WriteLine in migration guides
- Fix ITestExecutor signature to ValueTask ExecuteTest in 2 files
- Remove phantom TUnitCacheTestResults MSBuild properties
- Fix ConcurrentDictionary.GetOrAddAsync to correct pattern
- Fix chaos engineering example parameter mismatch in test-variants.md
- Fix GitLab CI TRX/JUnit format error in ci-cd-reporting.md
- Merge properties.md into test-context.md as "Custom Properties" section
- Merge class-constructors.md into dependency-injection.md with expanded content
- Merge order.md into depends-on.md as "Test Ordering & Dependencies"
- Combine and-conditions, or-conditions, scopes into combining-assertions.md
- Delete combined-data-source-summary.md (redundant)
- Merge executors.md STA example into extension-points.md
- Delete examples/intro.md placeholder
- Remove "Version History" from combined-data-source.md

File count: 118 → 110
- Create extensions/code-coverage.md as single authoritative coverage page
- Remove ~600-word duplicated coverage sections from xunit.md, nunit.md,
  mstest.md, and extensions.md (replaced with links)
- Deduplicate cleanup.md by removing copy-pasted hook parameter sections
  from setup.md (replaced with cross-reference)
- Consolidate SharedType explanations: class-data-source.md now links to
  property-injection.md as authoritative source
- Remove weak BeforeEvery/AfterEvery entries that just said "same as"

647 lines of duplication removed
Reorganize 7 old directories into 3 new ones:
- test-lifecycle/ + test-authoring/ → writing-tests/
- advanced/ + customization-extensibility/ + extensions/ + experimental/ → extending/
- parallelism/ → execution/ (merged in)
- advanced/performance-best-practices.md → guides/performance.md

Rewrite sidebars.ts:
- Remove emoji from all category labels
- Promote Assertions to top-level (was buried 3 levels deep)
- Flatten max nesting from 5 levels to 3
- Dissolve "Platform-Specific Scenarios" catch-all
- Merge Extensibility + Customization + Extensions into one section

Update all internal cross-references across 14 files.
Add missing frontmatter to 5 assertion docs.
Delete 4 stale _category_.json files.
Tone normalization:
- Remove all first-person voice from framework-differences.md and things-to-know.md
- Remove marketing copy from property-injection.md and philosophy.md
- Remove emoji from headings across 13 files (benchmarks, installation, extensions, CI/CD)
- Fix "tests tests" typo in framework-differences.md

Padding trimmed (~1170 lines removed):
- boolean.md: remove 7 filler sections (LINQ, string methods, type checking, etc.)
- numeric.md: remove math library and arithmetic sections
- datetime.md: remove quarter calculation, first/last day, timezone sections
- equality-and-comparison.md: fix EqualTo alias, fix UtcNow double-call, remove redundant examples
- collections.md: remove duplicate nested/find-and-assert sections
- awaiting.md: strip grab-bag examples, keep core await explanation
- property-injection.md: reduce 3 identical container examples to 1
- generic-attributes.md: remove fabricated patterns (Fibonacci, Builder, Factory, IJsonSerializable)
- cookbook.md: replace duplicate TestWebServer with cross-reference
- method-data-source.md: reduce 4 code blocks to 2 (Func pattern only)

Pages expanded:
- playwright.md: 80→400 words (real interaction test, browser config, parallel limits)
- libraries.md: 50→250 words (csproj example, consumer usage)
- test-configuration.md: 80→200 words (missing keys, nested syntax, typed values)
- repeating.md: 130→250 words (Repeat vs Retry distinction, real test body)
- timeouts.md: 140→250 words (cancellation behavior, real test body)
- test-filters.md: 230→350 words (namespace, property, combined filters)
- explicit.md: 130→200 words (concrete filter commands, category example)
- parallel-groups.md: 85→250 words (clear semantics, step-by-step scenario)
- Fix cookbook.md link to deleted examples/intro.md
- Fix artifacts.md, hooks-cleanup.md, lifecycle.md links to renamed setup/cleanup files
- Fix ChooseYourJourney component links to new directory paths

Build passes with zero broken links.
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation Restructure Review

This is a high-quality docs overhaul. The scope is large (100 files, +1168/-2547) but the changes are coherent and the stated goals are well-executed.

What works well

API fixes are accurate and impactful. All six API inconsistencies flagged in the summary are real bugs that would have confused readers and sent them on a wild chase:

  • → (enum member import shorthand)
  • Wrong signature
  • Non-existent removed

Deduplication is well-targeted. The code coverage content was literally copy-pasted four times across the xunit/nunit/mstest/aspnet migration guides. Extracting it to and cross-linking is the correct architecture.

** is a clean merge** of the three thin standalone pages (, , ). The result is more useful than any of the originals individually.

**New and ** replace stubs with real, runnable content. The page in particular explains both and clearly with a concrete MEDI example.

Filler removal is thorough. The state-machine OrderWorkflow example, the fabricated performance benchmark loop, the string/datetime pattern sections in — all were padding that overstated API surface. Removing them and replacing with a cross-reference is the right call.


Issues to address

1. No redirect configuration (high priority)

The PR checklist explicitly marks "Verify redirects work for any bookmarked old URLs" as unchecked, and no redirect config appears in the diff. Every path under these prefixes is changing:

Old prefix New prefix
or

That's ~50+ URL paths broken simultaneously. External links (GitHub issues, Stack Overflow, Discord, any blog post), search engine index entries, and user bookmarks all hit 404s the moment this merges.

The better approach before merging is to add to with a array, or use Docusaurus's frontmatter on moved pages. The callback pattern works well for prefix-based moves:

Some renames also need point redirects (e.g., → , → , → ).

2. attribute content lost

was deleted (it was a 25-line stub covering and how to filter by property value with ). This content doesn't appear in any new page. The property attribute and its filtering syntax is non-obvious enough that it warrants at least a section somewhere — perhaps in or a brief addition to .

3. — simplest example removed

The basic single-item example ( returning one test case) was deleted. The page now opens with prose describing multi-item patterns and jumps straight to . A new user who just wants to understand the most minimal usage hits a wall. The old example was verbose but served as an anchor. Consider keeping a minimal two-line example at the top before escalating to the enumerable pattern.

4. "Guides" section is a catch-all

After the restructure, the Guides sidebar category contains 15 pages with no clear organizing principle: best practices, performance, cookbook, ASP.NET Core integration, Aspire, Playwright, complex infrastructure, FsCheck, OpenTelemetry, file-based C#, F# interactive, TUnit CI pipeline, instrumenting global test IDs, F# assertions, and troubleshooting. This is everything that didn't fit elsewhere.

This isn't a blocker for this PR but it's worth flagging: when users scan the sidebar looking for "how do I integrate with Playwright", they now need to look inside a Guides section that also contains troubleshooting and best practices. A follow-up split into "Integration Examples" and "Guides" (or promoting examples back to a top-level category) would improve discoverability.


Summary

The API fixes alone justify merging, and the content deduplication is a genuine improvement. The redirect gap is the primary concern — it has a real user impact on every external link to the docs that exists today. The other issues are minor. Consider adding the redirect plugin config before merging, or opening a fast follow-up PR immediately after.

Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation Restructure Review

This is a high-quality docs overhaul. The scope is large (100 files, +1168/-2547) but the changes are coherent and the stated goals are well-executed.

What works well

API fixes are accurate and impactful. All six API inconsistencies flagged in the summary are real bugs that would have confused readers:

  • IAsyncInitializable to IAsyncInitializer
  • context.OutputWriter to context.Output
  • HookType.Test to bare Test (enum member import shorthand)
  • TestDetails.TestName to Metadata.TestName
  • Wrong ITestExecutor signature
  • Non-existent ConcurrentDictionary.GetOrAddAsync() removed

Deduplication is well-targeted. The code coverage content was copy-pasted four times across migration guides. Extracting it to extending/code-coverage.md and cross-linking is the correct architecture.

combining-assertions.md is a clean merge of the three thin standalone pages (and-conditions.md, or-conditions.md, scopes.md). The result is more useful than any of the originals individually.

New dependency-injection.md and parallel-groups.md replace stubs with real, runnable content. The dependency injection page explains both IClassConstructor and DependencyInjectionDataSourceAttribute clearly with a concrete MEDI example.

Filler removal is thorough. The state-machine OrderWorkflow example, the fabricated performance benchmark loop, the string/datetime padding in awaiting.md — all were inflated content that overstated API surface. Removing them and replacing with cross-references is the right call.


Issues to address

1. No redirect configuration (high priority)

The PR checklist explicitly marks "Verify redirects work for any bookmarked old URLs" as unchecked, and no redirect config appears in the diff. Every path under these prefixes is changing:

Old prefix New prefix
test-authoring/* writing-tests/*
test-lifecycle/* writing-tests/*
parallelism/* execution/*
advanced/* extending/* or guides/*
customization-extensibility/* extending/*
experimental/* extending/*
extensions/* extending/*

That is ~50+ URL paths broken simultaneously. External links (GitHub issues, Discord, blog posts), search engine index entries, and user bookmarks all hit 404s the moment this merges.

The recommended approach before merging is to add @docusaurus/plugin-client-redirects to docusaurus.config.js. The createRedirects callback handles prefix-based moves efficiently without enumerating every page manually:

plugins: [
  [
    '@docusaurus/plugin-client-redirects',
    {
      createRedirects(existingPath) {
        if (existingPath.includes('/writing-tests/')) {
          return [
            existingPath.replace('/writing-tests/', '/test-authoring/'),
            existingPath.replace('/writing-tests/', '/test-lifecycle/'),
          ];
        }
        if (existingPath.includes('/extending/')) {
          return [
            existingPath.replace('/extending/', '/customization-extensibility/'),
            existingPath.replace('/extending/', '/advanced/'),
            existingPath.replace('/extending/', '/extensions/'),
            existingPath.replace('/extending/', '/experimental/'),
          ];
        }
        if (existingPath.includes('/execution/not-in-parallel') ||
            existingPath.includes('/execution/parallel-')) {
          return [existingPath.replace('/execution/', '/parallelism/')];
        }
        return undefined;
      },
    },
  ],
],

Some renames also need point redirects: test-authoring/aot-compatibility to writing-tests/aot, test-authoring/depends-on to writing-tests/ordering, advanced/performance-best-practices to guides/performance.

2. [Property] attribute content lost

test-lifecycle/properties.md was deleted — it covered [PropertyAttribute] and filtering by property value with --treenode-filter /*/*/*/*[PropertyName=PropertyValue]. This content does not appear in any new page. The property attribute and its filtering syntax is non-obvious enough to warrant at least a section somewhere — either in writing-tests/test-context.md or a brief addition to execution/test-filters.md.

3. method-data-source.md — simplest example removed

The basic single-item example (returning a single Func wrapping AdditionTestData) was replaced with inline prose. The page now opens describing multi-item patterns and jumps straight to IEnumerable<Func>. A new user wanting to understand the minimal usage hits a wall. A minimal example at the top before escalating to the enumerable pattern would help.

4. "Guides" section is a catch-all

After the restructure, the Guides sidebar category contains 15 pages with no clear organizing principle: best practices, performance, cookbook, ASP.NET Core, Aspire, Playwright, complex infrastructure, FsCheck, OpenTelemetry, file-based C#, F# interactive, TUnit CI pipeline, instrumenting global test IDs, F# assertions, and troubleshooting. This is everything that did not fit elsewhere.

Not a blocker, but worth flagging: users looking for "how do I integrate with Playwright" now scan a Guides section that also contains troubleshooting and best practices. A follow-up split into "Integration Examples" and "Guides" — or promoting examples back to a top-level category — would improve discoverability.


Summary

The API fixes alone justify merging, and the structural deduplication is a genuine improvement. The redirect gap is the primary concern — it breaks every external link to the docs that exists today. The other issues are minor. Consider adding the redirect plugin config before merging, or opening a fast follow-up PR immediately after.

- Add delegates, regex-assertions, type-checking to sidebar (were orphaned)
- Move F# assertions under Assertions section, troubleshooting to top-level
- Rename "Test Set Ups" / "Test Clean Ups" to "Setup Hooks" / "Cleanup Hooks"
- Fix "defined it finishes" typos in hooks-cleanup.md
- Fix dash-capital pattern across hooks and ordering pages
- Fix # → ## heading level for IDE Support in running-your-tests.md
- Fix Test Lifecycle link pointing to hooks-setup instead of lifecycle
- Add missing await on assertions in methodology, generic-attributes
- Use short-form [Before(Test)] in libraries.md example
- Remove potentially fabricated testconfig.json coverage config
- Fix casual contractions and first-person voice
- Clean up marketing tone in framework-differences.md
- Add cross-references between setup and cleanup hook pages
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up Review — New Issues Found

Building on the previous review, the redirect gap and the items noted there are still open. This pass adds two additional compile-breaking code examples that the previous review missed.


Critical: TestExecutionException constructor signature is wrong

In docs/docs/extending/exception-handling.md (the SafeTestExecutor example), the PR fixed context.TestNamecontext.Metadata.TestName but left the constructor call broken:

// What the doc shows — does NOT compile:
throw new TestExecutionException(
    $"Test '{context.Metadata.TestName}' failed with unexpected exception",
    ex);

The actual constructor (TestExecutionException.cs) takes three parameters:

public TestExecutionException(
    Exception? testException,
    IReadOnlyList<Exception> hookExceptions,
    IReadOnlyList<Exception> eventReceiverExceptions)

There is no (string, Exception) overload. A corrected example for ITestExecutor custom exception handling would be:

catch (Exception ex) when (ex is not TUnitException)
{
    // Either rethrow wrapped in a TUnitException subtype, or just rethrow:
    throw new TestExecutionException(ex, [], []);
}

This is a pre-existing doc bug that wasn't introduced by this PR, but the partial fix (changing just the property path) makes it look like the example was reviewed and verified — making it more misleading than before.


Critical: IClassConstructor.Create<T>() signature doesn't match the actual interface

In docs/docs/writing-tests/dependency-injection.md, the new IClassConstructor example uses:

public class CustomConstructor : IClassConstructor
{
    public T Create<[DynamicallyAccessedMembers(...)] T>(
        ClassConstructorMetadata classConstructorMetadata) where T : class
    {
        return Activator.CreateInstance<T>();
    }
}

The actual interface (IClassConstructor.cs) is:

Task<object> Create(
    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type,
    ClassConstructorMetadata classConstructorMetadata);

The interface is non-generic, returns Task<object>, and accepts a Type as its first parameter. The doc example won't implement the interface and won't compile. A correct minimal example:

public class CustomConstructor : IClassConstructor
{
    public Task<object> Create(
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type,
        ClassConstructorMetadata classConstructorMetadata)
    {
        return Task.FromResult(Activator.CreateInstance(type)!);
    }
}

Since the new dependency-injection.md page is a significant expansion of previously thin docs, this is the first time many readers will see this interface — the broken example will send them down a frustrating path.


What's working well in this revision

  • extending/code-coverage.md is thorough: covers Coverlet removal, output formats, GitHub Actions + Azure Pipelines YAML, and troubleshooting. The xUnit/NUnit/MSTest migration guides pointing here instead of duplicating it is the right call.
  • HookType.TestTest (static import shorthand) and ITestExecutor.ExecuteAsyncExecuteTest with the correct Func<ValueTask> return type are all accurate fixes in exception-handling.md.
  • The dependency-injection.md DependencyInjectionDataSourceAttribute<TScope> section is correct and the MEDI example is a real improvement over the old stubs.

Summary

Issue Severity File
No redirects for ~50 moved URLs (from previous review) High docusaurus.config.ts
new TestExecutionException(string, Exception) — ctor doesn't exist Critical extending/exception-handling.md
IClassConstructor.Create<T>() — wrong interface signature Critical writing-tests/dependency-injection.md
test-lifecycle/properties.md content lost (from previous review) Low

The two code examples are straightforward to fix and should be addressed before merge — users copy-pasting them will hit compiler errors immediately.

…llelism

- Fix homepage code examples (un-awaited assertions, void→async Task)
- Fix ChooseYourJourney link targets (migration overview, test lifecycle)
- Rewrite misleading extensions info box in running-your-tests
- Change navbar/footer label from "Tutorial" to "Docs"
- Remove unrendered JS date expression in methodology.md
- Add prose to assertions/library.md

- Expand type-checking.md with IsTypeOf, IsAssignableTo, negative cases
- Expand culture.md with "Why This Matters" section and more examples
- Add doc section overview to intro.md
- Trim C# operator testing from null-and-default.md
- Add assertion bodies to empty test methods in parallelism examples

- Merge not-in-parallel, parallel-groups, parallel-limiter into single
  execution/parallelism.md with comparison table
- Reorder sidebar: move awaiting before Value Assertions, library to end
- Add Next links to getting-started pages and See Also sections
- Move auto-import note to top of writing-your-first-test step-by-step
- Fix over-indented code blocks in filebased-csharp.md
- Replace placeholder connection string in aspnet.md
- Remove 10 orphaned Docusaurus default images
- Fix TestExecutionException constructor: use (Exception?, [], []) instead
  of non-existent (string, Exception) overload
- Fix IClassConstructor.Create signature: non-generic Task<object> with
  Type parameter, not generic Create<T>
- Add minimal single-item Func<T> example to method-data-source.md
Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Third-Pass Review — Previous Issues Still Open

The last commit (10b3445) landed after the second review — it does good work merging the three parallelism stubs into a single execution/parallelism.md and polishing several other pages. However, the two compile-breaking code examples flagged in the previous review have not been fixed, and redirects are still absent.


Still open from previous review

1. TestExecutionException constructor is still wrong (exception-handling.md)

The SafeTestExecutor example still uses a two-argument constructor that does not exist:

// Current doc (does not compile):
throw new TestExecutionException(
    $"Test '{context.Metadata.TestName}' failed with unexpected exception",
    ex);

The only constructor in TestExecutionException.cs is:

public TestExecutionException(
    Exception? testException,
    IReadOnlyList<Exception> hookExceptions,
    IReadOnlyList<Exception> eventReceiverExceptions)

Correct example:

catch (Exception ex)
{
    // Wrap unexpected exceptions so TUnit records them properly
    throw new TestExecutionException(ex, [], []);
}

This is the most user-visible example on the exception-handling page. Leaving a non-compiling constructor call teaches readers the wrong API.


2. IClassConstructor.Create<T>() signature is still wrong (dependency-injection.md)

The CustomConstructor example uses a generic method that doesn't implement the actual interface:

// Current doc — this method does NOT match IClassConstructor:
public T Create<[DynamicallyAccessedMembers(...)] T>(
    ClassConstructorMetadata classConstructorMetadata) where T : class
{
    return Activator.CreateInstance<T>();
}

The actual interface (TUnit.Core/Interfaces/IClassConstructor.cs):

Task<object> Create(
    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type,
    ClassConstructorMetadata classConstructorMetadata);

Correct minimal example:

public class CustomConstructor : IClassConstructor
{
    public Task<object> Create(
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type,
        ClassConstructorMetadata classConstructorMetadata)
    {
        return Task.FromResult(Activator.CreateInstance(type)\!);
    }
}

The page is new content introduced by this PR and is one of the most useful pages for users integrating DI containers. A wrong method signature here will silently fail to satisfy the interface and mislead readers.


3. Redirect configuration still missing

No @docusaurus/plugin-client-redirects config has been added to docs/docusaurus.config.ts. The ~50 moved URLs will all 404 on merge. As noted in the previous review, a createRedirects callback covers the prefix-based moves with minimal boilerplate.


What's improved since the last review

  • Three parallelism stubs (parallel-groups, parallel-limiter, not-in-parallel) have been merged into a single execution/parallelism.md — this is exactly the right call.
  • Homepage and intro were updated and look clean.
  • The overall sidebar structure is solid; the depth is now well within the max-3 goal.

Summary

Item Status
TestExecutionException constructor ❌ Still broken
IClassConstructor.Create signature ❌ Still broken
Redirect configuration ❌ Not added
Parallelism page consolidation ✅ Fixed in last commit
Overall structure / deduplication ✅ Good

The two code bugs should be straightforward one-line fixes. The redirect config is the only remaining architectural item. Once those three are addressed this is ready to merge.

Copy link
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up Review

Reviewing the changes since the previous review to check whether flagged issues were addressed.


Previous issues resolved ✅

[Property] attribute content restored — The deleted test-lifecycle/properties.md content now lives in writing-tests/test-context.md under a new ## Custom Properties section. The replacement is better than the original: it explains the three use-cases (filtering, runtime logic, inheritance) with real examples and uses TestContext.Current\!.Metadata.TestDetails.CustomProperties (the correct API) instead of the placeholder stub.

Simplest example added to method-data-source.md — "Here's the simplest example — a method that returns a single Func<T>, creating one test case" is now the opening example before the multi-item enumerable patterns. This gives new users an anchor to start from.

API signatures corrected (latest commit) — Three fixes caught by review are now accurate:

  • ITestExecutor signature: ExecuteTest(TestContext context, Func<ValueTask> action) (was wrong return type and wrong parameter name)
  • TestExecutionException constructor: new TestExecutionException(ex, [], []) (was fabricated (string, Exception) overload)
  • [Before(HookType.Class)] throughout troubleshooting.md[Before(Class)] (enum member import shorthand)

dependency-injection.md substantially expanded — The page now covers both IClassConstructor with a proper [DynamicallyAccessedMembers] annotation and DependencyInjectionDataSourceAttribute<TScope> with a complete MEDI walkthrough. The scope lifecycle explanation is clear.

Sidebar nesting reduced — The new structure has 9 flat top-level categories vs the old 7 categories with 4–5 levels of nesting. Writing Tests, Assertions, Running Tests, Extending TUnit, Migration Guides, Guides, Reference, About TUnit, and Getting Started are all at the same depth and easier to scan.


Still outstanding ⚠️

Redirect configuration remains absent. The docusaurus.config.ts diff is still only the label rename ("Tutorial" → "Docs"). No @docusaurus/plugin-client-redirects block was added. The PR checklist still has "Verify redirects work for any bookmarked old URLs" unchecked.

Every external URL under these prefixes will return 404 the moment this merges:

Broken prefix New location
/docs/test-lifecycle/* /docs/writing-tests/*
/docs/test-authoring/* /docs/writing-tests/*
/docs/parallelism/* /docs/execution/parallelism
/docs/advanced/* /docs/extending/*
/docs/customization-extensibility/* /docs/extending/*
/docs/extensions/* /docs/extending/*
/docs/experimental/* /docs/extending/*

A minimal fix would be adding this to docusaurus.config.ts before the themes or plugins array:

[
  '@docusaurus/plugin-client-redirects',
  {
    createRedirects(existingPath: string) {
      const map: Record<string, string> = {
        '/docs/writing-tests': '/docs/test-lifecycle',
        '/docs/writing-tests': '/docs/test-authoring',
        '/docs/execution/parallelism': '/docs/parallelism',
        '/docs/extending': '/docs/advanced',
        '/docs/extending': '/docs/customization-extensibility',
        '/docs/extending': '/docs/extensions',
        '/docs/extending': '/docs/experimental',
      };
      for (const [newPrefix, oldPrefix] of Object.entries(map)) {
        if (existingPath.startsWith(newPrefix)) {
          return [existingPath.replace(newPrefix, oldPrefix)];
        }
      }
    },
  },
],

This would require npm install @docusaurus/plugin-client-redirects in the docs/ directory as well.


Summary

Three of the four issues from the previous review were addressed well — in some cases (the [Property] content) the replacement is meaningfully better than the original. The redirect gap remains the only open item. Everything else looks ready to merge.

@thomhurst thomhurst merged commit af562b6 into main Feb 26, 2026
14 of 16 checks passed
@thomhurst thomhurst deleted the docs/restructure-and-cleanup branch February 26, 2026 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant