2 # Copyright Simon Lydell 2015.
4 # This file is part of VimFx.
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.
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.
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/>.
20 testUtils = require('./utils')
21 prefs = require('../lib/prefs')
22 utils = require('../lib/utils')
24 {utils: Cu} = Components
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, {})
31 # In the tests, `vimfx` refers to the API object, while `$vimfx` refers to the
32 # passed in `VimFx` instance.
34 exports['test exports'] = (assert, $vimfx, teardown) -> getAPI((vimfx) ->
35 teardown(-> callbacks.pop())
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',
43 assert.equal(typeof vimfx.addKeyOverrides, 'function', 'addKeyOverrides')
44 assert.equal(typeof vimfx.on, 'function', 'on')
45 assert.equal(vimfx.modes, $vimfx.modes, 'modes')
48 exports['test get'] = (assert, $vimfx, teardown) -> getAPI((vimfx) ->
49 reset = prefs.tmp('hint_chars', 'abcd')
55 assert.equal(vimfx.get('hint_chars'), 'abcd')
58 exports['test getDefault'] = (assert, $vimfx, teardown) -> getAPI((vimfx) ->
59 default_hint_chars = $vimfx.options.hint_chars
60 reset = prefs.tmp('hint_chars', 'abcd')
66 assert.equal(vimfx.getDefault('hint_chars'), default_hint_chars)
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: ['ö', 'Ö']})
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
84 event = {code: 'KeyQ'}
86 # Add a simple test command.
89 description: 'Test command'
91 vimfx.set('custom.mode.normal.test_command', 'ö')
93 # Add a slightly more complex command.
94 vimfx.get('categories')['new_category'] = {
95 name: -> 'New category'
100 description: 'Test ignore mode command'
102 category: 'new_category'
104 vimfx.set('custom.mode.ignore.test_command', 'ö <ö> <c-c-invalid>')
106 $vimfx.createKeyTrees()
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)
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)
120 modes = $vimfx.getGroupedCommands({enabledOnly: true})
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'
127 [..., {command: test_command}] = category_misc.commands
128 assert.equal(test_command.description(), 'Test command')
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, ['ö'])
138 # Remove the added commands.
139 delete vimfx.modes.normal.commands.test_command
140 delete vimfx.modes.ignore.commands.test_command
141 $vimfx.createKeyTrees()
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)
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)
157 modes = $vimfx.getGroupedCommands({enabledOnly: true})
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'
164 [..., {command: last_command}] = category_misc.commands
165 assert.notEqual(last_command.description(), 'Test command')
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')
173 exports['test addCommand order'] = \
174 (assert, $vimfx, teardown) -> getAPI((vimfx) ->
176 delete vimfx.modes.normal.commands.test_command
182 description: 'Test command'
184 }, Function.prototype)
185 vimfx.set('custom.mode.normal.test_command', 'ö')
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'
192 [{command: first_command}] = category_misc.commands
193 assert.equal(first_command.description(), 'Test command')
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
203 reset?() # Defined below.
204 $vimfx.options = originalOptions
205 $vimfx.optionOverrides = originalOptionOverrides
209 vimfx.addOptionOverrides(
211 (location) -> location.hostname == 'example.com'
212 {prevent_autofocus: false}
216 assert.equal($vimfx.options.prevent_autofocus, true)
218 reset = testUtils.stub(utils, 'getCurrentLocation', -> {
219 hostname: 'example.com'
222 assert.equal($vimfx.options.prevent_autofocus, false)
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 = {}
233 resetScrollToBottom?() # Defined below.
234 resetGetCurrentLocation?() # Defined below.
235 $vimfx.options = originalOptions
236 $vimfx.keyOverrides = originalKeyOverrides
240 vimfx.addKeyOverrides(
242 (location, mode) -> mode == 'normal' and location.hostname == 'example.co'
246 (location, mode) -> mode == 'ignore' and location.href == 'about:blank'
251 resetScrollToBottom = prefs.tmp('mode.normal.scroll_to_bottom', '<foobar>j')
252 $vimfx.createKeyTrees()
253 $vimfx.reset('normal')
255 match = $vimfx.consumeKeyEvent({key: 'j'}, {mode: 'ignore'}, null)
258 resetGetCurrentLocation = testUtils.stub(utils, 'getCurrentLocation', -> {
259 hostname: 'example.co'
263 match = $vimfx.consumeKeyEvent({key: '1'}, {mode: 'normal'}, null)
264 assert.equal(match.type, 'count')
265 assert.equal(match.count, 1)
267 match = $vimfx.consumeKeyEvent({key: 'j'}, {mode: 'normal'}, null)
270 match = $vimfx.consumeKeyEvent({key: 'foobar', ctrlKey: true},
271 {mode: 'normal'}, null)
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)
280 $vimfx.reset('ignore')
282 match = $vimfx.consumeKeyEvent({key: 'j'}, {mode: 'ignore'}, null)
285 match = $vimfx.consumeKeyEvent({key: 'escape'}, {mode: 'ignore'}, null)
289 exports['test vimfx.[gs]et(Default)? errors'] = \
290 (assert, $vimfx, teardown) -> getAPI((vimfx) ->
291 teardown(-> callbacks.pop())
293 throws(assert, /unknown pref/i, 'undefined', ->
297 throws(assert, /unknown pref/i, 'undefined', ->
301 throws(assert, /unknown pref/i, 'undefined', ->
305 throws(assert, /unknown pref/i, 'unknown_pref', ->
306 vimfx.get('unknown_pref')
309 throws(assert, /unknown pref/i, 'unknown_pref', ->
310 vimfx.getDefault('unknown_pref')
313 throws(assert, /no default/i, 'custom.mode.normal.foo', ->
314 vimfx.getDefault('custom.mode.normal.foo')
317 throws(assert, /no default/i, 'translations', ->
318 vimfx.getDefault('translations')
321 throws(assert, /unknown pref/i, 'unknown_pref', ->
322 vimfx.set('unknown_pref', 'foo')
325 throws(assert, /boolean, number, string or null/i, 'undefined', ->
326 vimfx.set('hint_chars')
329 throws(assert, /boolean, number, string or null/i, 'object', ->
330 vimfx.set('hint_chars', ['a', 'b', 'c'])
334 exports['test vimfx.addCommand errors'] = \
335 (assert, $vimfx, teardown) -> getAPI((vimfx) ->
336 teardown(-> callbacks.pop())
338 throws(assert, /name.+string.+required/i, 'undefined', ->
342 throws(assert, /name.+a-z.+underscore/i, 'Command', ->
343 vimfx.addCommand({name: 'Command'})
346 throws(assert, /name.+a-z.+underscore/i, 'command-name', ->
347 vimfx.addCommand({name: 'command-name'})
350 throws(assert, /name.+a-z.+underscore/i, 'ö', ->
351 vimfx.addCommand({name: 'ö'})
354 throws(assert, /non-empty description/i, 'undefined', ->
355 vimfx.addCommand({name: 'test'})
358 throws(assert, /non-empty description/i, '', ->
359 vimfx.addCommand({name: 'test', description: ''})
362 throws(assert, /unknown mode.+available.+normal/i, 'toString', ->
363 vimfx.addCommand({name: 'test', description: 'Test', mode: 'toString'})
366 throws(assert, /unknown category.+available.+location/i, 'toString', ->
367 vimfx.addCommand({name: 'test', description: 'Test', category: 'toString'})
370 throws(assert, /order.+number/i, 'false', ->
371 vimfx.addCommand({name: 'test', description: 'Test', order: false})
374 throws(assert, /function/i, 'undefined', ->
375 vimfx.addCommand({name: 'test', description: 'Test'})
378 throws(assert, /function/i, 'false', ->
379 vimfx.addCommand({name: 'test_command', description: 'Test command'}, false)
383 throws = (assert, regex, badValue, fn) ->
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')