{"id":92,"date":"2019-02-07T12:38:22","date_gmt":"2019-02-07T11:38:22","guid":{"rendered":"https:\/\/informedica.nl\/?p=92"},"modified":"2020-11-15T09:57:02","modified_gmt":"2020-11-15T08:57:02","slug":"testing-a-user-interface-using-canopy","status":"publish","type":"post","link":"https:\/\/informedica.nl\/?p=92","title":{"rendered":"Testing a User Interface using Canopy"},"content":{"rendered":"\n<p>Testing a user interface is a challenging task in programming. However, new tools have emerged to make this better feasible. Using the setup of an web app using the <a href=\"https:\/\/safe-stack.github.io\/docs\/\">SAFE template<\/a>, <a href=\"http:\/\/lefthandedgoat.github.io\/canopy\/\">canopy <\/a>is a testing library that enables UI testing in the browser.<\/p>\n\n\n<p><!--more--><\/p>\n\n\n<p>One of the best programming practices is the use of a REPL (Run Evaluate Print Loop). F# uses script files and the FSI for this process. Normally I develop code in an script file run it in the REPL and continue until I have created a specific feature. Ideally, the same can be applied to setting up and running tests.<\/p>\n\n\n\n<p>The first step is to import the needed libraries in the script file. With the pakket manager Paket, there is an option to have a script file generated that will reference all the needed libraries for a specific project. This can be done command line:<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-shell\">\n      Shell    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-909907823\" \n    id=\"codemirror-909907823\"\n  >.paket\/paket.exe generate-load-scripts --framework net45<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-909907823'), {\n      mode: 'shell',\n      readOnly: true,\n      theme: 'material', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p>Or a directive can be added in the paket.dependencies file:<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-plain\">\n      Plain Text    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-2035446784\" \n    id=\"codemirror-2035446784\"\n  >generate_load_scripts: true<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-2035446784'), {\n      mode: '',\n      readOnly: true,\n      theme: 'material', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p>The resulting references script file can be loaded in the script file used to create the tests. First the project is started up for development. Then the script file with tests is run in the REPL. This will fire up a browser, load the application and run the UI tests:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"fsharp\" class=\"language-fsharp\">#load \".\/..\/..\/..\/.paket\/load\/net472\/UITests\/uitests.group.fsx\"\r\n\r\nopen System.IO\r\nopen canopy.runner.classic\r\nopen canopy.configuration\r\nopen canopy.classic\r\nopen canopy.types\r\n\r\nlet filepath = __SOURCE_DIRECTORY__\r\nlet driverpath =\r\n    @\".\/..\/..\/..\/packages\/uitests\/Selenium.WebDriver.ChromeDriver\/driver\/win32\"\r\nlet chromepath = Path.Combine(filepath, driverpath)\r\n\r\ntype PageIds =\r\n    | Parent of string * PageIds list\r\n    | Child of string\r\n\r\nmodule Literals =\r\n    \/\/ starting div for the elmish app\r\n    [&lt;Literal>]\r\n    let appId = \"#elmish-app\"\r\n\r\n    [&lt;Literal>]\r\n    let homePageId = \"#homepage\"\r\n\r\n    [&lt;Literal>]\r\n    let appBarId = \"#appbar\"\r\n\r\n    [&lt;Literal>]\r\n    let bottomBarId = \"#bottombar\"\r\n\r\n    [&lt;Literal>]\r\n    let bodyId = \"#body\"\r\n\r\n    [&lt;Literal>]\r\n    let title = \"GenPRES\"\r\n\r\nlet checkPageDivs ids =\r\n    let rec check previd ids =\r\n        match ids with\r\n        | [] -> ()\r\n        | p :: cs ->\r\n            match p with\r\n            | Child id ->\r\n                if previd = \"\" then\r\n                    sprintf \"checking single: %s\" id |> describe\r\n                    displayed id\r\n                else\r\n                    sprintf \"checking child: %s of parent: %s\" id previd\r\n                    |> describe\r\n                    (element previd |> elementWithin id) |> displayed\r\n            | Parent(p, cs_) ->\r\n                if previd = \"\" then\r\n                    sprintf \"checking main: %s\" p |> describe\r\n                    displayed p\r\n                else\r\n                    sprintf \"checking child: %s of parent: %s\" p previd\r\n                    |> describe\r\n                    (element previd |> elementWithin p) |> displayed\r\n                check p cs_\r\n            check previd cs\r\n    check \"\" ids\r\n\r\nchromeDir &lt;- chromepath\r\nsuites &lt;- [ suite() ]\r\nstart chrome\r\n\"check if the app is correctly loaded\" &amp;&amp;&amp; fun _ ->\r\n    \/\/ go to the url\r\n    url \"http:\/\/localhost:8080\/\"\r\n    describe \"checking loaded page ids for the home page\"\r\n    [ Parent(Literals.appId,\r\n             [ Parent(Literals.homePageId,\r\n                      [ Child Literals.appBarId\r\n                        Child Literals.bodyId\r\n                        Child Literals.bottomBarId ]) ]) ]\r\n    |> checkPageDivs\r\n    describe \"check if the page title is GenPRES\"\r\n    \"GenPRES\" === title()\r\n    describe \"check if the appbar title is GenPRES\"\r\n    let title = (element \"#appbar\" |> elementWithin \"#title\")\r\n    \"GenPRES\" === (read title)\r\nrun()\r\nquit()<\/code><\/pre>\n\n\n\n<p>The results look like:<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-plain\">\n      Plain Text    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-1622558107\" \n    id=\"codemirror-1622558107\"\n  >DevTools listening on ws:\/\/127.0.0.1:55656\/devtools\/browser\/caf57c30-9676-4bbe-9ef3-27a5319d3cf4\n Test: check if the app is correctly loaded\n Binding session to &#039;c:\\Development\\Informedica\\apps\\GenPres2.paket\\load\\net472\\UITests..\/..\/..\/..\/packages\/uitests\/Selenium.WebDriver\/lib\/net45\/WebDriver.dll&#039;\u2026\n 2\/7\/2019 12:31:43 PM: checking loaded page ids for the home page\n 2\/7\/2019 12:31:43 PM: checking main: #elmish-app\n 2\/7\/2019 12:31:43 PM: checking child: #homepage of parent: #elmish-app\n 2\/7\/2019 12:31:44 PM: checking child: #appbar of parent: #homepage\n 2\/7\/2019 12:31:44 PM: checking child: #body of parent: #homepage\n 2\/7\/2019 12:31:44 PM: checking child: #bottombar of parent: #homepage\n 2\/7\/2019 12:31:44 PM: check if the page title is GenPRES\n 2\/7\/2019 12:31:44 PM: check if the appbar title is GenPRES\n Passed\n 0 minutes 2 seconds to execute\n 1 passed\n 0 skipped\n 0 failed<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-1622558107'), {\n      mode: '',\n      readOnly: true,\n      theme: 'material', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Testing a user interface is a challenging task in programming. However, new tools have emerged to make this better feasible. Using the setup of an web app using the SAFE template, canopy is a testing library that enables UI testing in the browser.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"class_list":["post-92","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/informedica.nl\/index.php?rest_route=\/wp\/v2\/posts\/92","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/informedica.nl\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/informedica.nl\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/informedica.nl\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/informedica.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=92"}],"version-history":[{"count":4,"href":"https:\/\/informedica.nl\/index.php?rest_route=\/wp\/v2\/posts\/92\/revisions"}],"predecessor-version":[{"id":186,"href":"https:\/\/informedica.nl\/index.php?rest_route=\/wp\/v2\/posts\/92\/revisions\/186"}],"wp:attachment":[{"href":"https:\/\/informedica.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=92"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/informedica.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=92"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/informedica.nl\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=92"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}