screw-unit-server 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/CHANGES +5 -0
  2. data/README.markdown +347 -0
  3. data/Rakefile +70 -0
  4. data/bin/screw_unit +6 -0
  5. data/bin/screw_unit_server +10 -0
  6. data/core/EXAMPLE.html +68 -0
  7. data/core/LICENSE +22 -0
  8. data/core/README.markdown +307 -0
  9. data/core/TODO +2 -0
  10. data/core/example/models/cat.js +5 -0
  11. data/core/example/models/man.js +17 -0
  12. data/core/example/spec/matchers/have.js +8 -0
  13. data/core/example/spec/models/cat_spec.js +31 -0
  14. data/core/example/spec/models/man_spec.js +34 -0
  15. data/core/example/spec/spec_helper.js +5 -0
  16. data/core/example/spec/suite.html +25 -0
  17. data/core/lib/jquery-1.2.3.js +3408 -0
  18. data/core/lib/jquery.fn.js +29 -0
  19. data/core/lib/jquery.print.js +108 -0
  20. data/core/lib/screw.assets.js +36 -0
  21. data/core/lib/screw.behaviors.js +91 -0
  22. data/core/lib/screw.builder.js +80 -0
  23. data/core/lib/screw.css +90 -0
  24. data/core/lib/screw.events.js +38 -0
  25. data/core/lib/screw.matchers.js +65 -0
  26. data/core/lib/screw.server.js +21 -0
  27. data/core/spec/behaviors_spec.js +178 -0
  28. data/core/spec/matchers_spec.js +93 -0
  29. data/core/spec/print_spec.js +119 -0
  30. data/core/spec/spec_helper.js +0 -0
  31. data/core/spec/suite.html +18 -0
  32. data/init.rb +0 -0
  33. data/lib/screw_unit.rb +26 -0
  34. data/lib/screw_unit/resources.rb +2 -0
  35. data/lib/screw_unit/resources/spec.rb +37 -0
  36. data/spec/functional/functional_spec.rb +14 -0
  37. data/spec/functional/functional_spec_helper.rb +55 -0
  38. data/spec/functional_suite.rb +10 -0
  39. data/spec/spec_suite.rb +3 -0
  40. data/spec/unit/js_test_core/specs/spec_dir_spec.rb +43 -0
  41. data/spec/unit/js_test_core/specs/spec_file_spec.rb +43 -0
  42. data/spec/unit/unit_spec_helper.rb +120 -0
  43. data/spec/unit_suite.rb +10 -0
  44. data/vendor/js-test-core/CHANGES +9 -0
  45. data/vendor/js-test-core/README +12 -0
  46. data/vendor/js-test-core/Rakefile +72 -0
  47. data/vendor/js-test-core/lib/js_test_core.rb +30 -0
  48. data/vendor/js-test-core/lib/js_test_core/client.rb +50 -0
  49. data/vendor/js-test-core/lib/js_test_core/rack.rb +2 -0
  50. data/vendor/js-test-core/lib/js_test_core/rack/commonlogger.rb +5 -0
  51. data/vendor/js-test-core/lib/js_test_core/rails_server.rb +22 -0
  52. data/vendor/js-test-core/lib/js_test_core/resources.rb +11 -0
  53. data/vendor/js-test-core/lib/js_test_core/resources/dir.rb +52 -0
  54. data/vendor/js-test-core/lib/js_test_core/resources/file.rb +32 -0
  55. data/vendor/js-test-core/lib/js_test_core/resources/file_not_found.rb +15 -0
  56. data/vendor/js-test-core/lib/js_test_core/resources/runners.rb +15 -0
  57. data/vendor/js-test-core/lib/js_test_core/resources/runners/firefox_runner.rb +75 -0
  58. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_dir.rb +50 -0
  59. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_file.rb +17 -0
  60. data/vendor/js-test-core/lib/js_test_core/resources/suite.rb +24 -0
  61. data/vendor/js-test-core/lib/js_test_core/resources/suite_finish.rb +19 -0
  62. data/vendor/js-test-core/lib/js_test_core/resources/web_root.rb +62 -0
  63. data/vendor/js-test-core/lib/js_test_core/selenium.rb +2 -0
  64. data/vendor/js-test-core/lib/js_test_core/selenium/selenium_driver.rb +5 -0
  65. data/vendor/js-test-core/lib/js_test_core/server.rb +111 -0
  66. data/vendor/js-test-core/lib/js_test_core/thin.rb +3 -0
  67. data/vendor/js-test-core/lib/js_test_core/thin/backends/js_test_core_server.rb +9 -0
  68. data/vendor/js-test-core/lib/js_test_core/thin/js_test_core_connection.rb +42 -0
  69. data/vendor/js-test-core/spec/example_core/JsTestCore.css +0 -0
  70. data/vendor/js-test-core/spec/example_core/JsTestCore.js +0 -0
  71. data/vendor/js-test-core/spec/example_public/favicon.ico +0 -0
  72. data/vendor/js-test-core/spec/example_public/javascripts/foo.js +3 -0
  73. data/vendor/js-test-core/spec/example_public/robots.txt +0 -0
  74. data/vendor/js-test-core/spec/example_public/stylesheets/example.css +3 -0
  75. data/vendor/js-test-core/spec/example_specs/failing_spec.js +5 -0
  76. data/vendor/js-test-core/spec/example_specs/foo/failing_spec.js +6 -0
  77. data/vendor/js-test-core/spec/example_specs/foo/passing_spec.js +6 -0
  78. data/vendor/js-test-core/spec/spec_suite.rb +2 -0
  79. data/vendor/js-test-core/spec/specs/failing_spec.js +0 -0
  80. data/vendor/js-test-core/spec/unit/js_test_core/client_spec.rb +137 -0
  81. data/vendor/js-test-core/spec/unit/js_test_core/rails_server_spec.rb +45 -0
  82. data/vendor/js-test-core/spec/unit/js_test_core/resources/dir_spec.rb +42 -0
  83. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_not_found_spec.rb +26 -0
  84. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_spec.rb +88 -0
  85. data/vendor/js-test-core/spec/unit/js_test_core/resources/runner_spec.rb +24 -0
  86. data/vendor/js-test-core/spec/unit/js_test_core/resources/runners/firefox_runner_spec.rb +197 -0
  87. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_dir_spec.rb +79 -0
  88. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_file_spec.rb +42 -0
  89. data/vendor/js-test-core/spec/unit/js_test_core/resources/suite_finish_spec.rb +94 -0
  90. data/vendor/js-test-core/spec/unit/js_test_core/resources/suite_spec.rb +44 -0
  91. data/vendor/js-test-core/spec/unit/js_test_core/resources/web_root_spec.rb +103 -0
  92. data/vendor/js-test-core/spec/unit/js_test_core/server_spec.rb +131 -0
  93. data/vendor/js-test-core/spec/unit/thin/js_test_core_connection_spec.rb +92 -0
  94. data/vendor/js-test-core/spec/unit/unit_spec_helper.rb +125 -0
  95. data/vendor/js-test-core/spec/unit_suite.rb +10 -0
  96. metadata +186 -0
