]> git.gir.st - VimFx.git/blob - extension/test/test-api.coffee
Merge branch 'master' into develop
[VimFx.git] / extension / test / test-api.coffee
1 ###
2 # Copyright Simon Lydell 2015.
3 #
4 # This file is part of VimFx.
5 #
6 # VimFx is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # VimFx is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
18 ###
19
20 testUtils = require('./utils')
21 prefs = require('../lib/prefs')
22 utils = require('../lib/utils')
23
24 {utils: Cu} = Components
25
26 apiPref = 'extensions.VimFx.api_url'
27 apiUrl = Services.prefs.getComplexValue(apiPref, Ci.nsISupportsString).data
28 # Hack: Also import `_callbacks` so callbacks added by tests can be `.pop()`ed.
29 {getAPI, _callbacks: callbacks} = Cu.import(apiUrl, {})
30
31 # In the tests, `vimfx` refers to the API object, while `$vimfx` refers to the
32 # passed in `VimFx` instance.
33
34 exports['test exports'] = (assert, $vimfx, teardown) -> getAPI((vimfx) ->
35 teardown(-> callbacks.pop())
36
37 assert.equal(typeof vimfx.get, 'function', 'get')
38 assert.equal(typeof vimfx.getDefault, 'function', 'getDefault')
39 assert.equal(typeof vimfx.set, 'function', 'set')
40 assert.equal(typeof vimfx.addCommand, 'function', 'addCommand')
41 assert.equal(typeof vimfx.addOptionOverrides, 'function',
42 'addOptionOverrides')
43 assert.equal(typeof vimfx.addKeyOverrides, 'function', 'addKeyOverrides')
44 assert.equal(typeof vimfx.on, 'function', 'on')
45 assert.equal(vimfx.modes, $vimfx.modes, 'modes')
46 )
47
48 exports['test get'] = (assert, $vimfx, teardown) -> getAPI((vimfx) ->
49 reset = prefs.tmp('hint_chars', 'abcd')
50 teardown(->
51 reset?()
52 callbacks.pop()
53 )
54
55 assert.equal(vimfx.get('hint_chars'), 'abcd')
56 )
57
58 exports['test getDefault'] = (assert, $vimfx, teardown) -> getAPI((vimfx) ->
59 default_hint_chars = $vimfx.options.hint_chars
60 reset = prefs.tmp('hint_chars', 'abcd')
61 teardown(->
62 reset?()
63 callbacks.pop()
64 )
65
66 assert.equal(vimfx.getDefault('hint_chars'), default_hint_chars)
67 )
68
69 exports['test customization'] = (assert, $vimfx, teardown) -> getAPI((vimfx) ->
70 originalOptions = Object.assign({}, $vimfx.options)
71 originalCategories = Object.assign({}, $vimfx.options.categories)
72 $vimfx.options.keyValidator = null
73 $vimfx.options.ignore_keyboard_layout = true
74 vimfx.set('translations', {KeyQ: ['ö', 'Ö']})
75 teardown(->
76 $vimfx.options = originalOptions
77 $vimfx.options.categories = originalCategories
78 delete $vimfx.modes.normal.commands.test_command
79 delete $vimfx.modes.ignore.commands.test_command
80 callbacks.pop()
81 )
82
83 nonce = {}
84 event = {code: 'KeyQ'}
85
86 # Add a simple test command.
87 vimfx.addCommand({
88 name: 'test_command'
89 description: 'Test command'
90 }, -> nonce)
91 vimfx.set('custom.mode.normal.test_command', 'ö')
92
93 # Add a slightly more complex command.
94 vimfx.get('categories')['new_category'] = {
95 name: -> 'New category'
96 order: -100
97 }
98 vimfx.addCommand({
99 name: 'test_command'
100 description: 'Test ignore mode command'
101 mode: 'ignore'
102 category: 'new_category'
103 }, -> nonce)
104 vimfx.set('custom.mode.ignore.test_command', 'ö <ö> <c-c-invalid>')
105
106 $vimfx.createKeyTrees()
107
108 # Test that the new simple command can be run.
109 $vimfx.reset('normal')
110 match = $vimfx.consumeKeyEvent(event, {mode: 'normal'}, null)
111 assert.equal(match.type, 'full')
112 assert.equal(match.command.run(), nonce)
113
114 # Test that the new complex command can be run.
115 $vimfx.reset('ignore')
116 match = $vimfx.consumeKeyEvent(event, {mode: 'ignore'}, null)
117 assert.equal(match.type, 'full')
118 assert.equal(match.command.run(), nonce)
119
120 modes = $vimfx.getGroupedCommands({enabledOnly: true})
121
122 # Test that the new simple command can show up in the help dialog.
123 mode_normal = modes.find((mode) -> mode._name == 'normal')
124 category_misc = mode_normal.categories.find(
125 (category) -> category._name == 'misc'
126 )
127 [..., {command: test_command}] = category_misc.commands
128 assert.equal(test_command.description(), 'Test command')
129
130 # Test that the new complex command can show up in the help dialog.
131 mode_ignore = modes.find((mode) -> mode._name == 'ignore')
132 [category_new] = mode_ignore.categories
133 assert.equal(category_new.name, 'New category')
134 [test_command] = category_new.commands
135 assert.equal(test_command.command.description(), 'Test ignore mode command')
136 assert.deepEqual(test_command.enabledSequences, ['ö'])
137
138 # Remove the added commands.
139 delete vimfx.modes.normal.commands.test_command
140 delete vimfx.modes.ignore.commands.test_command
141 $vimfx.createKeyTrees()
142
143 # Test that the new simple command cannot be run.
144 $vimfx.reset('normal')
145 match = $vimfx.consumeKeyEvent(event, {mode: 'normal'}, null)
146 if match.type == 'full'
147 value = try match.command.run() catch then null
148 assert.notEqual(value, nonce)
149
150 # Test that the new complex command cannot be run.
151 $vimfx.reset('ignore')
152 match = $vimfx.consumeKeyEvent(event, {mode: 'ignore'}, null)
153 if match.type == 'full'
154 value = try match.command.run() catch then null
155 assert.notEqual(value, nonce)
156
157 modes = $vimfx.getGroupedCommands({enabledOnly: true})
158
159 # Test that the new simple command cannot show up in the help dialog.
160 mode_normal = modes.find((mode) -> mode._name == 'normal')
161 category_misc = mode_normal.categories.find(
162 (category) -> category._name == 'misc'
163 )
164 [..., {command: last_command}] = category_misc.commands
165 assert.notEqual(last_command.description(), 'Test command')
166
167 # Test that the new complex command cannot show up in the help dialog.
168 mode_ignore = modes.find((mode) -> mode._name == 'ignore')
169 [first_category] = mode_ignore.categories
170 assert.notEqual(first_category.name, 'New category')
171 )
172
173 exports['test addCommand order'] = \
174 (assert, $vimfx, teardown) -> getAPI((vimfx) ->
175 teardown(->
176 delete vimfx.modes.normal.commands.test_command
177 callbacks.pop()
178 )
179
180 vimfx.addCommand({
181 name: 'test_command'
182 description: 'Test command'
183 order: 0
184 }, Function.prototype)
185 vimfx.set('custom.mode.normal.test_command', 'ö')
186
187 modes = $vimfx.getGroupedCommands()
188 mode_normal = modes.find((mode) -> mode._name == 'normal')
189 category_misc = mode_normal.categories.find(
190 (category) -> category._name == 'misc'
191 )
192 [{command: first_command}] = category_misc.commands
193 assert.equal(first_command.description(), 'Test command')
194 )
195
196 exports['test addOptionOverrides'] = \
197 (assert, $vimfx, teardown) -> getAPI((vimfx) ->
198 originalOptions = Object.assign({}, $vimfx.options)
199 originalOptionOverrides = Object.assign({}, $vimfx.optionOverrides)
200 $vimfx.optionOverrides = null
201 $vimfx.options.prevent_autofocus = true
202 teardown(->
203 reset?() # Defined below.
204 $vimfx.options = originalOptions
205 $vimfx.optionOverrides = originalOptionOverrides
206 callbacks.pop()
207 )
208
209 vimfx.addOptionOverrides(
210 [
211 (location) -> location.hostname == 'example.com'
212 {prevent_autofocus: false}
213 ]
214 )
215
216 assert.equal($vimfx.options.prevent_autofocus, true)
217
218 reset = testUtils.stub(utils, 'getCurrentLocation', -> {
219 hostname: 'example.com'
220 })
221
222 assert.equal($vimfx.options.prevent_autofocus, false)
223 )
224
225 exports['test addKeyOverrides'] = \
226 (assert, $vimfx, teardown) -> getAPI((vimfx) ->
227 originalOptions = Object.assign({}, $vimfx.options)
228 originalKeyOverrides = Object.assign({}, $vimfx.keyOverrides)
229 $vimfx.options.keyValidator = null
230 $vimfx.options.ignore_keyboard_layout = false
231 $vimfx.options.translations = {}
232 teardown(->
233 resetScrollToBottom?() # Defined below.
234 resetGetCurrentLocation?() # Defined below.
235 $vimfx.options = originalOptions
236 $vimfx.keyOverrides = originalKeyOverrides
237 callbacks.pop()
238 )
239
240 vimfx.addKeyOverrides(
241 [
242 (location, mode) -> mode == 'normal' and location.hostname == 'example.co'
243 ['j', '<c-foobar>']
244 ],
245 [
246 (location, mode) -> mode == 'ignore' and location.href == 'about:blank'
247 ['<escape>']
248 ]
249 )
250
251 resetScrollToBottom = prefs.tmp('mode.normal.scroll_to_bottom', '<foobar>j')
252 $vimfx.createKeyTrees()
253 $vimfx.reset('normal')
254
255 match = $vimfx.consumeKeyEvent({key: 'j'}, {mode: 'ignore'}, null)
256 assert.ok(match)
257
258 resetGetCurrentLocation = testUtils.stub(utils, 'getCurrentLocation', -> {
259 hostname: 'example.co'
260 href: 'about:blank'
261 })
262
263 match = $vimfx.consumeKeyEvent({key: '1'}, {mode: 'normal'}, null)
264 assert.equal(match.type, 'count')
265 assert.equal(match.count, 1)
266
267 match = $vimfx.consumeKeyEvent({key: 'j'}, {mode: 'normal'}, null)
268 assert.ok(not match)
269
270 match = $vimfx.consumeKeyEvent({key: 'foobar', ctrlKey: true},
271 {mode: 'normal'}, null)
272 assert.ok(not match)
273
274 match = $vimfx.consumeKeyEvent({key: 'foobar'}, {mode: 'normal'}, null)
275 assert.equal(match.type, 'partial')
276 match = $vimfx.consumeKeyEvent({key: 'j'}, {mode: 'normal'}, null)
277 assert.equal(match.type, 'full')
278 assert.strictEqual(match.count, undefined)
279
280 $vimfx.reset('ignore')
281
282 match = $vimfx.consumeKeyEvent({key: 'j'}, {mode: 'ignore'}, null)
283 assert.ok(match)
284
285 match = $vimfx.consumeKeyEvent({key: 'escape'}, {mode: 'ignore'}, null)
286 assert.ok(not match)
287 )
288
289 exports['test vimfx.[gs]et(Default)? errors'] = \
290 (assert, $vimfx, teardown) -> getAPI((vimfx) ->
291 teardown(-> callbacks.pop())
292
293 throws(assert, /unknown pref/i, 'undefined', ->
294 vimfx.get()
295 )
296
297 throws(assert, /unknown pref/i, 'undefined', ->
298 vimfx.getDefault()
299 )
300
301 throws(assert, /unknown pref/i, 'undefined', ->
302 vimfx.set()
303 )
304
305 throws(assert, /unknown pref/i, 'unknown_pref', ->
306 vimfx.get('unknown_pref')
307 )
308
309 throws(assert, /unknown pref/i, 'unknown_pref', ->
310 vimfx.getDefault('unknown_pref')
311 )
312
313 throws(assert, /no default/i, 'custom.mode.normal.foo', ->
314 vimfx.getDefault('custom.mode.normal.foo')
315 )
316
317 throws(assert, /no default/i, 'translations', ->
318 vimfx.getDefault('translations')
319 )
320
321 throws(assert, /unknown pref/i, 'unknown_pref', ->
322 vimfx.set('unknown_pref', 'foo')
323 )
324
325 throws(assert, /boolean, number, string or null/i, 'undefined', ->
326 vimfx.set('hint_chars')
327 )
328
329 throws(assert, /boolean, number, string or null/i, 'object', ->
330 vimfx.set('hint_chars', ['a', 'b', 'c'])
331 )
332 )
333
334 exports['test vimfx.addCommand errors'] = \
335 (assert, $vimfx, teardown) -> getAPI((vimfx) ->
336 teardown(-> callbacks.pop())
337
338 throws(assert, /name.+string.+required/i, 'undefined', ->
339 vimfx.addCommand()
340 )
341
342 throws(assert, /name.+a-z.+underscore/i, 'Command', ->
343 vimfx.addCommand({name: 'Command'})
344 )
345
346 throws(assert, /name.+a-z.+underscore/i, 'command-name', ->
347 vimfx.addCommand({name: 'command-name'})
348 )
349
350 throws(assert, /name.+a-z.+underscore/i, 'ö', ->
351 vimfx.addCommand({name: 'ö'})
352 )
353
354 throws(assert, /non-empty description/i, 'undefined', ->
355 vimfx.addCommand({name: 'test'})
356 )
357
358 throws(assert, /non-empty description/i, '', ->
359 vimfx.addCommand({name: 'test', description: ''})
360 )
361
362 throws(assert, /unknown mode.+available.+normal/i, 'toString', ->
363 vimfx.addCommand({name: 'test', description: 'Test', mode: 'toString'})
364 )
365
366 throws(assert, /unknown category.+available.+location/i, 'toString', ->
367 vimfx.addCommand({name: 'test', description: 'Test', category: 'toString'})
368 )
369
370 throws(assert, /order.+number/i, 'false', ->
371 vimfx.addCommand({name: 'test', description: 'Test', order: false})
372 )
373
374 throws(assert, /function/i, 'undefined', ->
375 vimfx.addCommand({name: 'test', description: 'Test'})
376 )
377
378 throws(assert, /function/i, 'false', ->
379 vimfx.addCommand({name: 'test_command', description: 'Test command'}, false)
380 )
381 )
382
383 throws = (assert, regex, badValue, fn) ->
384 assert.throws(fn)
385 try fn() catch error
386 assert.ok(error.message.startsWith('VimFx:'), 'start with VimFx')
387 assert.ok(error.message.endsWith(": #{badValue}"), 'show bad value')
388 assert.ok(regex.test(error.message), 'regex match')
Imprint / Impressum