{"id":6431,"date":"2015-04-27T05:30:20","date_gmt":"2015-04-27T05:30:20","guid":{"rendered":"http:\/\/fluentbytes.com\/?p=6431"},"modified":"2015-04-27T05:30:20","modified_gmt":"2015-04-27T05:30:20","slug":"testing-angular-sites-with-codedui","status":"publish","type":"post","link":"https:\/\/fluentbytes.com\/?p=6431","title":{"rendered":"Testing Angular sites with CodedUI"},"content":{"rendered":"<p>Last week we hosted the first of a series of Pluralsight Study group meetings at our company <a href=\"http:\/\/xpirit.com\/\">Xpirit<\/a> together with the <a href=\"http:\/\/www.dotned.nl\/studiegroep\/\">DotNed<\/a> user group. The study group focuses on the new training I just got published on pluralsight called \u201c<a href=\"http:\/\/www.pluralsight.com\/courses\/codedui-testing-web-applications\">Testing Web Applications with CodedUI<\/a>\u201d.<\/p>\n<p>In the first few chapters we covered last week we looked at how the CodedUI object model works and as one of the hands on assignments we thought it would be fun to test an Angular sample website created by my fellow MVP <a href=\"http:\/\/blogs.msmvps.com\/theproblemsolver\/\">Maurice de Beijer<\/a> that he uses in his training on Angular. (<a title=\"http:\/\/rawstack.azurewebsites.net\/\" href=\"http:\/\/rawstack.azurewebsites.net\/\">http:\/\/rawstack.azurewebsites.net\/<\/a>)<\/p>\n<p>The site we wanted to test with CodedUI is located here and shows a list of movies as an infinite scroll list and it has admin pages where you can filter the list of movies and then click one of the rows to edit the movie details.<\/p>\n<p>The scenario we wanted to test was as follows:<\/p>\n<p>Goto the site, Click on the Admin link, enter a movie in the filter box, Click on one row and then alter the rating.<\/p>\n<p>In my course I always urge people to find unique identifiers to find the controls you want to interact with, but as Maurice showed me with his Angular website, there is no use of the id attribute in any of the pages. This seems to be a common practice and therefore we need to find some other ways to uniquely identify the controls we want to interact with so we can find them on the screen.<\/p>\n<p>With Angular it is very common you use attributes like: ng-model, ng-controller, ng-repeat, ng-submit, etc. So there is a way to uniquely identify these controls we just need another way to find them then using an id attribute.<\/p>\n<p>Basically there are two options you have to achieve to find the controls with CodedUI. the first one is the one that most closely matches the CodedUI object model and the way CodedUI finds controls. We need to specify search properties and additional filter properties to find the control. The problem with this approach is that it is not working when you are using the cross browser plug-in and want to playback on chrome or Firefox. (what happens is that all filterProperties are ignored except taginstance, meaning you will most likely have a match that can contain multiple objects in stead of just one.<\/p>\n<p>Since it is a common requirement to test cross multiple browsers this options is only useful for those who only test on the IE browser. Here is a code sample on finding the Filter control on the Admin page (<a title=\"http:\/\/rawstack.azurewebsites.net\/MoviesAdmin#\/moviesAdminList\" href=\"http:\/\/rawstack.azurewebsites.net\/MoviesAdmin#\/moviesAdminList\">http:\/\/rawstack.azurewebsites.net\/MoviesAdmin#\/moviesAdminList<\/a>)<\/p>\n<pre class=\"brush: csharp;\">var bw = BrowserWindow.Launch(new Uri(\"http:\/\/rawstack.azurewebsites.net\"));\nHtmlControl filterbox = new HtmlControl(bw);\nfilterbox.SearchProperties.Add(HtmlControl.PropertyNames.TagName, \"input\");\nfilterbox.FilterProperties.Add(HtmlControl.PropertyNames.ControlDefinition, \"ng-model=\\\"filterOptions.filterText\\\"\");\nKeyboard.SendKeys(filterbox, \"Aliens 2\");\n<\/pre>\n<p>&nbsp;<\/p>\n<p>The second way of implementing this search, is by utilizing the ExecuteScript method on the BrowserWindow class. We construct a simple piece of JavaScript that runs in all browsers where we use CssSelectors to find the unique match on the ng-* attributes and then return the right type of Html control. You can see the code here below:<\/p>\n<pre class=\"brush: csharp;\">const string javascript = \"document.querySelector('{0}');\";\nvar bw = BrowserWindow.Launch(new Uri(\"http:\/\/rawstack.azurewebsites.net\"));\nstring selector = \"[ng-model='filterOptions.filterText']\";\nvar control = bw.ExecuteScript(string.Format(javascript,selector));\nHtmlEdit filter= control as HtmlEdit;\nfilter.Text = \"Alien\";\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Great thing about the ExecuteScript method is that it returns a correctly typed object so you can interact with the control with it\u2019s provided convenience properties that make interaction with the controls more easy.<\/p>\n<p>With this way of finding the control, we also ensure it works cross browser, since&nbsp; the ExecuteScript method is implemented for all supported browsers in CodedUI. You can apply any Css selector that is supported by the document.querySelector method. see here for more info on selectors: <a title=\"http:\/\/www.javascriptkit.com\/dhtmltutors\/css_selectors_api.shtml\" href=\"http:\/\/www.javascriptkit.com\/dhtmltutors\/css_selectors_api.shtml\">http:\/\/www.javascriptkit.com\/dhtmltutors\/css_selectors_api.shtml<\/a><\/p>\n<p>In my <a href=\"http:\/\/fluentbytes.com\/testing-angular-sites-with-codedui-part-2\/\">next post<\/a> I will show you the full steps on testing the full scenario.<\/p>\n<p>Hope this helps,<\/p>\n<p>Marcel<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week we hosted the first of a series of Pluralsight Study group meetings at our company Xpirit together with the DotNed user group. The study group focuses on the new training I just got published on pluralsight called \u201cTesting Web Applications with CodedUI\u201d. In the first few chapters we covered last week we looked [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[8],"tags":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/fluentbytes.com\/index.php?rest_route=\/wp\/v2\/posts\/6431"}],"collection":[{"href":"https:\/\/fluentbytes.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fluentbytes.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fluentbytes.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/fluentbytes.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6431"}],"version-history":[{"count":0,"href":"https:\/\/fluentbytes.com\/index.php?rest_route=\/wp\/v2\/posts\/6431\/revisions"}],"wp:attachment":[{"href":"https:\/\/fluentbytes.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6431"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fluentbytes.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6431"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fluentbytes.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6431"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}