Spying on a Javascript constructor using Jasmine - ruby-on-rails-3.1

I'm writing specs for some Javascript classes (backbone.js views, written in Coffeescript) and I'd like to ensure that one view constructs another.
I'm attempting to do this by spying on the constructor, like so:
describe 'Avia.AviaView', ->
beforeEach ->
#aviaView = new Avia.AviaView()
#matricesView = new Backbone.View()
spyOn(Avia.MatricesView, 'constructor').andReturn #matricesView
describe 'initialize', ->
beforeEach ->
#aviaView.initialize()
it 'creates a new MatricesView ', ->
expect(Avia.MatricesView.constructor).toHaveBeenCalledOnce()
The initialize() call on AviaView definitely causes the MatricesView constructor to be called, courtesy this line:
new Avia.MatricesView($("#tabs-3")).initialize()
It definitely works; if I run the app manually I can see the constructor being called during initialize(). However my Jasmine spec fails:
Running Jasmine specs...
F
Avia.AviaView initialize creates a new MatricesView . (/Users/dev/avia/spec/javascripts/views/avia_view_spec.js.coffee:13)
Expected constructor to be called exactly once, but was called '0' times (line ~14)
expect(Avia.MatricesView.constructor).toHaveBeenCalledOnce();
FAIL: 1 test, 1 failure, 0.008 secs.
I've spoken to several of my colleagues, and they agree that this should work ... can anyone suggest a good way of spying on constructors?

How about:
describe 'Avia.AviaView', ->
beforeEach ->
#aviaView = new Avia.AviaView()
#matricesView = new Backbone.View()
spyOn(Avia, 'MatricesView').andReturn #matricesView
describe 'initialize', ->
beforeEach ->
#aviaView.initialize()
it 'creates a new MatricesView ', ->
expect(Avia.MatricesView).toHaveBeenCalledOnce()

Related

coVerify fails when running multiple tests but succeeds if the test is run alone

I am using open weather map to get weather data. For this I call the api like this:
openWeatherMapAPI.oneCall().historical()
.byCoordinateAndTimestamp(
Coordinate.of(latitude.toDouble(), longitude.toDouble()),
startDateTime.toEpochSecond()
)
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava()
To mock this I use
mockkConstructor(OpenWeatherMapClient::class)
coEvery {
anyConstructed<OpenWeatherMapClient>().oneCall()
.historical().byCoordinateAndTimestamp(any(), any())
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava()
} returns testUtilsImplementation.getSuccessfulHistoricalWeatherResponse()
And to verify calls this:
coVerify(exactly = 5) {
anyConstructed<OpenWeatherMapClient>().oneCall()
.historical().byCoordinateAndTimestamp(any(), any())
.language(Language.ENGLISH)
.unitSystem(UnitSystem.METRIC)
.retrieve()
.asJava()
}
If I run this test alone, everything is fine but when I run multiple tests at the same time the coVerify fails.
Verification failed: call 1 of 7: OpenWeatherMapClient(mockkConstructor<OpenWeatherMapClient>()).oneCall()) was not called
The things I dont understand are:
I would expect it to fail because of too many calls. But according to the message it isnt even called once
where is the 7 coming from?
Adding unmockkConstructor(OpenWeatherMapClient::class) or unMockAll() or clearAllMocks() changes nothing
Can anyone point me in a direction?

Several aRFC with WAIT, how to synchronize access to variable in callback?

I am using asynchronous RFC calls for doing some parallel work in SAP. Here you can see my pseudo code.
* class variable
data: gv_counter type i .
....
method start_tasks .
do 10 times .
call function 'my_remote_function'
starting new task task_identifier
calling task_finish on end of task .
enddo .
wait for asynchronous tasks until gv_counter eq 10 .
endmethod .
.....
method task_finish .
gv_counter = gv_counter + 1 .
endmethod .
As you can see I start 10 processes and I wait until they are all finished.
My question is about the method task_finish and the access to the global class variable gv_counter. How can I ensure that the access to the variable gv_counter is synchronized?
E.g. in Java I would do something like that:
synchronized {
gv_counter += 1 ;
}
Here is a quotation from the SAP documentation on the topic.
Addition 2
... {CALLING meth}|{PERFORMING subr} ON END OF TASK
...
If multiple callback routines are registered during a program section, they are executed in an undefined order when the work process changes in a roll-in.
For me it means that they will be executed one after another (in order) which is however undefined. This would mean that your variable would always reach the value of 10.
You can actually debug it, to see how it is processed sequentially when you put a breakpoint in the task_finish method. Here is my example.
REPORT ZZZ.
CLASS lcl_main DEFINITION FINAL CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS:
main,
task_finish
IMPORTING
p_task TYPE clike.
PRIVATE SECTION.
CLASS-DATA:
gv_counter TYPE i.
CLASS-METHODS:
start_tasks.
ENDCLASS.
CLASS lcl_main IMPLEMENTATION.
METHOD main.
start_tasks( ).
ENDMETHOD.
METHOD start_tasks.
DATA: l_task TYPE string.
DO 10 TIMES.
l_task = sy-index.
CALL FUNCTION 'Z_ARFC_ECHO'
STARTING NEW TASK l_task
CALLING task_finish ON END OF TASK
EXPORTING
i_value = sy-index.
ENDDO.
WAIT FOR ASYNCHRONOUS TASKS UNTIL gv_counter = 10.
ENDMETHOD.
METHOD task_finish.
DATA: l_value TYPE sy-index.
RECEIVE RESULTS FROM FUNCTION 'Z_ARFC_ECHO'
IMPORTING
e_echo = l_value.
WRITE: /, p_task, l_value.
gv_counter = gv_counter + 1.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
lcl_main=>main( ).
My RFC looks as follows
FUNCTION Z_ARFC_ECHO.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*" IMPORTING
*" VALUE(I_VALUE) TYPE SY-INDEX
*" EXPORTING
*" VALUE(E_ECHO) TYPE SY-INDEX
*"----------------------------------------------------------------------
e_echo = i_value.
ENDFUNCTION.
What is also interesting (and also mentioned in the documentation) the list output statements like WRITE are not processed in such a handler, so that's why you do not see anything getting printed at the end of the execution of the abovementioned report.

