From ec6268546a839025062d4ad3e805af8fa0cca720 Mon Sep 17 00:00:00 2001 From: Beau Collins Date: Fri, 21 Aug 2026 10:50:08 -0700 Subject: [PATCH] Add CollapseWebPaths test: transitive-dependency res must be registered Transitive-dependency res is staged under a nested `release/res//res` path, but generateImageRegistry only scans the immediate children of `src/` (DiskUtils::listDirectory(sourceDirectory)). Transitive modules' images are copied into the package yet never added to `_image_registry.js`, so getAssets() resolves them to nothing at runtime and the icons render blank. Only the direct dependency (whose res sits at top-level `src//res`) is registered. This test builds a package with a direct-dep res and a transitive-dep res (staged under `release/res/shared/res`) and asserts both appear in the registry. It fails on the current renderer because the transitive entry is dropped. Co-Authored-By: Claude Opus 4.8 --- .../toolbox/test/CollapseWebPaths_tests.cpp | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/valdi/compiler/toolbox/test/CollapseWebPaths_tests.cpp b/valdi/compiler/toolbox/test/CollapseWebPaths_tests.cpp index 207dd0d4d..d275d5e21 100644 --- a/valdi/compiler/toolbox/test/CollapseWebPaths_tests.cpp +++ b/valdi/compiler/toolbox/test/CollapseWebPaths_tests.cpp @@ -208,6 +208,45 @@ TEST(CollapseWebPaths, appliesImageInliningPolicyPerModule) { "};\n"); } +// Transitive-dependency res is staged under a nested `release/res//res` +// path, but generateImageRegistry only scans the immediate children of `src/`. +// The transitive module's images are copied into the package yet never added to +// _image_registry.js, so getAssets() cannot resolve them at runtime (icons render +// blank). The registry must cover every module's res, including transitive deps. +TEST(CollapseWebPaths, registersTransitiveDependencyResources) { + CollapseTemporaryDirectory directory; + auto directIcon = directory.write("inputs/direct_icon.png", "png\n"); + auto transitiveIcon = directory.write("inputs/transitive_icon.png", "png\n"); + auto manifest = directory.write("manifest.tsv", + fmt::format("{}\tsrc/lead/res/direct_icon.png\n" + "{}\tsrc/release/res/shared/res/transitive_icon.png\n", + directIcon, + transitiveIcon)); + auto stringsManifest = directory.write("strings.tsv", ""); + auto declarationsManifest = directory.write("declarations.tsv", ""); + auto webWorkersManifest = directory.write("web-workers.tsv", ""); + auto imagePolicyManifest = directory.write("image-policy.tsv", ""); + auto output = directory.path().appending("output"); + + auto result = collapseWebPaths(output.toStringBox(), + manifest.toStringBox(), + StringCache::getGlobal().makeString(std::string_view("@scope/package")), + stringsManifest.toStringBox(), + declarationsManifest.toStringBox(), + webWorkersManifest.toStringBox(), + imagePolicyManifest.toStringBox()); + + ASSERT_TRUE(result) << result.description(); + auto registry = directory.read("output/src/_image_registry.js"); + // Direct dependency is registered today. + EXPECT_NE(registry.find("__r['lead/res']"), std::string::npos) << registry; + // Transitive dependency (staged under release/res//res) must also be + // registered. This fails on the current renderer: its icons are bundled but + // absent from the registry. + EXPECT_NE(registry.find("__r['shared/res']"), std::string::npos) << registry; + EXPECT_NE(registry.find("transitive_icon.png"), std::string::npos) << registry; +} + } // namespace } // namespace Valdi