UNPKG

7.33 kBJavaScriptView Raw
1
2/* jshint browser:true */
3/* global El, View */
4
5!function(describe) {
6 var assert = describe.assert
7 , GLOBAL = {}
8
9 assert.wait = function() {
10 var k
11 , obj = this
12 , hooks = []
13 , hooked = []
14
15 for (k in obj) if (typeof obj[k] === "function") swap(k)
16 function swap(k) {
17 hooked.push(k, obj[k])
18 obj[k] = function() {
19 hooks.push(k, arguments)
20 return obj
21 }
22 }
23
24 return function() {
25 if (!hooks) return
26 for (var v, scope = obj, i = hooked.length; i--; i--) {
27 obj[hooked[i-1]] = hooked[i]
28 }
29 // i == -1 from previous loop
30 for (; (v = hooks[++i]); ) {
31 scope = scope[v].apply(scope, hooks[++i]) || scope
32 }
33 hooks = hooked = null
34 }
35 }
36 assert.open = function(url, replace) {
37 history.setUrl(url, replace)
38 return this
39 }
40
41 assert.resizeTo = function(width, height) {
42 El.css({ width: width, height: height })
43 View.emit("resize")
44 return this
45 }
46
47 assert.waitTill = function(fn, options) {
48 var result
49 , testCase = this
50 , count = 30
51 , resume = testCase.wait()
52
53 if (options.timeout) {
54 count = 0 | (options.timeout / 50)
55 }
56
57 this.ok(function() {
58 return !!result
59 }, options || "Function returns something")
60 test()
61
62 return testCase
63
64 function test() {
65 result = fn()
66 if (!result && count--) return setTimeout(test, 50)
67 testCase.ok(result)
68 resume()
69 }
70 }
71 assert.viewOpen = function(route, options) {
72 return this.waitTill(function() {
73 return View(route).open
74 }, options || "View " + route + " should be open")
75 }
76 assert.waitSelector = function(sel, options) {
77 return this.waitTill(function() {
78 return document.body.find.call(document.documentElement, sel)
79 }, options || "Selector "+sel+" should be in dom")
80 }
81 assert.countSelectors = function(sel, expected, options) {
82 this.waitSelector(sel, options)
83 this.ok(function() {
84 var nodes = document.body.findAll(sel)
85 , count = nodes && nodes.length
86 return count === expected
87 }, options || "Number of matches for " + sel + " should be " + expected)
88 return this
89 }
90 assert.haveText = function(sel, expected, options) {
91 this.waitSelector(sel, options)
92 this.waitTill(function() {
93 var node = document.body.find(sel)
94 , txt = node && node[node.tagName == "INPUT" ? "val" : "txt"]().trim()
95 return txt === expected
96 }, options || sel + " should have text: " + expected)
97 return this
98 }
99 assert.fill = function(sel, expected, options) {
100 this.waitSelector(sel, options)
101 this.ok(function() {
102 var node = document.body.find(sel)
103 , val = node && node.val(expected)
104 return val === expected
105 }, options || sel + " should have value " + expected)
106 return this
107 }
108 assert.click = function(sel, expected, options) {
109 this.waitSelector(sel, options)
110 this.ok(function() {
111 var ev
112 , node = document.body.find(sel)
113 , pointerX = 0
114 , pointerY = 0
115 , button = 0
116 , ctrlKey = false
117 , altKey = false
118 , shiftKey = false
119 , metaKey = false
120
121 if (node) {
122 if (node.dispatchEvent) {
123 ev = document.createEvent("MouseEvents")
124 ev.initMouseEvent("click", true, true, document.defaultView, button,
125 pointerX, pointerY, pointerX, pointerY,
126 ctrlKey, altKey, shiftKey, metaKey,
127 button, node)
128 node.dispatchEvent(ev)
129 } else if (node.click) {
130 node.click()
131 } else if (node.fireEvent) {
132 node.fireEvent("onclick")
133 } else if (typeof node.onclick == "function") {
134 node.onclick()
135 }
136 }
137 return !!node
138 }, options || sel + " should be clickable")
139 return this
140 }
141 assert.collectCssUsage = function(options) {
142 options = options || {}
143 var selectors = GLOBAL.selectorsUsage = {}
144 , styleSheets = document.styleSheets
145 , styleSheetsCount = styleSheets.length
146 , ignoreFiles = options.ignoreFiles
147 , ignoreSelectors = options.ignoreSelectors
148 , cleanSelectorRe = /:(?:focus|active|hover|unknown|:[-\w]+)\b/g
149
150 while (styleSheetsCount--) {
151 parseStyleSheet(styleSheets[styleSheetsCount])
152 }
153
154 function parseStyleSheet(styleSheet) {
155 var rule
156 , rules = styleSheet.cssRules || styleSheet.rules
157 , rulesCount = rules.length
158 , fileName = styleSheet.href
159
160 // In IE7 fileName already is relative
161 if (/^\w+:\/\//.test(fileName)) {
162 fileName = relative(location.href.replace(/\/[^\/]*$/, ""), styleSheet.href||"")
163 }
164
165 if (ignoreFiles && ignoreFiles.indexOf(fileName) > -1) return
166
167 // IE 8
168 if (styleSheet.imports) {
169 for (var i = styleSheet.imports.length; i--; ) {
170 parseStyleSheet(styleSheet.imports[i])
171 }
172 }
173
174 while (rulesCount--) {
175 rule = rules[rulesCount]
176 if (rule.styleSheet) {
177 parseStyleSheet(rule.styleSheet)
178 } else if (rule.selectorText) {
179 rule.selectorText.split(/\s*,\s*/).each(selFn)
180 } else {
181 //console.log("bad rule", rule)
182 }
183 }
184 function selFn(sel) {
185 sel = sel.replace(cleanSelectorRe, "").toLowerCase()
186 if (!sel || ignoreSelectors && ignoreSelectors.indexOf(sel) > -1) {
187 return
188 }
189 selectors[sel] = selectors[sel] || {files: [], count: 0}
190 if (selectors[sel].files.indexOf(fileName + ":" + rulesCount) == -1) {
191 selectors[sel].files.unshift(fileName + ":" + rulesCount)
192 }
193 }
194 }
195 View.on("show", count)
196 function count() {
197 var sel
198 , arr = Object.keys(selectors)
199 , len = arr.length
200
201 for (; (sel = arr[--len]); ) {
202 selectors[sel].count += document.body.findAll.call(document.documentElement, sel).length
203 }
204 }
205 return this
206 }
207
208 assert.assertCssUsage = function(options) {
209 options = options || {}
210 var assert = this.test(options.message || "it should use all css rules")
211
212 var sel
213 , selectors = GLOBAL.selectorsUsage
214 , arr = Object.keys(selectors)
215 , len = arr.length
216
217 assert.plan(len)
218 assert.options.noStack = true
219
220 for (; (sel = arr[--len]); ) {
221 assert.ok(selectors[sel].count, "Unused rule '" + sel + "' in " + selectors[sel].files)
222 }
223 return assert
224 }
225
226 assert.collectViewsUsage = function() {
227 var usage = GLOBAL.viewsUsage = {}
228
229 View.on("show", function(route) {
230 var view = View.views[route]
231 for(; (usage[route] = usage[route]||0), usage[route]++, (route = (view = view.parent||{}).route); );
232 })
233 return this
234 }
235
236 assert.assertViewsUsage = function() {
237 var assert = this.it("should use all views")
238 var route
239 , routes = Object.keys(View.views)
240 , len = routes.length
241 , usage = GLOBAL.viewsUsage
242
243 assert.plan(len)
244 assert.options.noStack = true
245
246 for (; (route = routes[--len]); ) {
247 assert.ok(usage[route], "Unused view " + route)
248 }
249 return assert
250 }
251
252 function clear(path) {
253 if (typeof path != "string") {
254 throw new TypeError("Path must be a string. Received " + typeof path)
255 }
256 return path.replace(/\/+$/, "")
257 }
258 var normalizeRe = /^\.\/|(?:^\/\.\.|\/)(\/)|\/(?:[^\/]*\/\.)?\.(\/|$)/
259
260 function normalize(path) {
261 for (; path != (path = path.replace(normalizeRe, "$1$2")); );
262 return path
263 }
264
265 function relative(from, to) {
266 from = normalize(clear(from))
267 to = normalize(clear(to))
268
269 if (from === to) return ""
270
271 from = from.split("/")
272 to = to.split("/")
273
274 for (var i = from.length, common = i; i--; ) {
275 if (from[i] !== to[i]) common = i
276 from[i] = ".."
277 }
278
279 return from.slice(common).concat(to.slice(common)).join("/")
280 }
281
282 assert.isVisible = function(el) {
283 return this.ok(el.offsetWidth > 0 && el.offsetHeight > 0)
284 }
285
286}(describe) // jshint ignore:line
287
288