<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joan Miquel Torres</title>
    <description>The latest articles on DEV Community by Joan Miquel Torres (@bitifet).</description>
    <link>https://dev.to/bitifet</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F104985%2F80bedd33-709d-48ce-8fd9-fc22e9cf9db2.jpeg</url>
      <title>DEV Community: Joan Miquel Torres</title>
      <link>https://dev.to/bitifet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bitifet"/>
    <language>en</language>
    <item>
      <title>How We Gave Every Documentation Example Its Own Test — and Why It Caught Real Bugs</title>
      <dc:creator>Joan Miquel Torres</dc:creator>
      <pubDate>Tue, 03 Mar 2026 17:01:24 +0000</pubDate>
      <link>https://dev.to/bitifet/how-we-gave-every-documentation-example-its-own-test-and-why-it-caught-real-bugs-4k9d</link>
      <guid>https://dev.to/bitifet/how-we-gave-every-documentation-example-its-own-test-and-why-it-caught-real-bugs-4k9d</guid>
      <description>&lt;p&gt;Documentation examples have a dirty secret: they're code, but they're rarely&lt;br&gt;
treated &lt;em&gt;like&lt;/em&gt; code.&lt;/p&gt;

&lt;p&gt;We write them carefully when we publish them, and then — slowly, quietly —&lt;br&gt;
they drift. The API changes. A parameter gets renamed. The behavior shifts&lt;br&gt;
slightly. Yet the docs example keeps running in our heads as the canonical&lt;br&gt;
demonstration, even after it stops being accurate.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://github.com/bitifet/SmarkForm" rel="noopener noreferrer"&gt;SmarkForm&lt;/a&gt; — a markup-driven form&lt;br&gt;
library whose entire value proposition is its declarative HTML API — this risk&lt;br&gt;
is especially acute. Our documentation site is full of &lt;em&gt;interactive&lt;/em&gt; examples.&lt;br&gt;
People copy them. People &lt;em&gt;trust&lt;/em&gt; them. If they're wrong, the library looks&lt;br&gt;
broken — because to the person reading the docs, the example &lt;em&gt;is&lt;/em&gt; the library.&lt;/p&gt;

&lt;p&gt;This is the story of how we solved it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Starting Point: A Library With Living Examples
&lt;/h2&gt;

&lt;p&gt;SmarkForm's documentation is a Jekyll site with dozens of&lt;br&gt;
&lt;a href="https://smarkform.bitifet.net/about/showcase" rel="noopener noreferrer"&gt;interactive playground examples&lt;/a&gt;.&lt;br&gt;
Each example is a fully functional mini form, rendered live in the browser,&lt;br&gt;
showing features like nested subforms, variable-length lists, context-driven&lt;br&gt;
hotkeys, and more.&lt;/p&gt;

&lt;p&gt;The examples aren't just screenshots — they use a component called&lt;br&gt;
&lt;code&gt;sampletabs_tpl&lt;/code&gt; that renders a tabbed interface with a live form, the HTML&lt;br&gt;
source, the JavaScript source, and a JSON import/export playground. Anyone&lt;br&gt;
reading the docs can click Import, tweak the JSON, and see the form respond.&lt;/p&gt;

&lt;p&gt;That richness is exactly what makes untested examples so dangerous. There's a&lt;br&gt;
lot of moving parts to get right.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Foundation: Migrating to Playwright
&lt;/h2&gt;

&lt;p&gt;Before we could build co-located tests, we had to fix the foundation. In&lt;br&gt;
October 2025, the existing test suite — Puppeteer + Mocha, over 2,000 lines —&lt;br&gt;
was migrated to &lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt;. This wasn't just a&lt;br&gt;
tooling swap. It opened the door to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running tests across &lt;strong&gt;Chromium, Firefox, and WebKit&lt;/strong&gt; with a single command.&lt;/li&gt;
&lt;li&gt;A much cleaner API for async interactions.&lt;/li&gt;
&lt;li&gt;Better tracing and debugging when things went wrong.&lt;/li&gt;
&lt;li&gt;A modern, actively maintained ecosystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Playwright migration itself was a prerequisite for everything that followed.&lt;br&gt;
With a solid, multi-browser foundation in place, the next question became: how&lt;br&gt;
do we use it to test the documentation examples?&lt;/p&gt;


&lt;h2&gt;
  
  
  The Idea: Co-Located Tests
&lt;/h2&gt;

&lt;p&gt;The insight was simple: &lt;strong&gt;put the test right next to the example&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not in a separate &lt;code&gt;test/&lt;/code&gt; folder that grows out of sync. Not in a spreadsheet&lt;br&gt;
of "things to manually verify." Right there, in the same Markdown file, in the&lt;br&gt;
same &lt;code&gt;{% capture %}&lt;/code&gt; block that describes the example.&lt;/p&gt;

&lt;p&gt;Here's what it looks like in practice. A documentation example in SmarkForm's&lt;br&gt;
Jekyll site looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;{% capture my_example_html %}
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;data-smark&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;data-smark&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;data-smark=&lt;/span&gt;&lt;span class="s"&gt;'{"action":"export"}'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
{% endcapture %}

{% include components/sampletabs_tpl.md
    formId="my_example"
    htmlSource=my_example_html
    tests=false
%}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;tests=false&lt;/code&gt; means: &lt;em&gt;I know there's no custom test here; that's intentional&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But for examples where behavior matters, you add a capture block with real&lt;br&gt;
Playwright test code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;{% capture my_example_tests %}
export default async ({ page, expect, id, root, readField, writeField }) =&amp;gt; {
    await expect(root).toBeVisible();&lt;span class="sb"&gt;

    const input = root.locator('input[name="username"]');
    await input.fill('alice');

    expect(await readField('username')).toBe('alice');
&lt;/span&gt;};
{% endcapture %}

{% include components/sampletabs_tpl.md
    formId="my_example"
    htmlSource=my_example_html
    tests=my_example_tests
%}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;export default async function&lt;/code&gt; is a real Playwright test. It gets&lt;br&gt;
extracted, executed, and reported as a test result — for every browser.&lt;/p&gt;


