GTM Template API is the greatest thing that has happened to GTM after GTM itself. Especially because of the built in Test API. As soon as we start to create something interesting we have to think about testing. Of Course TRUE TDD is hardly possible but at least we can try.
One note, to make this test I have to add require("Promise")
at the very beginning but this line returns a warning. Maybe in the near future GTM Templates will have a special API for testing Promises but now this testing method is better than nothing.
Reminder
In this post we will show how to test Promise API
based on an example from the previous post. For a quick recap, we did following steps:
- Call
sendHttpRequest
to get user state - Prepare date
- Call
sendHttpRequest
two times to update user state - Update event parameters
- Call
runContainer
to generate new event with updated parameters from user state
What to test
We can test that runContainer
will be called with new event parameters, event_name
is changed and properties are increased.
Implementation
Let’s start from code example and after that go line by line
|
|
At first I mock incoming event
|
|
Lines 9 - 13 we mock API methods getEventData
and getAllEventData
. Now these methods will return our fake data.
Next mock userData
data returned by sendHttpRequest
. The tricky part.
|
|
Line 22 returns userDataBody
- a fake response from the server. But we need to inject this response into sendHttpRequest
.
In the previous post we used sendHttpRequest
for two reasons to get user data and to update data. These scenarios have different endpoints. So we copy the GET endpoint from the previous post. If sendHttpRequest
is called with this GET endpoint it means we are trying to get data, otherwise we are trying to update data.
Let’s remember how GET case works:
sendHttpRequest(
getGetEndpoint(),
{ headers: getHeaders(), method: "GET", timeout: 5000 },
""
)
.then((result) => {
const userData = prepareBody(result.body);
callback(userData);
})
.catch((error) => {
logToConsole("getData error", error);
data.gtmOnFailure();
});
So sendHttpRequest
returns a Promise
and we need to pass our fake userDataBody
into resolve
function
|
|
Lines 32 - 41 are about the second scenario. We are mocking the update case. The code was:
Promise.all(
requestsParams.map((requestsParam) =>
sendHttpRequest(
requestsParam.endpoint,
{ headers: getHeaders(), method: "PUT", timeout: 5000 },
requestsParam.body
)
)
)
.then((results) => {
if (
results.filter((result) => result.statusCode === 200).length ===
requestsParams.length
) {
This time we call sendHttpRequest
twice and in success path we check only statusCode
.
|
|
Now here we add two if statements
with endpoints for each user property. And in both cases pass {statusCode:200}
to the resolver.
Yes that’s all. Next the final part about runContainer
. It will be easy.
|
|
So, we have just defined the result event. Please consider:
- We changed
event_name
tologin_init
- We increased
sessionCounter
andloginCounter
- We added new property
userProperty
fromuserData
- We left other events properties untouched
In lines 53 - 64 we mock runContainer
and use assertThat API
to check if a new event has the expected value That’s practically all.
|
|
We run test by using runCode
and check getEventData
, getAllEventData
, sendHttpRequest
were called.
Test or not to test
You may ask, what’s the profit of all these tests? If you collect real important data and marketing KPI really depends on how audiences and events are built - you for sure will continue to experiment and add more new properties and new logic. In this case you have to guarantee that a new code wouldn’t break the existing one.
May the Test API be with you.