chore(tests): drop legacy Karma tests

we no longer use Karma tests, all actual tests have been migrated to
vitest. The leftover tests are already covered by unit tests in
packages.

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
pull/55608/head
Ferdinand Thiessen 2025-10-07 14:06:39 +07:00
parent 87c90f9678
commit 1f24865caf
No known key found for this signature in database
GPG Key ID: 45FAE7268762B400
12 changed files with 120 additions and 4850 deletions

@ -114,35 +114,6 @@ jobs:
if: ${{ !cancelled() }}
uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1
jsunit:
runs-on: ubuntu-latest
needs: [versions, changes]
if: ${{ needs.versions.result != 'failure' && needs.changes.outputs.src != 'false' }}
env:
CYPRESS_INSTALL_BINARY: 0
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: Set up node ${{ needs.versions.outputs.nodeVersion }}
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: ${{ needs.versions.outputs.nodeVersion }}
- name: Set up npm ${{ needs.versions.outputs.npmVersion }}
run: npm i -g 'npm@${{ needs.versions.outputs.npmVersion }}'
- name: Install dependencies
run: npm ci
- name: Test
run: npm run test:jsunit
handlebars:
runs-on: ubuntu-latest
needs: [versions, changes]
@ -177,7 +148,7 @@ jobs:
permissions:
contents: none
runs-on: ubuntu-latest-low
needs: [changes, test, jsunit, handlebars]
needs: [changes, test, handlebars]
if: always()
@ -185,4 +156,4 @@ jobs:
steps:
- name: Summary status
run: if ${{ needs.changes.outputs.src != 'false' && (needs.test.result != 'success' || needs.jsunit.result != 'success' || needs.handlebars.result != 'success') }}; then exit 1; fi
run: if ${{ needs.changes.outputs.src != 'false' && (needs.test.result != 'success' || needs.handlebars.result != 'success') }}; then exit 1; fi

@ -1,44 +0,0 @@
/**
* DOMParser HTML extension
* 2012-09-04
*
* By Eli Grey, http://eligrey.com
* Public domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*
* SPDX-FileCopyrightText: 2012 Eli Grey, http://eligrey.com
* SPDX-License-Identifier: CC0-1.0
*/
/*! @source https://gist.github.com/1129031 */
/* global document, DOMParser */
(function(DOMParser) {
'use strict'
const DOMParser_proto = DOMParser.prototype
const real_parseFromString = DOMParser_proto.parseFromString
// Firefox/Opera/IE throw errors on unsupported types
try {
// WebKit returns null on unsupported types
if ((new DOMParser()).parseFromString('', 'text/html')) {
// text/html parsing is natively supported
return
}
} catch (ex) {}
DOMParser_proto.parseFromString = function(markup, type) {
if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
const doc = document.implementation.createHTMLDocument('')
if (markup.toLowerCase().indexOf('<!doctype') > -1) {
doc.documentElement.innerHTML = markup
} else {
doc.body.innerHTML = markup
}
return doc
} else {
return real_parseFromString.apply(this, arguments)
}
}
}(DOMParser))

@ -1,191 +0,0 @@
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2014 ownCloud Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/**
* Simulate the variables that are normally set by PHP code
*/
// from core/js/config.php
window.TESTING = true
window.datepickerFormatDate = 'MM d, yy'
window.dayNames = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
]
window.dayNamesShort = [
'Sun.',
'Mon.',
'Tue.',
'Wed.',
'Thu.',
'Fri.',
'Sat.',
]
window.dayNamesMin = [
'Su',
'Mo',
'Tu',
'We',
'Th',
'Fr',
'Sa',
]
window.monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
window.monthNamesShort = [
'Jan.',
'Feb.',
'Mar.',
'Apr.',
'May.',
'Jun.',
'Jul.',
'Aug.',
'Sep.',
'Oct.',
'Nov.',
'Dec.',
]
window.firstDay = 0
// setup dummy webroots
/* jshint camelcase: false */
window.oc_debug = true
// Mock @nextcloud/capabilities
window._oc_capabilities = {
files_sharing: {
api_enabled: true,
},
}
// FIXME: OC.webroot is supposed to be only the path!!!
window._oc_webroot = location.href + '/'
window._oc_appswebroots = {
files: window.webroot + '/apps/files/',
files_sharing: window.webroot + '/apps/files_sharing/',
}
window.OC ??= {}
OC.config = {
session_lifetime: 600 * 1000,
session_keepalive: false,
blacklist_files_regex: '\.(part|filepart)$',
version: '32.0.0',
}
OC.appConfig = {
core: {},
}
OC.theme = {
docPlaceholderUrl: 'https://docs.example.org/PLACEHOLDER',
}
window.oc_capabilities = {
}
/* jshint camelcase: true */
// mock for Snap.js plugin
window.Snap = function() {}
window.Snap.prototype = {
enable: function() {},
disable: function() {},
close: function() {},
}
window.isPhantom = /phantom/i.test(navigator.userAgent)
document.documentElement.lang = navigator.language
const el = document.createElement('input')
el.id = 'initial-state-core-config'
el.value = btoa(JSON.stringify(window.OC.config))
document.body.append(el);
// global setup for all tests
(function setupTests() {
let fakeServer = null,
$testArea = null,
ajaxErrorStub = null
/**
* Utility functions for testing
*/
const TestUtil = {
/**
* Returns the image URL set on the given element
* @param $el element
* @return {String} image URL
*/
getImageUrl: function($el) {
// might be slightly different cross-browser
const url = $el.css('background-image')
const r = url.match(/url\(['"]?([^'")]*)['"]?\)/)
if (!r) {
return url
}
return r[1]
},
}
beforeEach(function() {
// test area for elements that need absolute selector access or measure widths/heights
// which wouldn't work for detached or hidden elements
$testArea = $('<div id="testArea" style="position: absolute; width: 1280px; height: 800px; top: -3000px; left: -3000px; opacity: 0;"></div>')
$('body').append($testArea)
// enforce fake XHR, tests should not depend on the server and
// must use fake responses for expected calls
fakeServer = sinon.fakeServer.create()
// make it globally available, so that other tests can define
// custom responses
window.fakeServer = fakeServer
if (!OC.TestUtil) {
OC.TestUtil = TestUtil
}
moment.locale('en')
// reset plugins
OC.Plugins._plugins = []
// dummy select2 (which isn't loaded during the tests)
$.fn.select2 = function() { return this }
ajaxErrorStub = sinon.stub(OC, '_processAjaxError')
})
afterEach(function() {
// uncomment this to log requests
// console.log(window.fakeServer.requests);
fakeServer.restore()
$testArea.remove()
delete ($.fn.select2)
ajaxErrorStub.restore()
// reset pop state handlers
OC.Util.History._handlers = []
})
})()

File diff suppressed because it is too large Load Diff

