Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor jasmine tests #2902

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gruntfile.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ This file is generated by `grunt build`, do not edit it by hand.
'public/chosen.proto.js': ['coffee/lib/select-parser.coffee', 'coffee/lib/abstract-chosen.coffee', 'coffee/chosen.proto.coffee']
test:
files:
'spec/public/jquery_specs.js': 'spec/jquery/*.spec.coffee'
'spec/public/proto_specs.js': 'spec/proto/*.spec.coffee'
'spec/public/jquery_specs.js': ['spec/jquery.spec.coffee', 'spec/common/*.spec.coffee']
'spec/public/proto_specs.js': ['spec/proto.spec.coffee', 'spec/common/*.spec.coffee']

uglify:
options:
Expand Down
47 changes: 47 additions & 0 deletions spec/common/_helpers.spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Helper to distinguish arrays from other objects
type_is_array = Array.isArray || (value) -> {}.toString.call( value ) is '[object Array]'

# Helper to determine if a variable is a dom element
type_is_dom_elm = (el) -> typeof el is 'object' and el.style?

# Helper to create HTML for the select element in most tests
testcase_html = (options, attributes = '') ->
options_obj = {}
# If options is a simple array, convert to an object with equal keys and values
if type_is_array options
for option in options
options_obj[option] = option
else
options_obj = options

# Construct the HTML
tmpl = "<select #{attributes}>"
for value, label of options_obj
q = if value.indexOf('"') > -1 then "'" else '"'
tmpl += "<option value=#{q}#{value}#{q}>#{label}</option>"
tmpl += "</select>"

testcase = (options, settings = {}, attributes = '') ->
# If options is a string we're good, otherwise create the HTML
if typeof options is 'string'
tmpl = options
else
tmpl = testcase_html options, attributes

# Get a "testcase" that is adapted to jquery / prototype
obj = fw_testcase tmpl, settings

# Add commonly used function to the object
# these are just "shortcuts" making the tests a lot more readable for common
# operations like opening the dropdown or finding out how many results are shown
obj.open_drop = () -> @container.trigger('mousedown')
obj.get_val = () -> @select.val()
obj.get_results = () -> @div.find('.active-result')
obj.get_result_groups = () -> @div.find('.group-result')
obj.click_result = (n) -> @get_results()[n].trigger("mouseup")
obj.set_search = (v) ->
@search_field.val(v)
@search_field.trigger('keyup')

# Return the testcase
obj
46 changes: 46 additions & 0 deletions spec/common/basic.spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
describe "Basic setup", ->
# Check existence of jQuery object / Chosen global
fw_basictest()

it "should create very basic chosen", ->
this_test = testcase ['', 'United States', 'United Kingdom', 'Afghanistan']

# very simple check that the necessary elements have been created
["container", "container-single", "single", "default"].forEach (clazz)->
el = this_test.div.find(".chosen-#{clazz}")[0]
expect(type_is_dom_elm el.dom_el).toBe true
expect(this_test.get_val()).toBe ''

do this_test.open_drop
expect(this_test.container.hasClass('chosen-container-active')).toBe true

expect(this_test.get_results().length).toBe 3

this_test.click_result 2

#check that the select was updated correctly
expect(this_test.get_val()).toBe "Afghanistan"

describe "data-placeholder", ->
it "should render", ->
this_test = testcase ['', 'United States', 'United Kingdom', 'Afghanistan'], {}, 'data-placeholder="Choose a Country..."'
expect(this_test.div.find(".chosen-single > span")[0].text()).toBe "Choose a Country..."

it "should render with special characters", ->
this_test = testcase ['', 'United States', 'United Kingdom', 'Afghanistan'], {}, 'data-placeholder="&lt;None&gt;"'
expect(this_test.div.find(".chosen-single > span")[0].text()).toBe "<None>"

