I'm attempting to DRY up some jasmine tests by extracting out shared examples.
@sharedExamplesForThing = (thing) ->
beforeEach ->
@thingy = new thing
it "is neat", ->
expect(@thingy.neat).toBeTruthy()
describe "widget with shared behavior", ->
sharedExamplesForThing(-> new Widget)
This works nicely when everything is defined in one file. The problems I'm encountering occur when I try to move the sharedExamples to a separate file. I get Can't find variable: sharedExamplesForThing ...
So in the interest of debugging, I tried the following:
describe "widget with shared behavior", ->
it "is acting like a meany", ->
console.log sharedExamplesForThing
expect(false).toBeTruthy()
sharedExamplesForThing(-> new Widget)
In the is acting like a meany
block, the log shows sharedExamplesForThing
as [Function]
but I still get the Can't find variable
outside the it
. I feel like this might have something to do with a scoping issue outside of my current experience, but I could be completely wrong about that. What am I missing here?
(using rails, jasminerice, guard-jasmine)
I found the piece on shared examples from thoughtbot really useful.
I implemented it in coffeescript as follows:
1) In some helper file that is loaded before all spec files:
window.FooSpec =
sharedExamples: {}
window.itShouldBehaveLike = (->
exampleName = _.first(arguments)
exampleArguments =
_.select(_.rest(arguments), ((arg) => return !_.isFunction(arg)))
innerBlock = _.detect(arguments, ((arg) => return _.isFunction(arg)))
exampleGroup = FooSpec.sharedExamples[exampleName]
if(exampleGroup)
return describe(exampleName, (->
exampleGroup.apply(this, exampleArguments)
if(innerBlock) then innerBlock()
)
)
else
return it("cannot find shared behavior: '" + exampleName + "'", (->
expect(false).toEqual(true)
)
)
)
2) For my specs:
(a) I can define a shared behaviour:
FooSpec.sharedExamples["had a good day"] = (->
it "finds good code examples", ->
expect(this.thoughtbot_spy).toHaveBeenCalled()
)
(b) And use it anywhere in some spec as:
itShouldBehaveLike("had a good day")
(Note: I am assuming the spec has defined this.thoughtbot_spy
accordingly before the above line)
When you assign a top-level member variable in CoffeeScript it is assigned as a property of the global object (window
in a Browser). So it generates the following JavaScript:
window.sharedExamplesForThing = ...;
That means that you can refer to it outside the file as window.sharedExamplesForThing
or just sharedExamplesForThing
. So what you are doing should work assuming the shared example file has been loaded before the spec file. I think the problem you have having is that the spec file is loaded first (because describe functions are run as the file is loaded whereas it functions are run after all the files have loaded). So you might need to adjust the load order, you could try putting your shared examples files in a support
directory and then requiring this first.
Rather than assigning variables directly to the window object it may be better to set up a namespace to export your shared variables into (so that you don't clutter the global object):
window.MyNamespace = {}
MyNamespace.sharedExamplesForThing = ...
Then in your spec file you can refer to it as MyNamespace.sharedExamplesForThing
.
I find it helpful to look at the generated JavaScript to try to understand how CoffeeScript exports variables between files.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With