TDD – Testing Data Elements and Page Load Rules

From the point of view of IT or development, what your friendly marketer does in her tools really makes no difference, as long as she doesn’t kill the site.

But the other way round, she will be very upset if any change done by dev or IT kills her stuff.

My colleague Rudi Shumpert recently wrote about that in the Reason Marketing Tags Break. He is right: it is a communication issue, a question of acknowledging the interface and taking it into account.

Testing (automated testing!) the values of Data Elements and the firing of PLRs covers a huge part of the interface between your friendly marketer and dev/IT.

The tests themselves would be “the contract”, and passing them would give dev/IT the certainty that they didn’t break anything.

Testing

This post is a sequel to TDD for Analytics, please and TDD with DTM and Adobe Analytics. While those two were mainly a rant, speculation, and some musing, this one puts the money where my keyboard is and tries to actually do it.

Wish me luck!

Environment

After writing absurd Javascript code that would reload pages, maintain status via localStorage or cookies and use creative if-clauses as assertions, I was brought back to modern reality by a couple of friends. Specifically, they pointed me to magic wands like PhantomJS, CasperJS, or Nightmare. Sometimes not being a developer really makes your life more difficult than it’d have to be.

But now it is easy easier again, and that means I can start building tests! Let’s look at Data Elements!

Testing

But why Data Elements, you ask? We chose to test Data Elements… We chose to test Data Elements and do the other things, not because they are hard, but because they are easy.

How’s that for an inspirational reason?

Data Elements are straight-forward to test, really. You load a page that is instrumented with DTM, then you open the console and query the values of all the Data Elements that you need on the page using _satellite.getVar(), like so:

	_satellite.getVar("Page Name");

You can do that in your browser right now with any page that has DTM and at least one Data Element!

Here’s what mine looks like:

[Screenshot]
Checking the value of a Data Element
Btw: there is no reason why you should stop at the DEs! You can absolutely test the Data Layer, as well!

But a test is not a test unless it is automated, so can we automate this? Oh yes, we can! CasperJS does exactly that, using PhantomJS as a “pretend browser”.

[Screenshot]
Successful test run
The casperjs test command executes a “test suite” that is defined in the test_home.js file in this case.

You can see that the suite contains 5 tests, and that all of those 5 tests pass.

Green bar!

Great!

Data Elements

The first 4 Tests check whether the page in question (my home page) sets 4 Data Elements correctly.

Shall I show you what those tests look like?

Here’s the one that tests the “%Page Name%” Data Element:

var pagename = this.evaluate(function() {
	return _satellite.getVar("Page Name");
});
test.assertEquals(pagename, "Home", "%Page Name% Data Element test");

The interesting part is the call to this.evaluate().

Everything that is placed inside that call will be executed inside the mock browser, as if you’d type it into the console. All other code is executed by CasperJS, outside the mock browser and therefore not in the context of the page.

The evaluate() function is the bridge between the test framework and what happens inside the page inside the mock browser.

What’s really cool about it is that you can pass values into it, and you can get values back. That’s what the return statement does in the above example.

And getting values back is precisely what allows us to test!

See the test.assertEquals() statement?

That compares two values: what the page sent back against what we said it should send back (I want the page name to be “Home” on the home page).

These statements make or break the test. If there is anything you want to test on a given page, a test.assertXYZ() statement will do that. There’s a bunch of them for different sorts of assertions, you can find them all on the doc page for the CasperJS tester module.

Firing of Rules

Next, I’d like to test whether the correct rule(s) is/are firing on a given page. Can I do that?

Sure can!

DTM keeps tabs of what it logs, which means that we can sift through those log messages looking for “Rule XYZ fired” messages.

In addition to looking for the rules that I’d expect to fire, I would also test for the number of rules that have fired in total. That way you can catch situations where rules are added or removed.

Let’s go straight to the code:

casper.then(function() {
    var ruleNames = ["Normal Page Load", "Top of Page Stuff", "Session based rule for getVisitnum replacement"];
    var numFired = this.evaluate(function() {
        var numFired = 0;
        _satellite.each(_satellite.Logger.getHistory(), function(msg) {
            if (msg[1].indexOf("fired") >= 0) {
                numFired++;
            }
        });
        return numFired;
    });
    test.assertEquals(numFired, ruleNames.length, "Page should fire " + ruleNames.length + " rules");

    for (var i = ruleNames.length - 1; i >= 0; i--) {
        var plrres = this.evaluate(function(rn) {
            var fired = "no";
            _satellite.each(_satellite.Logger.getHistory(), function(msg) {
                if (msg[1].indexOf("fired") >= 0 && msg[1].indexOf(rn) >= 0) {
                    fired = "yes";
                }
            });
            return fired;
        }, ruleNames[i]);
        test.assertEquals(plrres, "yes", "PLR '" + ruleNames[i] + "' fired test");
    };
});

The bit that makes these tests great is that they run after a single call to casperJS. Nobody needs to manually open a browser, go to a page, open the console and query a Data Element. This is way faster!

Because it is still manual (per page and because I manually specified the DEs and PLRs to test), we must go further, perhaps using electron or selenium. I know, also, that I am not the only one doing something like this right now.

Appendix A – Some Setup

I used PhantomJS and CasperJS for the tests. The output of CasperJS is colourful and I’m on Windows, so I also used ConEmu.

The latter is easy to install. The other two require you to edit your PATH environment variable, but since you’re a developer, I won’t explain it or worry about you being able to do that. Chances are you have PhantomJS or CasperJS installed anyway.