@ -1,838 +0,0 @@
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2015 ownCloud Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/* global dav */
describe('OC.Files.Client tests', function() {
const Client = OC.Files.Client
let baseUrl
let client
let requestStub
let requestDeferred
beforeEach(function() {
requestDeferred = new $.Deferred()
requestStub = sinon.stub(dav.Client.prototype, 'request').returns(requestDeferred.promise())
baseUrl = 'https://testhost/owncloud/remote.php/webdav/'
client = new Client({
host: 'testhost',
root: '/owncloud/remote.php/webdav',
useHTTPS: true,
})
})
afterEach(function() {
client = null
requestStub.restore()
})
/**
* Send an status response and check that the given
* promise gets its success handler called with the error
* status code
*
* @param {Promise} promise promise
* @param {number} status status to test
*/
function respondAndCheckStatus(promise, status) {
const successHandler = sinon.stub()
const failHandler = sinon.stub()
promise.done(successHandler)
promise.fail(failHandler)
requestDeferred.resolve({
status,
body: '',
})
promise.then(function() {
expect(successHandler.calledOnce).toEqual(true)
expect(successHandler.getCall(0).args[0]).toEqual(status)
expect(failHandler.notCalled).toEqual(true)
})
return promise
}
/**
* Send an error response and check that the given
* promise gets its fail handler called with the error
* status code
*
* @param {Promise} promise promise object
* @param {number} status error status to test
*/
function respondAndCheckError(promise, status) {
const successHandler = sinon.stub()
const failHandler = sinon.stub()
promise.done(successHandler)
promise.fail(failHandler)
const errorXml
= '<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">'
+ ' <s:exception>Sabre\\DAV\\Exception\\SomeException</s:exception>'
+ ' <s:message>Some error message</s:message>'
+ '</d:error>'
const parser = new DOMParser()
requestDeferred.resolve({
status,
body: errorXml,
xhr: {
responseXML: parser.parseFromString(errorXml, 'application/xml'),
},
})
promise.then(function() {
expect(failHandler.calledOnce).toEqual(true)
expect(failHandler.getCall(0).args[0]).toEqual(status)
expect(failHandler.getCall(0).args[1].status).toEqual(status)
expect(failHandler.getCall(0).args[1].message).toEqual('Some error message')
expect(failHandler.getCall(0).args[1].exception).toEqual('Sabre\\DAV\\Exception\\SomeException')
expect(successHandler.notCalled).toEqual(true)
})
return promise
}
/**
* Returns a list of request properties parsed from the given request body.
*
* @param {string} requestBody request XML
*
* @return {Array.<String>} array of request properties in the format
* "{NS:}propname"
*/
function getRequestedProperties(requestBody) {
const doc = (new window.DOMParser()).parseFromString(
requestBody,
'application/xml',
)
const propRoots = doc.getElementsByTagNameNS('DAV:', 'prop')
const propsList = propRoots.item(0).childNodes
return _.map(propsList, function(propNode) {
return '{' + propNode.namespaceURI + '}' + propNode.localName
})
}
function makePropBlock(props) {
let s = '<d:prop>\n'
_.each(props, function(value, key) {
s += '<' + key + '>' + value + '</' + key + '>\n'
})
return s + '</d:prop>\n'
}
function makeResponseBlock(href, props, failedProps) {
let s = '<d:response>\n'
s += '<d:href>' + href + '</d:href>\n'
s += '<d:propstat>\n'
s += makePropBlock(props)
s += '<d:status>HTTP/1.1 200 OK</d:status>'
s += '</d:propstat>\n'
if (failedProps) {
s += '<d:propstat>\n'
_.each(failedProps, function(prop) {
s += '<' + prop + '/>\n'
})
s += '<d:status>HTTP/1.1 404 Not Found</d:status>\n'
s += '</d:propstat>\n'
}
return s + '</d:response>\n'
}
describe('file listing', function() {
// TODO: switch this to the already parsed structure
const folderContentsXml = dav.Client.prototype.parseMultiStatus('<?xml version="1.0" encoding="utf-8"?>'
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">'
+ makeResponseBlock(
'/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/',
{
'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
'd:getetag': '"56cfcabd79abb"',
'd:resourcetype': '<d:collection/>',
'oc:id': '00000011oc2d13a6a068',
'oc:fileid': '11',
'oc:permissions': 'GRDNVCK',
'oc:size': '120',
},
[
'd:getcontenttype',
'd:getcontentlength',
],
)
+ makeResponseBlock(
'/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt',
{
'd:getlastmodified': 'Fri, 10 Jul 2015 13:38:05 GMT',
'd:getetag': '"559fcabd79a38"',
'd:getcontenttype': 'text/plain',
'd:getcontentlength': 250,
'd:resourcetype': '',
'oc:id': '00000051oc2d13a6a068',
'oc:fileid': '51',
'oc:permissions': 'RDNVW',
},
[
'oc:size',
],
)
+ makeResponseBlock(
'/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/sub',
{
'd:getlastmodified': 'Fri, 10 Jul 2015 14:00:00 GMT',
'd:getetag': '"66cfcabd79abb"',
'd:resourcetype': '<d:collection/>',
'oc:id': '00000015oc2d13a6a068',
'oc:fileid': '15',
'oc:permissions': 'GRDNVCK',
'oc:size': '100',
},
[
'd:getcontenttype',
'd:getcontentlength',
],
)
+ '</d:multistatus>')
it('sends PROPFIND with explicit properties to get file list', function() {
client.getFolderContents('path/to space/文件夹')
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('PROPFIND')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9')
expect(requestStub.lastCall.args[2].Depth).toEqual('1')
const props = getRequestedProperties(requestStub.lastCall.args[3])
expect(props).toContain('{DAV:}getlastmodified')
expect(props).toContain('{DAV:}getcontentlength')
expect(props).toContain('{DAV:}getcontenttype')
expect(props).toContain('{DAV:}getetag')
expect(props).toContain('{DAV:}resourcetype')
expect(props).toContain('{http://owncloud.org/ns}fileid')
expect(props).toContain('{http://owncloud.org/ns}size')
expect(props).toContain('{http://owncloud.org/ns}permissions')
expect(props).toContain('{http://nextcloud.org/ns}is-encrypted')
})
it('sends PROPFIND to base url when empty path given', function() {
client.getFolderContents('')
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[1]).toEqual(baseUrl)
})
it('sends PROPFIND to base url when root path given', function() {
client.getFolderContents('/')
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[1]).toEqual(baseUrl)
})
it('parses the result list into a FileInfo array', function() {
const promise = client.getFolderContents('path/to space/文件夹')
expect(requestStub.calledOnce).toEqual(true)
requestDeferred.resolve({
status: 207,
body: folderContentsXml,
})
promise.then(function(status, response) {
expect(status).toEqual(207)
expect(_.isArray(response)).toEqual(true)
expect(response.length).toEqual(2)
// file entry
let info = response[0]
expect(info instanceof OC.Files.FileInfo).toEqual(true)
expect(info.id).toEqual(51)
expect(info.path).toEqual('/path/to space/文件夹')
expect(info.name).toEqual('One.txt')
expect(info.permissions).toEqual(26)
expect(info.size).toEqual(250)
expect(info.mtime).toEqual(1436535485000)
expect(info.mimetype).toEqual('text/plain')
expect(info.etag).toEqual('559fcabd79a38')
expect(info.isEncrypted).toEqual(false)
// sub entry
info = response[1]
expect(info instanceof OC.Files.FileInfo).toEqual(true)
expect(info.id).toEqual(15)
expect(info.path).toEqual('/path/to space/文件夹')
expect(info.name).toEqual('sub')
expect(info.permissions).toEqual(31)
expect(info.size).toEqual(100)
expect(info.mtime).toEqual(1436536800000)
expect(info.mimetype).toEqual('httpd/unix-directory')
expect(info.etag).toEqual('66cfcabd79abb')
expect(info.isEncrypted).toEqual(false)
})
})
it('returns parent node in result if specified', function() {
const promise = client.getFolderContents('path/to space/文件夹', { includeParent: true })
expect(requestStub.calledOnce).toEqual(true)
requestDeferred.resolve({
status: 207,
body: folderContentsXml,
})
promise.then(function(status, response) {
expect(status).toEqual(207)
expect(_.isArray(response)).toEqual(true)
expect(response.length).toEqual(3)
// root entry
const info = response[0]
expect(info instanceof OC.Files.FileInfo).toEqual(true)
expect(info.id).toEqual(11)
expect(info.path).toEqual('/path/to space')
expect(info.name).toEqual('文件夹')
expect(info.permissions).toEqual(31)
expect(info.size).toEqual(120)
expect(info.mtime).toEqual(1436522405000)
expect(info.mimetype).toEqual('httpd/unix-directory')
expect(info.etag).toEqual('56cfcabd79abb')
expect(info.isEncrypted).toEqual(false)
// the two other entries follow
expect(response[1].id).toEqual(51)
expect(response[2].id).toEqual(15)
})
})
it('rejects promise when an error occurred', function() {
const promise = client.getFolderContents('path/to space/文件夹', { includeParent: true })
respondAndCheckError(promise, 404)
})
it('throws exception if arguments are missing', function() {
// TODO
})
})
describe('file filtering', function() {
// TODO: switch this to the already parsed structure
const folderContentsXml = dav.Client.prototype.parseMultiStatus('<?xml version="1.0" encoding="utf-8"?>'
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">'
+ makeResponseBlock(
'/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/',
{
'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
'd:getetag': '"56cfcabd79abb"',
'd:resourcetype': '<d:collection/>',
'oc:id': '00000011oc2d13a6a068',
'oc:fileid': '11',
'oc:permissions': 'RDNVCK',
'oc:size': '120',
},
[
'd:getcontenttype',
'd:getcontentlength',
],
)
+ makeResponseBlock(
'/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt',
{
'd:getlastmodified': 'Fri, 10 Jul 2015 13:38:05 GMT',
'd:getetag': '"559fcabd79a38"',
'd:getcontenttype': 'text/plain',
'd:getcontentlength': 250,
'd:resourcetype': '',
'oc:id': '00000051oc2d13a6a068',
'oc:fileid': '51',
'oc:permissions': 'RDNVW',
},
[
'oc:size',
],
)
+ makeResponseBlock(
'/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/sub',
{
'd:getlastmodified': 'Fri, 10 Jul 2015 14:00:00 GMT',
'd:getetag': '"66cfcabd79abb"',
'd:resourcetype': '<d:collection/>',
'oc:id': '00000015oc2d13a6a068',
'oc:fileid': '15',
'oc:permissions': 'RDNVCK',
'oc:size': '100',
},
[
'd:getcontenttype',
'd:getcontentlength',
],
)
+ '</d:multistatus>')
it('sends REPORT with filter information', function() {
client.getFilteredFiles({
systemTagIds: ['123', '456'],
})
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('REPORT')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl)
const body = requestStub.lastCall.args[3]
const doc = (new window.DOMParser()).parseFromString(
body,
'application/xml',
)
const ns = 'http://owncloud.org/ns'
expect(doc.documentElement.localName).toEqual('filter-files')
expect(doc.documentElement.namespaceURI).toEqual(ns)
const filterRoots = doc.getElementsByTagNameNS(ns, 'filter-rules')
const rulesList = filterRoots[0] = doc.getElementsByTagNameNS(ns, 'systemtag')
expect(rulesList.length).toEqual(2)
expect(rulesList[0].localName).toEqual('systemtag')
expect(rulesList[0].namespaceURI).toEqual(ns)
expect(rulesList[0].textContent).toEqual('123')
expect(rulesList[1].localName).toEqual('systemtag')
expect(rulesList[1].namespaceURI).toEqual(ns)
expect(rulesList[1].textContent).toEqual('456')
})
it('sends REPORT with explicit properties to filter file list', function() {
client.getFilteredFiles({
systemTagIds: ['123', '456'],
})
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('REPORT')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl)
const props = getRequestedProperties(requestStub.lastCall.args[3])
expect(props).toContain('{DAV:}getlastmodified')
expect(props).toContain('{DAV:}getcontentlength')
expect(props).toContain('{DAV:}getcontenttype')
expect(props).toContain('{DAV:}getetag')
expect(props).toContain('{DAV:}resourcetype')
expect(props).toContain('{http://owncloud.org/ns}fileid')
expect(props).toContain('{http://owncloud.org/ns}size')
expect(props).toContain('{http://owncloud.org/ns}permissions')
expect(props).toContain('{http://nextcloud.org/ns}is-encrypted')
})
it('parses the result list into a FileInfo array', function() {
const promise = client.getFilteredFiles({
systemTagIds: ['123', '456'],
})
expect(requestStub.calledOnce).toEqual(true)
requestDeferred.resolve({
status: 207,
body: folderContentsXml,
})
promise.then(function(status, response) {
expect(status).toEqual(207)
expect(_.isArray(response)).toEqual(true)
// returns all entries
expect(response.length).toEqual(3)
// file entry
let info = response[0]
expect(info instanceof OC.Files.FileInfo).toEqual(true)
expect(info.id).toEqual(11)
// file entry
info = response[1]
expect(info instanceof OC.Files.FileInfo).toEqual(true)
expect(info.id).toEqual(51)
// sub entry
info = response[2]
expect(info instanceof OC.Files.FileInfo).toEqual(true)
expect(info.id).toEqual(15)
})
})
it('throws exception if arguments are missing', function() {
let thrown = null
try {
client.getFilteredFiles({})
} catch (e) {
thrown = true
}
expect(thrown).toEqual(true)
})
})
describe('file info', function() {
const responseXml = dav.Client.prototype.parseMultiStatus('<?xml version="1.0" encoding="utf-8"?>'
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns">'
+ makeResponseBlock(
'/owncloud/remote.php/webdav/path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/',
{
'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
'd:getetag': '"56cfcabd79abb"',
'd:resourcetype': '<d:collection/>',
'oc:id': '00000011oc2d13a6a068',
'oc:fileid': '11',
'oc:permissions': 'GRDNVCK',
'oc:size': '120',
'nc:is-encrypted': '1',
},
[
'd:getcontenttype',
'd:getcontentlength',
],
)
+ '</d:multistatus>')
it('sends PROPFIND with zero depth to get single file info', function() {
client.getFileInfo('path/to space/文件夹')
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('PROPFIND')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9')
expect(requestStub.lastCall.args[2].Depth).toEqual('0')
const props = getRequestedProperties(requestStub.lastCall.args[3])
expect(props).toContain('{DAV:}getlastmodified')
expect(props).toContain('{DAV:}getcontentlength')
expect(props).toContain('{DAV:}getcontenttype')
expect(props).toContain('{DAV:}getetag')
expect(props).toContain('{DAV:}resourcetype')
expect(props).toContain('{http://owncloud.org/ns}fileid')
expect(props).toContain('{http://owncloud.org/ns}size')
expect(props).toContain('{http://owncloud.org/ns}permissions')
expect(props).toContain('{http://nextcloud.org/ns}is-encrypted')
})
it('parses the result into a FileInfo', function() {
const promise = client.getFileInfo('path/to space/文件夹')
expect(requestStub.calledOnce).toEqual(true)
requestDeferred.resolve({
status: 207,
body: responseXml,
})
promise.then(function(status, response) {
expect(status).toEqual(207)
expect(_.isArray(response)).toEqual(false)
const info = response
expect(info instanceof OC.Files.FileInfo).toEqual(true)
expect(info.id).toEqual(11)
expect(info.path).toEqual('/path/to space')
expect(info.name).toEqual('文件夹')
expect(info.permissions).toEqual(31)
expect(info.size).toEqual(120)
expect(info.mtime).toEqual(1436522405000)
expect(info.mimetype).toEqual('httpd/unix-directory')
expect(info.etag).toEqual('56cfcabd79abb')
expect(info.isEncrypted).toEqual(true)
})
})
it('properly parses entry inside root', function() {
const responseXml = dav.Client.prototype.parseMultiStatus('<?xml version="1.0" encoding="utf-8"?>'
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">'
+ makeResponseBlock(
'/owncloud/remote.php/webdav/in%20root',
{
'd:getlastmodified': 'Fri, 10 Jul 2015 10:00:05 GMT',
'd:getetag': '"56cfcabd79abb"',
'd:resourcetype': '<d:collection/>',
'oc:id': '00000011oc2d13a6a068',
'oc:fileid': '11',
'oc:permissions': 'GRDNVCK',
'oc:size': '120',
},
[
'd:getcontenttype',
'd:getcontentlength',
],
)
+ '</d:multistatus>')
const promise = client.getFileInfo('in root')
expect(requestStub.calledOnce).toEqual(true)
requestDeferred.resolve({
status: 207,
body: responseXml,
})
promise.then(function(status, response) {
expect(status).toEqual(207)
expect(_.isArray(response)).toEqual(false)
const info = response
expect(info instanceof OC.Files.FileInfo).toEqual(true)
expect(info.id).toEqual(11)
expect(info.path).toEqual('/')
expect(info.name).toEqual('in root')
expect(info.permissions).toEqual(31)
expect(info.size).toEqual(120)
expect(info.mtime).toEqual(1436522405000)
expect(info.mimetype).toEqual('httpd/unix-directory')
expect(info.etag).toEqual('56cfcabd79abb')
expect(info.isEncrypted).toEqual(false)
})
})
it('rejects promise when an error occurred', function() {
const promise = client.getFileInfo('path/to space/文件夹')
respondAndCheckError(promise, 404)
})
it('throws exception if arguments are missing', function() {
// TODO
})
})
describe('permissions', function() {
function getFileInfoWithPermission(webdavPerm, isFile) {
const props = {
'd:getlastmodified': 'Fri, 10 Jul 2015 13:38:05 GMT',
'd:getetag': '"559fcabd79a38"',
'd:getcontentlength': 250,
'oc:id': '00000051oc2d13a6a068',
'oc:fileid': '51',
'oc:permissions': webdavPerm,
}
if (isFile) {
props['d:getcontenttype'] = 'text/plain'
} else {
props['d:resourcetype'] = '<d:collection/>'
}
const def = new $.Deferred()
requestStub.reset()
requestStub.returns(def)
const responseXml = dav.Client.prototype.parseMultiStatus('<?xml version="1.0" encoding="utf-8"?>'
+ '<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:oc="http://owncloud.org/ns">'
+ makeResponseBlock(
'/owncloud/remote.php/webdav/file.txt',
props,
)
+ '</d:multistatus>')
const promise = client.getFileInfo('file.txt')
expect(requestStub.calledOnce).toEqual(true)
def.resolve({
status: 207,
body: responseXml,
})
return promise
}
function testPermission(permission, isFile, expectedPermissions) {
const promise = getFileInfoWithPermission(permission, isFile)
promise.then(function(status, result) {
expect(result.permissions).toEqual(expectedPermissions)
})
}
function testMountType(permission, isFile, expectedMountType) {
const promise = getFileInfoWithPermission(permission, isFile)
promise.then(function(status, result) {
expect(result.mountType).toEqual(expectedMountType)
})
}
it('properly parses file permissions', function() {
// permission, isFile, expectedPermissions
const testCases = [
['', true, OC.PERMISSION_NONE],
['C', true, OC.PERMISSION_CREATE],
['K', true, OC.PERMISSION_CREATE],
['G', true, OC.PERMISSION_READ],
['W', true, OC.PERMISSION_UPDATE],
['D', true, OC.PERMISSION_DELETE],
['R', true, OC.PERMISSION_SHARE],
['CKGWDR', true, OC.PERMISSION_ALL],
]
_.each(testCases, function(testCase) {
return testPermission.apply(this, testCase)
})
})
it('properly parses mount types', function() {
const testCases = [
['CKGWDR', false, null],
['M', false, 'external'],
['S', false, 'shared'],
['SM', false, 'shared'],
]
_.each(testCases, function(testCase) {
return testMountType.apply(this, testCase)
})
})
})
describe('get file contents', function() {
it('returns file contents', function() {
const promise = client.getFileContents('path/to space/文件夹/One.txt')
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('GET')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt')
requestDeferred.resolve({
status: 200,
body: 'some contents',
})
promise.then(function(status, response) {
expect(status).toEqual(200)
expect(response).toEqual('some contents')
})
})
it('rejects promise when an error occurred', function() {
const promise = client.getFileContents('path/to space/文件夹/One.txt')
respondAndCheckError(promise, 409)
})
it('throws exception if arguments are missing', function() {
// TODO
})
})
describe('put file contents', function() {
it('sends PUT with file contents', function() {
const promise = client.putFileContents(
'path/to space/文件夹/One.txt',
'some contents',
)
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('PUT')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt')
expect(requestStub.lastCall.args[2]['If-None-Match']).toEqual('*')
expect(requestStub.lastCall.args[2]['Content-Type']).toEqual('text/plain;charset=utf-8')
expect(requestStub.lastCall.args[3]).toEqual('some contents')
respondAndCheckStatus(promise, 201)
})
it('sends PUT with file contents with headers matching options', function() {
const promise = client.putFileContents(
'path/to space/文件夹/One.txt',
'some contents',
{
overwrite: false,
contentType: 'text/markdown',
},
)
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('PUT')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/One.txt')
expect(requestStub.lastCall.args[2]['If-None-Match']).not.toBeDefined()
expect(requestStub.lastCall.args[2]['Content-Type']).toEqual('text/markdown')
expect(requestStub.lastCall.args[3]).toEqual('some contents')
respondAndCheckStatus(promise, 201)
})
it('rejects promise when an error occurred', function() {
const promise = client.putFileContents(
'path/to space/文件夹/One.txt',
'some contents',
)
respondAndCheckError(promise, 409)
})
it('throws exception if arguments are missing', function() {
// TODO
})
})
describe('create directory', function() {
it('sends MKCOL with specified path', function() {
const promise = client.createDirectory('path/to space/文件夹/new dir')
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('MKCOL')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9/new%20dir')
respondAndCheckStatus(promise, 201)
})
it('rejects promise when an error occurred', function() {
const promise = client.createDirectory('path/to space/文件夹/new dir')
respondAndCheckError(promise, 404)
})
it('throws exception if arguments are missing', function() {
// TODO
})
})
describe('deletion', function() {
it('sends DELETE with specified path', function() {
const promise = client.remove('path/to space/文件夹')
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('DELETE')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9')
respondAndCheckStatus(promise, 201)
})
it('rejects promise when an error occurred', function() {
const promise = client.remove('path/to space/文件夹')
respondAndCheckError(promise, 404)
})
it('throws exception if arguments are missing', function() {
// TODO
})
})
describe('move', function() {
it('sends MOVE with specified paths with fail on overwrite by default', function() {
const promise = client.move(
'path/to space/文件夹',
'path/to space/anotherdir/文件夹',
)
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('MOVE')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9')
expect(requestStub.lastCall.args[2].Destination)
.toEqual(baseUrl + 'path/to%20space/anotherdir/%E6%96%87%E4%BB%B6%E5%A4%B9')
expect(requestStub.lastCall.args[2].Overwrite)
.toEqual('F')
respondAndCheckStatus(promise, 201)
})
it('sends MOVE with silent overwrite mode when specified', function() {
const promise = client.move(
'path/to space/文件夹',
'path/to space/anotherdir/文件夹',
{ allowOverwrite: true },
)
expect(requestStub.calledOnce).toEqual(true)
expect(requestStub.lastCall.args[0]).toEqual('MOVE')
expect(requestStub.lastCall.args[1]).toEqual(baseUrl + 'path/to%20space/%E6%96%87%E4%BB%B6%E5%A4%B9')
expect(requestStub.lastCall.args[2].Destination)
.toEqual(baseUrl + 'path/to%20space/anotherdir/%E6%96%87%E4%BB%B6%E5%A4%B9')
expect(requestStub.lastCall.args[2].Overwrite)
.not.toBeDefined()
respondAndCheckStatus(promise, 201)
})
it('rejects promise when an error occurred', function() {
const promise = client.move(
'path/to space/文件夹',
'path/to space/anotherdir/文件夹',
{ allowOverwrite: true },
)
respondAndCheckError(promise, 404)
})
it('throws exception if arguments are missing', function() {
// TODO
})
})
})

