[TOC] # Angular Example See this [blog article](http://blog.wuzzeb.org/posts/2013-12-16-yesod-and-angular.html) for the reasoning behind how Angular is integrated into a Yesod application using this generator. This example application follows exactly this outline via the following. * The view consists of the Yesod handlers plus the widget hamlet/lucius/cassius. The widget files are located in the `templates` directory exactly like in a scaffolded application and the Yesod handlers are in `main.hs`. Note that the widget files do not use any julius. * The Angular code and directive templates are in the `angular-app` directory, and this directory is managed by `StaticSettings.hs`. `StaticSettings.hs` exports a variable of type `Route EmbeddedStatic` named `ng_modules_example_js`. All the Yesod handlers have to do is reference this one route. This Angular code must be written in a certian style for the generator to process it correctly. The style is explained in detail in the haddock for `Yesod.EmbeddedStatic.AngularJavascript`. The [README.md](https://bitbucket.org/wuzzeb/yesod-static-generators/src/tip/angular/example/angular-app/README.md) within the `angular-app` directory explains how the example application implemented these rules. ### Compiling and running the example To compile the application, from the directory containing the .cabal file, run ~~~ cabal build example-dev cabal build example-production ~~~ You can then run either one by ~~~ ./dist/build/example-dev/example-dev ./dist/build/example-production/example-production ~~~ Note that in development mode, each javascript file in `angular-app` is served separately to help with debugging. During production, a single javascript file containing all the code is served. # Testing A major goal of Angular is to make the code easy to test (as long as the right tools are in place). Designing the application as mentioned above fits nicely with the available testing tools. See this [blog post](http://blog.wuzzeb.org/posts/2013-12-17-testing-yesod-and-angular.html) for an explination of the testing tools and the various types of testing that should be done. ### Karma The example application has some karma tests of the Angular javascript code, located in the `tests/unit-js` directory. To run the tests, the current directory must be the `tests` directory. First, karma and the [karma-ng-hamlet2js-preprocessor](https://npmjs.org/package/karma-ng-hamlet2js-preprocessor) must be installed. ~~~ cd path/to/example/tests npm install karma karma-jasmine karma-firefox-launcher karma-phantomjs-launcher karma-ng-hamlet2js-preprocessor ~~~ (Could also install globally with the `-g` flag.) Now, if you have Firefox installed, the tests can be run by: ~~~ ./node_modules/karma/bin/karma start ~~~ Karma is configured via `karma.conf.js` and the test code itself is in `tests/unit-js`. The test code uses [jasmine](http://pivotal.github.io/jasmine/). The test code is mostly normal Angular/jasmine test code, with only two notable changes: * The `angular-mock.js` file defines `window.module = angular.mock.module` as a shortcut and if you search on google for examples you will see many tests using `beforeEach(module("modname"))`. Since we use `window.module` inside `angular-app` to hold the actual Angular module, when writing tests you will need to use `beforeEach(angular.mock.module("modname"))` inside the test code. * The directive hamlet is loaded by the [karma-ng-hamlet2js-preprocessor](https://npmjs.org/package/karma-ng-hamlet2js-preprocessor) karma preprocessor, which is configured inside `karma.conf.js`. ### yesod-test Since Angular is separate from from the handlers and routes, testing the Yesod handlers is identical to using `yesod-test` on any other Yesod application. Therefore, the example application does not include any tests of the Yesod handlers and routes using `yesod-test`. ### WebDriver The example application has a small end to end test using [webdriver](https://hackage.haskell.org/package/webdriver), [webdriver-angular](https://hackage.haskell.org/package/webdriver-angular), and [hspec-webdriver](https://hackage.haskell.org/package/hspec-webdriver). The tests are in the `tests/end2end` directory. Before running them, you will first need to download `selenium-server-standalone-.jar` from [here](http://code.google.com/p/selenium/downloads/list) (or use a distro package). Also you will need to install the Java JRE, OpenJDK works fine. Start the selenium server ~~~ java -jar selenium-server-standalone-.jar ~~~ Next you need to start the yesod application, I suggest you test against the version built for production. In a scaffolded application, this is a good use for the `Staging` section of the config file. ~~~ ./dist/build/example-production/example-production ~~~ Finally, install [webdriver](http://hackage.haskell.org/package/webdriver), [webdriver-angular](http://hackage.haskell.org/package/webdriver-angular), and [hspec-webdriver](http://hackage.haskell.org/package/hspec-webdriver). Since the test code does not reference any Haskell modules or javascript code from our project, I find it easiest to run the test code from `ghci`. You could also call the test code from a test-suite section in the cabal file. ~~~ cd tests/end2end ghci todo.hs > main ~~~ If you use cabal sandboxes, you will need instead ~~~ ghci -package-db path/to/sandbox/i386-linux-ghc-7.6.3-packages.conf.d todo.hs ~~~ (of course the version and architecture might be different). You could also use `cabal repl` but that also loads all the Haskell modules which are not needed for the `todo.hs` test code.