GithubHelp home page GithubHelp logo

sunbox / teched2016-opa5-codereview Goto Github PK

View Code? Open in Web Editor NEW

This project forked from swennemers/teched2016-opa5-codereview

0.0 2.0 0.0 47 KB

SAP TechEd 2016 Code Review Session UX725 OPA5 – Kick-Start Asynchronous Acceptance Tests!

License: Apache License 2.0

JavaScript 97.26% HTML 2.74%

teched2016-opa5-codereview's Introduction

SAP TechEd 2016 Code Review Session UX725 OPA5 – Kick-Start Asynchronous Acceptance Tests!

Abstract

One Page Acceptance Tests (OPA5) is an API that’s especially useful for testing SAPUI5 controls. In this code review session, you’ll find out why. Learn how OPA5 simplifies asynchronous acceptance tests. And don’t worry about ramp-up time – OPA5 is integrated with SAPUI5 and the QUnit test framework.

Idea

Have a Fiori App and explain Opa5 by adding Opa5 tests.

Setup

  • SAP Web IDE with app
  • Clone this repository on the initial branch
  • You can also clone it 4 more times and create a local branches for step1 - step4

Script

Motivation for Opa5

  • Show the initial app (running in the web ide)
  • Why testing?
  • You need confidence in your app to stay agile, go fast and deliver often
  • Issues with non-integrated Testing Tools like Selenium, Protractor?
  • Finding the right DOM element to interact with is not API of SAPUI5/OpenUI5 controls
  • Complex controls have a deep nesting of DOM elements, that might even change
  • => just IDs is not enough
  • Even things that seem to happen immediately happening async
  • Rendering is async,
  • JS operations are async
  • Tests have to wait for the operations to happen to see results
  • Timeouts are a bad => just make tests flickering (faster/slower builds…)
  • Testing should be done in the same environment as development no need to install any web driver, etc.
  • JS and SAP Web IDE usage should be possible
  • What we want is a testing tool that integrates nicely with SAPUI5 and knows about when certain thing happen => Opa5 on top of QUnit

Step 1 - Opa5 Setup

  • Create suggested file structure and explain why
  • new folder "webapp/test/integration" => seperate integration tests from unit tests
  • new file "webapp/test/integration/opaTests.qunit.html"
    • opa tests run directly in the browser, instrumenting the app, no webdriver installation needed
    • bootstrapping SAPUI5 & Opa5
    • delegating test execution to an AllJourney.js
<!DOCTYPE html>
<html>
<head>
  <title>Opa5 tests for our Fiori App</title>
  <meta http-equiv='X-UA-Compatible' content='IE=edge'>
  <meta charset="utf-8">

  <script id="sap-ui-bootstrap"
  	src="../../../resources/sap-ui-core.js"
  	data-sap-ui-theme="sap_bluecrystal"
  	data-sap-ui-compatVersion="edge"
  	data-sap-ui-logLevel="ALL"
  	data-sap-ui-libs="sap.m"
  	data-sap-ui-resourceroots='{
  		"sap.ui.teched.appUnderTest" : "../../"
  	}'
  	data-sap-ui-frameOptions='deny'>
  </script>


  <script>
  	jQuery.sap.require("sap.ui.teched.appUnderTest.test.integration.AllJourneys");
  </script>

</head>
<body>
  	<div id="qunit"></div>
  	<div id="qunit-fixture"></div>
</body>
</html>
  • new file "webapp/test/integration/AllJourneys.js"
    • test cases = Journeys through your app
    • can be many journeys in a large app, so one to start them all
jQuery.sap.require("sap.ui.qunit.qunit-css");
jQuery.sap.require("sap.ui.thirdparty.qunit");
jQuery.sap.require("sap.ui.qunit.qunit-junit");
jQuery.sap.require("sap.ui.qunit.qunit-coverage");

QUnit.config.autostart = false;

sap.ui.require([
"sap/ui/test/Opa5"
], function(Opa5) {

   "use strict";
   Opa5.extendConfig({
  	 viewNamespace: "sap.ui.teched.appUnderTest.view."
   });

   sap.ui.require([
   ], function() {
  	 QUnit.start();
   });
});
  • Templates generate this Opa5 bootstrap stuff for you
  • Run opaTests.qunit.html as Web Application to show the "empty" test page

Step 2 - SearchJourney - Initially 3 items

  • Lets check the initial state with 3 items in the list (fixed data via mockserver!)
  • new OPA Journey "SearchJourney.js" with container AllJourneys.js
  • automatically integrated in AllJourneys
  • Tests following the Given, When, Then syntax
  • Tests read similar to english texts
  QUnit.module("List");

  opaTest("Should show 3 orders initially", function(Given, When, Then) {
  	Given.iStartMyApp();

  	Then.onTheMasterView.theListShouldHaveTheGivenNumberOfOrders(3);
  });
  • Where do the iStartMyApp and onTheMasterView.theListShouldHaveTheGivenNumberOfOrders functions come from?
  • Arrangement:
    • Update the AllJourneys.js