@@ -0,0 +1,65 @@
1
+ Screw.Matchers = (function($) {
2
+ return matchers = {
3
+ expect: function(actual) {
4
+ return {
5
+ to: function(matcher, expected, not) {
6
+ var matched = matcher.match(expected, actual);
7
+ if (not ? matched : !matched) {
8
+ throw(matcher.failure_message(expected, actual, not));
9
+ }
10
+ },
11
+
12
+ to_not: function(matcher, expected) {
13
+ this.to(matcher, expected, true);
14
+ }
15
+ }
16
+ },
17
+
18
+ equal: {
19
+ match: function(expected, actual) {
20
+ if (expected instanceof Array) {
21
+ for (var i = 0; i < actual.length; i++)
22
+ if (!Screw.Matchers.equal.match(expected[i], actual[i])) return false;
23
+ return actual.length == expected.length;
24
+ } else if (expected instanceof Object) {
25
+ for (var key in expected)
26
+ if (expected[key] != actual[key]) return false;
27
+ for (var key in actual)
28
+ if (actual[key] != expected[key]) return false;
29
+ return true;
30
+ } else {
31
+ return expected == actual;
32
+ }
33
+ },
34
+
35
+ failure_message: function(expected, actual, not) {
36
+ return 'expected ' + $.print(actual) + (not ? ' to not equal ' : ' to equal ') + $.print(expected);
37
+ }
38
+ },
39
+
40
+ match: {
41
+ match: function(expected, actual) {
42
+ if (expected.constructor == RegExp)
43
+ return expected.exec(actual.toString());
44
+ else
45
+ return actual.indexOf(expected) > -1;
46
+ },
47
+
48
+ failure_message: function(expected, actual, not) {
49
+ return 'expected ' + $.print(actual) + (not ? ' to not match ' : ' to match ') + $.print(expected);
50
+ }
51
+ },
52
+
53
+ be_empty: {
54
+ match: function(expected, actual) {
55
+ if (actual.length == undefined) throw(actual.toString() + " does not respond to length");
56
+
57
+ return actual.length == 0;
58
+ },
59
+
60
+ failure_message: function(expected, actual, not) {
61
+ return 'expected ' + $.print(actual) + (not ? ' to not be empty' : ' to be empty');
62
+ }
63
+ }
64
+ }
65
+ })(jQuery);
@@ -0,0 +1,21 @@
1
+ (function($) {
2
+ var ajax = $.ajax;
3
+ $(Screw).bind('after', function() {
4
+ var error_text = $(".error").map(function(i, element) {
5
+ return element.innerHTML;
6
+ }).get().join("\n");
7
+
8
+ var suite_id;
9
+ if(top.runOptions) {
10
+ suite_id = top.runOptions.getSessionId();
11
+ } else {
12
+ suite_id = 'user';
13
+ }
14
+
15
+ ajax({
16
+ type: "POST",
17
+ url: '/suites/' + suite_id + '/finish',
18
+ data: {"text": error_text}
19
+ });
20
+ });
21
+ })(jQuery);
@@ -0,0 +1,178 @@
1
+ Screw.Unit(function() {
2
+ var global_before_invoked = false, global_after_invoked = false;
3
+ before(function() { global_before_invoked = true });
4
+ after(function() { global_after_invoked = true });
5
+
6
+ describe('Behaviors', function() {
7
+ describe('#run', function() {
8
+ describe("a simple [describe]", function() {
9
+ it("invokes the global [before] before an [it]", function() {
10
+ expect(global_before_invoked).to(equal, true);
11
+ global_before_invoked = false;
12
+ });
13
+
14
+ it("invokes the global [before] before each [it]", function() {
15
+ expect(global_before_invoked).to(equal, true);
16
+ global_after_invoked = false;
17
+ });
18
+
19
+ it("invokes the global [after] after an [it]", function() {
20
+ expect(global_after_invoked).to(equal, true);
21
+ });
22
+ });
23
+
24
+ describe("a [describe] with a [before] and [after] block", function() {
25
+ var before_invoked = false, after_invoked = false;
26
+ before(function() { before_invoked = true });
27
+ after(function() { after_invoked = true });
28
+
29
+ describe('[after] blocks', function() {
30
+ it("does not invoke the [after] until after the first [it]", function() {
31
+ expect(after_invoked).to(equal, false);
32
+ });
33
+
34
+ it("invokes the [after] after the first [it]", function() {
35
+ expect(after_invoked).to(equal, true);
36
+ after_invoked = false;
37
+ });
38
+
39
+ it("invokes the [after] after each [it]", function() {
40
+ expect(after_invoked).to(equal, true);
41
+ });
42
+ });
43
+
44
+ describe('[before] blocks', function() {
45
+ it("invokes the [before] before an it", function() {
46
+ expect(before_invoked).to(equal, true);
47
+ before_invoked = false;
48
+ });
49
+
50
+ it("invokes the [before] before each it", function() {
51
+ expect(before_invoked).to(equal, true);
52
+ });
53
+ });
54
+ });
55
+
56
+ describe("A [describe] with two [before] and two [after] blocks", function() {
57
+ var before_invocations = [], after_invocations = [];
58
+ before(function() { before_invocations.push('before 1') });
59
+ before(function() { before_invocations.push('before 2') });
60
+
61
+ after(function() { after_invocations.push('after 1') });
62
+ after(function() { after_invocations.push('after 2') });
63
+
64
+ it("invokes the [before]s in lexical order before each [it]", function() {
65
+ expect(before_invocations).to(equal, ['before 1', 'before 2']);
66
+ });
67
+
68
+ it("invokes the [afters]s in lexical order after each [it]", function() {
69
+ expect(after_invocations).to(equal, ['after 1', 'after 2']);
70
+ });
71
+ });
72
+
73
+ describe("A describe with a nested describe", function() {
74
+ var before_invocations = [], after_invocations = [];
75
+ before(function() {
76
+ before_invocations = [];
77
+ before_invocations.push("outermost before");
78
+ });
79
+
80
+ after(function() {
81
+ after_invocations = [];
82
+ after_invocations.push("outermost after");
83
+ });
84
+
85
+ it("outside a nested [describe], does not invoke any of the nested's [before]s", function() {
86
+ expect(before_invocations).to(equal, ["outermost before"]);
87
+ });
88
+
89
+ it("outside a nested [describe], does not invoke any of the nested's [after]s", function() {
90
+ expect(after_invocations).to(equal, ["outermost after"]);
91
+ });
92
+
93
+ describe("a nested [describe]", function() {
94
+ before(function() {
95
+ before_invocations.push("inner before");
96
+ });
97
+
98
+ after(function() {
99
+ after_invocations.push("inner after");
100
+ });
101
+
102
+ it("runs [before]s in the parent [describe] before each [it]", function() {
103
+ expect(before_invocations).to(equal, ["outermost before", "inner before"]);
104
+ });
105
+
106
+ it("runs [after]s in the parent [describe] after each [it]", function() {
107
+ expect(after_invocations).to(equal, ["outermost after", "inner after"]);
108
+ });
109
+
110
+ describe("a doubly nested [describe]", function() {
111
+ before(function() {
112
+ before_invocations.push('innermost before');
113
+ });
114
+
115
+ after(function() {
116
+ after_invocations.push('innermost after');
117
+ });
118
+
119
+ describe('[before] blocks', function() {
120
+ it("runs [before]s in all ancestors before an [it]", function() {
121
+ expect(before_invocations).to(equal, ["outermost before", "inner before", "innermost before"]);
122
+ });
123
+
124
+ it("runs [before]s in all ancestors before each [it]", function() {
125
+ expect(before_invocations).to(equal, ["outermost before", "inner before", "innermost before"]);
126
+ });
127
+ });
128
+
129
+ describe('[after] blocks', function() {
130
+ it("runs [after]s in all ancestors after an [it]", function() {
131
+ expect(after_invocations).to(equal, ["outermost after", "inner after", "innermost after"]);
132
+ });
133
+
134
+ it("runs [after]s in all ancestors after each [it]", function() {
135
+ expect(after_invocations).to(equal, ["outermost after", "inner after", "innermost after"]);
136
+ });
137
+ });
138
+ });
139
+ });
140
+ });
141
+
142
+ describe("A describe block with exceptions", function() {
143
+ var after_invoked = false;
144
+ after(function() {
145
+ after_invoked = true;
146
+ });
147
+
148
+ describe("an exception in a test", function() {
149
+ it("fails because it throws an exception", function() {
150
+ throw('an exception');
151
+ });
152
+
153
+ it("invokes [after]s even if the previous [it] raised an exception", function() {
154
+ expect(after_invoked).to(equal, true);
155
+ });
156
+ });
157
+ });
158
+ });
159
+
160
+ describe("#selector", function() {
161
+ describe('a [describe]', function() {
162
+ it('manufactures a CSS selector that uniquely locates the [describe]', function() {
163
+ $('.describe').each(function() {
164
+ expect($($(this).fn('selector')).get(0)).to(equal, $(this).get(0))
165
+ });
166
+ });
167
+ });
168
+
169
+ describe('an [it]', function() {
170
+ it('manufactures a CSS selector that uniquely locates the [it]', function() {
171
+ $('.it').each(function() {
172
+ expect($($(this).fn('selector')).get(0)).to(equal, $(this).get(0))
173
+ });
174
+ });
175
+ });
176
+ });
177
+ });
178
+ });
@@ -0,0 +1,93 @@
1
+ Screw.Unit(function() {
2
+ describe("Matchers", function() {
3
+ describe('#equal', function() {
4
+ it("invokes the provided matcher on a call to expect", function() {
5
+ expect(true).to(equal, true);
6
+ expect(true).to_not(equal, false);
7
+ });
8
+
9
+ describe('when given an object', function() {
10
+ it("matches Objects with the same keys and values", function() {
11
+ expect({a: 'b', c: 'd'}).to(equal, {a: 'b', c: 'd'});
12
+ expect({a: 'b', c: 'd', e: 'f'}).to_not(equal, {a: 'b', c: 'd', e: 'G'});
13
+ });
14
+
15
+ });
16
+
17
+ describe('when given an array', function() {
18
+ it("matches Arrays with the same elements", function() {
19
+ expect([1, 2, 4]).to(equal, [1, 2, 4]);
20
+ expect([1, 2, 3]).to_not(equal, [3, 2, 1]);
21
+ });
22
+
23
+ it("recursively applies equality to complex elements", function() {
24
+ expect([{a: 'b'}, {c: 'd'}]).to(equal, [{a: 'b'}, {c: 'd'}]);
25
+ expect([{a: 'b'}, {c: 'd'}]).to_not(equal, [{a: 'b'}, {c: 'E'}]);
26
+ });
27
+ });
28
+
29
+ describe(".failure_message", function() {
30
+ it('prints "expected [expected] to (not) be equal [actual]"', function() {
31
+ var message = null;
32
+ try { expect(1).to(equal, 2) } catch(e) { message = e }
33
+ expect(message).to(equal, 'expected 1 to equal 2');
34
+
35
+ try { expect(1).to_not(equal, 1) } catch(e) { message = e }
36
+ expect(message).to(equal, 'expected 1 to not equal 1');
37
+ });
38
+ });
39
+ });
40
+
41
+ describe('#match', function() {
42
+ describe('when given a regular expression', function() {
43
+ it("matches Strings produced by the grammar", function() {
44
+ expect("The wheels of the bus").to(match, /bus/);
45
+ expect("The wheels of the bus").to_not(match, /boat/);
46
+ });
47
+ });
48
+
49
+ describe('when given a string', function() {
50
+ it("matches [expected]s containing [actual]s", function() {
51
+ expect("The wheels of the bus").to(match, "wheels");
52
+ expect("The wheels of the bus").to_not(match, "oars");
53
+ });
54
+ });
55
+
56
+ describe('when given an integer', function() {
57
+ it("matches [expected]s containing [actual]s", function() {
58
+ expect("1 time").to(match, 1);
59
+ expect("2 times").to_not(match, 3);
60
+ });
61
+ });
62
+
63
+ describe(".failure_message", function() {
64
+ it('prints "expected [actual] to (not) match [expected]', function() {
65
+ var message = null;
66
+ try { expect("hello").to(match, "schmello") } catch(e) { message = e }
67
+ expect(message).to(equal, 'expected "hello" to match "schmello"');
68
+
69
+ try { expect("hello").to_not(match, "ello") } catch(e) { message = e }
70
+ expect(message).to(equal, 'expected "hello" to not match "ello"');
71
+ });
72
+ });
73
+ });
74
+
75
+ describe('#be_empty', function() {
76
+ it("matches Arrays with no elements", function() {
77
+ expect([]).to(be_empty);
78
+ expect([1]).to_not(be_empty);
79
+ });
80
+
81
+ describe(".failure_message", function() {
82
+ it("prints 'expected [actual] to (not) be empty", function() {
83
+ var message = null;
84
+ try { expect([1]).to(be_empty) } catch(e) { message = e }
85
+ expect(message).to(equal, 'expected [ 1 ] to be empty');
86
+
87
+ try { expect([]).to_not(be_empty) } catch(e) { message = e }
88
+ expect(message).to(equal, 'expected [] to not be empty');
89
+ });
90
+ });
91
+ });
92
+ });
93
+ });
@@ -0,0 +1,119 @@
1
+ Screw.Unit(function() {
2
+ describe("Print", function() {
3
+ describe('when given undefined', function() {
4
+ it("returns 'undefined'", function() {
5
+ expect($.print(undefined)).to(equal, 'undefined');
6
+ });
7
+ });
8
+
9
+ describe('when given null', function() {
10
+ it("returns 'null'", function() {
11
+ expect($.print(null)).to(equal, 'null');
12
+ });
13
+ });
14
+
15
+ describe('when given a number', function() {
16
+ it("returns the string representation of the number", function() {
17
+ expect($.print(1)).to(equal, '1');
18
+ expect($.print(1.01)).to(equal, '1.01');
19
+ expect($.print(-1)).to(equal, '-1');
20
+ });
21
+ });
22
+
23
+ describe('when given a boolean', function() {
24
+ it("returns the string representation of the boolean", function() {
25
+ expect($.print(true)).to(equal, 'true');
26
+ expect($.print(false)).to(equal, 'false');
27
+ });
28
+ });
29
+
30
+ describe('when given a string', function() {
31
+ it("returns the string, quoted", function() {
32
+ expect($.print('asdf')).to(equal, '"asdf"');
33
+ });
34
+
35
+ describe('when the string is longer than the [max_string] option', function() {
36
+ it("returns the string, truncated", function() {
37
+ expect($.print('asdf', { max_string: 3 })).to(equal, '"asd..."');
38
+ });
39
+ });
40
+
41
+ describe('when the strings has quotes or escaped characters', function() {
42
+ it("returns the string, with quotes and escaped characters escaped", function() {
43
+ expect($.print('as"df')).to(equal, '"as\\"df"');
44
+ expect($.print('as\tdf')).to(equal, '"as\\tdf"');
45
+ });
46
+ });
47
+ });
48
+
49
+ describe('when given a function', function() {
50
+ it("returns the function's signature", function() {
51
+ expect($.print(function() {})).to(equal, 'function ()');
52
+ expect($.print(function foo() {})).to(equal, 'function foo()');
53
+ expect($.print(function foo(bar) {})).to(equal, 'function foo(bar)');
54
+ });
55
+ });
56
+
57
+ describe('when given an element', function() {
58
+ it("returns the string representation of the element", function() {
59
+ expect($.print($('<div>').get(0))).to(equal, '<div>');
60
+ expect($.print($('<div foo="bar">').get(0))).to(equal, '<div>');
61
+ });
62
+ });
63
+
64
+ describe('when given an array', function() {
65
+ it("returns the printed elements, comma separated, encircled by square brackets", function() {
66
+ expect($.print([])).to(equal, '[]');
67
+ expect($.print([1])).to(equal, '[ 1 ]');
68
+ expect($.print([1, 2, 3])).to(equal, '[ 1, 2, 3 ]');
69
+ });
70
+
71
+ describe('when the array is longer than the [max_array] option', function() {
72
+ it("returns the printed array, truncated", function() {
73
+ expect($.print([1, 2, 3, 4], { max_array: 2 })).to(equal, '[ 1, 2, 2 more... ]');
74
+ });
75
+ });
76
+
77
+ describe('when the array has arrays as its elements', function() {
78
+ it("returns the recursively printed array", function() {
79
+ expect($.print([[]])).to(equal, '[ [] ]');
80
+ expect($.print([ [1, 2, 3], 4 ])).to(equal, '[ [ 1, 2, 3 ], 4 ]');
81
+ });
82
+ });
83
+
84
+ describe('when the array has objects as its elements', function() {
85
+ it("returns recursively printed array", function() {
86
+ expect($.print([{}])).to(equal, '[ {} ]');
87
+ expect($.print([ { foo: 'bar' }, 'baz' ])).to(equal, '[ { foo: "bar" }, "baz" ]');
88
+ });
89
+ });
90
+ });
91
+
92
+ describe('when given a jQuery', function() {
93
+ it("returns the printed array of elements engirthed in '$()' ", function() {
94
+ expect($.print($('<div>'))).to(equal, '$([ <div> ])');
95
+ });
96
+ });
97
+
98
+ describe('when given an object', function() {
99
+ it("returns the keys and values of the object, enraptured with curly braces", function() {
100
+ expect($.print({})).to(equal, '{}');
101
+ expect($.print({ foo: 1, bar: 2 })).to(equal, '{ foo: 1, bar: 2 }');
102
+ });
103
+
104
+ describe('when the values of the object are non-primitive', function() {
105
+ it("recursively prints the keys and values", function() {
106
+ expect($.print({ foo: [1, 2] })).to(equal, '{ foo: [ 1, 2 ] }');
107
+ });
108
+
109
+ describe('when the object has circular references', function() {
110
+ it("returns elipses for circularities", function() {
111
+ var circular = {};
112
+ circular[0] = circular;
113
+ expect($.print(circular)).to(equal, '{ 0: { 0: ... } }');
114
+ });
115
+ });
116
+ });
117
+ });
118
+ });
119
+ });