Twig Smoke Rendering - Why do we Even Need it?

Two weeks ago our upgrade team started to upgrade Twig 1 to 2 and Latte 2 to 3 for two clients. There was no test that covers the templates, just a few integration ones that might have invoked a few % of happy paths render. Not good enough.

We need a CI test to be sure templates are working. I had an initial idea, but knowing the value of external input, I asked on Twitter for brainstorming. I'm happy I did. Alexander Schranz came with a tip that led me on a 2-week journey, and I would love to share it with you today.

Why do we need Smoke Render all Templates?

First, let me tell you about the 3 reasons why we need smoke-render all TWIG templates:


  1. Twig 1 and 2 contains a few BC breaks. Not only in Twig itself but also in related Twig Bundle. We're not interested in the complete list of BC breaks, but rather if they break our templates and where exactly.

  1. We need to render templates directly, without controllers and variables. The controller renders only a specific path. Based on variables, it can include one template snippet but forget the other:
{% if value %}
    {% include 'snippet/first_option.twig' %}
{% else %}
    {% include 'snippet/second_option.twig' %}
{% endif %}

  1. We must ensure all the functions, filters, and constants exist. What if the join filter was removed and replaced by implode? This is also useful for static analysis of templates.

The smoke rendering means "test that everything works". Render template and expect valid HTML. Not a file by file, test by test, but all TWIG files we can find in the project in a single test run. It could look like this:

bin/console twig-smoke-render templates

Why not use the TWIG Lint command?

You might think: "but Tomas, Symfony is already doing that for you":

bin/console lint:twig templates

That could work if we care about syntax errors like {{ value }. But we care about more than bare language syntax. We care about meaning and context:

That's why we don't use only php -l, but also PHPStan to check PHP code with context.



Now we have a Goal of Doom and a team of whys.

We're ready to set on the journey!


To be continued...


Happy coding!




Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors. I'd really appreciate it!