If you’re not a developer (hey! Why would you read this blog?), ask one to help you install them if needed, or follow the instructions to the letter.

Can you find out whether you’ve done it right? You bet!

Open ConEmu (on Windows) or a command prompt (on Linux or OSX), then type phantomjs --version and hit enter. Same for CasperJS. If you see something like the following, you’re good:

[Screenshot]
PhantomJS and CasperJS installed successfully
Note how I am not using PhantomJS 2! CasperJS seems to require an older version, which can be found here.

I am playing around with testing a lot these days, and rather than copying all my code into blog articles (which would then become awfully long), i have decided to host it all on github in a project called analytics-tests-test.

Feel free to fork and participate!

And look forward to some selenium tomorrow!

19 thoughts on “TDD – Testing Data Elements and Page Load Rules

  1. Nice to read you again!

    You can help me to understand something…
    It concerns the use of %My data element% syntax Vs _satellite.getVar(“My data element”) (or _satellite.getDataElement(“My data element”) ).

    It seems that the first one persists the data on the page view but, fortunately for me, not using the javascript function.
    How can I recompute the value of my data element to use %% syntax in the configuration and not need to make workaround using the function in the custom code?
    FYI, it concerns the configuration of my AA tool overview (page name and related traffic attributes).

    Thank you for your help.

    Like

      1. On the sitecatalyst overview tool to populate the page name.

        1) I’ve created a Data Element with a custom JS catching my virtual page URL from my digital data layer and computing the page name. I set the persistence on the page view scope because no better choice
        2a) If I call my data element on the UI settings using %%, I get the old version of my digital data layer attribute
        2b) If I call my data element using getDataElement function in customize page code (after UI settings), I get the up-to-date version following my digital data layer state

        This behavior is very strange because, for me, %% syntax is just a shortcut for UI (Like {{}}) in GTM)…but it seems that it is not the case…

        It is not a blocking problem because I can keep the current custom code workaround. I’m just wondering for the future, if Adobe decide to align the getDataElement with %% using the persistence… and so the bad effect on virtual page loads tags…

        Like

  2. Hi Jan Exner,

    At our company we even go further then checking if rules are being fired. We actually intercept image requests from network traffic with casperjs and phantomjs and validate image requests based on mandatory tracking variables.

    Good blogpost but we could have used it a few months back.

    Good post for a lot of people!

    Like

    1. Sorry I was late! 😉

      I think testing can help two different types of people:

      – what you do helps the marketing or analytics people. Having a test that checks the actual tracking means that you guys know that the data in the reports is reliable. That is very valuable.
      – what I suggest targets the developers who work on the site. The tests I describe are for them, not for marketing, and they help dev check that they do not break anything further up.

      Having both kinds of tests in place is of course ideal.

      Like

  3. Hi Jan.

    This is a fantastic post and some great knowledge you shared. I noticed that you focus greatly on data layer and what DTM fires / stores. Have you thought about investigating the actual Analytics requests? Do you think there’s any value added compared to data layer testing? I can see two methods for request investigation:

    1. Using Selenium and Browsermob proxy (not sure whether something similar is achievable with Casper – I’m new to it, but definitely like to get to know it better) to capture requests.

    2. Using a “hack” in checking the s_c_il object created by Analytics. This (specifically s_c_il[1]) I belive stores the values from the last request sent to Adobe Analytics so you could do some coding to store all changes of the object somewhere and then build proper tests to it. However, we’ll never know how long this object will be available, Adobe might kill it at some point 🙂

    Thoughts?

    Like

    1. Hi Michał,

      thanks for the feedback, glad it helped!

      I decided against testing Analytics.

      The main reason is that I would love developers/integrators to run this test. The idea is that they test before they go live, meaning we won’t get into situations where a new version of the site breaks our tracking. The test suite effectively becomes a contract between analytics (“what we need is …”) and dev (“you can have …”).

      Testing analytics is for a different audience: the marketers / analysts. It’ll come at some point, but I want to get the basics right, first.

      Does that make sense?

      Like

      1. Hi,
        yes, that makes a lot of sense.

        I will be awaiting an article for Analytics testing. In any case, I think the area of automatic testing for Analytics is still not covered enough, hopefully we will see more of that in the future.

        Like

  4. Hi Jan,

    if you’re interested, I have a running POC example in a java JUnit test on Maven with Selenium/Webdriver and BrowserMobProxy that allows to intercept either Google Analytics and Adobe Analytics calls (easily extendable to ad url’s as well).
    The proxy uses blacklist on tracking URL’s to avoid that any tracking calls are actually submitted to the tracking platform (no pollution of report suites). Still it intercepts the call in a requestFilter, allowing it to pass into a test condition.

    just leave me a note on my email address…

    Stefan

    Like

      1. Hi Jan,

        It’s part of a bigger setup in which I try to get analytics part of the devops chain. In the mean time I also found Simo Ahava’s blog on this…

        In this particular case I intercept the calls to the analytics platform without overloading the actual tracking calls. This makes it also suitable for intercepting all kind of tracking or advertising pixels you can deploy through a tag manager. This can be used to check the payload which would go to the receiving part, without actually sending data.
        So this is more on the technical / unit test part.

        Putting something like Cucumber in front of the tests could open it up to martech people to define the test scenario’s…

        Stefan

        Like

Leave a reply to Jan Exner Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.