sap.ui.require([
	"sap/ui/test/Opa5",
	"sap/ui/teched/appUnderTest/test/integration/pages/Common"
], function(Opa5, Common) {
	"use strict";
	Opa5.extendConfig({
		arrangements: new Common(),
		viewNamespace: "sap.ui.teched.appUnderTest.view."
	});
  • New folder /test/integration/pages
  • New file /test/integration/pages/Common.js
  • arrangement iStartMyApp
  • Load the component, Opa5 could also open an html file in an iframe, but component is faster (newer)
sap.ui.define([
  	'sap/ui/test/Opa5'
  ],
  function (Opa5) {
  	"use strict";

  	return Opa5.extend("sap.ui.teched.appUnderTest.test.integration.pages.Common", {

  		iStartMyApp: function (oOptions) {
  			oOptions = oOptions || {};
  			oOptions.componentConfig = {
  				name: "sap.ui.teched.appUnderTest"
  			};
  			this.iStartMyUIComponent(oOptions);
  		}
  	});
  }
);
  • theListShouldHaveTheGivenNumberOfOrders => Page Objects
  • Create OPA Page "Master.js", Container: AllJourneys.js, select view Master.view.xml, select searchField and list as controls
    • Update page object name: onTheMasterView
    • Explain Page Object
      • way to structure your test,
      • page object pattern,
      • single place to access all parts of a single part of the UI,
        • actions: stuff you do with your UI controls (being part of Given and When)
          • some pregenerated once, we will skip for now
        • assertions: stuff you want to see in the UI (being part of the Then)
          • pregenerated that we will update now
      • provide "readable", "use case relevant" naming for the actions in that part of the UI
    • Update the assertions and import the sap/ui/test/matchers/AggregationLengthEquals matcher:
      • explain the waitFor
        • include the async part (wait!For)
        • look for ids with the UI5 view prefix knowledge (list has the component and view id prefixed, but by accesing the view instance, the test framework doesn't have to care)
        • matchers to find controls in special conditions, aggregations, properties, ancestor, custom function
        • success function for real assertions
    theListShouldHaveTheGivenNumberOfOrders: function(iNumberOfOrders) {
    	return this.waitFor({
    		id: "list",
    		viewName: "Master",
    		matchers: new AggregationLengthEquals({
    			name: "items",
    			length: iNumberOfOrders
    		}),
    		success: function() {
    			Opa5.assert.ok(true, "The list has " + iNumberOfOrders + " orders.");
    		},
    		errorMessage: "List does not have all orders."
    	});
    }
    
    • Run the tests

Step 3 - SearchJourney - Search for an order

  • Lets search for a single order in the list
  • update the SearchJourney.js with the next test
    opaTest("Can find a single order", function(Given, When, Then) {
    	When.onTheMasterView.iEnterSeachTerm("58")
    		.and.iTriggerTheSearch();
    
    	Then.onTheMasterView.theListShouldHaveTheGivenNumberOfOrders(1);
    });
    
  • update the Master.js page object
    • better name for the searching
    • iTriggerTheSearch instead of iPressSearchField_searchField
    • iEnterSeachTerm instead of iEnterTextSearchField_searchField
    • have parameter for the text in iEnterSearchTerm that is passed to the EnterText action
    • Explain Actions:
    • Run the tests

Step 4 - SearchJourney - Navigate to the order

  • Lets navigate to that single order in the list to see the details

  • update the SearchJourney.js with the next test

    opaTest("Can navigate to an single order", function(Given, When, Then) {
    	When.onTheMasterView.iPressOnTheOrderWithTheID("5001658");
    
    	Then.onTheDetailView.iSeeTheTitle("Sales Order 5001658");
    });
    
  • update the Master.js page object

  • exchange require sap/ui/test/matchers/BindingPath matcher and replace the iPressList_list action with

  • we can access the binding information for more stable tests!

    iPressOnTheOrderWithTheID  : function(sId) {
       return this.waitFor({
       	controlType: "sap.m.ObjectListItem",
       	viewName: "Master",
       	matchers: new BindingPath({
       		path: "/SalesOrders('" + sId + "')"
       	}),
       	actions: new Press(),
       	errorMessage: "No order with the id " + sId + " was found."
       });
    }
    
  • Create OPA Page "Detail.js", Container: AllJourneys.js, select view Detail.view.xml, no controls to select

    • update the content with
    sap.ui.define([
    	"sap/ui/test/Opa5",
    	"sap/ui/test/actions/EnterText",
    	"sap/ui/test/matchers/Properties"
    ], function(Opa5, EnterText, Properties) {
    	"use strict";
    
    	Opa5.createPageObjects({
    	        onTheDetailView: {
    	            assertions: {
    	                iSeeTheTitle: function(sTitle) {
    	                    return this.waitFor({
    	                    	id: "objectHeader",
    	                    	viewName: "Detail",
    	                    	matchers : new Properties({
    	                    		title : sTitle
    	                    	}),
    	                    	success: function() {
    	                    		Opa5.assert.ok(true, "I can see the title " + sTitle);
    	                    	},
    	                    	errorMessage: "Was not able to find the control with the id objectHeader"
    	                    });
    	                }
    	            }
    	        }
    	});
    });
    

Conclusion

  • Summarize
  • Prefer to write plain Unit tests!
  • Use Opa5 for integration/acceptance tests

Additional Content

  • .and.iTeardownMyUIComponent() in SearchJourney.js
    • Setup and Teardown of the app for each Journey
  • Update the initial test with an assertion on the detail page title to see the benefit and reuse of page objects.
  • Code Coverage (currently on when starting the component), get a feeling how trustworthy tests are, cover only our app (not framework):
if (window.blanket){
	window.blanket.options("sap-ui-cover-only", "[sap/ui/teched/appUnderTest]");
	window.blanket.options("sap-ui-cover-never", "[sap/ui/teched/appUnderTest/test]");
}

teched2016-opa5-codereview's People

Contributors

swennemers avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.