Phoenix: How to test controller actions from the console?

I have created a new controller action and I would like to test it from the console to make sure it works.
How can I execute the action after running iex -S mix phx.server in the terminal? It seems to me that in order to do this, I need to create a conn struct as well as a user struct (since I am using Guardian).
My controller code looks like this:
defmodule HelloWeb.AssetController do
use HelloWeb, :controller
use Guardian.Phoenix.Controller
action_fallback HelloWeb.FallbackController
def new_action(conn, %{"id" => id}, user, _claims) do
# Stuff I want to test
end
# Other actions omitted
end
How can I test new_action from IEx?
You can use phoenix test helpers to achieve something like what's done in the ExUnit tests in iex:
iex(22)> conn = Phoenix.ConnTest.build_conn() |>
...(22)> Phoenix.Controller.put_view(HelloWeb.AssetView)
%Plug.Conn{...}
# This assumes you have at least one user created in the dev database
iex(23)> [user | _] = HelloWeb.Schemas.User |> HelloWeb.Repo.all
iex(23)> HelloWeb.AssetController.new_action(conn, %{"id" => some_id}, user, [])
# You can inspect this conn to see if what's rendered is OK
%Plug.Conn{...}

Casperjs not triggering page.error event on errors in evaluate

I want to catch errors on the remote page in Casper.
casper.thenEvaluate ->
document.querySelector("#selector-doesnt-exist").attribute-doesnt-exist = 'value'
I have the following listeners set up:
casper.on "page.error", (message, trace) ->
console.log(message)
casper.on "remote.message", (message) ->
console.log(message)
Neither of these is being triggered when the evaluate fails. Is there any way to listen to errors on the remote page?
I don't know how to do this either, and there's probably a more proper way.
Assuming you only want to catch errors in your own evaluate code (not errors on the part of the site you're loading), one solution would be to wrap the casper evaluate function to include a try-catch, and handle the error by returning it from the evaluate:
casper.myevaluate = (fn, args...) ->
s = #evaluate (fn,args) ->
try
fn.apply(this,args)
catch e
return {'ourError':e}
, fn, args
if s.ourError?
ErrorHandler.Exception(s.ourError)
return s
E.g. calling:
casper.myevaluate ()-> silly
...would call your error handler code with ReferenceError: Can't find variable: silly

How do I get visual studio to not wait on temporarily blocked tests?

I'm relatively new to unit testing, and trying it on my personal projects. I want to unit test some concurrent methods (futures which run actions in the thread pool). To avoid the test method finishing before the thread pooled action, I'm blocking the test. Here is the actual blocking code:
Private Shared Function BlockOnFuture(ByVal future As IFuture,
ByVal timeout As TimeSpan) As Boolean
Dim waitHandle = New System.Threading.ManualResetEvent(initialState:=False)
AddHandler future.Ready, Sub() waitHandle.Set()
If future.State <> FutureState.Unknown Then waitHandle.Set() 'already ready'
Return waitHandle.WaitOne(timeout)
End Function
Private Shared Function BlockOnFuture(ByVal future As IFuture) As Boolean
Return BlockOnFuture(future, New TimeSpan(0, 0, seconds:=5))
End Function
I have tests which intentionally don't set a future, for example:
<TestMethod()>
Public Sub CallWhenReady_Dangle()
Dim flag = True
Dim future = New FutureAction() 'A class which has methods to make it become ready'
Dim result = future.CallWhenReady(Sub(exception)
flag = False
End Sub)
'should fail, because the future action is not being set'
Assert.IsFalse(BlockOnFuture(result))
'future was not set so the action did not run'
Assert.IsTrue(flag)
'action did not run so the result should not be set either'
Assert.IsTrue(result.State = FutureState.Unknown)
End Sub
I think Visual studio runs the tests one by one, because every test waits patiently while this one takes 5 seconds to timeout and complete. Is there a way I can force certain tests to run concurrently? Am I approaching this wrong?
It's been a long day but I think my advice would be the approach is wrong. Really you want to stub out the future behavior.
A kluge would be to modify the default test timeout. You can do this with an attribute I think (most test Fx let you do this but I can't remember the syntax for MSTest which appears to b the one you're using).

Resources