One Swap

The menu dropdowns were empty. Tests were passing. The bug was one line — finding it required understanding the full evaluation chain.

While testing a new menu feature in the browser, the dropdown items were missing. The menu rendered. The dropdown appeared. It contained nothing.

The tests were passing.

The template engine processes a mix of conditionals and loops. A conditional like {{?label}} renders its content if the label property exists. A loop like {{#items}} iterates over a collection and provides each item as context. Both were used together: conditionals inside loops to handle separator rendering, label visibility, that kind of thing.

The bug: the engine was processing conditionals before loops.

So when {{?label}} ran, it evaluated against the root context — where there was no label property — and stripped the conditional block. By the time the loop ran, there was nothing left to render inside it. Every dropdown item was silently removed before the loop ever got a chance to provide the item data.

The fix was swapping two processing blocks. Loops first, then conditionals. One code change.

Finding it took longer than fixing it.

The reason the tests missed it: the assertions were checking the HTML string for the presence of CSS class names. Those class names appeared in the template itself, not inside the conditional blocks. So the output contained the classes, the assertions matched, and everything looked fine. The bug was inside the elements, not on them.

This is the kind of thing you only catch by opening a browser and looking at the DOM. Not running tests. Not reading code. Actually using the thing and noticing the menus are empty.

The pattern shows up in other contexts: if your test is checking the container and the bug is in the content, the test will always pass. Worth auditing which assertions verify structure and which verify substance.

The menu works now. The tests still pass. That second fact is now slightly less reassuring than it used to be.