Test.Bash() 2021 Resources

Thank you for watching my Test.Bash() talk! (or, congratulations on somehow stumbling across this page through some other means)

Here are some resources which were referenced in my session; I'll keep this updated if anything else arises during conference Q&A or on Twitter.

The big stuff

Postman script samples

The two snippets which I shared were designed to monitor the Google Pixel page on the EE store; the tests would pass when the Pixel 6 was not present on the page, and would fail when the Pixel 6 was found (because this would trigger an email notification from the Postman Monitor).

So, if you want to recreate this monitor, you might want to use the Pixel 7 (or whatever the next unreleased number is)!

To learn more about how to write test scripts in Postman, the Postman Learning Centre is your friend - visit the Writing tests page to get started.

// Straightforward example, which searches the entire HTML response (including headers)
pm.test("Pixel 6 absent from page", function () {
    pm.expect(pm.response.text()).to.not.include("Pixel 6");
});

// More complex example, which just looks at the "p" tags in the body
pm.test("Pixel 6 - cleverer check", function () {
    var html = cheerio(responseBody);
    var foundString = false;
    html.find("p").each(function (index, element) {
       if((element.children[0].data).includes("Pixel 6")) {
            foundString = true;
       }
    });
    pm.expect(foundString).to.eql(false); 
}); 

Flower protector script

You can probably get this script to run locally quite easily, although it'll be even easier if you use Scriptr, where you can also use the "Schedule" feature to automatically run it every night.

You'll need to modify several things in the script:

  • Add an API_KEY from Open Weather Map API (it's free)

  • Modify the two instances of your-address@your-domain.com to refer to the email address that you want to notify

  • Modify the lat/lon values in the getWeather function, to reflect the location that you want to monitor

The rest is an exercise for the reader - there's some other stuff happening in there (e.g. it will insert a random piece of "banter" into the email), experiment and see what else you can do!

var http = require('http');

// Generate your own key for Open Weather Map API, and insert below
API_KEY = 'insert-key-here';

hourlyForecast = getWeather(API_KEY);

// Is it already below freezing?
if (hourlyForecast.hourly[0].temp < 0) {
    var emailMessage = "It's already below freezing. Best get those pots in pronto."
    sendEmail("your-address@your-domain.com", emailMessage)
} else {
  
    freezingEpoch = null;
    overnightLow = 999;
	isFreezing = false;

    for(hour=1; hour < 14; hour++) {
        tempThisHour = hourlyForecast.hourly[hour].temp;
        if (tempThisHour < 0) {
            isFreezing = true;
            freezingEpoch = (freezingEpoch == null ? hourlyForecast.hourly[hour].dt : freezingEpoch);
            overnightLow = (tempThisHour < overnightLow ? tempThisHour : overnightLow);
        };
    }

    if (isFreezing) {
        console.log("It'll freeze tonight. Sending email");
        var date = new Date(freezingEpoch*1000);
        var emailMessage = "Temperature will dip below freezing at " + date.getHours() + ":" + (date.getMinutes() < 10 ? '0':'') + date.getMinutes() + ", with an overnight low of " + overnightLow + "°C.<br/>";
        var randomBanter = getBanter();
        sendEmail("your-address@your-domain.com", emailMessage + randomBanter);
    } else {
        console.log("No freezing tonight. Hooray");
    }
}

function getBanter() {
    const banter = ["DON'T LET THEM FREEZE","HELP ME, PLANT QUEEN","Best pop the pansies in the garage."];
	const random = Math.floor(Math.random() * banter.length);
	return banter[random];
}

function sendEmail(emailAddress,message) {

   var emailConfig = {

  	"to": emailAddress,
  	"fromName": "Pansy Protector",
  	"subject": "Cold night ahead ❄️",
  	"body": message
   	};
	return sendMail(emailConfig.to, emailConfig.fromName, emailConfig.subject, emailConfig.body); 
}

function getWeather(apiKey) {
    // You'll need to update the URL below to include the latitude & longitude of the location you wish to monitor
    var requestConfig = {
  		url: 'https://api.openweathermap.org/data/2.5/onecall?lat=1.2345&lon=-2.3456&exclude=current,minutely,daily,alerts&units=metric&appid=' + apiKey
    };
	var response = http.request(requestConfig);
    return JSON.parse(response.body);   
}

Distinguishing between manual execution and webhook triggers

This question came up from Ammar during Q&A. It's not relevant for PageProbe, as you can't trigger-in to PageProbe (it will only run on the schedule that you've defined), but here are some useful links for the other two tools:

  • Postman - When triggering a monitor via a webhook, the incoming request data is accessible in script. Therefore, if you want your script to perform extra/different actions when triggered via a webhook, you can check for the presence of this globals.previousRequest data; if it's not found, this means that it was triggered manually. More: Postman Learning Centre: Set up integrations to receive alerts

  • Scriptr - Every script that you produce in Scriptr has its own addressable API endpoint (referenced at the top of the script tab). When an external request is made to this URL, you can access any submitted data via the request.parameters object within your Scriptr script. Again, you can use the presence/absence of this data to determine whether the script was triggered via webhook, or a manual ad-hoc run. More: How to retrieve the parameters sent to my API via http?