&lt;h2&gt;
  
  
  Keeping It Navigable: Vim Fold Markers
&lt;/h2&gt;

&lt;p&gt;There's a side effect of co-location that isn't immediately obvious: the&lt;br&gt;
documentation files get &lt;em&gt;long&lt;/em&gt;. Very long. A single showcase page might contain&lt;br&gt;
a dozen &lt;code&gt;{% capture %}&lt;/code&gt; blocks — HTML source, CSS source, JavaScript, notes,&lt;br&gt;
and now tests — each running tens or hundreds of lines.&lt;/p&gt;

&lt;p&gt;The file is perfectly machine-readable. For a human editor reviewing or&lt;br&gt;
updating a specific example, it can become a wall of text.&lt;/p&gt;

&lt;p&gt;The SmarkForm project's solution to this is &lt;strong&gt;vim fold markers&lt;/strong&gt; — a&lt;br&gt;
convention borrowed directly from how &lt;code&gt;src/&lt;/code&gt; files are written — applied to&lt;br&gt;
the Markdown documentation files as well.&lt;/p&gt;

&lt;p&gt;In the library source code, functions are bracketed like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="c1"&gt;//{{{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... implementation&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="c1"&gt;//}}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In documentation Markdown files, capture blocks are bracketed with HTML&lt;br&gt;
comments wrapped in &lt;code&gt;{% raw %}&lt;/code&gt; to prevent Jekyll from consuming them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;{% raw %} &lt;span class="c"&gt;&amp;lt;!-- basic_form_html {{{ --&amp;gt;&lt;/span&gt; {% endraw %}
{% capture basic_form_html %}
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;data-smark&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;data-smark&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
{% endcapture %}{% raw %} &lt;span class="c"&gt;&amp;lt;!-- }}} --&amp;gt;&lt;/span&gt; {% endraw %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The closing marker sits on the &lt;strong&gt;same line&lt;/strong&gt; as &lt;code&gt;{% endcapture %}&lt;/code&gt; — one&lt;br&gt;
less line to scroll past. When a capture's closing &lt;code&gt;%}&lt;/code&gt; falls on its own&lt;br&gt;
line (a formatting choice sometimes made for long captures), the closing&lt;br&gt;
marker follows on the next line instead.&lt;/p&gt;

&lt;p&gt;With vim's &lt;code&gt;foldmethod=marker&lt;/code&gt; active, every capture block collapses to a&lt;br&gt;
single line — just the fold label. A documentation file with twelve captures&lt;br&gt;
becomes twelve navigable lines. You can jump directly to the example you want,&lt;br&gt;
expand it, edit it, and collapse it again — without losing your place in the&lt;br&gt;
surrounding structure.&lt;/p&gt;
&lt;h3&gt;
  
  
  Enabling It
&lt;/h3&gt;

&lt;p&gt;The project ships configuration files for the three most common editors, so&lt;br&gt;
this works automatically once a one-time prerequisite is met.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vim / Neovim&lt;/strong&gt; — native support, no plugins required.&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;set exrc&lt;/code&gt; to your &lt;code&gt;~/.vimrc&lt;/code&gt; or &lt;code&gt;~/.config/nvim/init.vim&lt;/code&gt; once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;exrc&lt;/span&gt;   " allow project&lt;span class="p"&gt;-&lt;/span&gt;level &lt;span class="p"&gt;.&lt;/span&gt;vimrc &lt;span class="k"&gt;files&lt;/span&gt;
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;secure&lt;/span&gt; " optional&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;sandbox&lt;/span&gt; project vimrc &lt;span class="p"&gt;(&lt;/span&gt;recommended&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, the project's &lt;code&gt;.vimrc&lt;/code&gt; takes over and sets &lt;code&gt;foldmethod=marker&lt;/code&gt;&lt;br&gt;
whenever you open a file in the project directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VS Code&lt;/strong&gt; — install the recommended extension.&lt;/p&gt;

&lt;p&gt;When you open the project in VS Code, you'll see a prompt to install&lt;br&gt;
recommended extensions. Accept it to install&lt;br&gt;
&lt;a href="https://marketplace.visualstudio.com/items?itemName=jmfirth.vscode-custom-folding" rel="noopener noreferrer"&gt;Custom Folding&lt;/a&gt;&lt;br&gt;
(listed in &lt;code&gt;.vscode/extensions.json&lt;/code&gt;). The &lt;code&gt;.vscode/settings.json&lt;/code&gt; file&lt;br&gt;
already configures &lt;code&gt;{{{&lt;/code&gt;/&lt;code&gt;}}}&lt;/code&gt; as the fold markers, so no further setup is&lt;br&gt;
needed. Once installed, &lt;code&gt;Fold All&lt;/code&gt; (&lt;code&gt;Ctrl+K, Ctrl+0&lt;/code&gt;) collapses all marked&lt;br&gt;
blocks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Emacs&lt;/strong&gt; — install the &lt;code&gt;folding&lt;/code&gt; package once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;M-x package-install RET folding RET
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, the project's &lt;code&gt;.dir-locals.el&lt;/code&gt; enables &lt;code&gt;folding-mode&lt;/code&gt;&lt;br&gt;
automatically whenever Emacs opens a file in the project directory.&lt;/p&gt;

&lt;p&gt;Even if your editor doesn't support fold markers natively, the pattern is still&lt;br&gt;
useful: the &lt;code&gt;{{{&lt;/code&gt; / &lt;code&gt;}}}&lt;/code&gt; strings are greppable labels. A quick &lt;code&gt;grep '{{{' showcase.md&lt;/code&gt;&lt;br&gt;
gives you an instant index of all captures in a file.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Architecture: Collector + Runner
&lt;/h2&gt;

&lt;p&gt;Under the hood, this works through a two-phase pipeline.&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 1: The Collector
&lt;/h3&gt;

&lt;p&gt;A Node.js script (&lt;code&gt;scripts/collect-docs-examples.js&lt;/code&gt;) scans the entire &lt;code&gt;docs/&lt;/code&gt;&lt;br&gt;
folder. For each Markdown file, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extracts all &lt;code&gt;{% capture %}&lt;/code&gt; blocks into an in-memory map.&lt;/li&gt;
&lt;li&gt;Finds every &lt;code&gt;{% include components/sampletabs_tpl.md %}&lt;/code&gt; call.&lt;/li&gt;
&lt;li&gt;Resolves each parameter: &lt;code&gt;htmlSource&lt;/code&gt;, &lt;code&gt;cssSource&lt;/code&gt;, &lt;code&gt;jsSource&lt;/code&gt;, &lt;code&gt;tests&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Applies transformations:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$$&lt;/code&gt; → &lt;code&gt;-${formId}&lt;/code&gt; (ensures unique DOM IDs per example)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;█&lt;/code&gt; (a filled square character) → four spaces (an indentation hack for
Jekyll, which strips leading whitespace in liquid captures)&lt;/li&gt;
&lt;li&gt;Strips &lt;code&gt;!important&lt;/code&gt; from CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Skips purely illustrative examples (&lt;code&gt;jsSource="-"&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Writes everything to a JSON manifest at &lt;code&gt;test/.cache/docs_examples.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The collector also handles some subtleties. Jekyll filters like&lt;br&gt;
&lt;code&gt;{{ variable | replace: "old", "new" }}&lt;/code&gt; are simulated in JavaScript so the&lt;br&gt;
resolved content is identical to what Jekyll would produce. Docs-only&lt;br&gt;
parameters like &lt;code&gt;demoValue&lt;/code&gt; (which seeds a default value in the rendered page&lt;br&gt;
but is irrelevant to tests) are explicitly stripped.&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 2: The Runner
&lt;/h3&gt;

&lt;p&gt;A Playwright test file (&lt;code&gt;test/co_located_tests.tests.js&lt;/code&gt;) loads the manifest&lt;br&gt;
and generates one test per example. For each example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It assembles a minimal HTML page containing the example's HTML, CSS, and
JavaScript, plus a &lt;code&gt;&amp;lt;script src="/dist/SmarkForm.umd.js"&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It writes that page to a temp file and serves it via the local test server.&lt;/li&gt;
&lt;li&gt;It navigates Playwright to the page and waits for SmarkForm to initialize.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smoke checks&lt;/strong&gt; always run: the form container is visible; console error
and page error counts match expectations.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;tests&lt;/code&gt; is a code string (not &lt;code&gt;"false"&lt;/code&gt;), the code is written to a
temporary &lt;code&gt;.mjs&lt;/code&gt; file and dynamically imported. The exported default
function is called with &lt;code&gt;{ page, expect, id, root, readField, writeField }&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The helpers passed to each test function are worth noting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;root&lt;/code&gt; — a Playwright locator pointing to &lt;code&gt;#myForm-${id}&lt;/code&gt;, the example's
container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;readField(path)&lt;/code&gt; — exports a field's current value via SmarkForm's own
&lt;code&gt;.find(path).export()&lt;/code&gt; API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;writeField(path, value)&lt;/code&gt; — imports a value into a field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means co-located tests can test behavior at the SmarkForm API level, not&lt;br&gt;
just at the DOM level. You can assert &lt;code&gt;expect(await readField('price')).toBe(42)&lt;/code&gt;&lt;br&gt;
instead of digging into the DOM for the raw input value.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Enforcement Rule
&lt;/h3&gt;

&lt;p&gt;One critical design decision: &lt;strong&gt;every example must declare &lt;code&gt;tests=...&lt;/code&gt;&lt;/strong&gt;, even&lt;br&gt;
if just &lt;code&gt;tests=false&lt;/code&gt;. If an example is missing the parameter, the test suite&lt;br&gt;
fails with a clear message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Example showcase.md_basic_form is missing co-located tests.
Please add a tests= parameter to the {% include %} block,
or use tests=false to explicitly disable testing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enforcement ensures the question "does this example have a test?" is&lt;br&gt;
always explicitly answered. You can't accidentally omit it. The quality floor&lt;br&gt;
only goes up.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Naming Evolution
&lt;/h2&gt;

&lt;p&gt;The system went through a quick naming evolution that's worth mentioning because&lt;br&gt;
it reflects the conceptual clarity that emerged over time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first test harness was called &lt;code&gt;docs_examples.tests.js&lt;/code&gt; — named after
what it tested (docs examples).&lt;/li&gt;
&lt;li&gt;It was soon renamed to &lt;code&gt;co_located_tests.tests.js&lt;/code&gt; — named after the
&lt;em&gt;strategy&lt;/em&gt; (tests living alongside the code they test).&lt;/li&gt;
&lt;li&gt;A companion file, &lt;code&gt;co_located_tests_validation.tests.js&lt;/code&gt;, handles the
meta-level: it tests the manifest itself, verifying that every example has
valid &lt;code&gt;tests&lt;/code&gt; and error-count declarations, and that transformations
(no stray &lt;code&gt;$$&lt;/code&gt;, no &lt;code&gt;█&lt;/code&gt; characters) were applied correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The naming made it clearer that the &lt;em&gt;principle&lt;/em&gt; — co-location — was the&lt;br&gt;
important thing, not the specific mechanism.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Workflow: Interactive Test Picking
&lt;/h2&gt;

&lt;p&gt;Writing tests is one thing. &lt;em&gt;Running a single test while you're developing&lt;/em&gt;&lt;br&gt;
is another. The co-located tests are loaded and run by Playwright, which means&lt;br&gt;
you can already filter them with &lt;code&gt;-g&lt;/code&gt; and &lt;code&gt;--project&lt;/code&gt;. But the project added&lt;br&gt;
something nicer: an interactive test picker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;:pick
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This drops you into an interactive shell menu where you choose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What to test&lt;/strong&gt;: regular tests, co-located tests (all), or co-located
tests for a specific documentation file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which example&lt;/strong&gt;: if you chose a specific file, which &lt;code&gt;formId&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which browser&lt;/strong&gt;: Chromium, Firefox, or WebKit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After selecting, it builds the right Playwright command and runs it. It also&lt;br&gt;
remembers your last choice, so a &lt;code&gt;--repeat&lt;/code&gt; flag lets you quickly re-run the&lt;br&gt;
same test after changing something.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;:pick &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--repeat&lt;/span&gt; &lt;span class="nt"&gt;--headed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This combination — pick once, repeat with &lt;code&gt;--headed&lt;/code&gt; or &lt;code&gt;--debug&lt;/code&gt; — was a&lt;br&gt;
genuine quality-of-life improvement for the write-test-fix loop.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bugs It Caught
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. Writing tests for existing examples&lt;br&gt;
immediately surfaced bugs that had been lurking unnoticed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Hotkeys State Bug
&lt;/h3&gt;

&lt;p&gt;While writing a test for the 2nd-level hotkeys example in the showcase, the&lt;br&gt;
author (&lt;a href="https://github.com/bitifet" rel="noopener noreferrer"&gt;@bitifet&lt;/a&gt;) encoded an expectation that&lt;br&gt;
seemed obvious: &lt;em&gt;releasing the Alt key while Ctrl is held should return to&lt;br&gt;
the 1st-level hotkeys display&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The test was committed with a note: &lt;em&gt;"It fails while checking that releasing&lt;br&gt;
ALT returns to previous status if Ctrl is hold. But this is a REAL bug, so&lt;br&gt;
the test is Ok."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The very next commit fixed &lt;code&gt;src/lib/hotkeys.js&lt;/code&gt;. The bug had existed in the&lt;br&gt;
library, silently, until a documentation example was tested.&lt;/p&gt;

&lt;h3&gt;
  
  
  The datetime-local Naming Bug
&lt;/h3&gt;

&lt;p&gt;When the &lt;code&gt;datetime-local&lt;/code&gt; component type was added, a co-located test caught&lt;br&gt;
a naming inconsistency: the example source used &lt;code&gt;"datetimeLocal"&lt;/code&gt; (camelCase)&lt;br&gt;
while the implementation expected &lt;code&gt;"datetime-local"&lt;/code&gt; (kebab-case). The test&lt;br&gt;
failed; the example source was corrected.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Smoke Check Safety Net
&lt;/h3&gt;

&lt;p&gt;Beyond specific behavioral tests, the smoke checks — which run for &lt;em&gt;every&lt;/em&gt;&lt;br&gt;
example — have caught examples that failed to initialize at all due to&lt;br&gt;
a breaking API change. If an example produces a console error it's not&lt;br&gt;
expected to, the test fails immediately. No manual clicking through the docs&lt;br&gt;
required.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;p&gt;At the time of the 0.12.6 release (which introduced co-located tests), the&lt;br&gt;
library described it this way in the changelog:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Major improvements to testing infrastructure and coverage:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Migrated the test suite to Playwright, covering Chromium, Firefox, and WebKit.&lt;/li&gt;
&lt;li&gt;Added smoke tests for all examples in the documentation.&lt;/li&gt;
&lt;li&gt;Co-located, feature-specific tests for each example are now possible — and enforced.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The suite covers dozens of interactive documentation examples, each exercised&lt;br&gt;
across three browsers, all driven by the same living documentation that users&lt;br&gt;
read and trust.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes This Approach Work
&lt;/h2&gt;

&lt;p&gt;A few principles made the co-located test strategy effective in SmarkForm:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The test is right next to what it tests.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's no context-switching between "the docs example" and "the test for the&lt;br&gt;
docs example." They're in the same file, a few lines apart. When you update&lt;br&gt;
the example, you immediately see its test and update it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Tests are enforced, not optional.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The "you must declare &lt;code&gt;tests=&lt;/code&gt; or &lt;code&gt;tests=false&lt;/code&gt;" rule means there's no&lt;br&gt;
ambiguity. It's not a linting warning; it's a test failure. Every example is&lt;br&gt;
accounted for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The test interface is ergonomic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;readField&lt;/code&gt; / &lt;code&gt;writeField&lt;/code&gt; helpers let you interact with the form at&lt;br&gt;
the SmarkForm API level. You don't have to know whether a number field renders&lt;br&gt;
as an &lt;code&gt;&amp;lt;input type="number"&amp;gt;&lt;/code&gt; or something else — you just call&lt;br&gt;
&lt;code&gt;readField('price')&lt;/code&gt; and assert on the returned value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The test picker reduces friction.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When testing one specific example in one specific browser is two menu selections&lt;br&gt;
away, you do it more often. Lower friction → more tests written → more bugs&lt;br&gt;
found earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The examples are isolated.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each example gets its own minimal HTML page, its own SmarkForm instance, its&lt;br&gt;
own error tracking. There's no bleed-through between examples. The smoke checks&lt;br&gt;
for one example don't affect another.&lt;/p&gt;




&lt;h2&gt;
  
  
  Takeaways for Your Own Project
&lt;/h2&gt;

&lt;p&gt;If your project has a documentation site with interactive examples, here's the&lt;br&gt;
core idea distilled:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treat documentation examples as first-class test subjects.&lt;/strong&gt; They're not&lt;br&gt;
just prose — they're code that runs in your users' browsers (or in their&lt;br&gt;
heads when they copy-paste). Test them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Put the test near the example.&lt;/strong&gt; The closer the test is to what it tests,&lt;br&gt;
the more likely it will be maintained. Co-location is the key.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enforce test presence.&lt;/strong&gt; An optional test is a test that won't get written.&lt;br&gt;
Make it a breaking build failure when a test is absent and undeclared.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Invest in ergonomic helpers.&lt;/strong&gt; The test interface should feel natural to&lt;br&gt;
someone who knows the library API. If writing a test requires knowing the&lt;br&gt;
DOM structure, that's a leaky abstraction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make the test loop fast.&lt;/strong&gt; A test picker, a &lt;code&gt;--repeat&lt;/code&gt; flag, a &lt;code&gt;--headed&lt;/code&gt;&lt;br&gt;
mode — any investment in the write-test-fix loop pays compound interest.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Co-located tests for documentation examples started as an experiment in the&lt;br&gt;
SmarkForm project and quickly became one of the most practically impactful&lt;br&gt;
improvements to the development workflow. They've caught real bugs — bugs that&lt;br&gt;
had existed in the library, invisible, until someone wrote down what the correct&lt;br&gt;
behavior &lt;em&gt;should&lt;/em&gt; be and a test confirmed it wasn't.&lt;/p&gt;

&lt;p&gt;More than the bugs, though, what co-located tests provide is &lt;em&gt;confidence&lt;/em&gt; — the&lt;br&gt;
confidence to refactor, to add a feature, to change a behavior, and know that&lt;br&gt;
the documentation examples will tell you immediately if you've broken something&lt;br&gt;
that matters.&lt;/p&gt;

&lt;p&gt;Documentation and tests have always had a troubled relationship. Co-location is&lt;br&gt;
one way to give them a common home — and to stop treating the docs as a place&lt;br&gt;
where bugs go to hide.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;SmarkForm is an open-source, markup-driven form library for building complex&lt;br&gt;
HTML forms with nested subforms, variable-length lists, and JSON import/export.&lt;br&gt;
→ &lt;a href="https://smarkform.bitifet.net" rel="noopener noreferrer"&gt;smarkform.bitifet.net&lt;/a&gt; · &lt;a href="https://github.com/bitifet/SmarkForm" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>automation</category>
      <category>documentation</category>
      <category>testing</category>
    </item>
    <item>
      <title>Generating a Parametric SVG Logo with Pug</title>
      <dc:creator>Joan Miquel Torres</dc:creator>
      <pubDate>Mon, 02 Feb 2026 23:22:00 +0000</pubDate>
      <link>https://dev.to/bitifet/generating-a-parametric-svg-logo-with-pug-8m0</link>
      <guid>https://dev.to/bitifet/generating-a-parametric-svg-logo-with-pug-8m0</guid>
      <description>&lt;p&gt;Designing a logo is usually treated as a one-off, visual task.&lt;br&gt;
Designing a &lt;em&gt;logo system&lt;/em&gt;—with variants, themes, sizes, and guarantees of consistency—is a very different problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn44fa3v5i5jwvxy0ke0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn44fa3v5i5jwvxy0ke0v.png" alt="New SmarkForm logo" width="406" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article I’ll show how I ended up generating &lt;strong&gt;real SVG logo files&lt;/strong&gt;, fully parametric, using &lt;strong&gt;Pug&lt;/strong&gt;, &lt;strong&gt;embedded and subsetted fonts&lt;/strong&gt;, and a &lt;strong&gt;CLI-driven pipeline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This approach has been used to create a &lt;strong&gt;new &lt;em&gt;SmarkForm&lt;/em&gt; logo&lt;/strong&gt;, which will &lt;strong&gt;replace the current one starting from upcoming version 0.13.0&lt;/strong&gt;.&lt;br&gt;
The logo is not just an asset anymore: it is &lt;em&gt;generated&lt;/em&gt;, reproducible, and version-controlled.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://smarkform.bitifet.net" rel="noopener noreferrer"&gt;SmarkForm&lt;/a&gt;&lt;/strong&gt; is a free and open-source toolkit for &lt;strong&gt;declarative, markup-driven form generation&lt;/strong&gt; — from simple inputs to complex nested forms and dynamic lists, with first-class &lt;strong&gt;JSON import/export&lt;/strong&gt;. It is framework-agnostic and styling-agnostic by design, and &lt;strong&gt;that same philosophy now applies to its branding&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;I wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;single logo definition&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Variants for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;light / dark&lt;/li&gt;
&lt;li&gt;monochrome&lt;/li&gt;
&lt;li&gt;compact / full&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fonts &lt;strong&gt;embedded and subsetted&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Output as &lt;strong&gt;real &lt;code&gt;.svg&lt;/code&gt; files&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generated via &lt;strong&gt;CLI&lt;/strong&gt;, not a browser&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reproducible and scriptable&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: &lt;strong&gt;branding as code&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Pug?
&lt;/h2&gt;

&lt;p&gt;Pug gives you three things that are surprisingly powerful for SVG work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Logic&lt;/strong&gt; (conditions, defaults, variants)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parametrization&lt;/strong&gt; (options passed from CLI)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readable structure&lt;/strong&gt; for complex SVG trees&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;SVG is XML.&lt;br&gt;
Pug is extremely good at generating structured XML.&lt;/p&gt;

&lt;p&gt;That combination is criminally underrated.&lt;/p&gt;


&lt;h2&gt;
  
  
  Turning SVG into a First-Class Template
&lt;/h2&gt;

&lt;p&gt;The key decision was this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t generate HTML that &lt;em&gt;contains&lt;/em&gt; SVG.&lt;br&gt;
Generate SVG directly so that it can be linked everywhere.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;doctype svg&lt;/code&gt; instead of (default in Pug) &lt;code&gt;doctype html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The root node is &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Follow svg specs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  A Pug mixin as the logo engine
&lt;/h3&gt;

&lt;p&gt;Implementing the svg as a Pug mixin let me actually start with an HTML document showcasing different parameters combinations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even colors and fonts were originally parametyzed &lt;strong&gt;allowing to examine several configurations side by side&lt;/strong&gt; until the winner was choosen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At the end of the process only functional parameters have been kept.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mixin smarkformLogo(options = {})
  -
    const {
      mode = 'light',
      compact = false,
      monochrome = false,
      size = 100
    } = options;

    const height = size;
    const width  = compact
      ? Math.round(height * 1.105)
      : Math.round(height * 4.1);

  svg(
    xmlns="http://www.w3.org/2000/svg"
    width=width
    height=height
    viewBox=`0 0 ${width} ${height}`
    role="img"
    aria-label="SmarkForm logo"
  )
    // SVG content here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point we already have something valuable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dimensions are computed&lt;/li&gt;
&lt;li&gt;Variants are driven by data&lt;/li&gt;
&lt;li&gt;The SVG is no longer static&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Choosing and Subsetting Fonts
&lt;/h2&gt;

&lt;p&gt;External fonts are fragile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network-dependent&lt;/li&gt;
&lt;li&gt;Inconsistent&lt;/li&gt;
&lt;li&gt;Sometimes forbidden in branding assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the decision was to &lt;strong&gt;embed the font directly in the SVG&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Picking a font with the right license
&lt;/h3&gt;

&lt;p&gt;For SmarkForm I used &lt;strong&gt;Work Sans&lt;/strong&gt;, available from&lt;br&gt;
👉 &lt;a href="https://fonts.google.com" rel="noopener noreferrer"&gt;https://fonts.google.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Fonts is particularly useful because you can filter by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open-source licenses (SIL Open Font License, Apache 2.0, etc.)&lt;/li&gt;
&lt;li&gt;Font weights&lt;/li&gt;
&lt;li&gt;Variable fonts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it easy to ensure your branding assets are legally safe to embed and redistribute.&lt;/p&gt;
&lt;h3&gt;
  
  
  Subsetting the font
&lt;/h3&gt;

&lt;p&gt;Instead of embedding a full font file, I generated &lt;strong&gt;subsetted WOFF2 files&lt;/strong&gt; containing only the glyphs actually used in the logo.&lt;/p&gt;

&lt;p&gt;This keeps the SVG:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller&lt;/li&gt;
&lt;li&gt;Faster to load&lt;/li&gt;
&lt;li&gt;More intentional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools like &lt;code&gt;pyftsubset&lt;/code&gt; (from fonttools) are perfect for this step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examnple:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyftsubset static/WorkSans-Regular.ttf &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;SmarkForm}"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--flavor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;woff2 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--output-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;WorkSans-SmarkForm-Regular.woff2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In my case, for stylistic reasons, I used two different faces of the font so I had to do this twice (once for WorkSans-Regular and one for WorkSans-SemiBold).&lt;/p&gt;

&lt;p&gt;You can stick with one or pick for even different fonts. I reckon keeping things simpler is better for a logo though.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Embedding Fonts via Base64
&lt;/h2&gt;

&lt;p&gt;Once you have your subsetted &lt;code&gt;.woff2&lt;/code&gt;, embedding it is straightforward.&lt;/p&gt;

&lt;p&gt;From the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;base64&lt;/span&gt; &amp;lt; WorkSans-SmarkForm-Regular.woff2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inline it into the template.&lt;/p&gt;

&lt;p&gt;A small stylistic trick I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WorkSans_regular_b64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
  base64 &amp;lt; WorkSans-SmarkForm-Regular.woff2
`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Declaring binary (base64) data in a variable at the beginning keeps the actual code cleaner afterwards.&lt;/li&gt;
&lt;li&gt;The backticks sit &lt;em&gt;outside&lt;/em&gt; the base64 block, so alignment stays clean.&lt;/li&gt;
&lt;li&gt;Newlines and spaces are stripped afterwards (avoiding css issues).&lt;/li&gt;
&lt;li&gt;Assuming the file is in the current directory, in Vim you can simply type
&lt;code&gt;:vip!bash&lt;/code&gt; to insert in place the file contents encoded in base64.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A subtle but important detail
&lt;/h3&gt;

&lt;p&gt;Base64 &lt;strong&gt;itself&lt;/strong&gt; allows arbitrary whitespace and newlines.&lt;br&gt;
CSS &lt;strong&gt;does not&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you forget to strip whitespace, your font may silently fail to load.&lt;br&gt;
This is one of those details that’s obvious &lt;em&gt;after&lt;/em&gt; you hit it once.&lt;/p&gt;


&lt;h2&gt;
  
  
  Wiring Fonts to SVG Text via CSS
&lt;/h2&gt;

&lt;p&gt;Fonts are referenced via CSS inside &lt;code&gt;&amp;lt;defs&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defs
  style.
    @font-face {
      font-family: 'WS-Regular';
      src: url('data:font/woff2;base64,#{WorkSans_regular_b64}') format('woff2');
    }

    @font-face {
      font-family: 'WS-SemiBold';
      src: url('data:font/woff2;base64,#{WorkSans_SemiBold_b64}') format('woff2');
    }

    text.regular {
      font-family: 'WS-Regular';
      dominant-baseline: middle;
    }

    text.semibold {
      font-family: 'WS-SemiBold';
      dominant-baseline: middle;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.regular&lt;/code&gt; / &lt;code&gt;.semibold&lt;/code&gt; classes don’t mean anything special by themselves —&lt;br&gt;
they’re simply a clean way to bind &lt;strong&gt;specific font weights and behaviors&lt;/strong&gt; to specific parts of the logo.&lt;/p&gt;


&lt;h2&gt;
  
  
  Rendering Text Safely in SVG
&lt;/h2&gt;

&lt;p&gt;One small but important gotcha when generating SVG with Pug:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text.regular(
  x=lmargin
  y=height / 2
  font-size=height * 0.6
  fill=primaryColor
)='&amp;lt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;strong&gt;must be passed as a string&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Otherwise it’s interpreted as markup and breaks the SVG.&lt;br&gt;
Once you do this explicitly, Pug behaves exactly as expected&lt;br&gt;
by replacing them with their correspondent HTML entities.&lt;/p&gt;


&lt;h2&gt;
  
  
  Compact vs Full Variants (Same Source)
&lt;/h2&gt;

&lt;p&gt;With logic in place, variants are trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if compact
  text.semibold(...) 'S'
  text.semibold(...) '}'
else
  text.regular(...) '&amp;lt;'
  text.semibold(...) 'Smark'
  text.semibold(...) 'Form'
  text.semibold(...) '}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No duplication.&lt;br&gt;
No parallel files.&lt;br&gt;
One definition, many outcomes.&lt;/p&gt;


&lt;h2&gt;
  
  
  Generating Real SVG Files from the CLI
&lt;/h2&gt;

&lt;p&gt;This is the payoff.&lt;/p&gt;

&lt;p&gt;Once the template outputs &lt;strong&gt;only SVG&lt;/strong&gt;, you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx pug-cli &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-O&lt;/span&gt; &lt;span class="s1"&gt;'{ compact: true, mode: "dark" }'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &amp;lt; smarkform_logo.pug &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; smarkform_compact_dark.svg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that file is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A valid SVG&lt;/li&gt;
&lt;li&gt;Fully self-contained&lt;/li&gt;
&lt;li&gt;Embeddable anywhere&lt;/li&gt;
&lt;li&gt;Diff-friendly&lt;/li&gt;
&lt;li&gt;Reproducible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can script &lt;strong&gt;all variants&lt;/strong&gt; in seconds.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fobvgzo96expf5akp7w4e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fobvgzo96expf5akp7w4e.png" alt="SmarkForm logo variants" width="589" height="577"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Integration into the SmarkForm project
&lt;/h2&gt;

&lt;p&gt;Integrating the new logo into the &lt;em&gt;SmarkForm&lt;/em&gt; codebase turned out to be refreshingly simple.&lt;/p&gt;

&lt;p&gt;The existing assets already lived under /docs/assets, so I introduced a new logo directory for better organization, with a src subdirectory to hold the source files.&lt;/p&gt;

&lt;p&gt;The Pug template that generates the logo variants now lives in &lt;code&gt;/docs/assets/logo/src&lt;/code&gt;, alongside a small Bash script responsible for rendering the desired SVG outputs. The script is intentionally minimal and largely self-documenting, making it easy to adjust or extend if new variants are needed in the future.&lt;/p&gt;

&lt;p&gt;Importantly, this script is not part of the build process. The generated SVG files are stable, self-contained assets and remain valid until the logo source itself changes. In practice, this means the script only needs to be executed when the Pug template is modified—keeping the build pipeline clean and avoiding unnecessary regeneration work.&lt;/p&gt;

&lt;p&gt;You can find both the generator template and the accompanying script in the aforementioned &lt;a href="https://github.com/bitifet/SmarkForm/tree/main/docs/assets/logo/src" rel="noopener noreferrer"&gt;/docs/assets/logo/src&lt;/a&gt; directory in the SmarkForm GitHub repository.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Scales
&lt;/h2&gt;

&lt;p&gt;This approach scales because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logos become &lt;strong&gt;data-driven&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Branding lives &lt;strong&gt;inside the repository&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Changes are auditable&lt;/li&gt;
&lt;li&gt;Variants never drift out of sync&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just as importantly, it respects SmarkForm’s philosophy:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SmarkForm is markup-driven and styling-agnostic.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The branding system does &lt;strong&gt;not&lt;/strong&gt; impose a visual identity on user forms.&lt;br&gt;
Instead, it provides optional, lightweight visual cues — icons or small banners — so end users may recognize a form as being powered by SmarkForm and know what kind of experience to expect.&lt;/p&gt;

&lt;p&gt;Developers and designers remain fully in control.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This started as “I just want a logo SVG”.&lt;/p&gt;

&lt;p&gt;It ended as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A parametric branding system&lt;/li&gt;
&lt;li&gt;A CLI-driven asset pipeline&lt;/li&gt;
&lt;li&gt;A single source of truth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you already treat &lt;strong&gt;UI as code&lt;/strong&gt;,&lt;br&gt;
there’s no good reason your &lt;strong&gt;branding assets&lt;/strong&gt; shouldn’t be treated the same way.&lt;/p&gt;

&lt;p&gt;Once you do it like this, going back feels… unnecessary 😉&lt;/p&gt;

</description>
      <category>automation</category>
      <category>design</category>
      <category>frontend</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>PostgreSQL and high availability in Node.js</title>
      <dc:creator>Joan Miquel Torres</dc:creator>
      <pubDate>Mon, 12 Aug 2024 17:54:04 +0000</pubDate>
      <link>https://dev.to/bitifet/postgresql-and-high-availability-in-nodej-5akj</link>
      <guid>https://dev.to/bitifet/postgresql-and-high-availability-in-nodej-5akj</guid>
      <description>&lt;p&gt;For those using PostgreSQL with Node.JS and worried about High Availability and outage resilience, I have published this wrapper solving important issues in node-pg:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/bitifet/node-postgres-ha" rel="noopener noreferrer"&gt;https://github.com/bitifet/node-postgres-ha&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am looking forward to cherry-pick the improvements as PRs to actual node-postgres but, by now, it fits our goals of preventing issues derived from eventual server or network malfunctions.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Simulate TCP network congestion with netjam</title>
      <dc:creator>Joan Miquel Torres</dc:creator>
      <pubDate>Tue, 06 Aug 2024 21:24:17 +0000</pubDate>
      <link>https://dev.to/bitifet/simulate-tcp-network-congestion-with-netjam-5dm9</link>
      <guid>https://dev.to/bitifet/simulate-tcp-network-congestion-with-netjam-5dm9</guid>
      <description>&lt;p&gt;Network issues always come in production.&lt;/p&gt;

&lt;p&gt;We tend to, at most, perform some stress tests to check what happen in&lt;br&gt;
(unrealistic) high load situations or even stop some critical services,&lt;br&gt;
like databases, to see how resilient is our application or service..&lt;/p&gt;

&lt;p&gt;But the truth is that there can be worst situations...&lt;/p&gt;

&lt;p&gt;I mean: If your database goes down, you'll rapidly get errors due to TCP&lt;br&gt;
connection attempts being rejected.&lt;/p&gt;

&lt;p&gt;But, when network speed decreases due to the amount of traffic, network errors,&lt;br&gt;
etc... You may end up with lots of pending requests that will never end causing&lt;br&gt;
much more trouble that could be easily avoided if we had properly detected the&lt;br&gt;
situation.&lt;/p&gt;

&lt;p&gt;To be able to address that situations we need to reproduce them, at least at&lt;br&gt;
some level.&lt;/p&gt;

&lt;p&gt;As a first approach, I tried with &lt;em&gt;iptables&lt;/em&gt; DROP rules, but this is drastic&lt;br&gt;
solution: Either you have a perfect connection or all packets are lost. And I&lt;br&gt;
wanted to play with several &lt;a href="https://node-postgres.com/apis/client#new-client" rel="noopener noreferrer"&gt;PostgreSQL&lt;br&gt;
timeouts&lt;/a&gt; and their effect in&lt;br&gt;
different situations.&lt;/p&gt;

&lt;p&gt;Finally I ended up implementing my own tool to simulate different levels of&lt;br&gt;
traffic congestion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.npmjs.com/package/netjam" rel="noopener noreferrer"&gt;Npm package&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/bitifet/netjam" rel="noopener noreferrer"&gt;Git repository&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't know if there are other similar tools out there (at least I haven't&lt;br&gt;
found any until now: If you know any, please tell me in the comments).&lt;/p&gt;

&lt;p&gt;...And it's still far from perfect.&lt;/p&gt;

&lt;p&gt;But, at least, it helped me to learn a lot about how PostgreSQL timeouts work&lt;br&gt;
and the effects they can have in different situations.&lt;/p&gt;

&lt;p&gt;And it is a very simple-to-use tool. Specially now that I bundled it as a &lt;em&gt;npm&lt;/em&gt;&lt;br&gt;
package so that, if you have Node/NPM in your system, you only need to execute&lt;br&gt;
the following to get started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx netjam &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, to create a &lt;em&gt;jamable&lt;/em&gt; TCP tunnel to local PostgreSQL Server&lt;br&gt;
listening in its default port (5432) you only need to execute the following&lt;br&gt;
command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx netjam localhost 5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you will get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Server listening on port 5000

STATUS:
┌─────────────┬────────────────────────────┐
│   &lt;span class="o"&gt;(&lt;/span&gt;index&lt;span class="o"&gt;)&lt;/span&gt;   │           Values           │
├─────────────┼────────────────────────────┤
│ remoteHost  │        &lt;span class="s1"&gt;'localhost'&lt;/span&gt;         │
│ remotePort  │           &lt;span class="s1"&gt;'5432'&lt;/span&gt;           │
│ listenPort  │            5000            │
│  timestamp  │ &lt;span class="s1"&gt;'2024-08-06T18:52:11.042Z'&lt;/span&gt; │
│   waiting   │             0              │
│    open     │             0              │
│   closed    │             0              │
│  withError  │             0              │
│     tx      │             0              │
│     rx      │             0              │
│  iputDelay  │             0              │
│ outputDelay │             0              │
│ logInterval │       &lt;span class="s1"&gt;'0 (Disabled)'&lt;/span&gt;       │
└─────────────┴────────────────────────────┘

AVAILABLE COMMANDS:
  inputDelay    - Sets input delay to specified value
  outputDelay   - Sets output delay to specified value
  delay         - Sets overall balanced delay to specified value
  logInterval   - Show/Set status &lt;span class="o"&gt;(&lt;/span&gt;stderr&lt;span class="o"&gt;)&lt;/span&gt; logging interval &lt;span class="k"&gt;in &lt;/span&gt;msecs
  quit          - Quit the program

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By now it is capable to speed down transmission and reception speed by&lt;br&gt;
introducing small delays between packet transmission and reception at the other&lt;br&gt;
side.&lt;/p&gt;

&lt;p&gt;In the future it could be extended by introducing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Random (on customizable probability) transmission errors through data&lt;br&gt;
mangling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Random packet loosing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delay configuration as ranges (so it will take a random value between given&lt;br&gt;
bounds for each tx/rx packet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Who knows... Any ideas?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Simplify Web Form Development with SmarkForm</title>
      <dc:creator>Joan Miquel Torres</dc:creator>
      <pubDate>Fri, 07 Jul 2023 11:28:00 +0000</pubDate>
      <link>https://dev.to/bitifet/simplify-web-form-development-with-smarkform-1j51</link>
      <guid>https://dev.to/bitifet/simplify-web-form-development-with-smarkform-1j51</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Creating web forms can often feel like reinventing the wheel. Every time we need to implement a form, we find ourselves going through the same process.&lt;/p&gt;

&lt;p&gt;For simple forms with a few plain fields, it may be pretty straightforward. However, as soon as we need a little more complexity, such as lists, nested data, dynamic options, and more, it can quickly become a time-consuming and effort-intensive task that diverts our focus from the core functionality of our applications. But fear not! With SmarkForm, you can break free from this repetitive cycle and streamline your form development process.&lt;/p&gt;

&lt;p&gt;SmarkForm is a powerful and straightforward JavaScript library that will greatly simplify form development in your web applications. With SmarkForm, you can quickly and efficiently create interactive forms without having to worry about writing complex JavaScript code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is SmarkForm?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is based on the idea that web forms should be easy to create and maintain directly in HTML markup, without the need for writing a lot of additional JavaScript code.&lt;/p&gt;

&lt;p&gt;We just need to add a few properties in so-called &lt;em&gt;data-smark&lt;/em&gt; attributes to make our HTML markup  more semantic and let SmarkForm library do the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features of SmarkForm:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy and quick creation of interactive forms.&lt;/li&gt;
&lt;li&gt;Complete separation between layout design and application logic.&lt;/li&gt;
&lt;li&gt;Support for complex data structures, such as nested objects and arrays.&lt;/li&gt;
&lt;li&gt;Ability to manually sort and add or remove items from a lists (arrays).&lt;/li&gt;
&lt;li&gt;(Comming soon) Dynamic loading of options for select fields based on the values of other form fields.&lt;/li&gt;
&lt;li&gt;Customization and extensibility through custom components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Try it yourself:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Learn more about SmarkFor in its &lt;a href="https://smarkform.bitifet.net" rel="noopener noreferrer"&gt;Documentation site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don't miss its &lt;a href="https://smarkform.bitifet.net/resources/examples" rel="noopener noreferrer"&gt;examples section&lt;/a&gt; where you can check out its HTML source and JS example.&lt;/p&gt;

&lt;p&gt;Smarkform is available both as standard ESM and legacy UMD modules in &lt;a href="https://www.npmjs.com/package/smarkform" rel="noopener noreferrer"&gt;npm package&lt;/a&gt; and CDN.&lt;/p&gt;

&lt;p&gt;Former examples use UMD CDN so that they can be downloaded as single and fully functional HTML pages.&lt;/p&gt;

&lt;p&gt;It's styles are also served as separate CDN but you can use your own styling.&lt;/p&gt;

&lt;p&gt;Feel free to play modifying them as you like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have any questions or if you find this article unclear or incomplete, please let me know.&lt;/p&gt;

&lt;p&gt;I've made an effort to be approachable and prevent it from being tedious by excluding certain details that can already be found in the documentation and examples.&lt;/p&gt;

&lt;p&gt;However, if you believe that something is lacking, please provide your feedback in the comments.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>library</category>
    </item>
  </channel>
</rss>