describe "disabled fieldset", ->
it "should render as disabled", ->
# More complicated tests need to pass the HTML directly to tmpl_testcase
this_test = testcase """
<fieldset disabled>
<select data-placeholder='Choose a Country...'>
<option value=''></option>
<option value='United States'>United States</option>
<option value='United Kingdom'>United Kingdom</option>
<option value='Afghanistan'>Afghanistan</option>
</select>
</fieldset>
"""
expect(this_test.container.hasClass("chosen-disabled")).toBe true
14 changes: 14 additions & 0 deletions spec/common/events.spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
describe "Events", ->
it "should fire the right events", ->
this_test = testcase ['', 'United States', 'United Kingdom', 'Afghanistan']

# Track order of events
event_sequence = []
this_test.div.onEvt 'input', (evt) -> event_sequence.push evt.type
this_test.div.onEvt 'change', (evt) -> event_sequence.push evt.type

do this_test.open_drop

this_test.click_result 2

expect(event_sequence).toEqual ['input', 'change']
37 changes: 37 additions & 0 deletions spec/common/max_shown_results.spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
describe "search", ->
it "should display only matching items when entering a search term", ->
this_test = testcase ['United States', 'United Kingdom', 'Afghanistan']

do this_test.open_drop

# Expect all results to be shown
expect(this_test.get_results().length).toBe 3

#Type something
this_test.set_search("Afgh")

# Expect to only have one result: 'Afghanistan'.
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].text()).toBe "Afghanistan"

it 'should only show max_shown_results items in results', ->
this_test = testcase ['United States', 'United Kingdom', 'Afghanistan'], {max_shown_results: 1}

do this_test.open_drop

# Expect only one result due to max_shown_results
expect(this_test.get_results().length).toBe 1

# Enter some text in the search field.
this_test.set_search("United")

# Showing only one result: the one that occurs first.
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].text()).toBe "United States"

# Enter some more text in the search field.
this_test.set_search("United Ki")

# Still only one result, but not the first one.
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].text()).toBe "United Kingdom"
115 changes: 115 additions & 0 deletions spec/common/searching.spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
describe "Searching", ->
it "should not match the actual text of HTML entities", ->
this_test = testcase {
'': ''
'This & That': 'This &amp; That'
'This < That': 'This &lt; That'
}
do this_test.open_drop

expect(this_test.get_results().length).toBe 2

# Search for the html entity by name
this_test.set_search 'mp'

# There should be no results
expect(this_test.get_results().length).toBe 0

it "renders options correctly when they contain characters that require HTML encoding", ->
this_test = testcase ['A &amp; B']
do this_test.open_drop
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].html()).toBe "A &amp; B"
this_test.set_search 'A'
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].html()).toBe "<em>A</em> &amp; B"

it "renders optgroups correctly when they contain html encoded tags", ->
this_test = testcase """
<select>
<optgroup label="A &lt;b&gt;hi&lt;/b&gt; B">
<option value="Item">Item</option>
</optgroup>
</select>
"""
do this_test.open_drop
expect(this_test.get_result_groups().length).toBe 1
expect(this_test.get_result_groups()[0].html()).toBe "A &lt;b&gt;hi&lt;/b&gt; B"

it "renders optgroups correctly when they contain characters that require HTML encoding when searching", ->
this_test = testcase """
<select>
<optgroup label="A &amp; B">
<option value="Item">Item</option>
</optgroup>
</select>
"""
do this_test.open_drop
expect(this_test.get_result_groups().length).toBe 1
expect(this_test.get_result_groups()[0].html()).toBe "A &amp; B"
this_test.set_search 'A'
expect(this_test.get_result_groups().length).toBe 1
expect(this_test.get_result_groups()[0].html()).toBe "<em>A</em> &amp; B"

it "renders no results message correctly when it contains characters that require HTML encoding", ->
this_test = testcase ['Item']
do this_test.open_drop

this_test.set_search '&'
expect(this_test.div.find(".no-results").length).toBe 1
expect(this_test.div.find(".no-results")[0].html().trim()).toBe "No results match <span>&amp;</span>"

