Come Out and Play!

This is the ninth post for the build phase in the first Build-Measure-Learn cycle. In the last post I described the implementation to pass the failing acceptance test. This first solution is based on the import service of the application layer, but it is missing the presentation on the user interface. In this post, I will describe the first step building a user interface, the implementation of an import dialog with file upload and a simple document view. Of course, this implementation will be guided by an acceptance test.

Context

The project is still in the build phase of the first Build-Measure-Learn cycle. And I am still working on the story ‘Import a file with a single text paragraph’. At present, there is a running acceptance test at API level for the small story ‘Import a file with a single text paragraph’. What is st­ill missing is some kind of user interface to upload a file and show the document to the user.

Introduction

The focus of this blog post is on the implementation of a user interface guided by an acceptance test. Of course, this means that a decision about the appropriate technologies must be taken. The Text Analyser Platform will be built as a web application. For this purpose, I am going to use the web application framework Play. The user interface will be a web page containing a file upload for document import and a document view for the presentation of the imported document data. The implementation of the glue code of the acceptance test will be done with CucumberSelenium and ScalaTest.The Play framework comes with a predefined project setup regarding the source code structure. This structure is adaptable but there is no compelling reason for changing it. This means that the import functions implemented so far have to be integrated in the predefined source code structure of Play. Here, Play is the substantial criterion for the organisation of the code base. The implementation made with Play is part of the framework layer in the Hexagonal architecture, see also the sixth post.

Play Framework, 1st Part of the Implementation

The Play framework is an action-based and stateless open-source web application framework, see [Play Framework]. This blog post is not an introduction to the Play Framework. If you are interested in using Play, then you should consult other sources like the official website [Play Framework]. Here I will only present the relevant Play artefacts. I won’t give any explanation for the background of those Play artefacts. Nevertheless, you will find references to the technical background.

Let’s begin with a central element of Play, the configuration files.

Configuration Files

The main configuration file for a Play application is the file application.conf. Preliminary a default configuration with a newly generated secret key is used.

Another configuration file named logback.xmlis needed for the logging framework Logback. Play uses SLF4Jbacked by Logback.

The interesting part is, what the routesfile looks like. It defines the HTTP method and URI pattern, both associated with a file upload action.

The routes File for the File Upload
The routes File for the File Upload

The routeleads to the page with the file upload controls. The page is opened by the action #index of the HomeController. The page looks like this:

The File Upload Dialog Before the Import
The File Upload Dialog Before the Import

This is the file upload form. It has a button to select a file from a local volume. And a button to start the import of the file.The next picture shows an excerpt from the Play template which implements the file upload form. A Play Scala template is a text file which contains chunks of Scala code to generate an HTML or XML or CSV file.

Template Code for the File Upload Controls
Template Code for the File Upload Controls

You can find more background information on the Play template mechanism on [Play Templates].

At this point, the web page is anaemic, the buttons do not trigger any functionality. But before implementing the behaviour with the file upload controller, the acceptance test has to be implemented.

The Acceptance Test for the File Import Dialog

The first acceptance test I wrote aims at the API level. Now I need to write an acceptance test for the UI. Those acceptance tests are written using Cucumber feature files. All feature files are located in the feature folder.

Content of the Feature Folder
Content of the Feature Folder

I placed the new test scenario in a feature file named single-paragraph-word-doc-ui.feature.

The Feature File

Feature File single-paragraph-word-doc-ui.feature
Feature File single-paragraph-word-doc-ui.feature

The feature is called “Import a Word® file using a file upload dialog”. The acceptance test does not make any assumption on the UI technology, it is intentionally technology agnostic. Why? Because a good acceptance test defines what should happen and not how it should happen.

The scenario looks like this:

  1. The import dialog must be started which provides the possibility to upload a file.
  2. When the user selects a Word® file which contains a single paragraph and starts the upload.
  3. Then the file is imported, the text of the paragraph should be available in the system and also displayed by the user interface. 

Next, the three steps of the test scenario have to be realised.

Glue Code

Test execution is done by the JUnit Runner for Cucumber. 

JUnit Runner for the Test Execution
JUnit Runner for the Test Execution

The test runner defines the package which contains the glue code and it defines the file folder where the feature file can be found.

Main part of the glue code are the step definitions in class SingleParagraphWordDocStepDefsUI. It contains the implementations of the step definitions. The glue code utilises ScalaTest + Play, see [Play Functional Test]. And for browser-based tests ScalaTest uses Selenium, see [Scalatest using Selenium].

The step definitions class starts with a declaration of important member variables.

Step definition class
Step definition class

The step definition implementation needs to instantiate a test server. The test server is initialised with a port number and an application instance. A browser object is created to simulate the client actions. Particularly the instance of the TestBrowser plays an important role in the step definitions of GivenWhen and Then.

The Given step definition sets up the initial context of this acceptance test.

Glue Code for the Given Condition
Glue Code for the Given Condition

The figure above shows the implementation of the Givenstep. The test server is started, and the browser navigates to the start page. Then some basic conditions are checked, it assures the presence of a file input control and a button for the file upload. Also, the window title is checked.

