Test design, black box techniques, white box techniques, test techniques, ISO/IEC/IEEE 29119-4:2015 technologies

The main idea for this post is to walk through the Test Design techniques to recall widely known ones, consider all the other practices that are often left behind, and eventually get the full and complete picture of the TDt. As a starting point, I chose the list from ISO/IEC/IEEE 29119-4 Test Techniques.

Apollo, graphql, react, express, bootstrap, webpack, babel, sql, universal technologies

The SysGears Team is pleased to announce the availability of Apollo Universal Starter Kit with Hot Code Reload for backend & frontend.

Lift, scala technologies

This post describes two approaches to implementing file download in Lift framework. Firstly, we will have a look at the implementation that uses ResponseShortcutException described in the Lift Cookbook. Then, I'll show how to solve the same task with the help of REST service in the way that follows a common Lift approach. Each of the methods has its own pros and cons, so it's up to you to decide which one works better for your task.

Ionic, angularjs technologies

Modal dialogs are designed to bring important pieces of information to users from any page without changing an active routing state. It is often convenient to utilize a modal dialog that itself contains a number of views and its own routing. And, since the $ionicModal service does not provide this functionality, here is where custom modal implementations come into play.

Angularjs technologies

It is often important to simultaneously show a fairly large number of elements on a web page to provide users with the most concise information possible. In order to make all those elements visible on a screen, their functionality usually has to be considerably limited. That is when the ability to open every separate element in a fullscreen view can be very helpful. This post shows how this can be achieved in AngularJS, with two custom directives which allow to move elements to a fullscreen view without changing their scope.

Here is an example of the scenario described above.

${img (id: "pic1", location:"/images/blog/inline/2015-12-30-charts-before.jpg", alt:"Charts before")} Picture 1. Charts

As it can be seen on the Picture 1, there are three charts on the page, rendered side by side. Let's assume that the page is designed to provide users with some overall statistical information. So, it is necessary to display all the charts on the same page at once. But, at the same time, we would like to allow users to magnify a specific chart and turn off / on a chart line (here, charts were taken just as an example, they could be replaced with any other elements, such as grids, or forms).

Ideally, there should be an ability to display each chart in a fullscreen mode without affecting the other charts or reloading the page. Another significant thing, it would be nice if the chart had the same scope regardless of its state (whether it is displayed in a fullscreen view or as a part of a page).

Writing the directives

Let's get to writing the directives. The first directive, called fullscreenBlock, compiles as a button and serves as a trigger for executing the second modalWrapper directive which does the actual work of moving the element to a fullscreen view:

`js fullscreenBlock directives.directive('fullscreenBlock', ['$compile', function ($compile) { var jqLite = angular.element; var link = function (scope, element, attrs) { // Compiles the default 'fullscreen' button for opening the fullscreen view. // This fullscreen button can be overridden by passing a custom html string to // the `fullscreen-block` attribute. var fullscreenButton = function () { return jqLite($compile( '<div class="row">' + '<span class="pull-right">' + // scope information '<p>(scope id: <b>' + scope.$id + '</b>)</p>' + '<p>(parent scope id: <b>' + scope.$parent.$id + '</b>)</p>' + '<span name="fullscreen" ng-click="fullscreenMode($event)"' + 'tooltip="Expand" style="cursor: pointer">' + '<i class="glyphicon glyphicon-fullscreen"></i>' + '</span>' + '</span>' + '</div>' )(scope)); }; // if there is no custom html passed to the attribute, default one is used element.prepend((attrs.fullscreenBlock.length > 0) ? attrs.fullscreenBlock : fullscreenButton()); }; // This function helps to find the first parent element which contains the // 'fullscreen-block' attribute. The function can be replaced with JQuery // `closest()` method if JQuery library is used. var closest = function (element) { return (jqLite(element).parent().attr('fullscreen-block') !== undefined) ? jqLite(element).parent() : closest(jqLite(element).parent()); }; var controller = function ($scope) { // handles the ng-click event $scope.fullscreenMode = function (event) { var modalWrapper = '<modal-wrapper></modal-wrapper>'; jqLite(closest(event.target)).wrap(modalWrapper); $compile(modalWrapper)($scope); }; }; return { link: link, controller: ['$scope', controller] } }]); `