@ -1,219 +0,0 @@
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2015 ownCloud Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
describe('jquery.avatar tests', function() {
let $div
let devicePixelRatio
beforeEach(function() {
$('#testArea').append($('<div id="avatardiv">'))
$div = $('#avatardiv')
devicePixelRatio = window.devicePixelRatio
window.devicePixelRatio = 1
spyOn(window, 'Image').and.returnValue({
onload: function() {
},
onerror: function() {
},
})
})
afterEach(function() {
$div.remove()
window.devicePixelRatio = devicePixelRatio
})
describe('size', function() {
it('undefined', function() {
$div.avatar('foo')
expect(Math.round($div.height())).toEqual(64)
expect(Math.round($div.width())).toEqual(64)
})
it('undefined but div has height', function() {
$div.height(9)
$div.avatar('foo')
expect(window.Image).toHaveBeenCalled()
window.Image().onerror()
expect(Math.round($div.height())).toEqual(9)
expect(Math.round($div.width())).toEqual(9)
})
it('undefined but data size is set', function() {
$div.data('size', 10)
$div.avatar('foo')
expect(window.Image).toHaveBeenCalled()
window.Image().onerror()
expect(Math.round($div.height())).toEqual(10)
expect(Math.round($div.width())).toEqual(10)
})
it('defined', function() {
$div.avatar('foo', 8)
expect(window.Image).toHaveBeenCalled()
window.Image().onerror()
expect(Math.round($div.height())).toEqual(8)
expect(Math.round($div.width())).toEqual(8)
})
})
it('undefined user', function() {
spyOn($div, 'imageplaceholder')
spyOn($div, 'css')
$div.avatar()
expect($div.imageplaceholder).toHaveBeenCalledWith('?')
expect($div.css).toHaveBeenCalledWith('background-color', '#b9b9b9')
})
describe('no avatar', function() {
it('show placeholder for existing user', function() {
spyOn($div, 'imageplaceholder')
$div.avatar('foo', undefined, undefined, undefined, undefined, 'bar')
expect(window.Image).toHaveBeenCalled()
window.Image().onerror()
expect($div.imageplaceholder).toHaveBeenCalledWith('foo', 'bar')
})
it('show placeholder for non existing user', function() {
spyOn($div, 'imageplaceholder')
spyOn($div, 'css')
$div.avatar('foo')
expect(window.Image).toHaveBeenCalled()
window.Image().onerror()
expect($div.imageplaceholder).toHaveBeenCalledWith('?')
expect($div.css).toHaveBeenCalledWith('background-color', '#b9b9b9')
})
it('show no placeholder is ignored', function() {
spyOn($div, 'imageplaceholder')
spyOn($div, 'css')
$div.avatar('foo', undefined, undefined, true)
expect(window.Image).toHaveBeenCalled()
window.Image().onerror()
expect($div.imageplaceholder).toHaveBeenCalledWith('?')
expect($div.css).toHaveBeenCalledWith('background-color', '#b9b9b9')
})
})
describe('url generation', function() {
beforeEach(function() {
window.devicePixelRatio = 1
})
it('default', function() {
window.devicePixelRatio = 1
$div.avatar('foo', 32)
expect(window.Image).toHaveBeenCalled()
expect(window.Image().src).toEqual('http://localhost/index.php/avatar/foo/32')
})
it('high DPI icon', function() {
window.devicePixelRatio = 4
$div.avatar('foo', 32)
expect(window.Image).toHaveBeenCalled()
expect(window.Image().src).toEqual('http://localhost/index.php/avatar/foo/128')
})
it('high DPI icon round up size', function() {
window.devicePixelRatio = 1.9
$div.avatar('foo', 32)
expect(window.Image).toHaveBeenCalled()
expect(window.Image().src).toEqual('http://localhost/index.php/avatar/foo/61')
})
})
describe('valid avatar', function() {
beforeEach(function() {
window.devicePixelRatio = 1
})
it('default (no ie8 fix)', function() {
$div.avatar('foo', 32)
expect(window.Image).toHaveBeenCalled()
window.Image().onload()
expect(window.Image().height).toEqual(32)
expect(window.Image().width).toEqual(32)
expect(window.Image().src).toEqual('http://localhost/index.php/avatar/foo/32')
})
it('default high DPI icon', function() {
window.devicePixelRatio = 1.9
$div.avatar('foo', 32)
expect(window.Image).toHaveBeenCalled()
window.Image().onload()
expect(window.Image().height).toEqual(32)
expect(window.Image().width).toEqual(32)
expect(window.Image().src).toEqual('http://localhost/index.php/avatar/foo/61')
})
it('with ie8 fix (ignored)', function() {
$div.avatar('foo', 32, true)
expect(window.Image).toHaveBeenCalled()
window.Image().onload()
expect(window.Image().height).toEqual(32)
expect(window.Image().width).toEqual(32)
expect(window.Image().src).toEqual('http://localhost/index.php/avatar/foo/32')
})
it('unhide div', function() {
$div.hide()
$div.avatar('foo', 32)
expect(window.Image).toHaveBeenCalled()
window.Image().onload()
expect(window.Image().height).toEqual(32)
expect(window.Image().width).toEqual(32)
expect(window.Image().src).toEqual('http://localhost/index.php/avatar/foo/32')
})
it('callback called', function() {
const observer = { callback: function() { dump('FOO') } }
spyOn(observer, 'callback')
$div.avatar('foo', 32, undefined, undefined, function() {
observer.callback()
})
expect(window.Image).toHaveBeenCalled()
window.Image().onload()
expect(window.Image().height).toEqual(32)
expect(window.Image().width).toEqual(32)
expect(window.Image().src).toEqual('http://localhost/index.php/avatar/foo/32')
expect(observer.callback).toHaveBeenCalled()
})
})
})