The step definition for the When part describes the interaction with the user interface to start a file upload.

Glue Code for the When Condition
Glue Code for the When Condition

It uses the Word® file simple-text-passage.docx for the import. This is the same file which is used by the API acceptance test. Two actions are taken. First the instance of TestBrowser is instructed to enter the path of the Word® file into the form field. And then the browser instance is used to perform a click on the ‘Start Import’button. This start the document import.

Next, the import result is checked in the last step, the step definition for the Thenpart.

Glue Code for the Then Condition
Glue Code for the Then Condition

After the start of the file upload the document should be displayed on the web page. The Then step definition defines the checks of the import result. The web page resulting from the file upload action has to be the same, confirmed by the check for the title. Another check regards a page element for the paragraph. It ensures that the paragraph contains a certain text. The expected value of the text is taken from the Word® file. At the end the test setup, browser and server instance, is cleaned up.

At the current state of the implementation the acceptance test is failing. It is missing the implementation of the file upload and the start of the document import. This failing test is guiding the implementation.

2nd Part of the Implementation Using Play

The file upload is triggered by the ‘Start Import’ button. Since a file upload needs a POST of a web form it requires an appropriate entry in the routes file.

The Upload Action

The routeleads to the upload action which then calls the document import:

Upload Method of the File Controller
Upload Method of the File Controller

First, the upload action performs some basic checks on the filename. In case the filename is valid, the file import is triggered by the method #importFile. This method creates a DocumentRepository and a DocumentParser. Then it starts the file import with the reference to the recently uploaded file. After the import, the upload file is cleaned up and the action routes to the index page with the new document instance as parameter.

Here, the upload action is responsible for the wiring of the collaborators taking part in the import process. The action belongs to the framework layer. It creates an instance of the document parser which uses Apache Tika and an instance of a document repository. At this stage of development there is no database for the document data, so a dummy repository is used.

What’s next?

There is a first page of the user interface, a document parser and a document model, and last but not least two acceptance tests.
What is missing?
Of course, some kind of data store to persist the document models.

The next post focusses on the introduction of a document storage. I am going to write about the decision process and the first implementation steps to persist a document model.

Update on the Technology

This table summarises the technology selection.

Technology Version  
Scala 2.11.1 A genius language for maximum productivity.
Sbt 1.2.3 Probably the best build tool one can use.
ScalaTest 3.0.1 Probably the best test framework for Scala.
Cucumber for Scala 1.2.5 A popular BDD framework.
Play 2.6.19 Stateless web application framework.
ScalaTest + Play 3.1.2 Provides integration support between ScalaTest and Play

Trade Mark Acknowledgements

“Word” is a registered trade mark of Microsoft Corporation in the United States.

Resources

[ApacheTika] Apache Tika
<http://tika.apache.org> accessed November 20th, 2017

[Cucumber] Cucumber.io
<https://cucumber.io/> accessed July 26th, 2017

[CucumberReference] Reference Cucumber
<https://cucumber.io/docs/reference> accessed November 15th, 2017

[CucumberScala] Cucumber JVM-Cucumber Scala
<https://cucumber.io/docs/reference/jvm#scala> accessed August 14th, 2017

[FluentLenium] FluentLenium – Provides a fluent interface for Selenium
<http://fluentlenium.org>

[Logback] Logback – Logging Framework
<https://logback.qos.ch> accessed October 25th, 2018

[Play Framework] Play Framework Website
<https://www.playframework.com> accessed October 21th, 2018

[Play Application Anatomy] Anatomy of a Play Application
<https://www.playframework.com/documentation/2.6.x/Anatomy>

[Play File Upload] Play – Handling File Upload
<https://www.playframework.com/documentation/2.6.x/ScalaFileUpload>

[Play Functional Test] Testing Play – Writing functional tests with ScalaTest
<https://www.playframework.com/documentation/2.6.x/ScalaFunctionalTestingWithScalaTest> accessed October 25th, 2018

[Play Templates] Play Template Engine
<https://www.playframework.com/documentation/2.6.x/ScalaTemplates> accessed October 26th, 2018

[ScalaTest] ScalaTest – A testing tool for Scala and Java developers
<http://www.scalatest.org/> accessed August 14th, 2017

[ScalaTest + Play] ScalaTest + Play – Integration between ScalaTest and Play
<https://github.com/playframework/scalatestplus-play> accessed October 26th, 2018

[Scalatest using Selenium] Scalatest using Selenium
<http://www.scalatest.org/user_guide/using_selenium>

[SeleniumHQ] SeleniumHQ – A suite of tools to automate browsers
<https://www.seleniumhq.org>

[SLF4J] SLF4J – Simple Logging Facade for Java
<https://www.slf4j.org> accessed October 25th, 2018

[TAP] Text Analyzer Platform – Gather, analyse and utilise information rich text!
<https://github.com/GeorgiosAndreadakis/TextAnalyzerPlatform>

Next-to-last post: https://4tap.blog/2017/12/10/writing-a-failing-acceptance-test-with-cucumber/

Last post: https://4tap.blog/2018/01/21/apache-tika-to-the-rescue/

 

Leave a Reply