diff --git a/tests/Elastic.Markdown.Tests/Inline/ImagePathResolutionTests.cs b/tests/Elastic.Markdown.Tests/Inline/ImagePathResolutionTests.cs
new file mode 100644
index 000000000..6ee67d23c
--- /dev/null
+++ b/tests/Elastic.Markdown.Tests/Inline/ImagePathResolutionTests.cs
@@ -0,0 +1,208 @@
+// Licensed to Elasticsearch B.V under one or more agreements.
+// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Abstractions.TestingHelpers;
+using System.Threading.Tasks;
+using Elastic.Documentation.Configuration;
+using Elastic.Documentation.Navigation;
+using Elastic.Markdown.IO;
+using Elastic.Markdown.Myst;
+using Elastic.Markdown.Myst.InlineParsers;
+using Elastic.Markdown.Tests;
+using FluentAssertions;
+using Xunit;
+
+namespace Elastic.Markdown.Tests.Inline;
+
+public class ImagePathResolutionTests(ITestOutputHelper output)
+{
+ [Fact]
+ public async Task UpdateRelativeUrlUsesNavigationPathWhenAssemblerBuildEnabled()
+ {
+ const string relativeAssetPath = "images/pic.png";
+ var nonAssemblerResult = await ResolveUrlForBuildMode(relativeAssetPath, assemblerBuild: false, pathPrefix: "this-is-not-relevant");
+ var assemblerResult = await ResolveUrlForBuildMode(relativeAssetPath, assemblerBuild: true, pathPrefix: "platform");
+
+ nonAssemblerResult.Should().Be("/docs/setup/images/pic.png");
+ assemblerResult.Should().Be("/docs/platform/setup/images/pic.png");
+ }
+
+ [Fact]
+ public async Task UpdateRelativeUrlWithoutPathPrefixKeepsGlobalPrefix()
+ {
+ var relativeAssetPath = "images/funny-image.png";
+ var assemblerResult = await ResolveUrlForBuildMode(relativeAssetPath, assemblerBuild: true, pathPrefix: null);
+
+ assemblerResult.Should().Be("/docs/setup/images/funny-image.png");
+ }
+
+ [Fact]
+ public async Task UpdateRelativeUrlAppliesCustomPathPrefix()
+ {
+ var relativeAssetPath = "images/image.png";
+ var assemblerResult = await ResolveUrlForBuildMode(relativeAssetPath, assemblerBuild: true, pathPrefix: "custom");
+
+ assemblerResult.Should().Be("/docs/custom/setup/images/image.png");
+ }
+
+ ///
+ /// Resolves a relative asset URL the same way the assembler would for a single markdown file, using the provided navigation path prefix.
+ ///
+ private async Task ResolveUrlForBuildMode(string relativeAssetPath, bool assemblerBuild, string? pathPrefix)
+ {
+ const string guideRelativePath = "setup/guide.md";
+ var navigationUrl = BuildNavigationUrl(pathPrefix, guideRelativePath);
+ var files = new Dictionary
+ {
+ ["docs/docset.yml"] = new(
+ $"""
+ project: test
+ toc:
+ - file: index.md
+ - file: {guideRelativePath}
+ """
+ ),
+ ["docs/index.md"] = new("# Home"),
+ ["docs/" + guideRelativePath] = new(
+ $"""
+ # Guide
+
+ 
+ """
+ ),
+ ["docs/setup/" + relativeAssetPath] = new([])
+ };
+
+ var fileSystem = new MockFileSystem(files, new MockFileSystemOptions
+ {
+ CurrentDirectory = Paths.WorkingDirectoryRoot.FullName
+ });
+
+ var collector = new TestDiagnosticsCollector(output);
+ _ = collector.StartAsync(TestContext.Current.CancellationToken);
+
+ var configurationContext = TestHelpers.CreateConfigurationContext(fileSystem);
+ var buildContext = new BuildContext(collector, fileSystem, configurationContext)
+ {
+ UrlPathPrefix = "/docs",
+ AssemblerBuild = assemblerBuild
+ };
+
+ var documentationSet = new DocumentationSet(buildContext, new TestLoggerFactory(output), new TestCrossLinkResolver());
+
+ await documentationSet.ResolveDirectoryTree(TestContext.Current.CancellationToken);
+
+ // Normalize path for cross-platform compatibility (Windows uses backslashes)
+ var normalizedPath = guideRelativePath.Replace('/', Path.DirectorySeparatorChar);
+ if (documentationSet.TryFindDocumentByRelativePath(normalizedPath) is not MarkdownFile markdownFile)
+ throw new InvalidOperationException($"Failed to resolve markdown file for test. Tried path: {normalizedPath}");
+
+ // For assembler builds DocumentationSetNavigation seeds MarkdownNavigationLookup with navigation items whose Url already
+ // includes the computed path_prefix. To exercise the same branch in isolation, inject a stub navigation entry with the
+ // expected Url (and minimal metadata for the surrounding API contract).
+ _ = documentationSet.MarkdownNavigationLookup.Remove(markdownFile);
+ documentationSet.MarkdownNavigationLookup.Add(markdownFile, new NavigationItemStub(navigationUrl));
+ documentationSet.MarkdownNavigationLookup.TryGetValue(markdownFile, out var navigation).Should()
+ .BeTrue("navigation lookup should contain current page");
+ navigation?.Url.Should().Be(navigationUrl);
+
+ var parserState = new ParserState(buildContext)
+ {
+ MarkdownSourcePath = markdownFile.SourceFile,
+ YamlFrontMatter = null,
+ CrossLinkResolver = documentationSet.CrossLinkResolver,
+ TryFindDocument = file => documentationSet.TryFindDocument(file),
+ TryFindDocumentByRelativePath = path => documentationSet.TryFindDocumentByRelativePath(path),
+ PositionalNavigation = documentationSet
+ };
+
+ var context = new ParserContext(parserState);
+ context.TryFindDocument(context.MarkdownSourcePath).Should().BeSameAs(markdownFile);
+ context.Build.AssemblerBuild.Should().Be(assemblerBuild);
+
+ var resolved = DiagnosticLinkInlineParser.UpdateRelativeUrl(context, relativeAssetPath);
+
+ await collector.StopAsync(TestContext.Current.CancellationToken);
+
+ return resolved;
+ }
+
+ ///
+ /// Helper that mirrors the assembler's path-prefix handling in DocumentationSetNavigation:
+ /// combines the relative path_prefix from navigation.yml with the markdown path (stripped of ".md") so our stub
+ /// navigation item carries the same Url the production code would have provided.
+ ///
+ private static string BuildNavigationUrl(string? pathPrefix, string docRelativePath)
+ {
+ var docPath = docRelativePath.Replace('\\', '/').Trim('/');
+ if (docPath.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
+ docPath = docPath[..^3];
+
+ var segments = new List();
+ if (!string.IsNullOrWhiteSpace(pathPrefix))
+ segments.Add(pathPrefix.Trim('/'));
+ if (!string.IsNullOrWhiteSpace(docPath))
+ segments.Add(docPath);
+
+ var combined = string.Join('/', segments);
+ return "/" + combined.Trim('/');
+ }
+
+ ///
+ /// Minimal navigation stub so UpdateRelativeUrl can rely on navigation metadata without constructing the full site navigation tree.
+ ///
+ private sealed class NavigationItemStub(string url) : INavigationItem
+ {
+ private sealed class NavigationModelStub : INavigationModel
+ {
+ }
+
+ ///
+ /// Simplified root navigation item to satisfy the IRootNavigationItem contract.
+ ///
+ private sealed class RootNavigationItemStub : IRootNavigationItem
+ {
+ ///
+ /// Leaf implementation used by the root stub. Navigation requires both root and leaf nodes present.
+ ///
+ private sealed class LeafNavigationItemStub(RootNavigationItemStub root) : ILeafNavigationItem
+ {
+ public string Url => "/";
+ public string NavigationTitle => "Root";
+ public IRootNavigationItem NavigationRoot { get; } = root;
+ public INodeNavigationItem? Parent { get; set; }
+ public bool Hidden => false;
+ public int NavigationIndex { get; set; }
+ public INavigationModel Model { get; } = new NavigationModelStub();
+ }
+
+ public RootNavigationItemStub() => Index = new LeafNavigationItemStub(this);
+
+ public string Url => "/";
+ public string NavigationTitle => "Root";
+ public IRootNavigationItem NavigationRoot => this;
+ public INodeNavigationItem? Parent { get; set; }
+ public bool Hidden => false;
+ public int NavigationIndex { get; set; }
+ public string Id => "root";
+ public ILeafNavigationItem Index { get; }
+ public IReadOnlyCollection NavigationItems { get; private set; } = [];
+ public bool IsUsingNavigationDropdown => false;
+ public Uri Identifier => new("https://example.test/");
+ public void SetNavigationItems(IReadOnlyCollection navigationItems) => NavigationItems = navigationItems;
+ }
+
+ private static readonly RootNavigationItemStub Root = new();
+
+ public string Url { get; } = url;
+ public string NavigationTitle => "Stub";
+ public IRootNavigationItem NavigationRoot => Root;
+ public INodeNavigationItem? Parent { get; set; }
+ public bool Hidden => false;
+ public int NavigationIndex { get; set; }
+ }
+}