nextcloud-server/core/js/tests/specs/coreSpec.js

1148 lines
34 KiB
JavaScript

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2014 ownCloud Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
describe('Core base tests', function() {
let debounceStub
beforeEach(function() {
debounceStub = sinon.stub(_, 'debounce').callsFake(function(callback) {
return function() {
// defer instead of debounce, to make it work with clock
_.defer(callback)
}
})
})
afterEach(function() {
// many tests call window.initCore so need to unregister global events
// ideally in the future we'll need a window.unloadCore() function
$(document).off('ajaxError.main')
$(document).off('unload.main')
$(document).off('beforeunload.main')
OC._userIsNavigatingAway = false
OC._reloadCalled = false
debounceStub.restore()
})
describe('Base values', function() {
it('Sets webroots', function() {
expect(OC.getRootPath()).toBeDefined()
expect(window._oc_appswebroots).toBeDefined()
})
})
describe('filePath', function() {
beforeEach(function() {
window._oc_webroot = 'http://localhost'
window._oc_appswebroots.files = OC.getRootPath() + '/apps3/files'
})
afterEach(function() {
delete window._oc_appswebroots.files
})
it('Uses a direct link for css and images,', function() {
expect(OC.filePath('core', 'css', 'style.css')).toEqual('http://localhost/core/css/style.css')
expect(OC.filePath('files', 'css', 'style.css')).toEqual('http://localhost/apps3/files/css/style.css')
expect(OC.filePath('core', 'img', 'image.png')).toEqual('http://localhost/core/img/image.png')
expect(OC.filePath('files', 'img', 'image.png')).toEqual('http://localhost/apps3/files/img/image.png')
})
it('Routes PHP files via index.php,', function() {
expect(OC.filePath('core', 'ajax', 'test.php')).toEqual('http://localhost/index.php/core/ajax/test.php')
expect(OC.filePath('files', 'ajax', 'test.php')).toEqual('http://localhost/index.php/apps/files/ajax/test.php')
})
})
describe('Link functions', function() {
const TESTAPP = 'testapp'
const TESTAPP_ROOT = OC.getRootPath() + '/appsx/testapp'
beforeEach(function() {
window._oc_appswebroots[TESTAPP] = TESTAPP_ROOT
})
afterEach(function() {
// restore original array
delete window._oc_appswebroots[TESTAPP]
})
it('Generates correct links for core apps', function() {
expect(OC.linkTo('core', 'somefile.php')).toEqual(OC.getRootPath() + '/core/somefile.php')
expect(OC.linkTo('admin', 'somefile.php')).toEqual(OC.getRootPath() + '/admin/somefile.php')
})
it('Generates correct links for regular apps', function() {
expect(OC.linkTo(TESTAPP, 'somefile.php')).toEqual(OC.getRootPath() + '/index.php/apps/' + TESTAPP + '/somefile.php')
})
it('Generates correct remote links', function() {
expect(OC.linkToRemote('webdav')).toEqual(window.location.protocol + '//' + window.location.host + OC.getRootPath() + '/remote.php/webdav')
})
describe('Images', function() {
it('Generates image path with given extension', function() {
expect(OC.imagePath('core', 'somefile.jpg')).toEqual(OC.getRootPath() + '/core/img/somefile.jpg')
expect(OC.imagePath(TESTAPP, 'somefile.jpg')).toEqual(TESTAPP_ROOT + '/img/somefile.jpg')
})
it('Generates image path with svg extension', function() {
expect(OC.imagePath('core', 'somefile')).toEqual(OC.getRootPath() + '/core/img/somefile.svg')
expect(OC.imagePath(TESTAPP, 'somefile')).toEqual(TESTAPP_ROOT + '/img/somefile.svg')
})
})
})
describe('Query string building', function() {
it('Returns empty string when empty params', function() {
expect(OC.buildQueryString()).toEqual('')
expect(OC.buildQueryString({})).toEqual('')
})
it('Encodes regular query strings', function() {
expect(OC.buildQueryString({
a: 'abc',
b: 'def',
})).toEqual('a=abc&b=def')
})
it('Encodes special characters', function() {
expect(OC.buildQueryString({
unicode: '汉字',
})).toEqual('unicode=%E6%B1%89%E5%AD%97')
expect(OC.buildQueryString({
b: 'spaace value',
'space key': 'normalvalue',
'slash/this': 'amp&ersand',
})).toEqual('b=spaace%20value&space%20key=normalvalue&slash%2Fthis=amp%26ersand')
})
it('Encodes data types and empty values', function() {
expect(OC.buildQueryString({
keywithemptystring: '',
keywithnull: null,
keywithundefined: null,
something: 'else',
})).toEqual('keywithemptystring=&keywithnull&keywithundefined&something=else')
expect(OC.buildQueryString({
booleanfalse: false,
booleantrue: true,
})).toEqual('booleanfalse=false&booleantrue=true')
expect(OC.buildQueryString({
number: 123,
})).toEqual('number=123')
})
})
describe('Parse query string', function() {
it('Parses query string from full URL', function() {
const query = OC.parseQueryString('http://localhost/stuff.php?q=a&b=x')
expect(query).toEqual({ q: 'a', b: 'x' })
})
it('Parses query string from query part alone', function() {
const query = OC.parseQueryString('q=a&b=x')
expect(query).toEqual({ q: 'a', b: 'x' })
})
it('Returns null hash when empty query', function() {
const query = OC.parseQueryString('')
expect(query).toEqual(null)
})
it('Returns empty hash when empty query with question mark', function() {
const query = OC.parseQueryString('?')
expect(query).toEqual({})
})
it('Decodes regular query strings', function() {
const query = OC.parseQueryString('a=abc&b=def')
expect(query).toEqual({
a: 'abc',
b: 'def',
})
})
it('Ignores empty parts', function() {
const query = OC.parseQueryString('&q=a&&b=x&')
expect(query).toEqual({ q: 'a', b: 'x' })
})
it('Ignores lone equal signs', function() {
const query = OC.parseQueryString('&q=a&=&b=x&')
expect(query).toEqual({ q: 'a', b: 'x' })
})
it('Includes extra equal signs in value', function() {
const query = OC.parseQueryString('u=a=x&q=a=b')
expect(query).toEqual({ u: 'a=x', q: 'a=b' })
})
it('Decodes plus as space', function() {
const query = OC.parseQueryString('space+key=space+value')
expect(query).toEqual({ 'space key': 'space value' })
})
it('Decodes special characters', function() {
let query = OC.parseQueryString('unicode=%E6%B1%89%E5%AD%97')
expect(query).toEqual({ unicode: '汉字' })
query = OC.parseQueryString('b=spaace%20value&space%20key=normalvalue&slash%2Fthis=amp%26ersand')
expect(query).toEqual({
b: 'spaace value',
'space key': 'normalvalue',
'slash/this': 'amp&ersand',
})
})
it('Decodes empty values', function() {
const query = OC.parseQueryString('keywithemptystring=&keywithnostring')
expect(query).toEqual({
keywithemptystring: '',
keywithnostring: null,
})
})
it('Does not interpret data types', function() {
const query = OC.parseQueryString('booleanfalse=false&booleantrue=true&number=123')
expect(query).toEqual({
booleanfalse: 'false',
booleantrue: 'true',
number: '123',
})
})
})
describe('Generate Url', function() {
it('returns absolute urls', function() {
expect(OC.generateUrl('csrftoken')).toEqual(OC.getRootPath() + '/index.php/csrftoken')
expect(OC.generateUrl('/csrftoken')).toEqual(OC.getRootPath() + '/index.php/csrftoken')
})
it('substitutes parameters which are escaped by default', function() {
expect(OC.generateUrl('apps/files/download/{file}', { file: '<">ImAnUnescapedString/!' })).toEqual(OC.getRootPath() + '/index.php/apps/files/download/%3C%22%3EImAnUnescapedString%2F!')
})
it('substitutes parameters which can also be unescaped via option flag', function() {
expect(OC.generateUrl('apps/files/download/{file}', { file: 'subfolder/Welcome.txt' }, { escape: false })).toEqual(OC.getRootPath() + '/index.php/apps/files/download/subfolder/Welcome.txt')
})
it('substitutes multiple parameters which are escaped by default', function() {
expect(OC.generateUrl('apps/files/download/{file}/{id}', { file: '<">ImAnUnescapedString/!', id: 5 })).toEqual(OC.getRootPath() + '/index.php/apps/files/download/%3C%22%3EImAnUnescapedString%2F!/5')
})
it('substitutes multiple parameters which can also be unescaped via option flag', function() {
expect(OC.generateUrl('apps/files/download/{file}/{id}', { file: 'subfolder/Welcome.txt', id: 5 }, { escape: false })).toEqual(OC.getRootPath() + '/index.php/apps/files/download/subfolder/Welcome.txt/5')
})
it('doesnt error out with no params provided', function() {
expect(OC.generateUrl('apps/files/download{file}')).toEqual(OC.getRootPath() + '/index.php/apps/files/download%7Bfile%7D')
})
})
describe('Util', function() {
describe('computerFileSize', function() {
it('correctly parses file sizes from a human readable formated string', function() {
const data = [
['125', 125],
['125.25', 125],
['125.25B', 125],
['125.25 B', 125],
['0 B', 0],
['99999999999999999999999999999999999999999999 B', 99999999999999999999999999999999999999999999],
['0 MB', 0],
['0 kB', 0],
['0kB', 0],
['125 B', 125],
['125b', 125],
['125 KB', 128000],
['125kb', 128000],
['122.1 MB', 128031130],
['122.1mb', 128031130],
['119.2 GB', 127990025421],
['119.2gb', 127990025421],
['116.4 TB', 127983153473126],
['116.4tb', 127983153473126],
['8776656778888777655.4tb', 9.650036181387265e+30],
[1234, null],
[-1234, null],
['-1234 B', null],
['B', null],
['40/0', null],
['40,30 kb', null],
[' 122.1 MB ', 128031130],
['122.1 MB ', 128031130],
[' 122.1 MB ', 128031130],
[' 122.1 MB ', 128031130],
['122.1 MB ', 128031130],
[' 125', 125],
[' 125 ', 125],
]
for (let i = 0; i < data.length; i++) {
expect(OC.Util.computerFileSize(data[i][0])).toEqual(data[i][1])
}
})
it('returns null if the parameter is not a string', function() {
expect(OC.Util.computerFileSize(NaN)).toEqual(null)
expect(OC.Util.computerFileSize(125)).toEqual(null)
})
it('returns null if the string is unparsable', function() {
expect(OC.Util.computerFileSize('')).toEqual(null)
expect(OC.Util.computerFileSize('foobar')).toEqual(null)
})
})
describe('stripTime', function() {
it('strips time from dates', function() {
expect(OC.Util.stripTime(new Date(2014, 2, 24, 15, 4, 45, 24)))
.toEqual(new Date(2014, 2, 24, 0, 0, 0, 0))
})
})
})
describe('naturalSortCompare', function() {
// cit() will skip tests if running on PhantomJS because it has issues with
// localeCompare(). See https://github.com/ariya/phantomjs/issues/11063
//
// Please make sure to run these tests in Chrome/Firefox manually
// to make sure they run.
const cit = window.isPhantom ? xit : it
// must provide the same results as \OCP\Util::naturalSortCompare
it('sorts alphabetically', function() {
const a = [
'def',
'xyz',
'abc',
]
a.sort(OC.Util.naturalSortCompare)
expect(a).toEqual([
'abc',
'def',
'xyz',
])
})
cit('sorts with different casing', function() {
const a = [
'aaa',
'bbb',
'BBB',
'AAA',
]
a.sort(OC.Util.naturalSortCompare)
expect(a).toEqual([
'aaa',
'AAA',
'bbb',
'BBB',
])
})
it('sorts with numbers', function() {
const a = [
'124.txt',
'abc1',
'123.txt',
'abc',
'abc2',
'def (2).txt',
'ghi 10.txt',
'abc12',
'def.txt',
'def (1).txt',
'ghi 2.txt',
'def (10).txt',
'abc10',
'def (12).txt',
'z',
'ghi.txt',
'za',
'ghi 1.txt',
'ghi 12.txt',
'zz',
'15.txt',
'15b.txt',
]
a.sort(OC.Util.naturalSortCompare)
expect(a).toEqual([
'15.txt',
'15b.txt',
'123.txt',
'124.txt',
'abc',
'abc1',
'abc2',
'abc10',
'abc12',
'def.txt',
'def (1).txt',
'def (2).txt',
'def (10).txt',
'def (12).txt',
'ghi.txt',
'ghi 1.txt',
'ghi 2.txt',
'ghi 10.txt',
'ghi 12.txt',
'z',
'za',
'zz',
])
})
it('sorts with chinese characters', function() {
const a = [
'十.txt',
'一.txt',
'二.txt',
'十 2.txt',
'三.txt',
'四.txt',
'abc.txt',
'五.txt',
'七.txt',
'八.txt',
'九.txt',
'六.txt',
'十一.txt',
'波.txt',
'破.txt',
'莫.txt',
'啊.txt',
'123.txt',
]
a.sort(OC.Util.naturalSortCompare)
expect(a).toEqual([
'123.txt',
'abc.txt',
'一.txt',
'七.txt',
'三.txt',
'九.txt',
'二.txt',
'五.txt',
'八.txt',
'六.txt',
'十.txt',
'十 2.txt',
'十一.txt',
'啊.txt',
'四.txt',
'波.txt',
'破.txt',
'莫.txt',
])
})
cit('sorts with umlauts', function() {
const a = [
'öh.txt',
'Äh.txt',
'oh.txt',
'Üh 2.txt',
'Üh.txt',
'ah.txt',
'Öh.txt',
'uh.txt',
'üh.txt',
'äh.txt',
]
a.sort(OC.Util.naturalSortCompare)
expect(a).toEqual([
'ah.txt',
'äh.txt',
'Äh.txt',
'oh.txt',
'öh.txt',
'Öh.txt',
'uh.txt',
'üh.txt',
'Üh.txt',
'Üh 2.txt',
])
})
})
describe('Plugins', function() {
let plugin
beforeEach(function() {
plugin = {
name: 'Some name',
attach: function(obj) {
obj.attached = true
},
detach: function(obj) {
obj.attached = false
},
}
OC.Plugins.register('OC.Test.SomeName', plugin)
})
it('attach plugin to object', function() {
const obj = { something: true }
OC.Plugins.attach('OC.Test.SomeName', obj)
expect(obj.attached).toEqual(true)
OC.Plugins.detach('OC.Test.SomeName', obj)
expect(obj.attached).toEqual(false)
})
it('only call handler for target name', function() {
const obj = { something: true }
OC.Plugins.attach('OC.Test.SomeOtherName', obj)
expect(obj.attached).not.toBeDefined()
OC.Plugins.detach('OC.Test.SomeOtherName', obj)
expect(obj.attached).not.toBeDefined()
})
})
describe('Notifications', function() {
let showHtmlSpy
let clock
/**
* Returns the HTML or plain text of the given notification row.
*
* This is needed to ignore the close button that is added to the
* notification row after the text.
*/
const getNotificationText = function($node) {
return $node.contents()[0].outerHTML
|| $node.contents()[0].nodeValue
}
beforeEach(function() {
clock = sinon.useFakeTimers()
})
afterEach(function() {
// jump past animations
clock.tick(10000)
clock.restore()
$('body .toastify').remove()
})
describe('showTemporary', function() {
it('shows a plain text notification with default timeout', function() {
OC.Notification.showTemporary('My notification test')
const $row = $('body .toastify')
expect($row.length).toEqual(1)
expect(getNotificationText($row)).toEqual('My notification test')
})
it('shows a HTML notification with default timeout', function() {
OC.Notification.showTemporary('<a>My notification test</a>', { isHTML: true })
const $row = $('body .toastify')
expect($row.length).toEqual(1)
expect(getNotificationText($row)).toEqual('<a>My notification test</a>')
})
it('hides itself after 7 seconds', function() {
OC.Notification.showTemporary('')
let $row = $('body .toastify')
expect($row.length).toEqual(1)
// travel in time +7000 milliseconds
clock.tick(7500)
$row = $('body .toastify')
expect($row.length).toEqual(0)
})
it('hides itself after a given time', function() {
OC.Notification.showTemporary('', { timeout: 10000 })
let $row = $('body .toastify')
expect($row.length).toEqual(1)
// travel in time +7000 milliseconds
clock.tick(7500)
$row = $('body .toastify')
expect($row.length).toEqual(1)
// travel in time another 4000 milliseconds
clock.tick(4000)
$row = $('body .toastify')
expect($row.length).toEqual(0)
})
})
describe('show', function() {
it('hides itself after a given time', function() {
OC.Notification.show('', { timeout: 10000 })
let $row = $('body .toastify')
expect($row.length).toEqual(1)
clock.tick(11500)
$row = $('body .toastify')
expect($row.length).toEqual(0)
})
it('does not hide itself if no timeout given to show', function() {
OC.Notification.show('')
let $row = $('body .toastify')
expect($row.length).toEqual(1)
// travel in time +1000 seconds
clock.tick(1000000)
$row = $('body .toastify')
expect($row.length).toEqual(1)
})
})
describe('showHtml', function() {
it('hides itself after a given time', function() {
OC.Notification.showHtml('<p></p>', { timeout: 10000 })
let $row = $('body .toastify')
expect($row.length).toEqual(1)
clock.tick(11500)
$row = $('body .toastify')
expect($row.length).toEqual(0)
})
it('does not hide itself if no timeout given to show', function() {
OC.Notification.showHtml('<p></p>')
let $row = $('body .toastify')
expect($row.length).toEqual(1)
// travel in time +1000 seconds
clock.tick(1000000)
$row = $('body .toastify')
expect($row.length).toEqual(1)
})
})
describe('hide', function() {
it('hides a temporary notification before its timeout expires', function() {
const hideCallback = sinon.spy()
const notification = OC.Notification.showTemporary('')
let $row = $('body .toastify')
expect($row.length).toEqual(1)
OC.Notification.hide(notification, hideCallback)
// Give time to the hide animation to finish
clock.tick(1000)
$row = $('body .toastify')
expect($row.length).toEqual(0)
expect(hideCallback.calledOnce).toEqual(true)
})
it('hides a notification before its timeout expires', function() {
const hideCallback = sinon.spy()
const notification = OC.Notification.show('', { timeout: 10000 })
let $row = $('body .toastify')
expect($row.length).toEqual(1)
OC.Notification.hide(notification, hideCallback)
// Give time to the hide animation to finish
clock.tick(1000)
$row = $('body .toastify')
expect($row.length).toEqual(0)
expect(hideCallback.calledOnce).toEqual(true)
})
it('hides a notification without timeout', function() {
const hideCallback = sinon.spy()
const notification = OC.Notification.show('')
let $row = $('body .toastify')
expect($row.length).toEqual(1)
OC.Notification.hide(notification, hideCallback)
// Give time to the hide animation to finish
clock.tick(1000)
$row = $('body .toastify')
expect($row.length).toEqual(0)
expect(hideCallback.calledOnce).toEqual(true)
})
})
it('cumulates several notifications', function() {
const $row1 = OC.Notification.showTemporary('One')
const $row2 = OC.Notification.showTemporary('Two', { timeout: 2000 })
const $row3 = OC.Notification.showTemporary('Three')
const $el = $('body')
let $rows = $el.find('.toastify')
expect($rows.length).toEqual(3)
expect($rows.eq(0).is($row3)).toEqual(true)
expect($rows.eq(1).is($row2)).toEqual(true)
expect($rows.eq(2).is($row1)).toEqual(true)
clock.tick(3000)
$rows = $el.find('.toastify')
expect($rows.length).toEqual(2)
expect($rows.eq(0).is($row3)).toEqual(true)
expect($rows.eq(1).is($row1)).toEqual(true)
})
it('hides the given notification when calling hide with argument', function() {
const $row1 = OC.Notification.show('One')
const $row2 = OC.Notification.show('Two')
const $el = $('body')
let $rows = $el.find('.toastify')
expect($rows.length).toEqual(2)
OC.Notification.hide($row2)
clock.tick(3000)
$rows = $el.find('.toastify')
expect($rows.length).toEqual(1)
expect($rows.eq(0).is($row1)).toEqual(true)
})
})
describe('global ajax errors', function() {
let reloadStub, ajaxErrorStub, clock
let notificationStub
const waitTimeMs = 6500
let oldCurrentUser
beforeEach(function() {
oldCurrentUser = OC.currentUser
OC.currentUser = 'dummy'
clock = sinon.useFakeTimers()
reloadStub = sinon.stub(OC, 'reload')
document.head.dataset.user = 'dummy'
notificationStub = sinon.stub(OC.Notification, 'show')
// unstub the error processing method
ajaxErrorStub = OC._processAjaxError
ajaxErrorStub.restore()
window.initCore()
})
afterEach(function() {
OC.currentUser = oldCurrentUser
reloadStub.restore()
notificationStub.restore()
clock.restore()
})
it('does not reload the page if the user was navigating away', function() {
const xhr = { status: 0 }
OC._userIsNavigatingAway = true
clock.tick(100)
$(document).trigger(new $.Event('ajaxError'), xhr)
clock.tick(waitTimeMs)
expect(reloadStub.notCalled).toEqual(true)
})
it('shows a temporary notification if the connection is lost', function() {
const xhr = { status: 0 }
spyOn(OC, '_ajaxConnectionLostHandler')
$(document).trigger(new $.Event('ajaxError'), xhr)
clock.tick(101)
expect(OC._ajaxConnectionLostHandler.calls.count()).toBe(1)
})
})
describe('Snapper', function() {
let snapConstructorStub
let snapperStub
let clock
beforeEach(function() {
snapConstructorStub = sinon.stub(window, 'Snap')
snapperStub = {}
snapperStub.enable = sinon.stub()
snapperStub.disable = sinon.stub()
snapperStub.close = sinon.stub()
snapperStub.on = sinon.stub()
snapperStub.state = sinon.stub().returns({
state: sinon.stub(),
})
snapConstructorStub.returns(snapperStub)
clock = sinon.useFakeTimers()
// _.now could have been set to Date.now before Sinon replaced it
// with a fake version, so _.now must be stubbed to ensure that the
// fake Date.now will be called instead of the original one.
_.now = sinon.stub(_, 'now').callsFake(function() {
return new Date().getTime()
})
$('#testArea').append('<div id="app-navigation">The navigation bar</div><div id="app-content">Content</div>')
})
afterEach(function() {
snapConstructorStub.restore()
clock.restore()
_.now.restore()
// Remove the event handler for the resize event added to the window
// due to calling window.initCore() when there is an #app-navigation
// element.
$(window).off('resize')
viewport.reset()
})
it('is enabled on a narrow screen', function() {
viewport.set(480)
window.initCore()
expect(snapConstructorStub.calledOnce).toBe(true)
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.called).toBe(false)
})
it('is disabled when disallowing the gesture on a narrow screen', function() {
viewport.set(480)
window.initCore()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.called).toBe(false)
expect(snapperStub.close.called).toBe(false)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.disable.alwaysCalledWithExactly(true)).toBe(true)
expect(snapperStub.close.called).toBe(false)
})
it('is not disabled again when disallowing the gesture twice on a narrow screen', function() {
viewport.set(480)
window.initCore()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.called).toBe(false)
expect(snapperStub.close.called).toBe(false)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.disable.alwaysCalledWithExactly(true)).toBe(true)
expect(snapperStub.close.called).toBe(false)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.called).toBe(false)
})
it('is enabled when allowing the gesture after disallowing it on a narrow screen', function() {
viewport.set(480)
window.initCore()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.called).toBe(false)
expect(snapperStub.close.called).toBe(false)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.disable.alwaysCalledWithExactly(true)).toBe(true)
expect(snapperStub.close.called).toBe(false)
OC.allowNavigationBarSlideGesture()
expect(snapperStub.enable.calledTwice).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.called).toBe(false)
})
it('is not enabled again when allowing the gesture twice after disallowing it on a narrow screen', function() {
viewport.set(480)
window.initCore()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.called).toBe(false)
expect(snapperStub.close.called).toBe(false)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.disable.alwaysCalledWithExactly(true)).toBe(true)
expect(snapperStub.close.called).toBe(false)
OC.allowNavigationBarSlideGesture()
expect(snapperStub.enable.calledTwice).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.called).toBe(false)
OC.allowNavigationBarSlideGesture()
expect(snapperStub.enable.calledTwice).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.called).toBe(false)
})
it('is disabled on a wide screen', function() {
viewport.set(1280)
window.initCore()
expect(snapConstructorStub.calledOnce).toBe(true)
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
})
it('is not disabled again when disallowing the gesture on a wide screen', function() {
viewport.set(1280)
window.initCore()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
})
it('is not enabled when allowing the gesture after disallowing it on a wide screen', function() {
viewport.set(1280)
window.initCore()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
OC.allowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
})
it('is enabled when resizing to a narrow screen', function() {
viewport.set(1280)
window.initCore()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
viewport.set(480)
// Setting the viewport width does not automatically trigger a
// resize.
$(window).resize()
// The resize handler is debounced to be executed a few milliseconds
// after the resize event.
clock.tick(1000)
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
})
it('is not enabled when resizing to a narrow screen after disallowing the gesture', function() {
viewport.set(1280)
window.initCore()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
viewport.set(480)
// Setting the viewport width does not automatically trigger a
// resize.
$(window).resize()
// The resize handler is debounced to be executed a few milliseconds
// after the resize event.
clock.tick(1000)
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
})
it('is enabled when resizing to a narrow screen after disallowing the gesture and allowing it', function() {
viewport.set(1280)
window.initCore()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
OC.allowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
viewport.set(480)
// Setting the viewport width does not automatically trigger a
// resize.
$(window).resize()
// The resize handler is debounced to be executed a few milliseconds
// after the resize event.
clock.tick(1000)
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
})
it('is enabled when allowing the gesture after disallowing it and resizing to a narrow screen', function() {
viewport.set(1280)
window.initCore()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
viewport.set(480)
// Setting the viewport width does not automatically trigger a
// resize.
$(window).resize()
// The resize handler is debounced to be executed a few milliseconds
// after the resize event.
clock.tick(1000)
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
OC.allowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
})
it('is disabled when disallowing the gesture after disallowing it, resizing to a narrow screen and allowing it', function() {
viewport.set(1280)
window.initCore()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
viewport.set(480)
// Setting the viewport width does not automatically trigger a
// resize.
$(window).resize()
// The resize handler is debounced to be executed a few milliseconds
// after the resize event.
clock.tick(1000)
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
OC.allowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledTwice).toBe(true)
expect(snapperStub.disable.getCall(1).calledWithExactly(true)).toBe(true)
})
it('is disabled when resizing to a wide screen', function() {
viewport.set(480)
window.initCore()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.called).toBe(false)
expect(snapperStub.close.called).toBe(false)
viewport.set(1280)
// Setting the viewport width does not automatically trigger a
// resize.
$(window).resize()
// The resize handler is debounced to be executed a few milliseconds
// after the resize event.
clock.tick(1000)
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
})
it('is not disabled again when disallowing the gesture after resizing to a wide screen', function() {
viewport.set(480)
window.initCore()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.called).toBe(false)
expect(snapperStub.close.called).toBe(false)
viewport.set(1280)
// Setting the viewport width does not automatically trigger a
// resize.
$(window).resize()
// The resize handler is debounced to be executed a few milliseconds
// after the resize event.
clock.tick(1000)
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.calledOnce).toBe(true)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
})
it('is not enabled when allowing the gesture after disallowing it, resizing to a narrow screen and resizing to a wide screen', function() {
viewport.set(1280)
window.initCore()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
OC.disallowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
viewport.set(480)
// Setting the viewport width does not automatically trigger a
// resize.
$(window).resize()
// The resize handler is debounced to be executed a few milliseconds
// after the resize event.
clock.tick(1000)
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledOnce).toBe(true)
expect(snapperStub.close.calledOnce).toBe(true)
viewport.set(1280)
$(window).resize()
clock.tick(1000)
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledTwice).toBe(true)
expect(snapperStub.close.calledTwice).toBe(true)
OC.allowNavigationBarSlideGesture()
expect(snapperStub.enable.called).toBe(false)
expect(snapperStub.disable.calledTwice).toBe(true)
expect(snapperStub.close.calledTwice).toBe(true)
})
})
})