I am writing Jasmine test but it shows strange behavior.
This is my code:
root = exports ? this
class root.SomeClass
constructor: ->
#index = 0
incrementIndex: -> #index++
decrementIndex: -> #index--
And this is my test code:
describe "Object", ->
object = new SomeClass
describe ".index", ->
describe "when index = 3", ->
object.index = 3
describe "when next button is clicked", ->
object.incrementIndex()
it "returns 4", ->
expect(object.index).toBe 4
describe "when previous button is clicked", ->
object.decrementIndex()
it "returns 3", ->
expect(object.index).toBe 2
The test result is below:
Failing 2 specs
Photos initialized .index when index = 3 when next button is clicked returns 4.
Expected 3 to be 4.
Photos initialized .index when index = 3 when previous button is clicked returns 3.
Expected 3 to be 2.
And it is strange that when I comment out the last 4 lines of test code, the test pass. I could not understand what is happening... >_<
Thank you for your help.
Your tests interact which each other. Do setup in beforeEach blocks.
describe "Object", ->
object = undefined
beforeEach ->
object = new SomeClass
describe ".index", ->
describe "when index = 3", ->
beforeEach ->
object.index = 3
describe "when next button is clicked", ->
beforeEach ->
object.incrementIndex()
it "returns 4", ->
expect(object.index).toBe 4
describe "when previous button is clicked", ->
beforeEach ->
object.decrementIndex()
it "returns 3", ->
expect(object.index).toBe 2
Not checked if this piece of code is valid, but still shows how you should fix your tests. Note object = undefined in the 2 line. You need to declare variable here, otherwise object will be local to each beforeEach and it block.
Related
I'm experimenting to understand PureScript channels and signals better, and specifically their use with the UI library Flame.
I've created the following as a small example:
module Main where
import Prelude
import Effect (Effect)
import Flame (Html, QuerySelector(..))
import Flame.Application.NoEffects as FAN
import Flame.HTML.Attribute as HA
import Flame.HTML.Element as HE
data Message
= ButtonOne
| ButtonTwo
type Model
= { buttonOneCount :: Int
, buttonTwoCount :: Int
}
init :: Model
init =
{ buttonOneCount: 0
, buttonTwoCount: 0
}
update :: Model -> Message -> Model
update model message = case message of
ButtonOne -> model { buttonOneCount = model.buttonOneCount + 1 }
ButtonTwo -> model { buttonTwoCount = model.buttonTwoCount + 1 }
view :: Model -> Html Message
view model =
HE.main "main"
[ HE.button [ HA.onClick ButtonOne ] "Button One"
, HE.p_ ("button one: " <> show model.buttonOneCount)
, HE.button [ HA.onClick ButtonTwo ] "Button Two"
, HE.p_ ("button two: " <> show model.buttonTwoCount)
]
main :: Effect Unit
main = do
-- flameChannel :: Channel (Array Message)
flameChannel <-
FAN.mount (QuerySelector "main")
{ init, update, view }
pure unit
I'm aware that any changes should be handled in update here, but as an experiment I'd like to subscribe to changes to flameChannel in main and run some code based on the Message Flame sends through that channel.
Just to get started, what could be added to make this output to the JavaScript console when the user clicks Button One or Button Two, using flameChannel in main?
I've tried playing around with various combinations of functions from purescript-signal: subscribe, runSignal, get, but got nowhere. I have also looked around at various games on GitHub that use the purescript-signal library, but they just seem to throw runSignal into the code, everything works and I don't understand why (also, those examples are a bit complex and far from what I'm trying to do).
ok let's see - as you've already noticed you get a Channel (from signal) back that will notify you about Messages
you should now be able to use Signal.Channel.subscribe to turn this into a Signal
Now the way Signal works is that you should provide a Signal signaling Effects (those will be executed/run) to runSignal - so you have to turn your Signal (Array Message) into a Signal (Effect Unit) first.
Luckily Signal is a Functor so you can use map or the provided ~> (flipped map) to do this. I would suggest using flattenArray first to make your life a bit easier:
logMessage :: Message -> Effect Unit
logMessage msg =
case msg of
ButtonOne -> log "button one"
ButtonTwo -> log "button two"
and in main:
main = do
flameChannel <-
FAN.mount (QuerySelector "main")
{ init, update, view }
let logSignal =
map logMessage $ flip flattenArray ButtonOne $ subscribe flameChannel
runSignal logSignal
this should work
disclaimer: I did not try to compile this - if you get any issues please report and I'll see to it
How to get data below/above annotated keyword present in other line? I am able to annotate keyword but not able to get information
Sample text:
Underwriter's Name Appraiser's Name Appraisal Company Name
Alice Wheaton Cooper Bruce Banner Stark Industries
Code
TYPESYSTEM utils.PlainTextTypeSystem;
ENGINE utils.PlainTextAnnotator;
EXEC(PlainTextAnnotator, {Line});
ADDRETAINTYPE(WS);
Line{->TRIM(WS)};
REMOVERETAINTYPE(WS);
Document{->FILTERTYPE(SPECIAL)};
DECLARE UnderWriterKeyword, NameKeyword, UnderWriterNameKeyword;
DECLARE UnderWriterName(String label, String value);
CW{REGEXP("\\bUnderwriter") -> UnderWriterKeyword};
CW{REGEXP("Name")->NameKeyword};
(UnderWriterKeyword SW NameKeyword){->UnderWriterNameKeyword};
ADDRETAINTYPE(SPACE);
Line{CONTAINS(UnderWriterNameKeyword)} Line -> {
(CW SPACE)+ {-> MARK(UnderWriterName)};
};
REMOVERETAINTYPE(SPACE)
Expected Output :
Underwriter's Name: Alice Wheaton Cooper
Appraiser's Name: Bruce Banner
Appraisal Company Name: Stark Industries
Please suggest if it is possible in RUTA ? If true, how to get data?
TYPESYSTEM utils.PlainTextTypeSystem;
ENGINE utils.PlainTextAnnotator;
DECLARE Header;
DECLARE ColumnDelimiter;
DECLARE Cell(INT column);
DECLARE Keyword (STRING label);
DECLARE Keyword UnderWriterNameKeyword, AppraiserNameLicenseKeyword,
AppraisalCompanyNameKeyword;
"Underwriter's Name" -> UnderWriterNameKeyword ( "label" = "UnderWriter
Name");
"Appraiser's Name/License" -> AppraiserNameLicenseKeyword ( "label" =
"Appraiser Name");
"Appraisal Company Name" -> AppraisalCompanyNameKeyword ( "label" =
"Appraisal Company Name");
DECLARE Entry(Keyword keyword);
EXEC(PlainTextAnnotator, {Line,Paragraph});
ADDRETAINTYPE(WS);
Line{->TRIM(WS)};
Paragraph{->TRIM(WS)};
SPACE[3,100]{-PARTOF(ColumnDelimiter) -> ColumnDelimiter};
Line -> {ANY+{-PARTOF(Cell),-PARTOF(ColumnDelimiter) -> Cell};};
REMOVERETAINTYPE(WS);
INT index = 0;
BLOCK(structure) Line{}{
ASSIGN(index, 0);
Line{STARTSWITH(Paragraph) -> Header};
c:Cell{-> c.column = index, index = index + 1};
}
Header<-{hc:Cell{hc.column == c.column}<-{k:Keyword;};}
# c:#Cell{-PARTOF(Header) -> e:Entry, e.keyword = k};
DECLARE Entity (STRING label, STRING value);
DECLARE Entity UnderWriterName, AppraiserNameLicense, AppraisalCompanyName;
FOREACH(entry) Entry{}{
entry{ -> CREATE(UnderWriterName, "label" = k.label, "value" =
entry.ct)}<-{k:entry.keyword{PARTOF(UnderWriterNameKeyword)};};
entry{ -> CREATE(AppraiserNameLicense, "label" = k.label, "value" =
entry.ct)}<-{k:entry.keyword{PARTOF(AppraiserNameLicenseKeyword)};};
entry{ -> CREATE(AppraisalCompanyName, "label" = k.label, "value" =
entry.ct)}<-{k:entry.keyword{PARTOF(AppraisalCompanyNameKeyword)};};
}
The most important rule is the following:
Header<-{hc:Cell{hc.column == c.column}<-{k:Keyword;};}
# c:#Cell{-PARTOF(Header) -> e:Entry, e.keyword = k};
It contains three rule element, Header,# and Cell, and works this way:
The rule starts to match with the Cell rule element because it is tagged as anchor with #.
This rule element matches on all Cell annotations that or not part of a Header annotation. It starts with the first Cell annotation that fulfills this condition and calls it "c".
The next rule element is # which matches until the next rule element is able to match.
The next rule element matches on a Header annotation if the inlined rule is able to match within the span of the Header annotation. The inlined rule matches on the Cell annotations remembered as "hc" within this span that have the same value for the feature column. The match is successful, if it contains a Keyword remembered as "k".
If these three rule elements matched successfully, then the actions are applied.
The first action creates an Entry annotation called "e" on the span of the Cell annotation.
The second action assigns the keyword to the Entry feature keyword.
As a summary, the rule creates an Entry annotation for each Cell annotation that is not part of the header and assigns the header keyword of the corresponding column in order to define the type of the entry.
Take a look at inlined rules in Ruta.
You could define your condition for one line and annotate the needed info inside the next one:
Line{CONTAINS(UserName)} Line -> { //your logic here };
I'm using a Freemarker macro for managing the content of two maps.
<#macro MACRO_NAME v>
<#nested v.val, v.msg>
</#macro>
Fruit map is structured like this
Map("fruits" -> Map("val", Map("banana" -> "yellow, "orange" -> "orange"), "msg" -> null))
And the other map, animals, looks like this
Map("animals" -> Map("insects" -> Map("butterflies" -> Map("val" -> Map("Hasora anura" -> "blue", Hasora badra -> "yellow"), "msg" -> null))))
It is ok if val is null, because I've a check in my Freemarker code. If fruits.val is null the following code will output false, false (the correct behavior)
${fruits.val???c}
<#MACRO_NAME fruits; fu, fuMsg>
${fu???c}
</#MACRO_NAME>
${animals.insects.butterflies.val???c}
<#MACRO_NAME animals.insects.butterflies; butterflies, buMsg>
${butterflies???c}
</#MACRO_NAME>
But my Problem is that if animals.insects.butterflies.val is null, this will output false, true but it should be false, false too.
I've have no idea why this happens.
wow a really weird behavior I think
the answer is: never, never name the loop var like your map key.
<#MACRO_NAME animals.insects.butterflies; bu, buMsg> instead of
<#MACRO_NAME animals.insects.butterflies; butterflies, buMsg> will work...
it was just a naming problem.
I'm trying to write a simple package for Atom.io editor. This is my first experience with Coffeescript.
So I'm probably missing something trivial.
Anyway, this is my index.coffee
module.exports =
activate: ->
atom.workspaceView.command "md-utils:unorderedList", => #unorderedList()
unorderedList: ->
out = ""
editor = atom.workspace.activePaneItem
selection = editor.getSelection()
lines = selection.getText().split "\n"
for line in lines
out += "- " + line + "\n"
console.log(lines)
selection.insertText(out)
And here it is my index-spec.coffee
{WorkspaceView} = require 'atom'
describe "Markdown Utilities", ->
[editor, editorView] = []
unorderedList = (callback) ->
editorView.trigger "md-utils:unorderedList"
runs(callback)
beforeEach ->
atom.workspaceView = new WorkspaceView
atom.workspaceView.openSync()
editorView = atom.workspaceView.getActiveView()
editor = editorView.getEditor()
describe "when text is selected", ->
it "formats it correctly", ->
console.log = jasmine.createSpy("log")
editor.setText """
a
b
c
d
"""
editor.selectAll()
unorderedList ->
expect(console.log).toHaveBeenCalled()
expect(editor.getText()).toBe """
- a
- b
- c
- d
"""
Now, when I run the spec looks like the method in the index.coffee is not even called.
Both expectations failed :
Expected spy log to have been called.
Expected 'a b c d' to be '-a -b -c -d"
The method in itself works , so I do not understand why test fails.
Any suggestion is much appreciated
Actually your specs lack of a package activation, which is generally done with something like this:
beforeEach ->
atom.workspaceView = new WorkspaceView
atom.workspaceView.openSync()
editorView = atom.workspaceView.getActiveView()
editor = editorView.getEditor()
# Package activation is done within a promise so this will wait for the end of it
# before actually running the tests.
waitsForPromise -> atom.packages.activatePackage('your-package-name')
As your package is never activated, the command you define in the activate method is never registered, so the event triggered in your unorderedList helper never reach it.
I'm trying to write a jasmine test in coffeescript that uses a beforeEach block. This runs into a problem with coffeescript's variable scoping. Here's what I'd like to write:
describe 'PhoneDetailCtrl', () ->
beforeEach () ->
scope = angular.scope()
$browser = scope.$service('$browser')
it 'should fetch phone detail', () ->
scope.params = {phoneId:'xyz'}
$browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'})
ctrl = scope.$new(PhoneDetailCtrl)
expect(ctrl.phone).toEqualData({})
$browser.xhr.flush()
expect(ctrl.phone).toEqualData({name:'phone xyz'})
This doesn't work, though, because the scope and $browser will get declared with var in the innermost scope. That is, once in the beforeEach and then again in the it block. I can force the variables to be declared in the right scope by initializing them, but this seems very strange:
describe 'PhoneDetailCtrl', () ->
$browser = {}
scope = {}
beforeEach () ->
scope = angular.scope()
$browser = scope.$service('$browser')
it 'should fetch phone detail', () ->
scope.params = {phoneId:'xyz'}
...
This works, but the javascript it compiles to is actually
describe('PhoneListCtrl', function() {
var $browser, ctrl, scope;
$browser = {};
ctrl = {};
scope = {};
where all I need is the line var $browser, ctrl, scope;. Can I write this more concisely in coffeescript?
You are doing it the right way.
This is described in the CoffeeScript documentation. I wouldn't worry about the JS that it creates. Yes, it is a bit messy if you were to write it yourself, but this is one of the things that you have to live with when you use a re-writer like CoffeeScript.
You do, however, have a couple of options which are pretty nice.
You can put the variables in the current context if you wish (which happens to be your jasmine.Spec object for the curious, so it is a relatively safe and appropriate place to be putting variables... just don't overwrite existing vars in the context.):
describe 'PhoneDetailCtrl', () ->
beforeEach () ->
#scope = angular.scope()
#$browser = #scope.$service('$browser')
it 'should fetch phone detail', () ->
#scope.params = {phoneId:'xyz'}
#... etc
You can also setup your own variable in which to store things
describe 'PhoneDetailCtrl', () ->
setup = {}
beforeEach () ->
setup.scope = angular.scope()
setup.$browser = setup.scope.$service('$browser')
it 'should fetch phone detail', () ->
setup.scope.params = {phoneId:'xyz'}
#... etc
Your test could be written like the following:
describe "MyGame", ->
mygame = null
beforeEach inject (_MyGame_) ->
mygame = _MyGame_
it "should have two players", ->
expect(mygame.opponents.length).toEqual 2
Much cleaner syntax - without the need to make things global.