From a3feecac6239e6e14e331e1faec6ea62f5a32f97 Mon Sep 17 00:00:00 2001 From: Tim Abbott Date: Thu, 27 Jun 2024 11:29:37 -0700 Subject: [PATCH] docs: Add mock_template documentation to docs. Previously, this content was only available in an error message, and provided less context. --- docs/testing/testing-with-node.md | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/docs/testing/testing-with-node.md b/docs/testing/testing-with-node.md index 23f077a761..e40c24e1e7 100644 --- a/docs/testing/testing-with-node.md +++ b/docs/testing/testing-with-node.md @@ -153,6 +153,68 @@ The test runner (`index.js`) automatically runs all .js files in the `web/tests` directory, so you can simply start editing a file in that directory to create a new test. +## Verifying HTML templates with `mock_template` + +As a project, we prefer [end-to-end +testing][testing-philosophy-end-to-end] where possible, since those +tests are usually both more effective at catching bugs and cheaper to +maintain than tests that make heavy use of mocks. + +One place where mocks can often be useful is when testing logic for +rendering an HTML template in Zulip. The interesting logic that one +wants to verify can be split between two places: + +- Computing the **context data** object passed into the HTML template. +- Conditional logic in the HTML template itself. + +It can work well to write tests that verify properties of the computed +HTML template, for example, is a given CSS class present in the +result. + +But often, one can write a more readable test by instead verifying +the values of parameters in the context passed into the template +rendering. The `mock_template` function in Zulip's testing library +is designed to support this this. + +We use `mock_template` in our unit tests to verify that the JS code is +calling the template with the expected context data. And then we use +the results of mock_template to supply the JS code with either the +actual HTML from the template or some kind of zjquery stub. + +The `mock_template` function accepts 3 parameters: + +- The path within `web/templates` to the [Handlebars + template](../subsystems/html-css.md) that you'd like to mock. +- Whether to call the actual template rendering function so that you + can verify the HTML generated by this specific template. Since + Handlebars rendering in tests takes time and rarely catches bugs, we + recommend using `false` if you're only planning to check the context + data. +- A callback function that you can use to include assertions about + what parameters were passed into the template. This function + receives a `data` parameter, with the context data, and an `html` + parameter if the real template was rendered. + +The following illustrates the two common patterns for using this method. + +```js +run_test("test something calling template", ({mock_template}) => { + mock_template("path/to/template.hbs", false, (data) => { + assert.deepEqual(data, {...}; + // or assert.deepEqual(data.foo, {...}); + return "stub-for-zjquery"; + }); + + mock_template("path/to/template.hbs", true, (data, html) => { + assert.deepEqual(data, {...}; + assert.ok(html.startWith(...)); + return html; + }); +}); +``` + +[testing-philosophy-end-to-end]: https://zulip.readthedocs.io/en/stable/testing/philosophy.html#integration-testing-or-unit-testing + ## Coverage reports You can automatically generate coverage reports for the JavaScript unit