@ -1,37 +0,0 @@
/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
describe('jquery.placeholder tests', function() {
let $div
beforeEach(function() {
$('#testArea').append($('<div id="placeholderdiv">'))
$div = $('#placeholderdiv')
})
afterEach(function() {
$div.remove()
})
describe('placeholder text', function() {
it('shows one first letter if one word in a input text', function() {
spyOn($div, 'html')
$div.imageplaceholder('Seed', 'Name')
expect($div.html).toHaveBeenCalledWith('N')
})
it('shows two first letters if two words in a input text', function() {
spyOn($div, 'html')
$div.imageplaceholder('Seed', 'First Second')
expect($div.html).toHaveBeenCalledWith('FS')
})
it('shows two first letters if more then two words in a input text', function() {
spyOn($div, 'html')
$div.imageplaceholder('Seed', 'First Second Middle')
expect($div.html).toHaveBeenCalledWith('FS')
})
})
})

@ -1,89 +0,0 @@
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2014 ownCloud Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
describe('OC.L10N tests', function() {
const TEST_APP = 'jsunittestapp'
beforeEach(function() {
window._oc_appswebroots[TEST_APP] = OC.getRootPath() + '/apps3/jsunittestapp'
window.OC = window.OC ?? {}
window.OC.appswebroots = window.OC.appswebroots || {}
window.OC.appswebroots[TEST_APP] = OC.getRootPath() + '/apps3/jsunittestapp'
})
afterEach(function() {
OC.L10N._unregister(TEST_APP)
delete window._oc_appswebroots[TEST_APP]
delete window.OC.appswebroots[TEST_APP]
})
describe('text translation', function() {
beforeEach(function() {
spyOn(console, 'warn')
OC.L10N.register(TEST_APP, {
'Hello world!': 'Hallo Welt!',
'Hello {name}, the weather is {weather}': 'Hallo {name}, das Wetter ist {weather}',
sunny: 'sonnig',
})
})
it('returns untranslated text when no bundle exists', function() {
OC.L10N._unregister(TEST_APP)
expect(t(TEST_APP, 'unknown text')).toEqual('unknown text')
})
it('returns untranslated text when no key exists', function() {
expect(t(TEST_APP, 'unknown text')).toEqual('unknown text')
})
it('returns translated text when key exists', function() {
expect(t(TEST_APP, 'Hello world!')).toEqual('Hallo Welt!')
})
it('returns translated text with placeholder', function() {
expect(t(TEST_APP, 'Hello {name}, the weather is {weather}', { name: 'Steve', weather: t(TEST_APP, 'sunny') })).toEqual('Hallo Steve, das Wetter ist sonnig')
})
it('returns text with escaped placeholder', function() {
expect(t(TEST_APP, 'Hello {name}', { name: '<strong>Steve</strong>' })).toEqual('Hello &lt;strong&gt;Steve&lt;/strong&gt;')
})
it('returns text with not escaped placeholder', function() {
expect(t(TEST_APP, 'Hello {name}', { name: '<strong>Steve</strong>' }, null, { escape: false })).toEqual('Hello <strong>Steve</strong>')
})
it('uses DOMPurify to escape the text', function() {
expect(t(TEST_APP, '<strong>These are your search results<script>alert(1)</script></strong>', null, { escape: false })).toEqual('<strong>These are your search results</strong>')
})
it('keeps old texts when registering existing bundle', function() {
OC.L10N.register(TEST_APP, {
sunny: 'sonnig',
new: 'neu',
})
expect(t(TEST_APP, 'sunny')).toEqual('sonnig')
expect(t(TEST_APP, 'new')).toEqual('neu')
})
})
describe('plurals', function() {
function checkPlurals() {
expect(n(TEST_APP, 'download %n file', 'download %n files', 0)).toEqual('0 Dateien herunterladen')
expect(n(TEST_APP, 'download %n file', 'download %n files', 1)).toEqual('1 Datei herunterladen')
expect(n(TEST_APP, 'download %n file', 'download %n files', 2)).toEqual('2 Dateien herunterladen')
expect(n(TEST_APP, 'download %n file', 'download %n files', 1024)).toEqual('1024 Dateien herunterladen')
}
it('generates plural for default text when translation does not exist', function() {
spyOn(console, 'warn')
OC.L10N.register(TEST_APP, {
})
expect(n(TEST_APP, 'download %n file', 'download %n files', 0)).toEqual('download 0 files')
expect(n(TEST_APP, 'download %n file', 'download %n files', 1)).toEqual('download 1 file')
expect(n(TEST_APP, 'download %n file', 'download %n files', 2)).toEqual('download 2 files')
expect(n(TEST_APP, 'download %n file', 'download %n files', 1024)).toEqual('download 1024 files')
})
it('generates plural with default function when no forms specified', function() {
spyOn(console, 'warn')
OC.L10N.register(TEST_APP, {
'_download %n file_::_download %n files_':
['%n Datei herunterladen', '%n Dateien herunterladen'],
})
checkPlurals()
})
})
})

