Skip to content
This repository has been archived by the owner on Sep 15, 2024. It is now read-only.

Unit Tests Controllers / Inject #42

Open
nob13 opened this issue Jun 8, 2015 · 5 comments
Open

Unit Tests Controllers / Inject #42

nob13 opened this issue Jun 8, 2015 · 5 comments
Labels

Comments

@nob13
Copy link

nob13 commented Jun 8, 2015

Hi,
thanks a lot of for this library. When trying out I encounter the following problem: How can I unit test Angular-Specific code written in Scala? UTest is not a problem, but how can I inject a controller programatically? Providing it with an explicit scope, could possibly be do-able, but what happens if the controller needs multiple services and some of them need to be mocked?

@mysticfall
Copy link
Member

Hi,

Recently, I had to handle a similar issue so I suppose it might help with your case as well. I managed to write a several AngularJS related test cases using that method, but it involves a Javascript workaround and using Greenlight(https://github.com/greencatsoft/greenlight) which is our own testing framework for Scala/Scala.js.

  • greenlight-jasmine-adapter.js:
'use strict';

window.mocha = {};

window.beforeEachHooks = [];
window.afterEachHooks = [];

window.currentSuite = {};
window.currentSpec = {};

window.setup = function(callback) {
    beforeEachHooks.push(callback);
}

window.teardown = function(callback) {
    afterEachHooks.push(callback);
}
  • JasmineAdapter.scala:
trait JasmineAdapter {
  this: TestSuite with BeforeAndAfter =>
}

object JasmineAdapter extends GlobalScope {

  def beforeEachHooks: js.Array[js.ThisFunction0[Any, Unit]] = js.native

  def afterEachHooks: js.Array[js.ThisFunction0[Any, Unit]] = js.native
}
  • AngularMockTest.scala:
trait AngularMockTest extends TestSuite with BeforeAndAfter with BeforeAndAfterAll with JasmineAdapter {

  import AngularMockTest._
  import JasmineAdapter._

  def name: String

  def modules: Seq[String] = Nil

  private var moduleCallbacks: Seq[Function1[Module, Unit]] = Nil

  beforeAll {
    val module = Angular.module(name, modules)

    moduleCallbacks foreach {
      callback => callback(module)
    }
  }

  before {
    beforeEachHooks.foreach(_(window))

    module(name)
  }

  after {
    afterEachHooks.foreach(_(window))
  }

  def withModule(callback: Module => Unit) {
    this.moduleCallbacks :+= callback
  }

  def withService[A](name: String)(callback: A => Unit): Unit = {
    val handler: js.Function1[A, Unit] = callback

    inject(js.Array(name, handler))
  }
}

object AngularMockTest extends GlobalScope {

  def module(name: String): Unit = js.native

  def inject(dependencies: js.Array[Any]): Unit = js.native
}

With those codes in place, I was able to write a test case like this:

  "UserDirectoryProxy.register()" should "create a user with the given information" in {
    withService[UserDirectoryProxy]("userDirectory") { directory =>
      val created = await {
        directory.register("john", "John Snow", "john", "[email protected]",
          "winteriscoming", Locale("en", Some("US")))
      }

      created should not be (empty)

      created.id should be ("john")
      created.name should be ("John Snow")
      created.nickname should be ("john")
      created.email should be ("[email protected]")
      created.locale should be (Locale("en", Some("US")))

      val found = await {
        directory.findById("john")
      }

      found should not be (empty)
      found.get should be (created)
    }
  }

  withModule { module =>
    module.factory[UserDirectoryProxy.Factory]
  }

Maybe I should include these support classes in this project. But I'm not sure about where to put that Javascript file, or if users like the idea of having a dependency to Greenlight, which they might not need.

Anyway, I suppose it might be able to give you an idea as to how to achieve it. Hope it helps!

@ticketapp
Copy link

Firstly thanks for your library.
Could you please explain me a bit more the process. I have done all that you are saying in your answer but when I run my test I get this error: TypeError: 'undefined' is not an object (evaluating 'array.length').

There are several things I'm not sure about:
where and how is called greenlight-jasmine-adapter.js? I call it in the file where I call angularJS, but I'm really not sure about this.
Moreover, is the window in the beforeAll and afterAll org.scalajs.dom.window?
Finally, is there something to do about Jasmine like import it in the test or in the build.sbt?

Thanks in advance ;)

@mysticfall
Copy link
Member

@ticketapp Those files I posted above are yet to be generalized sufficiently to be included in the project, so I just made them available as they are in the hope that someone might need them.

So, you can just copy & paste the content into your project to make it work. For the Javascript content, you can just make a separate JS file with it and include it in your jsDependencies.

And you are right in assuming the window variable to be org.scalajs.dom.window. I shouldn't have missed the relevant import statement.

It seems that somehow your test cases didn't find the variables defined in the greenlight-jasmine-adapter.js. Please make it sure that it is included in your project properly and post the relevant stacktrace if it wouldn't work.

Sorry for the late response!

@ticketapp
Copy link

Thanks for your response.
Indeed the problem is that the test cases don't find the variables defined in the greenlight-jasmine-adapter.jsfile.
I feel stupid but I don't find how to include the greenlight-jasmine-adapter.jsfile in my jsDependencies. In my project I import all the jsDepencies in the index.html file but to be honest, I don't understand how theindex.html file could be loaded in the tests.
.Maybe you know a Github repository where I can find some examples since there are some unclear points to me? (I took a look in yours but there isn't unfortunately.)

And of course, no problem for the late response, thank you for your help.

@mysticfall
Copy link
Member

@ticketapp Sorry, the only Angular.js project we have which include Scala.js test cases is a proprietary one, so I'm unable to share its codebase.

However, all the relevant parts are already posted in this thread so I suppose you should be able to run your tests once the problem with jsDependencies is sorted out.

You need to add the adapter JavaScript to the jsDependencies setting in your SBT build script, like this:

...
jsDependencies ++= Seq(
...
(ProvidedJS / "greenlight-jasmine-adapter.js" dependsOn "angular.min.js") % "test"
...
)

It presupposes greenlight-jasmine-adapter.js to be in /src/test/resources directory. (By the way, you can use the same script to run other test frameworks, like ScalaTest too)

Please let me know if you have any further questions. Sorry for the late response again!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants