Coder Social home page Coder Social logo

jasmine-fixture's Introduction

jasmine-fixture

Build Status

jasmine-fixture helps you write specs that interact with the DOM by making it easier to inject (and then clean up) HTML fixtures using a syntax that's just like jQuery's selectors. (As a result, it requires jQuery.)

Download the latest version here.

The concept

Here's one way to think about it:

In jQuery, you give $() a CSS selector and it finds elements on the DOM.

In jasmine-fixture, you give affix() a CSS selector and it adds those elements to the DOM.

This is very useful for tests, because it means that after setting up the state of the DOM with affix, your subject code under test will have the elements it needs to do its work.

Finally, jasmine-fixture will help you avoid test pollution by tidying up and remove everything you affix to the DOM after each spec runs.

affix() example

Let's say you want to write a Jasmine spec for some code that needs to select elements from the DOM with jQuery:

$('#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]')

In the good ol' days of manually crafting your HTML fixtures, you'd have to append some raw HTML to the DOM like this:

beforeEach(function(){
  $('<div id="toddler"><div class="hidden toy"><input name="toyName" value="cuddle bunny"></div></div>').appendTo('body');
});

afterEach(function(){
  $('#toddler').remove()
});

But jasmine-fixture's affix method lets you do this instead:

beforeEach(function(){
  affix('#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]')
});

That's right, the spec setup above was able to re-use the exact same ugly jQuery selector and everything just worked! That means:

  • No external (or worse, shared) fixture files means no risk that they become dumping grounds
  • The spec can remain comprehensive (meaning that future readers can understand what the code does without referencing an external file)
  • Less temptation to couple your unit test to your server or client-side HTML templates
  • More one-line setup, fewer multi-line globs of HTML crowding out the behavior your spec is trying to describe

Bottom line: it's just like jQuery, but in reverse! (And, of course, it'll clean up after itself after your spec runs.)

affixing the affixed by chaining invocations

#affix is both a globally available property on the window as well as a jQuery plugin that can be chained with existing jQuery objects (affixing itself beneath their results).

Let's say our subject has a $container element that's been added to the DOM like this:

var $container = affix('.container')

That means we can add things to the container by chaining a call to affix, like any other jQuery plugin:

var $content = $container.affix('#content')

Now our container with the class "container" has some content with the ID "content". Huzzah!

Note that for easy assignability, affix will always return the topmost element of the thing that it just appended, which in this example is <div id="content"></div> (which runs counter to most jQuery plugins, which return the original jQuery object).

more examples

I heard you wanted more examples, so I pulled some from affix's specs.

'span'                                                                  #<span></span>
'.foo'                                                                  #<div class="foo"></div>
'.foo-hah'                                                              #<div class="foo-hah"></div>
'#baz'                                                                  #<div id="baz"></div>
'h1.foo'                                                                #<h1 class="foo"></h1>
'h2#baz'                                                                #<h2 id="baz"></h2>
'h3#zing.zoom'                                                          #<h3 id="zing" class="zoom"></h3>
'h4.zoom#zing'                                                          #<h4 id="zing" class="zoom"></h4>
'div span ul li'                                                        #<div><span><ul><li></li></ul></span></div>
'a b c d e f g h i j k l m n o p q r s t u v w x y z'                   #<a><b><c><d><e><f><g><h><i><j><k><l><m><n><o><p><q><r><s><t><u><v><w><x><y><z></z></y></x></w></v></u></t></s></r></q></p></o></n></m></l></k></j></i></h></g></f></e></d></c></b></a>
'.boom.bang.pow#whoosh'                                                 #<div id="whoosh" class="boom bang pow"></div>
'#foo .panda'                                                           #<div id="foo"><div class="panda"></div></div>
'input#man .restroom'                                                   #<input id="man"></input>
'.pants.zipper'                                                         #<div class="pants zipper"></div>
'foo > bar > baz'                                                       #<foo><bar><baz></baz></bar></foo>
'input[value="12"]'                                                     #<input value="12">
'div[class="class1 class2 class3"] span[div="div1 div2 div3"]'          #<div class="class1 class2 class3"><span div="div1 div2 div3"></span></div>
'form fieldset[name=ok] input#foo.sp1.sp1[foo="woo"][value="13"]'       #<form><fieldset name="ok"><input foo="woo" value="13" id="foo" class="sp1 sp1"></fieldset></form>
'[name="foo"][bar="baz"]'                                               #<name name="foo" bar="baz"></name>
'div[data-bind="my_item"]'                                              #<div data-bind="my_item"></div>
'.ui-dialog[style="width: 1px; height: 5px"]'                           #<div style="width: 1px; height: 5px" class="ui-dialog"></div>
'#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]'      #<div id="toddler"><div class="hidden toy"><input name="toyName" value="cuddle bunny"></div></div>
'div h1+h2'                                                             #<div><h1></h1><h2></h2></div>

Contributing

  1. npm install -g lineman if you don't already have lineman installed.
  2. lineman build
  3. lineman spec to run the fast, isolated specs.
  4. Add your feature or bug fix on a feature branch, with tests.
  5. Submit a pull request.

Thanks

  • Thanks to Sergey Chikuyonok [email protected] for creating Emmet, which is what jasmine-fixture 2.x (& up?) uses to parse css selectors into markup
  • I want to offer thanks to Mike Kent, whose JavaScript port of ZenCoding was the basis for parsing most of this (classes, ids, elements, etc.) in version 1.x.
  • I also want to thank Peter Kananen, for pairing with me on the initial spike of the affix method.

jasmine-fixture's People

Contributors

bostonaholic avatar christophgockel avatar dandv avatar hyzual avatar joshjordan avatar kchien avatar kikihakiem avatar leviwilson avatar mthenw avatar searls avatar tkaufman avatar zspencer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jasmine-fixture's Issues

Inputs with type attribute throw an exception when affixed in IE8

Hi,
I can't seem to affix inputs with type attributes on IE8.

affix('input[type="checkbox"]'); // Throws TypeError: Object doesn't support this property or method

It also throws an error with type="hidden" and maybe other types as well.

I think it is due to a known problem in jQuery with IE8 :
http://bugs.jquery.com/ticket/8232

I don't know whether it can be fixed in jasmine-fixture, I just thought I'd report it anyway to save others some time.
I fixed it in my test by using jQuery's append() instead of affix() :

var $someClass = affix('.someClass');
$someClass.append('<input type="checkbox" />');

affix doesn't create inputbox with placehodler

Hi,

I'm moving from my jquery-based fixtures to jasmine-fixture (affix).
I've found that for some reasons affix doesn't create a placeholder property for input box.

Works:

           var usernameInput = $(document.createElement("input")).attr({
            type: 'text',
            id: 'username',
            name: 'username',
            palceholder: "username",
            autocomplete: "off"})[0];

Result:

<input type=​"text" id=​"username" name=​"username" palceholder=​"username" autocomplete=​"off">​

Doesn't work:

var usernameInput = affix('input[id="username"][type="text"][name="username][placeholder="username"][autocomplete="off"]')[0];

Result:

<input id=​"username" type=​"text" name=​"username" autocomplete=​"off">​

Please, advise.

Refactor into jQuery plugin

This could serve as a jQuery plugin, which could be used for lightweight templating. The syntax could be something like:

$.create('.container #something').appendTo('body')

Would you be interested in refactoring this and releasing?

How to create siblings

the documentation for affix is nice for creating parent/child relationships, but it is not clear how to create sibling nodes. Can you please provide more documentation on the markdown page how to do this?

Creates an id for data attributes with a hash symbol

  affix('a[data-target-pane="#pane-id"]')
  affix("#pane-id")

This creates an id on the link of "pane-id" which interferes with the actual pane element with the same id:

  <a data-target-pane="#pane-id" id="pane-id"></a>
  <div id="pane-id"></div>

Decimal value causing an errant class name

When I add a decimal value to an input field, like: affix('input[type="text"][value="4.99"][class="class-name"]') the class name appears as '.99' instead of 'class-name'.

Fixtures are not always removed from the dom

I have fixture like so:

beforeEach(function(){
  affix('body');
});

I then run some code that adds a couple of classes to the body. In this case it's a bootstrap modal opening, which adds .modal-open and another custom class.

I have another spec which expects this class to not be there. If it runs after the spec that adds the class, it fails because the class is still present from the previous spec.

If I had a $('body').removeClass('modal-open') to the end of the spec that adds it, everything works.

Cannot affix tags with dashes in their name (e.g. Angular directives)

Hi !
Thanks again for this library, it is very useful.

Lately I wanted to use it to unit-test some AngularJS code that made use of directives. One of my directives is an element named <backlog-item>. I would like to simply affix it. I don't want to use $compile because I just want to verify that traversing to this element with a bit of jQuery works.

I found out that I don't seem to be able to affix tags that contain dashes in their names : affix("backlog-item"); actually affixes a <backlog> tag.

Here is a plunker to show this situation : http://plnkr.co/edit/TSvf1H?p=preview

I hope something can be done, otherwise I have found a workaround by using $('<backlog-item').appendTo('body');

Calling affix with an object causes it to be escaped

I have an object:

var mockParams = {"object":"some-object-uuid"}

and I call affix with it

htmlDom = affix('a[data-xo-love="true"][data-params=' + JSON.stringify(mockParams) + ']')

causes the resulting dom to be

<a data-xo-love="true" data-params="{" object":"some-object-uuid"}"=""></a>

Data attributes are being converted to all lowercase

Hey Justin,

I came across some unexpected behavior using 2.0.0. When using affix() with data attributes, each key string is being downcased. I was expecting that any data attribute key that I passed in would not be altered. My use case was needing data attributes with camel-case keys (whether or not that's a good idea or not is certainly debatable).

I'm not sure this is actually worth fixing since there are some pretty easy workarounds, like directly setting the data attribute on the object via jQuery, but I wanted to submit this in case someone else comes across it.

Spec:

# uploader_spec.js.coffee

describe "Uploader", ->
  beforeEach ->
    @config =
      s3BucketEndpoint: "s3.amazon.com",
      s3AccessKey: "s3-access-key",
      s3Subdirectory: "test-dir",
  
    data = ""
    for key, value of @config
      data += "data-#{key}='#{value}' "

    affix(".js--uploader[#{data}]"

Console:

$(".js--audioUploader").data("s3BucketEndpoint")
undefined

$(".js--audioUploader").data("s3bucketendpoint")
"s3.amazon.com"

Ignoring dist in npm

Why is dist/ dir ignored in npm? Currently npm is becoming general purpose package manager and it would be cool to support it.

user should not have to manually download / build script after install from bower

running tests after installing current jasmine-fixture (1.07) via bower gives an error, since the built source is nowhere to be found. turns out its not in the release archive that is downloaded by bower.

$ bower install jasmine-fixture
bower not-cached git://github.com/searls/jasmine-fixture.git#*
bower resolve git://github.com/searls/jasmine-fixture.git#*
bower not-cached git://github.com/searls/jasmine-fixture.git#~1.0.7
bower resolve git://github.com/searls/jasmine-fixture.git#~1.0.7
bower download https://github.com/searls/jasmine-fixture/archive/1.0.7.tar.gz
bower download https://github.com/searls/jasmine-fixture/archive/1.0.7.tar.gz
bower extract jasmine-fixture#* archive.tar.gz
bower resolved git://github.com/searls/jasmine-fixture.git#1.0.7
bower extract jasmine-fixture#~1.0.7 archive.tar.gz
bower resolved git://github.com/searls/jasmine-fixture.git#1.0.7
bower install jasmine-fixture#1.0.7

how to build/link to source file if this is the case? for now, manually downloading but should be easy enough to update this to work nicely with bower. thanks! :)

input type & id

I'm having trouble when trying to affix an input with a type attribute and id like so:

affix("input[type='text']#address")

I've also tried:

affix("input[type='text'][id='address']")

It seems to work without setting the type attribute tho.

affix("input#address")

Affix function square brackets issue.

Example, using the affix method I have this;

[id="testInput"][type="text"][required="true"][pattern="[a-zA-Z0-9-]{1,20}"]

but the above does not work, its having a problem with the square brackets within the pattern

Given this is using the css pattern - it seems like its not successfully escaping the closing ] here and determining it as part of the selector?

Any ideas how to overcome this - it ends up not rendering properly, and we need the pattern to test against some js functions.

blocks is null in FireFox (works in chrome, however)

jasmine server:

rake jasmine
visit localhost:8888 in chrome (everything passes)

visit localhost:8888 in firefox, there are errors like the one below in jasmine-fixtures.js

the error

TypeError: blocks is null in http://localhost:8888/__spec__/helpers/jasmine-fixture.js (line 250)

and from rake jasmine:ci

 Failure/Error: fail out unless spec_results['result'] == 'passed'
 RuntimeError:
   TypeError: blocks is null in http://localhost:46641/__spec__/helpers/jasmine-fixture.js (line 250)

is something with jasmine-fixtures not compatible with firefox?

Siblings example

Maybe you should add siblings example to the examples list?

'div h1+h2' <div> <h1></h1> <h2></h2> </div>

How to add text nodes.

Hello Searls,

I'm just beginning js bdd, but I was wondering how does your affix add text nodes? Right now the demonstrate just adds dom nodes?

Thanks,
Roger

Hi, I am wondering, whether we can add multiple fixtures using affix?

For example, what if I want to add html like:

<div id="test">
    <div id="test1"></div>
    <div id="test2"></div>
</div>

Currently if I call affix multipe times like

affix('div#test div#test1')
affix('div#test div#test2')

Then I will get only

<div id="test">
    <div id="test1"></div>
</div>

Maybe the affix method should be able to detect the save id, and add something to the existing fixture.

also maybe affix should support css selectors like

affix('div#test div#test1, div#test div#test2')

What do you think?

support attributes that contain `[` and `]`

Right now if an attribute contains a ] character, jasmine-fixture assumes the attribute definition is complete and lops it off.

Example

affix('select[name="date[year]"]')

Will give you this HTML

<select name="date[year"></select>

Have a syntax shortcut to create sibling elements all at once

Hi,

as for now, creating nested elements is fairly easy: affix("#container #nested1 #nested2 ...").

However, the only way to create siblings is by doing so:

$container = affix('#container'); $container.affix('#sibling1'); $container.affix('#sibling2');

Even for reasonably small fixtures, this can become quite verbose and pushes the developer back to the old-school way of handling fixtures. ;P

I do not have any good solution in mind, this could maybe solved by introducing a specific separator '|' for instance.

But anyway, I must already thank you for the awesome piece of work you have done so far. Keep up the good work!

Release new version

Any chance you can release a new version? 0.0.2 does not include jasmine-fixture even though it's in master.

Names with multiple brackets are truncated

Ran into a situation where doing affix('input[name="some[thing][foo]"]') gets turned into <input name="some[thing][foo"></input>. None of the tests fail when I add it as a test case though. It seems like it might be a problem with the regular expressions only expecting one set of brackets inside a name. I haven't been able to track down the specific problem yet though.

Namespace collision with Bootstrap's JS

The Javascript library for Twitter's Bootstrap defines an affix method, and while testing something that used it I ran into errors in jasmine-fixture because of it.

The code using Bootstrap's affix might look something like this:

$('.issuable-affix').affix offset:
  top: -> @top = ($('.issuable-affix').offset().top - 70)
  bottom: -> @bottom = $('.footer').outerHeight(true)

And when running a spec using jasmine-fixture, we get the error: TypeError: selectorOptions.split is not a function

I don't have a solution to propose at the moment.

Incorrect value set on input field.

I tried this: affix('input[type="[email protected]"]');

I got $('input').val() == 'user.com'.

Tried tracking the issue down, but the html generation code seemed kinda impenetrable. I've got a workaround in my tests. Any thoughts on how to fix this for real?

Uncaught reference error 'emmet' when loading jasmine-fixture

Just downloaded and using in one project. Must be somethng I'm doing wrong as when I run my tests and load jasmine-fixture, I get the following error message
Uncaught ReferenceError: emmet is not defined
Here's the snippet showing the script tags that load up the libraries:

    <script type="text/javascript" src="javascript/jasmine-2.5.2/jasmine.js"></script>
    <script type="text/javascript" src="javascript/jasmine-2.5.2/jasmine-html.js"></script>
    <script type="text/javascript" src="javascript/jasmine-2.5.2/boot.js"></script>
    <link rel="stylesheet" href="javascript/jasmine-2.5.2/jasmine.css"></link>

    <script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.js"></script>
    <script type='text/javascript' src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>        
    <script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>

    <script type='text/javascript' src="javascript/jasmine-jquery.js"></script>
    <script type='text/javascript' src="javascript/jasmine-fixture.js"></script>

What am I missing here?

tidyUp and init() in global beforeEach

What are your thoughts in cleaning up in a global beforeEach(), rather than in afterEach()?

My reasons for desiring this feature:

  1. The book "Growing Object Oriented Software: Guided by Tests" (aka GOOS) on page 292, discusses tests with databases. In particular, they recommend cleaning up before each test; and one of their reasons is that they can diagnose failures better.
  2. Each test will still start with a clean slate if tidyUp() followed by init() is called in a global beforeEach().
  3. I made a local modification to do just this, and it came in handy when diagnosing a nasty bug involving applying $(selector).live() multiple times (in beforeEach()) without calling die().

If people prefer to clean up in afterEach(), this could be a configurable option (which I'm leaning towards).
By default, it would clean up in afterEach(), but you could configure it to clean up only in beforeEach().

The only difficult part would be to spec out this behavior and verifying that the specContainer is still around.

Thoughts?

Adding default text inside of element

I just have to say that this is not issue but it can be cool improvement for this library.

Current implementation doesn't allow us to inject default text inside of element. That functionality will provide better flexibility for developers. It can be easy used to add {{}} for mustache rendering etc.

Example

I need a div.sample-id with content {{variable}}. In order to affix that I have to:

affix('div.sample-id').text('{{variable}}')

It would be really handy if we have something like

affix('div.sample-id{any-text}') where {} will be parsed as text for element.

affix() does not resolve for me (Teaspoon context)

I love the idea of using jasmine-fixture (I'm hacking my fixture loading right now), but after putting jasmine-fixture.js in my spec/javascripts/support folder and requiring it in my spec_helper.coffee file, I'm unable to actually call the affix() method. I'm sure there's some silly thing I'm forgetting to do, although I have access to my other support methods/libraries in this same manner.

spec/javascripts/spec_helper.coffee:

# Teaspoon includes some support files, but you can use anything from your own support path too.
#=require support/jasmine-jquery
#=require support/sinon
#=require ./support/jasmine-sinon
#=require ./support/jasmine-fixture
#
# Deferring execution
# If you're using CommonJS, RequireJS or some other asynchronous library you can defer execution. Call Teaspoon.execute()
# after everything has been loaded. Simple example of a timeout:
#
# Teaspoon.defer = true
# setTimeout(Teaspoon.execute, 1000)
#
# Matching files
# By default Teaspoon will look for files that match _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your
# spec path and it'll be included in the default suite automatically. If you want to customize suites, check out the
# configuration in config/initializers/teaspoon.rb
#
# Manifest
# If you'd rather require your spec files manually (to control order for instance) you can disable the suite matcher in
# the configuration and use this file as a manifest.
#
# For more information: http://github.com/modeset/teaspoon
#
# You can require javascript files here. A good place to start is by requiring your application.js.
#=require_tree ./

Attempts to use affix:

beforeEach ->
  affix('#js_welcome_user_uid [data-userID="1234567"')
  affix('#city_assets_base_url [data-userID="http://someurl.anyurl.com"')

Results:

Failure/Error: ReferenceError: Can't find variable: affix in http://127.0.0.1:64915/assets/1.0.0/tests/tcpfa/app_spec.js?body=1 (line 4)

Any help would be greatly appreciated, especially if others have had experience with integrating jasmine-fixture into a teaspoon environment.

npm version

The available version up on npm is "1.0.8", is it possible to update this to 1.2.0 ?

Repeated elements, text nodes and hrefs with period character

First of all, awesome plugin.

Do you plan to add support for specifying repeating elements using the * operator, href attributes with . characters in them, or text content with spaces using the { } notation (as of Zen Coding v0.7)? For example:

div>ul>li>a[href="home.html"]{link}+p{foo bar}+span*3

Should result in:

<div>
  <ul>
    <li>
        <a href="home.html">link</a>
        <p>foo bar</p>
        <span></span>
        <span></span>
        <span></span>
    </li>
  </ul>
</div>

But is actually resulting in:

<div>
  <ul>
    <li>
      <a href="home.html" class="html" html="link">link</a>
      <p></p>
    </li>
  </ul>
  <bar></bar>
</div>

You can see that the parsing context seems to be incorrect: the ".html" part of the href is being turned into a class attribute, then again as an attribute in itself, with the text being used as the value of that attribute. Also, the paragraph text has lost the "foo" altogether, and the space seems to have switched context into creating a <bar> element. The * operator on the <span> also seems to be causing and error which prevents the markup from being generated.

Looks like you're working on these things in the "edge-case" branch. I'd offer to help, but know absolutely nothing about coffeescript! :(

Installation and Config instructions

I really like this and the 'concept' section explains the idea very well. However you are missing an install/config section that certainly I would find useful.
I am running my tests with karma. If this is not recommended what is the other way?
Should this script and jquery be downloaded and these files added to the files section in karma.config.js?
Do i need to use requirejs?
Are there ways to include this functionality using npm?

I have tried solving this but I am less comfortable with coffescript

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.