{"id":93015,"date":"2025-02-17T05:40:07","date_gmt":"2025-02-17T05:40:07","guid":{"rendered":"https:\/\/peraltafinancing.com\/analytics\/writing-tests-for-custom-templates-in-google-tag-manager\/"},"modified":"2025-02-17T05:40:07","modified_gmt":"2025-02-17T05:40:07","slug":"writing-tests-for-custom-templates-in-google-tag-manager","status":"publish","type":"post","link":"https:\/\/fivemor.com\/?p=93015","title":{"rendered":"Writing Tests For Custom Templates In Google Tag Manager"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div>\n<p><a href=\"https:\/\/tagmanager.google.com\/\">Google Tag Manager<\/a> introduced the capability to add <a href=\"https:\/\/developers.google.com\/tag-manager\/templates\/tests\">tests<\/a> to your <a href=\"https:\/\/www.simoahava.com\/analytics\/custom-templates-guide-for-google-tag-manager\/\">Custom Templates<\/a>. Tests, in this context, refer specifically to <strong>unit tests<\/strong> that you write in order to make sure your template code works in a predictable way.  Unit tests are also used to drive development, ensuring that you have added contingencies for all the different scenarios that the template, when coupled with user input, might introduce.<\/p>\n<div style=\"aspect-ratio: 957 \/ 338;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/11\/custom-template-tests.jpg\" title=\"Custom template tests\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"338\" width=\"957\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/11\/custom-template-tests.jpg#ZgotmplZ\" alt=\"Custom template tests\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>In this guide, I\u2019ll introduce how the <strong>Tests<\/strong> feature works. Some new APIs are introduced, as well as a <em>grammar<\/em> of sorts that you might be used to if you\u2019ve already worked with tests in a software development context.<\/p>\n<p>                <span class=\"simmer\"><br \/>\n  <span class=\"close\">X<\/span><\/p>\n<p>\n    <span class=\"fa fa-md fa-bell\"\/><br \/>\n    <strong>The Simmer Newsletter<\/strong>\n  <\/p>\n<p>\n    Subscribe to the <a href=\"https:\/\/www.simoahava.com\/newsletter\/\">Simmer newsletter<\/a> to get the latest news and content from Simo Ahava into your email inbox!\n  <\/p>\n<p>  <\/span><\/p>\n<h2 id=\"unit-tests-in-custom-templates\">Unit tests in Custom Templates<\/h2>\n<p><strong>Unit tests<\/strong> comprise code that is executed against the actual functions and variables of your template code.  The purpose of the test is to <strong>validate<\/strong> the template code, so that it returns an expected output for any given, tested input.<\/p>\n<p>The purpose of unit tests is to make your code more resilient to changes. By writing tests, you have a tool with which to verify that the changes you make in one place do not break something that happens in another place.<\/p>\n<p>With unit tests, you are testing the most atomic components of your code: the functions and variables. When you write tests, you aim for high <strong>code coverage<\/strong>. Coverage means the number of <strong>lines<\/strong> of code that are evaluated in some test.<\/p>\n<h3 id=\"simple-example-of-coverage\">Simple example of coverage<\/h3>\n<p>For example, say that you have a simple variable template like this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> getType = require(<span style=\"color:#a50\">'getType'<\/span>);\n<span style=\"color:#00a\">const<\/span> input = data.input;\n<span style=\"color:#00a\">if<\/span> (getType(input) === <span style=\"color:#a50\">'array'<\/span>) {\n  <span style=\"color:#00a\">return<\/span>;\n}\n<span style=\"color:#00a\">return<\/span> input;\n<\/code><\/pre>\n<\/div>\n<p>This template takes the user input and returns it. If the input is of type <strong>array<\/strong>, then <code>undefined<\/code> is returned instead.<\/p>\n<p>When writing tests for this variable, there are basically <strong>two<\/strong> scenarios you would need to test.<\/p>\n<h4 id=\"1-does-the-variable-return-undefined-for-array-input\">1. Does the variable return <code>undefined<\/code> for array input<\/h4>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#aaa;font-style:italic\">\/\/ Call runCode to run the template's code.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">const<\/span> mockData = {\n  input: <span style=\"color:#a50\">'notAnArray'<\/span>\n};\n\n<span style=\"color:#00a\">const<\/span> variableResult = runCode(mockData);\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Verify that the variable returns a result.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>assertThat(variableResult).isUndefined();\n<\/code><\/pre>\n<\/div>\n<p>Here you create a <strong>mock<\/strong> object that provides the input. This object has key-value pairs where each key corresponds to a property in the <code>data<\/code> object, reflecting the input the user would have added to the template fields.<\/p>\n<p>This object is passed to the <code>runCode<\/code> function, which is a template API that runs the template code against the data object.<\/p>\n<p>Finally, the result of <code>runCode<\/code> is passed to <code>assertThat<\/code>, which is an <strong>assertion<\/strong> method where you check whether the result of the code resolves to an expected value.<\/p>\n<h4 id=\"2-does-the-variable-return-the-input\">2. Does the variable return the input<\/h4>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> mockInput = <span style=\"color:#a50\">'something'<\/span>;\n<span style=\"color:#00a\">const<\/span> mockData = {\n  input: mockInput\n};\n\n<span style=\"color:#00a\">const<\/span> expected = mockInput;\n\n<span style=\"color:#00a\">const<\/span> variableResult = runCode(mockData);\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Verify that the variable returns a result.\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>assertThat(variableResult).isEqualTo(expected);\n<\/code><\/pre>\n<\/div>\n<p>As you can see, I\u2019m using constants and variables where possible to avoid hard-coding any values. This prevents simple typos from creating false positives or negatives in your tests.<\/p>\n<p>With these two tests, you actually achieve <strong>100% test coverage<\/strong> for the variable template, because the code tests all the possible variations of the variable.<\/p>\n<h4 id=\"what-about-missing-input\">What about missing input?<\/h4>\n<p>When writing tests, you\u2019re faced with interesting design decisions as well.<\/p>\n<p>Take the example above. We\u2019re not specifically testing a scenario where the user didn\u2019t add <em>any<\/em> input to the field. Why? Because we\u2019ve decided to handle that in the user interface, by adding a <a href=\"https:\/\/www.simoahava.com\/analytics\/custom-templates-guide-for-google-tag-manager\/#validation-rules\">validation rule<\/a> that prevents the template code from running if there is no input in the field.<\/p>\n<p>So when writing tests, you need to know how the template works, and you need to be able to comprehensively approach the different scenarios that imaginative users can exploit when working with your template code.<\/p>\n<h2 id=\"the-anatomy-of-a-test\">The anatomy of a test<\/h2>\n<p>You\u2019ve learned above that unit tests have some specific components. They are, in order:<\/p>\n<p><strong>Mock of the data object<\/strong><br \/><strong>Mocks of the template APIs (<code>mock()<\/code>)<\/strong><br \/><strong>The test runner (<code>runCode()<\/code>)<\/strong><br \/><strong>(Optional <code>fail()<\/code>)<\/strong><br \/><strong>Assertions (<code>assertApi()<\/code>, <code>assertThat()<\/code>)<\/strong><\/p>\n<h3 id=\"1-mocking\">1. Mocking<\/h3>\n<p>To test a function, you use <em>mock data<\/em>. This is because with automated tests there is no prompt for user input. The test needs to run independently of the template itself. With unit tests, you are <strong>only<\/strong> testing the code itself, not the user experience.<\/p>\n<p>In Google Tag Manager\u2019s custom templates, mock data comes in two guises: the contents of the <code>data<\/code> object, and the result of running <a href=\"https:\/\/developers.google.com\/tag-manager\/templates\/api\">template APIs<\/a>.<\/p>\n<h4 id=\"mocking-the-data-object\">Mocking the <code>data<\/code> object<\/h4>\n<p>The first is simple to do. You build an object, where each key corresponds to a property of the <code>data<\/code> object that your code processes.<\/p>\n<p>For example, if your template has a <a href=\"https:\/\/www.simoahava.com\/analytics\/custom-templates-guide-for-google-tag-manager\/#text-input\">text input<\/a> field named <code>name<\/code> and then a <a href=\"https:\/\/www.simoahava.com\/analytics\/custom-templates-guide-for-google-tag-manager\/#simple-table\">simple table<\/a> field named <code>optionalParameters<\/code>, you could build a mock object like this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> mockData = {\n  name: <span style=\"color:#a50\">'Simo Ahava'<\/span>,\n  optionalParameters: [{\n    parameterName: <span style=\"color:#a50\">'country'<\/span>,\n    parameterValue: <span style=\"color:#a50\">'Finland'<\/span>\n  },{\n    parameterName: <span style=\"color:#a50\">'hair_color'<\/span>,\n    parameterValue: <span style=\"color:#a50\">'n\/a'<\/span>\n  }]\n};\n<\/code><\/pre>\n<\/div>\n<p>This mock data object would correspond with field input like this:<\/p>\n<div style=\"aspect-ratio: 1903 \/ 603;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/11\/mockdata.jpg\" title=\"Mock data\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"603\" width=\"1903\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/11\/mockdata.jpg#ZgotmplZ\" alt=\"Mock data\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>You pass this mock data object to the <code>runCode<\/code> method (more on this below) so that the template code is run with input from the object.<\/p>\n<h4 id=\"mocking-template-apis\">Mocking template APIs<\/h4>\n<p>When you run tests for your template, you might not want the template to actually perform the API calls it is configured to do.<\/p>\n<p>Calling <a href=\"https:\/\/developers.google.com\/tag-manager\/templates\/api#sendpixel\"><code>sendPixel<\/code><\/a> over and over again with different inputs might <em>not<\/em> make a lot of sense.<\/p>\n<p>This is where API mocking plays a vital row. In the Tests interface, you can <strong>replace<\/strong> API functionality with a mock function. This way you can run the test <em>as if<\/em> the template had called the API, and process the returned value <em>as if<\/em> the API had returned it.<\/p>\n<p>For example, let\u2019s say we have a tag template that injects a script onto the page, where the domain name is input by the user into a template field. This is what the template code would look like:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> sendPixel = require(<span style=\"color:#a50\">'sendPixel'<\/span>);\n\n<span style=\"color:#00a\">const<\/span> domainName = data.domainName;\n\nsendPixel(domainName, data.gtmOnSuccess, data.gtmOnFailure);\n<\/code><\/pre>\n<\/div>\n<p>To test this, you could write a test that simply checks if <code>gtmOnSuccess<\/code> was called for a valid hostname and <code>gtmOnFailure<\/code> for an invalid one:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> mockData = {\n  domainName: <span style=\"color:#a50\">'https:\/\/invalid.com'<\/span>\n};\nrunCode(mockData);\nassertApi(<span style=\"color:#a50\">'gtmOnFailure'<\/span>).wasCalled();\n<\/code><\/pre>\n<\/div>\n<p>However, this test actually tries to send the pixel request to the domain name, meaning it\u2019s difficult to test positive and negative results without polluting the endpoint.<\/p>\n<p>Instead, you can <strong>mock<\/strong> the API like this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> mockData = {\n  domainName: <span style=\"color:#a50\">'https:\/\/invalid.com'<\/span>\n};\n\nmock(<span style=\"color:#a50\">'sendPixel'<\/span>, (url, onSuccess, onFailure) =&gt; {\n  onFailure();\n});\n\nrunCode(mockData);\n\nassertApi(<span style=\"color:#a50\">'gtmOnFailure'<\/span>).wasCalled();\n<\/code><\/pre>\n<\/div>\n<p>With <code>mock<\/code>, you instruct the test to use the function stub you provide, meaning whenever the <code>sendPixel<\/code> API is invoked, it always runs the <code>onFailure()<\/code> method regardless of input (at least, in this current test).<\/p>\n<p>So when using APIs that invoke external endpoints, it might be a good idea to mock them.<\/p>\n<p>Mocks are reset with every test, so you don\u2019t have to worry about your <code>onFailure()<\/code> leaking into other tests, too.<\/p>\n<h3 id=\"2-running-the-code\">2. Running the code<\/h3>\n<p>Once you have your mocks ready, you can invoke the <code>runCode()<\/code> method.<\/p>\n<p>This method runs the template code, mocking the APIs you have chosen to replace, and using the data object that you pass to it as an argument.<\/p>\n<p>If you do not pass any object to it as an argument, or if you pass an empty object, the template will be run as if the user had not added any input to any field.<\/p>\n<p>With <strong>tag templates<\/strong>, you just need to execute <code>runCode()<\/code>, because your assertions will be made against the APIs that have been called. Tag templates do not return anything, so there\u2019s nothing to assess from the result of <code>runCode()<\/code>.<\/p>\n<p>With <strong>variable templates<\/strong>, the template should actually <strong>return<\/strong> something, and thus your assertions should also be done against the <em>result<\/em> of <code>runCode()<\/code>.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> mockData = {input: <span style=\"color:#a50\">'test'<\/span>};\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ With tag templates\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>runCode(mockData);\nassertApi(<span style=\"color:#a50\">'someApi'<\/span>).wasCalled();\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ With variable templates\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">const<\/span> result = runCode(mockData);\nassertThat(result).isEqualTo(<span style=\"color:#a50\">'test'<\/span>);\n<\/code><\/pre>\n<\/div>\n<p>Once the test has run, you are ready to <strong>assert<\/strong> the results.<\/p>\n<h3 id=\"3-failing-the-test\">3. Failing the test<\/h3>\n<p>Custom Templates offer an API you can use to immediately fail a test.<\/p>\n<p>Note that the typical use case for <code>fail()<\/code> is to evaluate the <em>test itself<\/em> rather than the code that is being tested.<\/p>\n<p>Some like to use a fail mechanism to indicate tests that have not yet been written, others like to use it to expose paths that should never be encountered by tests.<\/p>\n<p>Typically, you wouldn\u2019t use <code>fail()<\/code> in production-ready code, because there would not be incomplete tests and assertion logic would handle all possible permutations of the template code.<\/p>\n<p>To use <code>fail()<\/code> is dead simple &#8211; just add the command to a branch of the code, and set the failure message as the argument.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> mockData = {input: <span style=\"color:#a50\">'test'<\/span>};\n\n<span style=\"color:#00a\">const<\/span> result = runCode(mockData);\n\n<span style=\"color:#00a\">if<\/span> (result === <span style=\"color:#00a\">undefined<\/span>) {\n  fail(<span style=\"color:#a50\">'Result should never be undefined.'<\/span>);\n}\nassertThat(result).isEqualTo(<span style=\"color:#a50\">'test'<\/span>);\n<\/code><\/pre>\n<\/div>\n<p>You can use <code>fail()<\/code> to create custom assertions. For example, to check if the object returned by the code contains some property, you could do this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> mockData = {input: <span style=\"color:#a50\">'test'<\/span>};\n\n<span style=\"color:#00a\">const<\/span> result = runCode(mockData);\n\n<span style=\"color:#00a\">if<\/span> (result.hasOwnProperty(<span style=\"color:#a50\">'someProperty'<\/span>)) {\n  assertThat(<span style=\"color:#00a\">true<\/span>);\n} <span style=\"color:#00a\">else<\/span> {\n  fail(<span style=\"color:#a50\">'Variable did not have \"someProperty\".'<\/span>);\n}\n<\/code><\/pre>\n<\/div>\n<p>It\u2019s not pretty, but it does its job while we wait for new assertion APIs to be added.<\/p>\n<h3 id=\"4-assertions\">4. Assertions<\/h3>\n<p>With <strong>assertions<\/strong>, you are making statements about the results of the test. The best assertion libraries are a pleasure to use, because assertions are written with a grammar and syntax reminiscent of actual language.<\/p>\n<p>For example, to assert that the variable template code returns a specific value, you add something like:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\">assertThat(runCodeResult).isEqualTo(<span style=\"color:#a50\">'some value'<\/span>);\n<\/code><\/pre>\n<\/div>\n<p>The test is a <strong>success<\/strong> if the assertion resolves to <code>true<\/code>. In other words, if the <code>runCodeResult<\/code> had exactly the value <code>'some value'<\/code>, the test would pass.<\/p>\n<p>With APIs, you are asserting whether the API was called or not.<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\">assertApi(<span style=\"color:#a50\">'sendPixel'<\/span>).wasCalled();\n<\/code><\/pre>\n<\/div>\n<p>This test would be a success if the <code>sendPIxel<\/code> API was invoked during the execution of the test code.<\/p>\n<blockquote>\n<p><strong>NOTE!<\/strong> To test whether an API was called with specific parameters, you should <strong>mock<\/strong> that API instead.<\/p>\n<\/blockquote>\n<p>You can add <strong>more than one assertion<\/strong> to a test case. All the assertions must pass for the test to be a success. I do recommend trying to keep the number of assertions per test to a minimum, though, as having granular test cases lets you more easily identify the link between the failed test and the broken code that caused it to fail.<\/p>\n<h4 id=\"using-assertthat\">Using <code>assertThat<\/code><\/h4>\n<p>The <code>assertThat<\/code> API allows you to make assertions about the result of the code execution. The assertions follow the syntax used by e.g. Google\u2019s <a href=\"https:\/\/truth.dev\/\">Truth<\/a> and the <a href=\"https:\/\/joel-costigliola.github.io\/assertj\/\">AssertJ<\/a> library.<\/p>\n<p>The <code>assertThat<\/code> API is most useful when testing variable templates, because the assertions would be run against the result (the returned value) of the variable template itself.<\/p>\n<p>The syntax is this:<\/p>\n<p><code>assertThat(someValueToTest).assertion(someExpectedValue);<\/code><\/p>\n<p>The <code>assertThat()<\/code> method takes the value to test as an argument, and it returns an object with all the different assertion APIs listed below.<\/p>\n<p>Some of the APIs (e.g. <code>isEqualTo()<\/code>) take an argument, where the asserted value is tested against this argument.<\/p>\n<p>Many APIs don\u2019t take any arguments at all &#8211; they are used for quick, simple assertions such as whether the asserted value was defined or not.<\/p>\n<p>Here are the assertions supported by the API.<\/p>\n<table>\n<thead>\n<tr>\n<th>Assertion<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>isEqualTo(someValue)<\/code><\/td>\n<td>Checks if the asserted value is equal to <code>someValue<\/code>. Equality is not strict &#8211; you can check if <code>[1, 2, 3]<\/code> equals <code>[1, 2, 3]<\/code> and the test will pass. Similarly, you can check complex objects and the assertion will succeed if they have the exact same keys and values.<\/td>\n<\/tr>\n<tr>\n<td><code>isNotEqualTo(someValue)<\/code><\/td>\n<td>The assertion is a success if the asserted value is not equal to <code>someValue<\/code>. Same rules about strictness apply here.<\/td>\n<\/tr>\n<tr>\n<td><code>isStrictlyEqualTo(someValue)<\/code><\/td>\n<td>Similar to <code>isEqualTo<\/code>, except this time the asserted value must have exactly the same value as the target value. Thus objects and arrays would not pass the test, as they would point to different references.<\/td>\n<\/tr>\n<tr>\n<td><code>isStrictlyNotEqualTo(someValue)<\/code><\/td>\n<td>The assertion is a success if the asserted value is <strong>not<\/strong> the exact equal of <code>someValue<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>isDefined()<\/code><\/td>\n<td>Assertion is a success if the asserted value is other than <code>undefined<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>isUndefined()<\/code><\/td>\n<td>Assertion is a success if the asserted value is <code>undefined<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>isNull()<\/code><\/td>\n<td>Assertion is a success if the asserted value is <code>null<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>isNotNull()<\/code><\/td>\n<td>Assertion is a success if the asserted value is anything other than <code>null<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>isTrue()<\/code><\/td>\n<td>Assertion is a success if the asserted value is <code>true<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>isFalse()<\/code><\/td>\n<td>Assertion is a success if the asserted value is <code>false<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>isTruthy()<\/code><\/td>\n<td>Assertion is a success if the asserted value is not <em>falsy<\/em> (see the next assertion for more details).<\/td>\n<\/tr>\n<tr>\n<td><code>isFalsy()<\/code><\/td>\n<td>Assertion is a success if the asserted value is <code>falsy<\/code>. Falsy values are: <code>undefined<\/code>, <code>null<\/code>, <code>false<\/code>, <code>NaN<\/code>, <code>0<\/code>, and <code>''<\/code>.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This is the <em>current<\/em> list of available assertions. I\u2019m sure more will be added with time.<\/p>\n<h4 id=\"using-assertapi\">Using <code>assertApi<\/code><\/h4>\n<p>The <code>assertApi()<\/code> function can be used to check if the template code has made calls to specific template APIs.<\/p>\n<p>This is a typical <em>flow test<\/em> &#8211; you are checking that certain things happen in order.<\/p>\n<p>For example, take the following template code:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> log = require(<span style=\"color:#a50\">'logToConsole'<\/span>);\n<span style=\"color:#00a\">const<\/span> makeTableMap = require(<span style=\"color:#a50\">'makeTableMap'<\/span>);\n<span style=\"color:#00a\">const<\/span> sendPixel = require(<span style=\"color:#a50\">'sendPixel'<\/span>);\n<span style=\"color:#00a\">const<\/span> injectScript = require(<span style=\"color:#a50\">'injectScript'<\/span>);\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Log input to console\n<\/span><span style=\"color:#aaa;font-style:italic\"\/>log(data.input);\n\n<span style=\"color:#aaa;font-style:italic\">\/\/ Shape into object\n<\/span><span style=\"color:#aaa;font-style:italic\"\/><span style=\"color:#00a\">const<\/span> obj = makeTableMap(data.input, <span style=\"color:#a50\">'propertyName'<\/span>, <span style=\"color:#a50\">'propertyValue'<\/span>);\n\n<span style=\"color:#00a\">if<\/span> (obj.someValue) {\n  sendPixel(<span style=\"color:#a50\">'https:\/\/endPoint.com\/?value='<\/span> + obj.someValue, data.gtmOnSuccess, data.gtmOnFailure);\n} <span style=\"color:#00a\">else<\/span> {\n  injectScript(<span style=\"color:#a50\">'https:\/\/endPoint.com\/script.js'<\/span>, data.gtmOnSuccess, data.gtmOnFailure);\n}\n<\/code><\/pre>\n<\/div>\n<p>To test the flow of this template, you could use a test like this:<\/p>\n<div class=\"highlight\">\n<pre style=\"background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-javascript\" data-lang=\"javascript\"><span style=\"color:#00a\">const<\/span> mockData = {someValue: <span style=\"color:#00a\">true<\/span>};\n\nrunCode(mockData);\n\nassertApi(<span style=\"color:#a50\">'logToConsole'<\/span>).wasCalled();\nassertApi(<span style=\"color:#a50\">'makeTableMap'<\/span>).wasCalled();\nassertApi(<span style=\"color:#a50\">'sendPixel'<\/span>).wasCalled();\nassertApi(<span style=\"color:#a50\">'injectScript'<\/span>).wasNotCalled();\n\nassertApi(<span style=\"color:#a50\">'gtmOnSuccess'<\/span>).wasCalled();\n<\/code><\/pre>\n<\/div>\n<p>Pay attention to the last line &#8211; with tag templates you should always have a test that checks whether the <code>gtmOnSuccess<\/code> API was called. You can also test for <code>gtmOnFailure<\/code> in some circumstances (specifically, when the template executes <code>data.gtmOnFailure()<\/code>).<\/p>\n<p><code>assertApi(apiName)<\/code> returns an object that has two assertions:<\/p>\n<table>\n<thead>\n<tr>\n<th>Assertion<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>wasCalled()<\/code><\/td>\n<td>Success if the API was called during test execution.<\/td>\n<\/tr>\n<tr>\n<td><code>wasNotCalled()<\/code><\/td>\n<td>Success if the API was NOT called during test execution.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This is very simple, by design. You can only check if the API was called or not.<\/p>\n<p>If you want to know whether it was called with some specific value, you need to mock the APIs instead.<\/p>\n<h3 id=\"the-test-setup\">The test Setup<\/h3>\n<p>When opening the <strong>Tests<\/strong> interface, you\u2019ll see the <strong>Setup<\/strong> box. You can use this to establish conditions that apply to all tests. It\u2019s a great place to define your <strong>mock<\/strong> objects for example, because then you don\u2019t have to write them over and over again in each test.<\/p>\n<div style=\"aspect-ratio: 957 \/ 291;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/11\/test-setup.jpg\" title=\"Test setup\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"291\" width=\"957\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/11\/test-setup.jpg#ZgotmplZ\" alt=\"Test setup\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>I recommend making liberal use of <strong>Setup<\/strong> &#8211; it can make it much easier to add more tests as your code goes through iterations.<\/p>\n<h2 id=\"running-tests\">Running tests<\/h2>\n<p>To run the tests, simply click the <strong>Run tests<\/strong> button at the top of the <strong>Tests<\/strong> view, or hit the play button next to any individual test.<\/p>\n<div style=\"aspect-ratio: 656 \/ 256;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/11\/run-tests.jpg\" title=\"run tests button\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"256\" width=\"656\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/11\/run-tests.jpg#ZgotmplZ\" alt=\"run tests button\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<p>The console will log any test results, so play close attention to it.<\/p>\n<div style=\"aspect-ratio: 533 \/ 280;\" class=\"figure nocaption\">\n<p>    <a href=\"https:\/\/www.simoahava.com\/images\/2019\/11\/failed-tests.jpg\" title=\"Failed tests\"><\/p>\n<p>    <img decoding=\"async\" class=\"fig-img\" height=\"280\" width=\"533\" loading=\"lazy\" src=\"https:\/\/www.simoahava.com\/images\/2019\/11\/failed-tests.jpg#ZgotmplZ\" alt=\"Failed tests\"\/><\/p>\n<p>    <\/a><\/p>\n<\/div>\n<h2 id=\"summary\">Summary<\/h2>\n<p>So. Why should you test? Well, let\u2019s start with this cryptic tweet from Google Tag Manager\u2019s tech lead, Brian.<\/p>\n<p>I imagine at some point tests will become mandatory for templates added to the <a href=\"https:\/\/tagmanager.google.com\/gallery\/\">gallery<\/a>.<\/p>\n<p>Another point is that tests bring you, the developer, comfort, since you can use them to validate that you don\u2019t generate broken code.<\/p>\n<p>Unit tests are problematic &#8211; the tests rely on mock data rather than actual use cases (those are explored with <strong>integration<\/strong> and <strong>functional<\/strong> tests). Their only purpose is to test the code you write, but the tests are done using \u2026 code you write.<\/p>\n<p>However, think of your template\u2019s users. When they download updates to your template from the gallery, they trust that the code works as it used to. Once your test gets more and more complex, it will be more and more difficult to manage the branching code.<\/p>\n<p>At that point, unit tests will be worth every second you spend with them.<\/p>\n<p>Do note that tests alone don\u2019t make your code work. You still need a good template. And writing tests just for coverage\u2019s sake doesn\u2019t make sense &#8211; you still need the tests to reflect actual use cases.<\/p>\n<p>I\u2019m looking forward to how the new <strong>Tests<\/strong> feature evolves in Google Tag Manager &#8211; it\u2019s a great leap forward for avoiding surprises and breaking mistakes in your template code!<\/p>\n<\/p><\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>Google Tag Manager introduced the capability to add tests to your Custom Templates. Tests, in this context, refer specifically to unit tests that you write in order to make sure your template code works in a predictable way. Unit tests are also used to drive development, ensuring that you have added contingencies for all the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":93016,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12033],"tags":[834,1531,14495,1791,11455,11326,2456],"dealstore":[],"offerexpiration":[],"class_list":["post-93015","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-custom","tag-google","tag-manager","tag-tag","tag-templates","tag-tests","tag-writing"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Writing Tests For Custom Templates In Google Tag Manager - Som2ny Network<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fivemor.com\/?p=93015\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Writing Tests For Custom Templates In Google Tag Manager - Som2ny Network\" \/>\n<meta property=\"og:description\" content=\"Google Tag Manager introduced the capability to add tests to your Custom Templates. Tests, in this context, refer specifically to unit tests that you write in order to make sure your template code works in a predictable way. Unit tests are also used to drive development, ensuring that you have added contingencies for all the [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fivemor.com\/?p=93015\" \/>\n<meta property=\"og:site_name\" content=\"Som2ny Network\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-17T05:40:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"957\" \/>\n\t<meta property=\"og:image:height\" content=\"338\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fivemor.com\/?p=93015#article\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/?p=93015\"},\"author\":{\"name\":\"admin\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\"},\"headline\":\"Writing Tests For Custom Templates In Google Tag Manager\",\"datePublished\":\"2025-02-17T05:40:07+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=93015\"},\"wordCount\":2398,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=93015#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg\",\"keywords\":[\"Custom\",\"Google\",\"Manager\",\"TAG\",\"Templates\",\"tests\",\"Writing\"],\"articleSection\":[\"Analytics\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fivemor.com\/?p=93015#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fivemor.com\/?p=93015\",\"url\":\"https:\/\/fivemor.com\/?p=93015\",\"name\":\"Writing Tests For Custom Templates In Google Tag Manager - Som2ny Network\",\"isPartOf\":{\"@id\":\"https:\/\/fivemor.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/fivemor.com\/?p=93015#primaryimage\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/?p=93015#primaryimage\"},\"thumbnailUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg\",\"datePublished\":\"2025-02-17T05:40:07+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fivemor.com\/?p=93015#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fivemor.com\/?p=93015\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/?p=93015#primaryimage\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg\",\"width\":957,\"height\":338},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fivemor.com\/?p=93015#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/fivemor.com\/?bp_activities=1\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Writing Tests For Custom Templates In Google Tag Manager\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fivemor.com\/#website\",\"url\":\"https:\/\/fivemor.com\/\",\"name\":\"Som2ny Network\",\"description\":\"Daily Deals\",\"publisher\":{\"@id\":\"https:\/\/fivemor.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fivemor.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/fivemor.com\/#organization\",\"name\":\"Som2ny Network\",\"url\":\"https:\/\/fivemor.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"contentUrl\":\"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png\",\"width\":300,\"height\":86,\"caption\":\"Som2ny Network\"},\"image\":{\"@id\":\"https:\/\/fivemor.com\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/fivemor.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png\",\"caption\":\"admin\"},\"sameAs\":[\"https:\/\/fivemor.com\"],\"url\":\"https:\/\/fivemor.com\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Writing Tests For Custom Templates In Google Tag Manager - Som2ny Network","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fivemor.com\/?p=93015","og_locale":"en_US","og_type":"article","og_title":"Writing Tests For Custom Templates In Google Tag Manager - Som2ny Network","og_description":"Google Tag Manager introduced the capability to add tests to your Custom Templates. Tests, in this context, refer specifically to unit tests that you write in order to make sure your template code works in a predictable way. Unit tests are also used to drive development, ensuring that you have added contingencies for all the [&hellip;]","og_url":"https:\/\/fivemor.com\/?p=93015","og_site_name":"Som2ny Network","article_published_time":"2025-02-17T05:40:07+00:00","og_image":[{"width":957,"height":338,"url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg","type":"image\/jpeg"}],"author":"admin","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fivemor.com\/?p=93015#article","isPartOf":{"@id":"https:\/\/fivemor.com\/?p=93015"},"author":{"name":"admin","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371"},"headline":"Writing Tests For Custom Templates In Google Tag Manager","datePublished":"2025-02-17T05:40:07+00:00","mainEntityOfPage":{"@id":"https:\/\/fivemor.com\/?p=93015"},"wordCount":2398,"commentCount":0,"publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"image":{"@id":"https:\/\/fivemor.com\/?p=93015#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg","keywords":["Custom","Google","Manager","TAG","Templates","tests","Writing"],"articleSection":["Analytics"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fivemor.com\/?p=93015#respond"]}]},{"@type":"WebPage","@id":"https:\/\/fivemor.com\/?p=93015","url":"https:\/\/fivemor.com\/?p=93015","name":"Writing Tests For Custom Templates In Google Tag Manager - Som2ny Network","isPartOf":{"@id":"https:\/\/fivemor.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/fivemor.com\/?p=93015#primaryimage"},"image":{"@id":"https:\/\/fivemor.com\/?p=93015#primaryimage"},"thumbnailUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg","datePublished":"2025-02-17T05:40:07+00:00","breadcrumb":{"@id":"https:\/\/fivemor.com\/?p=93015#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fivemor.com\/?p=93015"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/?p=93015#primaryimage","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2025\/02\/custom-template-tests.jpg","width":957,"height":338},{"@type":"BreadcrumbList","@id":"https:\/\/fivemor.com\/?p=93015#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/fivemor.com\/?bp_activities=1"},{"@type":"ListItem","position":2,"name":"Writing Tests For Custom Templates In Google Tag Manager"}]},{"@type":"WebSite","@id":"https:\/\/fivemor.com\/#website","url":"https:\/\/fivemor.com\/","name":"Som2ny Network","description":"Daily Deals","publisher":{"@id":"https:\/\/fivemor.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fivemor.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/fivemor.com\/#organization","name":"Som2ny Network","url":"https:\/\/fivemor.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/","url":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","contentUrl":"https:\/\/fivemor.com\/wp-content\/uploads\/2026\/07\/4a0953c4-logo-300x86-1.png","width":300,"height":86,"caption":"Som2ny Network"},"image":{"@id":"https:\/\/fivemor.com\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/fivemor.com\/#\/schema\/person\/b85e3c3dc0e1daea076524dc8810c371","name":"admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/fivemor.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/729ae85bf62b9917e93538db2f2688ca?s=96&r=g&default=https%3A%2F%2Ffivemor.com%2Fwp-content%2Fplugins%2Fbuddypress-first-letter-avatar%2Fimages%2Fdefault%2F96%2Flatin_a.png","caption":"admin"},"sameAs":["https:\/\/fivemor.com"],"url":"https:\/\/fivemor.com\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/93015","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=93015"}],"version-history":[{"count":0,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/posts\/93015\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=\/wp\/v2\/media\/93016"}],"wp:attachment":[{"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=93015"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=93015"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=93015"},{"taxonomy":"dealstore","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fdealstore&post=93015"},{"taxonomy":"offerexpiration","embeddable":true,"href":"https:\/\/fivemor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fofferexpiration&post=93015"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}