Show TOC

Step 8: Testing NavigationLocate this document in the navigation structure

So far, we have a list of posts on the home page of the app. But typically, a post comes with more details that should be displayed on a separate detail page. We call it the post page because it displays details of a post. In this step we will introduce a new journey to test the post page. We write tests that trigger typical navigation events with OPA. Testing navigation greatly helps in reducing manual testing efforts as it covers a lot of testing paths. It is good practice to cover every view of your application with at least one test, since OPA will check if an exception is thrown. In this way you can detect critical errors very fast.
Preview
Figure 1: We add an OPA test that selects an item from the table and navigates to the post page
Coding

You can view and download all files in the Explored app in the Demo Kit under Testing - Step 8.

webapp/test/integration/PostJourney.js (New)
sap.ui.require(
	["sap/ui/test/opaQunit"],
	function (opaTest) {
		"use strict";
		QUnit.module("Post");
		opaTest("Should see the post page when a user clicks on an entry of the list", function (Given, When, Then) {
			// Arrangements
			Given.iStartMyApp();
			//Actions
			When.onTheWorklistPage.iPressOnTheItemWithTheID("PostID_15");
			// Assertions
			Then.onThePostPage.theTitleShouldDisplayTheName("Jeans");
		});
		opaTest("Should go back to the TablePage", function (Given, When, Then) {
			// Actions
			When.onThePostPage.iPressTheBackButton();

			// Assertions
			Then.onTheWorklistPage.iShouldSeeTheTable();
		});
		opaTest("Should be on the post page again when browser forwards is pressed", function (Given, When, Then) {
			// Actions
			When.onTheBrowser.iPressOnTheForwardButton();
			// Assertions
			Then.onThePostPage.theTitleShouldDisplayTheName("Jeans").
				and.iTeardownMyAppFrame();
		});
	}
);

This new journey for the Post page introduces a test case that tests the navigation and also tests if the browser history is in the correct state, so that the user can navigate through our app with the back and forward button of the browser. This time, instead of adding a test we will add a new journey.

A journey represents a user’s task in our app. Journeys start with the startup of our app and end with a teardown in the last test. We don’t write isolated tests here, since starting up the app takes a lot of time and doing it too often slows down our test execution and feedback time considerably. If the execution speed of the tests is no problem, you may also write isolated tests.

Our new journey consists of three user interaction steps:
  1. User chooses a Post to view the details

  2. User chooses the Back button on the Detail page of the Post to see the list again

  3. User chooses the Forward button to revisit the details of the post