@ -1,394 +0,0 @@
/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2014 ownCloud Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/* global dav */
describe('Backbone Webdav extension', function() {
let davClientRequestStub
let davClientPropPatchStub
let davClientPropFindStub
let deferredRequest
beforeEach(function() {
deferredRequest = $.Deferred()
davClientRequestStub = sinon.stub(dav.Client.prototype, 'request')
davClientPropPatchStub = sinon.stub(dav.Client.prototype, 'propPatch')
davClientPropFindStub = sinon.stub(dav.Client.prototype, 'propFind')
davClientRequestStub.returns(deferredRequest.promise())
davClientPropPatchStub.returns(deferredRequest.promise())
davClientPropFindStub.returns(deferredRequest.promise())
})
afterEach(function() {
davClientRequestStub.restore()
davClientPropPatchStub.restore()
davClientPropFindStub.restore()
})
describe('collections', function() {
let TestModel
let TestCollection
beforeEach(function() {
TestModel = OC.Backbone.Model.extend({
sync: OC.Backbone.davSync,
davProperties: {
firstName: '{http://owncloud.org/ns}first-name',
lastName: '{http://owncloud.org/ns}last-name',
age: '{http://owncloud.org/ns}age',
married: '{http://owncloud.org/ns}married',
},
parse: function(data) {
return {
id: data.id,
firstName: data.firstName,
lastName: data.lastName,
age: parseInt(data.age, 10),
married: data.married === 'true' || data.married === true,
}
},
})
TestCollection = OC.Backbone.Collection.extend({
sync: OC.Backbone.davSync,
model: TestModel,
url: 'http://example.com/owncloud/remote.php/test/',
})
})
it('makes a POST request to create model into collection', function(done) {
const collection = new TestCollection()
const model = collection.create({
firstName: 'Hello',
lastName: 'World',
})
expect(davClientRequestStub.calledOnce).toEqual(true)
expect(davClientRequestStub.getCall(0).args[0])
.toEqual('POST')
expect(davClientRequestStub.getCall(0).args[1])
.toEqual('http://example.com/owncloud/remote.php/test/')
expect(davClientRequestStub.getCall(0).args[2]['Content-Type'])
.toEqual('application/json')
expect(davClientRequestStub.getCall(0).args[2]['X-Requested-With'])
.toEqual('XMLHttpRequest')
expect(davClientRequestStub.getCall(0).args[3])
.toEqual(JSON.stringify({
firstName: 'Hello',
lastName: 'World',
}))
const responseHeaderStub = sinon.stub()
.withArgs('Content-Location')
.returns('http://example.com/owncloud/remote.php/test/123')
deferredRequest.resolve({
status: 201,
body: '',
xhr: {
getResponseHeader: responseHeaderStub,
},
})
setTimeout(function() {
expect(model.id).toEqual('123')
done()
}, 0)
})
it('uses PROPFIND to retrieve collection', function(done) {
const successStub = sinon.stub()
const errorStub = sinon.stub()
const collection = new TestCollection()
collection.fetch({
success: successStub,
error: errorStub,
})
expect(davClientPropFindStub.calledOnce).toEqual(true)
expect(davClientPropFindStub.getCall(0).args[0])
.toEqual('http://example.com/owncloud/remote.php/test/')
expect(davClientPropFindStub.getCall(0).args[1])
.toEqual([
'{http://owncloud.org/ns}first-name',
'{http://owncloud.org/ns}last-name',
'{http://owncloud.org/ns}age',
'{http://owncloud.org/ns}married',
])
expect(davClientPropFindStub.getCall(0).args[2])
.toEqual(1)
expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With'])
.toEqual('XMLHttpRequest')
deferredRequest.resolve({
status: 207,
body: [
// root element
{
href: 'http://example.org/owncloud/remote.php/test/',
propStat: [],
},
// first model
{
href: 'http://example.org/owncloud/remote.php/test/123',
propStat: [{
status: 'HTTP/1.1 200 OK',
properties: {
'{http://owncloud.org/ns}first-name': 'Hello',
'{http://owncloud.org/ns}last-name': 'World',
},
}],
},
// second model
{
href: 'http://example.org/owncloud/remote.php/test/456',
propStat: [{
status: 'HTTP/1.1 200 OK',
properties: {
'{http://owncloud.org/ns}first-name': 'Test',
'{http://owncloud.org/ns}last-name': 'Person',
},
}],
},
],
})
setTimeout(function() {
expect(collection.length).toEqual(2)
let model = collection.get('123')
expect(model.id).toEqual('123')
expect(model.get('firstName')).toEqual('Hello')
expect(model.get('lastName')).toEqual('World')
model = collection.get('456')
expect(model.id).toEqual('456')
expect(model.get('firstName')).toEqual('Test')
expect(model.get('lastName')).toEqual('Person')
expect(successStub.calledOnce).toEqual(true)
expect(errorStub.notCalled).toEqual(true)
done()
}, 0)
})
function testMethodError(doCall, done) {
const successStub = sinon.stub()
const errorStub = sinon.stub()
doCall(successStub, errorStub)
deferredRequest.resolve({
status: 404,
body: '',
})
setTimeout(function() {
expect(successStub.notCalled).toEqual(true)
expect(errorStub.calledOnce).toEqual(true)
done()
}, 0)
}
it('calls error handler if error status in PROPFIND response', function(done) {
testMethodError(function(success, error) {
const collection = new TestCollection()
collection.fetch({
success,
error,
})
}, done)
})
it('calls error handler if error status in POST response', function(done) {
testMethodError(function(success, error) {
const collection = new TestCollection()
collection.create({
firstName: 'Hello',
lastName: 'World',
}, {
success,
error,
})
}, done)
})
})
describe('models', function() {
let TestModel
beforeEach(function() {
TestModel = OC.Backbone.Model.extend({
sync: OC.Backbone.davSync,
davProperties: {
firstName: '{http://owncloud.org/ns}first-name',
lastName: '{http://owncloud.org/ns}last-name',
age: '{http://owncloud.org/ns}age', // int
married: '{http://owncloud.org/ns}married', // bool
},
url: function() {
return 'http://example.com/owncloud/remote.php/test/' + this.id
},
parse: function(data) {
return {
id: data.id,
firstName: data.firstName,
lastName: data.lastName,
age: parseInt(data.age, 10),
married: data.married === 'true' || data.married === true,
}
},
})
})
it('makes a PROPPATCH request to update model', function() {
const model = new TestModel({
id: '123',
firstName: 'Hello',
lastName: 'World',
age: 32,
married: false,
})
model.save({
firstName: 'Hey',
age: 33,
married: true,
})
expect(davClientPropPatchStub.calledOnce).toEqual(true)
expect(davClientPropPatchStub.getCall(0).args[0])
.toEqual('http://example.com/owncloud/remote.php/test/123')
expect(davClientPropPatchStub.getCall(0).args[1])
.toEqual({
'{http://owncloud.org/ns}first-name': 'Hey',
'{http://owncloud.org/ns}age': '33',
'{http://owncloud.org/ns}married': 'true',
})
expect(davClientPropPatchStub.getCall(0).args[2]['X-Requested-With'])
.toEqual('XMLHttpRequest')
deferredRequest.resolve({
status: 201,
body: '',
})
expect(model.id).toEqual('123')
expect(model.get('firstName')).toEqual('Hey')
expect(model.get('age')).toEqual(33)
expect(model.get('married')).toEqual(true)
})
it('uses PROPFIND to fetch single model', function(done) {
const model = new TestModel({
id: '123',
})
model.fetch()
expect(davClientPropFindStub.calledOnce).toEqual(true)
expect(davClientPropFindStub.getCall(0).args[0])
.toEqual('http://example.com/owncloud/remote.php/test/123')
expect(davClientPropFindStub.getCall(0).args[1])
.toEqual([
'{http://owncloud.org/ns}first-name',
'{http://owncloud.org/ns}last-name',
'{http://owncloud.org/ns}age',
'{http://owncloud.org/ns}married',
])
expect(davClientPropFindStub.getCall(0).args[2])
.toEqual(0)
expect(davClientPropFindStub.getCall(0).args[3]['X-Requested-With'])
.toEqual('XMLHttpRequest')
deferredRequest.resolve({
status: 207,
body: {
href: 'http://example.org/owncloud/remote.php/test/123',
propStat: [{
status: 'HTTP/1.1 200 OK',
properties: {
'{http://owncloud.org/ns}first-name': 'Hello',
'{http://owncloud.org/ns}last-name': 'World',
'{http://owncloud.org/ns}age': '35',
'{http://owncloud.org/ns}married': 'true',
},
}],
},
})
setTimeout(function() {
expect(model.id).toEqual('123')
expect(model.get('firstName')).toEqual('Hello')
expect(model.get('lastName')).toEqual('World')
expect(model.get('age')).toEqual(35)
expect(model.get('married')).toEqual(true)
done()
})
})
it('makes a DELETE request to destroy model', function() {
const model = new TestModel({
id: '123',
firstName: 'Hello',
lastName: 'World',
})
model.destroy()
expect(davClientRequestStub.calledOnce).toEqual(true)
expect(davClientRequestStub.getCall(0).args[0])
.toEqual('DELETE')
expect(davClientRequestStub.getCall(0).args[1])
.toEqual('http://example.com/owncloud/remote.php/test/123')
expect(davClientRequestStub.getCall(0).args[2]['X-Requested-With'])
.toEqual('XMLHttpRequest')
expect(davClientRequestStub.getCall(0).args[3])
.toBeFalsy()
deferredRequest.resolve({
status: 200,
body: '',
})
})
function testMethodError(doCall, done) {
const successStub = sinon.stub()
const errorStub = sinon.stub()
doCall(successStub, errorStub)
deferredRequest.resolve({
status: 404,
body: '',
})
setTimeout(function() {
expect(successStub.notCalled).toEqual(true)
expect(errorStub.calledOnce).toEqual(true)
done()
})
}
it('calls error handler if error status in PROPFIND response', function(done) {
testMethodError(function(success, error) {
const model = new TestModel()
model.fetch({
success,
error,
})
}, done)
})
it('calls error handler if error status in PROPPATCH response', function(done) {
testMethodError(function(success, error) {
const model = new TestModel()
model.save({
firstName: 'Hey',
}, {
success,
error,
})
}, done)
})
})
})