`js modalWrapper directives.directive('modalWrapper',["$compile", "$document", function ($compile, $document) { var jqLite = angular.element; /* * The modal window template */ var template = '<div id="modal-fullscreen" class="modal modal-fullscreen"' + 'style="background: white">' + '<div class="modal-header">' + '<button type="button" class="close" ng-click="close()">&times;</button>' + '</div>' + '<div class="modal-body row" style="margin: 0; display: flex;"></div>' + '</div>'; var chart; /* * The link function. */ var link = function (scope, element) { scope.open(); // watches if modal is opened scope.$watch('showModal', function (newVal) { var modalEl = jqLite('modal-wrapper'); var fullscreenIcon = modalEl.find('[name="fullscreen"]'); // if modal is opened if (newVal) { // hides the fullscreen icon for the modal fullscreenIcon.addClass("ng-hide"); // inserts content from the page to the body of modal element. // JQuery's `insertBefore()` method can be used as well. modalEl[0].parentNode.insertBefore(element[0], modalEl[0]); // shows content a fullscreen view var content = modalEl.children(); // puts the element inside the modal element.find(".modal-body").append(content); // removes the <modal-wrapper> tag modalEl.remove(); // makes the modal visible jqLite('#modal-fullscreen').show(); // changes the element width // (`expand` is a custom class that sets width to 100%) content.addClass('expand'); // initializes the chart variable // (this line is specific to this concrete case) chart = content.scope()[element.find('canvas').attr('id')]; // if modal is closed } else if (!newVal) { // shows the 'fullscreen' button after the modal is closed fullscreenIcon.removeClass("ng-hide"); // looks up the element var modalBody = modalEl.find(".modal-body").children(); // inserts content from modal back to the page. // JQuery's `insertBefore()` method can be used as well. modalEl[0].parentNode.insertBefore(modalBody[0], modalEl[0]); // removes the modal modalEl.remove(); // changes the element width // (`expand` is a custom class that sets width to 100%) content.removeClass('expand'); } // triggers the chart resizing // (this line is specific to this concrete case) chart.resize(chart.render, true); }) }; /* * The controller function. */ var controller = function ($scope) { $scope.open = function () { $scope.showModal = true; }; $scope.close = function () { $scope.showModal = false; }; // closes the modal when the back button is clicked $scope.$on('$locationChangeStart', function(event) { if ($scope.showModal) { event.preventDefault(); $scope.close(); } }); }; return { restrict: 'E', scope: {}, template: template, link: link, controller: controller } }]); `

Here is a description of the directives shown above:

  • fullscreenBlock - compiles and inserts the 'fullscreen' button -- clicking this button wraps the enclosed element in the <modal-wrapper> directive. The directive is represented as an attribute which can receive an HTML string in order to render a custom button. This button should have the ng-click="fullscreenMode($event)" attribute defined, for instance: `html:nl <div fullscreen-block='<input type="button" ng-click="fullscreenMode($event)"/>'> `
  • modalWrapper - responsible for moving a selected element to the modal template, as a result the chart is displayed in a fullscreen without affecting the other elements in the DOM. The important part is that the chart is just moved from one place and to another, which allows you not to create a new scope, but to work with the initial one. Closing the modal window puts the chart back, leaving its state untouched.

Using directive in HTML

Next, let's see how to use the fullscreen-block directive in html.

`xml <div class="row" ng-controller="FullscreenModeController"> <div fullscreen-block ng-repeat="chart in data" class="col-md-4"> <div class="row"> <div class="col-md-10"> <canvas id="{{chart.name}}"></canvas> </div> <div ng-if="showLegend()" class="col-md-2"> <div ng-repeat="dataset in chart.datasets" class="row"> <label>{{dataset.label}}</label> <input type="checkbox" ng-model="dataset.show" ng-change="changeDataset(chart, dataset)" /> </div> </div> </div> </div> </div> `

The key point here is putting the <fullscreen-block> directive on the top of the element that is supposed to be scaled (the directive is a marker that encloses the element which should be moved and displayed in a fullscreen view).

Result

Finally, let's execute the code:

${img (id:"pic2", location:"/images/blog/inline/2015-12-30-charts-after1.jpg", alt:"Charts after")} Picture 2. A few charts that have the fullscreen-block attribute defined

${img (id:"pic3", location:"/images/blog/inline/2015-12-30-charts-after2.jpg", alt:"Charts after")} Picture 3. The fullscreen view that shows one of the charts

As you can see on the Picture 2, the fullscreen directive inserts the button (the top-right corner of the chart) which allows to magnify the chart element by displaying it in the fullscreen mode (Picture 3).

Note that Twitter Bootstrap's modal-fullscreen class was used for the fullscreen view.

You can play around with the jsFiddle example, try to open one of the charts, turn off a chart line, and then close the preview window. You will see that all the changes that have been made in the fullscreen mode are applied because the chart scope is always the same.

The full source code is available on GitHub.

Cheers,