webapp/test/integration/pages/Worklist.js – action object
sap.ui.require([
		'sap/ui/test/Opa5',
		'sap/ui/test/matchers/AggregationLengthEquals',
		'sap/ui/test/matchers/PropertyStrictEquals',
		'sap/ui/test/matchers/BindingPath',

		'sap/ui/demo/bulletinboard/test/integration/pages/Common'
	],
	function (Opa5, AggregationLengthEquals, PropertyStrictEquals, BindingPath, Common) {
		"use strict";
		var sViewName = "Worklist",
			sTableId = "table";
		Opa5.createPageObjects({
			onTheWorklistPage: {
				baseClass: Common,
				actions: {
…
                        ,
					iPressOnTheItemWithTheID: function (sId) {
						return this.waitFor({
							controlType: "sap.m.ColumnListItem",
							viewName: sViewName,
							matchers:  new BindingPath({
								path: "/Posts('" + sId + "')"
							}),
							success: function (aListItems) {
								aListItems[0].$().trigger("tap");
							},
							errorMessage: "No list item with the id " + sId + " was found."
						});
					}

Now that we have written our spec how the navigation to the Post page is planned, we first need to implement the "click" on a list item. To identify the item we are looking for, we use the BindingPath matcher. Doing so, we make sure that even if the order of the items changes, we always choose the same item.

webapp/test/integration/pages/Post.js (New)
sap.ui.require([
		'sap/ui/test/Opa5',
		'sap/ui/test/matchers/Properties',
		'sap/ui/demo/bulletinboard/test/integration/pages/Common'
	],
	function (Opa5, Properties, Common) {
		"use strict";
		var sViewName = "Post";
		Opa5.createPageObjects({
			onThePostPage: {
				baseClass: Common,
				actions: {
					iPressTheBackButton: function () {
						return this.waitFor({
							id: "page",
							viewName: sViewName,
							success: function (oPage) {
								oPage.$("navButton").trigger("tap");
							},
							errorMessage: "Did not find the nav button on object page"
						});
					}
				},
				assertions: {
					theTitleShouldDisplayTheName: function (sName) {
						return this.waitFor({
							success: function () {
								return this.waitFor({
									id: "objectHeader",
									viewName: sViewName,
									matchers: new Properties({
										title: sName
									}),
									success: function (oPage) {
										Opa5.assert.ok(true, "was on the remembered detail page");
									},
									errorMessage: "The Post " + sName + " is not shown"
								});
							}
						});
					}
				}
			}
		});
	});

After navigating to the Post page, we need a new OPA5 Page object for the page to implement our actions and assertions.

An OPA5 Page object is used to group and reuse actions and assertions that are related to a specific part of the screen. For more information, see Cookbook for OPA5.

We implement a press event on the page’s nav button and we assert that we are on the correct page by checking the title in the object header. The nav button is retrieved via DOM reference, because the page does not offer us an API here. Since the DOM ID is the most stable attribute, we are using this to retrieve the button.

webapp/test/integration/pages/Worklist.js – assertion object
,
					iShouldSeeTheTable: function () {
						return this.waitFor({
							id: sTableId,
							viewName: sViewName,
							success: function () {
								Opa5.assert.ok(true, "The table is visible");
							},
							errorMessage: "Was not able to see the table."
						});
					}

After going back, we want to move forwards again, but we need to check if the back navigation actually took place. So we assert that we are back on our table of posts again. We achieve this with a very simple waitFor statement just checking if the table is present.

webapp/test/integration/pages/Browser.js (New)
sap.ui.require([
		'sap/ui/test/Opa5',
		'sap/ui/demo/bulletinboard/test/integration/pages/Common'
	],
	function (Opa5, Common) {
		"use strict";
		Opa5.createPageObjects({
			onTheBrowser: {
				baseClass: Common,
				actions: {
					iPressOnTheForwardButton: function () {
						return this.waitFor({
							success: function () {
								Opa5.getWindow().history.forward();
							}
						});
					}
				},
				assertions: {}
			}
		});
	}); 

We now implement an action that is triggered when the Forward button is chosen. Since it is not part of the browser's UI and it could be used on any page of our application, we just declare our browser’s UI as an own OPA page object. To simulate the Forward button, we use the history API of the browser. We have to wrap our action in a waitFor statement. Otherwise the action would be executed before our app is started.

webapp/test/integration/AllJourneys.js
webapp/test/integration/AllJourneys.js
jQuery.sap.require("sap.ui.qunit.qunit-css");
jQuery.sap.require("sap.ui.thirdparty.qunit");
jQuery.sap.require("sap.ui.qunit.qunit-junit");
sap.ui.require([
	"sap/ui/test/Opa5",
	"sap/ui/demo/bulletinboard/test/integration/pages/Common",
	"sap/ui/demo/bulletinboard/test/integration/pages/Worklist",
	"sap/ui/demo/bulletinboard/test/integration/pages/Browser",
	"sap/ui/demo/bulletinboard/test/integration/pages/Post"

], function (Opa5, Common) {
	"use strict";
	Opa5.extendConfig({
		arrangements: new Common(),
		viewNamespace: "sap.ui.demo.bulletinboard.view."
	});
	sap.ui.require([
		"sap/ui/demo/bulletinboard/test/integration/WorklistJourney",
		"sap/ui/demo/bulletinboard/test/integration/PostJourney"

	], function () {
		QUnit.start();
	});
});

To make navigation tests complete, we add the new OPA page objects and journeys to the AllJourneys file that is invoked by the OPA test page. We add the OPA page objects Browser and Object and start the object and the navigation journey.

If you execute the tests now, you can see in the logs of the developer tools that OPA is waiting for the object page to be displayed. Of course, this will not happen as it is not yet implemented. But we already have a pretty good idea on how we will implement the feature in the next step