1772
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -34,7 +34,6 @@
"stylelint:fix": "npm run stylelint -- --fix",
"test": "vitest run",
"test:coverage": "vitest run --coverage --reporter=default --reporter=junit --outputFile=test-report.junit.xml",
"test:jsunit": "karma start tests/karma.config.js --single-run",
"test:update-snapshots": "vitest run --update",
"test:watch": "vitest watch",
"watch": "webpack --node-env development --progress --watch"
@ -164,23 +163,12 @@
"exports-loader": "^5.0.0",
"file-loader": "^6.2.0",
"handlebars-loader": "^1.7.3",
"jasmine-core": "~2.5.2",
"jasmine-sinon": "^0.4.0",
"jsdom": "^27.0.0",
"karma": "^6.4.4",
"karma-chrome-launcher": "^3.2.0",
"karma-coverage": "2.2.1",
"karma-jasmine": "^1.1.2",
"karma-jasmine-sinon": "^1.0.4",
"karma-spec-reporter": "^0.0.36",
"karma-viewport": "^1.0.9",
"mime": "^4.1.0",
"msw": "^2.11.3",
"puppeteer": "^24.23.0",
"raw-loader": "^4.0.2",
"regextras": "^0.8.0",
"sass": "^1.93.2",
"sinon": "<= 5.0.7",
"stylelint": "^16.24.0",
"stylelint-use-logical": "^2.1.2",
"tar": "^7.5.1",