this_test.set_search '&amp;'
expect(this_test.div.find(".no-results").length).toBe 1
expect(this_test.div.find(".no-results")[0].html().trim()).toBe "No results match <span>&amp;amp;</span>"

it "matches in non-ascii languages like Chinese when selecting a single item", ->
this_test = testcase ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二']
do this_test.open_drop
expect(this_test.get_results().length).toBe 12
this_test.set_search "一"
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].html()).toBe "<em>一</em>"

it "matches in non-ascii languages like Chinese when selecting a single item with search_contains", ->
this_test = testcase ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], {search_contains: true}
do this_test.open_drop
expect(this_test.get_results().length).toBe 12
this_test.set_search "一"
expect(this_test.get_results().length).toBe 2
expect(this_test.get_results()[0].html()).toBe "<em>一</em>"
expect(this_test.get_results()[1].html()).toBe "十<em>一</em>"

it "matches in non-ascii languages like Chinese when selecting multiple items", ->
this_test = testcase ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], {}, 'multi'
do this_test.open_drop
expect(this_test.get_results().length).toBe 12
this_test.set_search "一"
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].html()).toBe "<em>一</em>"

it "matches in non-ascii languages like Chinese when selecting multiple items with search_contains", ->
this_test = testcase ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], {search_contains: true}, 'multi'
do this_test.open_drop
expect(this_test.get_results().length).toBe 12
this_test.set_search "一"
expect(this_test.get_results().length).toBe 2
expect(this_test.get_results()[0].html()).toBe "<em>一</em>"
expect(this_test.get_results()[1].html()).toBe "十<em>一</em>"

it "highlights results correctly when multiple words are present", ->
this_test = testcase ['oh hello']
do this_test.open_drop
expect(this_test.get_results().length).toBe 1
this_test.set_search "h"
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].html()).toBe "oh <em>h</em>ello"

describe "respects word boundaries when not using search_contains", ->
this_test = testcase ['(lparen', '&lt;langle', '[lbrace', '{lcurly', '¡upsidedownbang', '¿upsidedownqmark', '.period', '-dash', '"leftquote', "'leftsinglequote", '“angledleftquote', '‘angledleftsinglequote', '«guillemet']
this_test.div.find("option").forEach (option) ->
boundary_thing = option.dom_el.value.slice(1)
it "correctly finds words that start after a(n) #{boundary_thing}", ->
this_test.set_search boundary_thing
expect(this_test.get_results().length).toBe 1
expect(this_test.get_results()[0].text().slice(1)).toBe(boundary_thing)
46 changes: 46 additions & 0 deletions spec/jquery.spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# The most basic test
fw_basictest = () ->
it "should add chosen to jQuery object", ->
do expect(jQuery.fn.chosen).toBeDefined

# A wrapper around needed "framework"-functions, so we can use the same jasmine
# tests for jquery and prototype
fw = (el) ->
{
# the actual element
dom_el: el

# some common dom traversal functions
find: (q) -> #Return an array of fw's
ret = []
$(el).find(q).each -> ret.push fw(this)
ret

# other functions needed during testing
hasClass: (clazz) -> $(el).hasClass clazz
trigger: (evt) -> $(el).trigger evt
val: (v) -> if v? then $(el).val v else do $(el).val
text: () -> do $(el).text
html: (v) -> if v? then $(el).html v else do $(el).html
onEvt: (evt, fn) -> $(el).on evt, fn
}

fw_testcase = (tmpl, settings = {}) ->
# Wrap each test in a div and put the "template" in it
# (usually just the select itself)
div = $("<div>").html tmpl

# Find the select
select = div.find "select"

# Create the Chosen instance - possibly with specific settings for this "case"
select.chosen settings

# Return an object that has easy access (through the "framework wrapper") to
# the elements
{
div: fw div[0]
select: fw select[0]
container: fw div.find(".chosen-container")[0]
search_field: fw(div.find(".chosen-search input")[0] or div.find(".chosen-search-input")[0])
}