@ -1,194 +0,0 @@
/**
* SPDX-FileCopyrightText: 2016-2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2014-2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/**
* This node module is run by the karma executable to specify its configuration.
*
* The list of files from all needed JavaScript files including the ones from the
* apps to test, and the test specs will be passed as configuration object.
*
* Note that it is possible to test a single app by setting the KARMA_TESTSUITE
* environment variable to the apps name, for example "core" or "files_encryption".
* Multiple apps can be specified by separating them with space.
*
* Setting the environment variable NOCOVERAGE to 1 will disable the coverage
* preprocessor, which is needed to be able to debug tests properly in a browser.
*/
if (!process.env.CHROMIUM_BIN) {
const chrome = require('puppeteer').executablePath()
process.env.CHROMIUM_BIN = chrome
}
/* jshint node: true */
module.exports = function(config) {
// respect NOCOVERAGE env variable
// it is useful to disable coverage for debugging
// because the coverage preprocessor will wrap the JS files somehow
var enableCoverage = !parseInt(process.env.NOCOVERAGE, 10);
console.log(
'Coverage preprocessor: ',
enableCoverage ? 'enabled' : 'disabled'
);
// read core files from core.json,
// these are required by all apps so always need to be loaded
// note that the loading order is important that's why they
// are specified in a separate file
var corePath = 'dist/';
var coreModule = require('../core/js/core.json');
var files = [
// core mocks
'core/js/tests/specHelper.js',
];
var preprocessors = {};
var srcFile, i;
// add core library files
for (i = 0; i < coreModule.libraries.length; i++) {
srcFile = corePath + coreModule.libraries[i];
files.push(srcFile);
}
files.push('core/js/tests/html-domparser.js');
files.push('dist/core-main.js');
files.push('dist/core-files_fileinfo.js');
files.push('dist/core-files_client.js');
files.push('dist/core-systemtags.js');
// add core modules files
for (i = 0; i < coreModule.modules.length; i++) {
srcFile = corePath + coreModule.modules[i];
files.push(srcFile);
if (enableCoverage) {
preprocessors[srcFile] = 'coverage';
}
}
// core tests
files.push('core/js/tests/specs/**/*.js');
// serve images to avoid warnings
files.push({
pattern: 'core/img/**/*',
watched: false,
included: false,
served: true
});
// include core CSS
files.push({
pattern: 'core/css/*.css',
watched: true,
included: true,
served: true
});
// Allow fonts
files.push({
pattern: 'core/fonts/*',
watched: false,
included: false,
served: true
});
console.log(files)
config.set({
// base path, that will be used to resolve files and exclude
basePath: '..',
// frameworks to use
frameworks: ['jasmine', 'jasmine-sinon', 'viewport'],
// list of files / patterns to load in the browser
files,
// list of files to exclude
exclude: [],
proxies: {
// prevent warnings for images
'/base/tests/img/': 'http://localhost:9876/base/core/img/',
'/base/tests/css/': 'http://localhost:9876/base/core/css/',
'/base/core/css/images/': 'http://localhost:9876/base/core/css/images/',
'/actions/': 'http://localhost:9876/base/core/img/actions/',
'/base/core/fonts/': 'http://localhost:9876/base/core/fonts/',
'/svg/': '../core/img/'
},
// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters: ['spec'],
specReporter: {
maxLogLines: 5,
suppressErrorSummary: false,
suppressFailed: false,
suppressPassed: true,
suppressSkipped: true,
showSpecTiming: false,
},
junitReporter: {
outputFile: 'tests/autotest-results-js.xml'
},
// web server port
port: 9876,
preprocessors: preprocessors,
coverageReporter: {
dir: 'tests/karma-coverage',
reporters: [
{ type: 'html' },
{ type: 'cobertura' },
{ type: 'lcovonly' }
]
},
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera (has to be installed with `npm install karma-opera-launcher`)
// - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`)
// - PhantomJS
// - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
// use PhantomJS_debug for extra local debug
browsers: ['Chrome_without_sandbox'],
// you can define custom flags
customLaunchers: {
PhantomJS_debug: {
base: 'PhantomJS',
debug: true
},
// fix CI
Chrome_without_sandbox: {
base: 'ChromiumHeadless',
flags: ['--no-sandbox'],
},
},
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};