Merge pull request #51275 from nextcloud/backport/51148/stable31

[stable31] fix(files): also show file list headers on empty views
pull/51616/head
Ferdinand Thiessen 2025-03-20 16:12:03 +07:00 committed by GitHub
commit 4d061566bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 292 additions and 133 deletions

@ -9,6 +9,9 @@
</template>
<script lang="ts">
import type { Folder, Header, View } from '@nextcloud/files'
import type { PropType } from 'vue'
/**
* This component is used to render custom
* elements provided by an API. Vue doesn't allow
@ -19,21 +22,21 @@ export default {
name: 'FilesListHeader',
props: {
header: {
type: Object,
type: Object as PropType<Header>,
required: true,
},
currentFolder: {
type: Object,
type: Object as PropType<Folder>,
required: true,
},
currentView: {
type: Object,
type: Object as PropType<View>,
required: true,
},
},
computed: {
enabled() {
return this.header.enabled(this.currentFolder, this.currentView)
return this.header.enabled?.(this.currentFolder, this.currentView) ?? true
},
},
watch: {
@ -49,7 +52,7 @@ export default {
},
mounted() {
console.debug('Mounted', this.header.id)
this.header.render(this.$refs.mount, this.currentFolder, this.currentView)
this.header.render(this.$refs.mount as HTMLElement, this.currentFolder, this.currentView)
},
}
</script>

@ -27,7 +27,7 @@
<template #before>
<!-- Headers -->
<FilesListHeader v-for="header in sortedHeaders"
<FilesListHeader v-for="header in headers"
:key="header.id"
:current-folder="currentFolder"
:current-view="currentView"
@ -62,20 +62,21 @@ import type { Node as NcNode } from '@nextcloud/files'
import type { ComponentPublicInstance, PropType } from 'vue'
import type { Location } from 'vue-router'
import { defineComponent } from 'vue'
import { getFileListHeaders, Folder, Permission, View, getFileActions, FileType } from '@nextcloud/files'
import { showError } from '@nextcloud/dialogs'
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { translate as t } from '@nextcloud/l10n'
import { Folder, Permission, View, getFileActions, FileType } from '@nextcloud/files'
import { t } from '@nextcloud/l10n'
import { useHotKey } from '@nextcloud/vue/dist/Composables/useHotKey.js'
import { defineComponent } from 'vue'
import { action as sidebarAction } from '../actions/sidebarAction.ts'
import { getSummaryFor } from '../utils/fileUtils'
import { useActiveStore } from '../store/active.ts'
import { useFileListWidth } from '../composables/useFileListWidth.ts'
import { useFileListHeaders } from '../composables/useFileListHeaders.ts'
import { useRouteParameters } from '../composables/useRouteParameters.ts'
import { useSelectionStore } from '../store/selection.js'
import { useUserConfigStore } from '../store/userconfig.ts'
import { getSummaryFor } from '../utils/fileUtils.ts'
import FileEntry from './FileEntry.vue'
import FileEntryGrid from './FileEntryGrid.vue'
@ -84,8 +85,8 @@ import FilesListHeader from './FilesListHeader.vue'
import FilesListTableFooter from './FilesListTableFooter.vue'
import FilesListTableHeader from './FilesListTableHeader.vue'
import FilesListTableHeaderActions from './FilesListTableHeaderActions.vue'
import logger from '../logger.ts'
import VirtualList from './VirtualList.vue'
import logger from '../logger.ts'
export default defineComponent({
name: 'FilesListVirtual',
@ -125,6 +126,7 @@ export default defineComponent({
return {
fileId,
fileListWidth,
headers: useFileListHeaders(),
openDetails,
openFile,
@ -140,7 +142,6 @@ export default defineComponent({
return {
FileEntry,
FileEntryGrid,
headers: getFileListHeaders(),
scrollToIndex: 0,
openFileId: null as number|null,
}

@ -0,0 +1,41 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { Header } from '@nextcloud/files'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { useFileListHeaders } from './useFileListHeaders.ts'
const getFileListHeaders = vi.hoisted(() => vi.fn())
vi.mock('@nextcloud/files', async (originalModule) => {
return {
...(await originalModule()),
getFileListHeaders,
}
})
describe('useFileListHeaders', () => {
beforeEach(() => vi.resetAllMocks())
it('gets the headers', () => {
const header = new Header({ id: '1', order: 5, render: vi.fn(), updated: vi.fn() })
getFileListHeaders.mockImplementationOnce(() => [header])
const headers = useFileListHeaders()
expect(headers.value).toEqual([header])
expect(getFileListHeaders).toHaveBeenCalledOnce()
})
it('headers are sorted', () => {
const header = new Header({ id: '1', order: 10, render: vi.fn(), updated: vi.fn() })
const header2 = new Header({ id: '2', order: 5, render: vi.fn(), updated: vi.fn() })
getFileListHeaders.mockImplementationOnce(() => [header, header2])
const headers = useFileListHeaders()
// lower order first
expect(headers.value.map(({ id }) => id)).toStrictEqual(['2', '1'])
expect(getFileListHeaders).toHaveBeenCalledOnce()
})
})

@ -0,0 +1,19 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { Header } from '@nextcloud/files'
import type { ComputedRef } from 'vue'
import { getFileListHeaders } from '@nextcloud/files'
import { computed, ref } from 'vue'
/**
* Get the registered and sorted file list headers.
*/
export function useFileListHeaders(): ComputedRef<Header[]> {
const headers = ref(getFileListHeaders())
const sorted = computed(() => [...headers.value].sort((a, b) => a.order - b.order) as Header[])
return sorted
}

@ -71,7 +71,7 @@
</div>
<!-- Drag and drop notice -->
<DragAndDropNotice v-if="!loading && canUpload" :current-folder="currentFolder" />
<DragAndDropNotice v-if="!loading && canUpload && currentFolder" :current-folder="currentFolder" />
<!-- Initial loading -->
<NcLoadingIcon v-if="loading && !isRefreshing"
@ -80,7 +80,15 @@
:name="t('files', 'Loading current folder')" />
<!-- Empty content placeholder -->
<template v-else-if="!loading && isEmptyDir">
<template v-else-if="!loading && isEmptyDir && currentFolder && currentView">
<div class="files-list__before">
<!-- Headers -->
<FilesListHeader v-for="header in headers"
:key="header.id"
:current-folder="currentFolder"
:current-view="currentView"
:header="header" />
</div>
<!-- Empty due to error -->
<NcEmptyContent v-if="error" :name="error" data-cy-files-content-error>
<template #action>
@ -169,6 +177,7 @@ import ViewGridIcon from 'vue-material-design-icons/ViewGrid.vue'
import { action as sidebarAction } from '../actions/sidebarAction.ts'
import { useNavigation } from '../composables/useNavigation.ts'
import { useFileListHeaders } from '../composables/useFileListHeaders.ts'
import { useFileListWidth } from '../composables/useFileListWidth.ts'
import { useRouteParameters } from '../composables/useRouteParameters.ts'
import { useFilesStore } from '../store/files.ts'
@ -178,12 +187,13 @@ import { useSelectionStore } from '../store/selection.ts'
import { useUploaderStore } from '../store/uploader.ts'
import { useUserConfigStore } from '../store/userconfig.ts'
import { useViewConfigStore } from '../store/viewConfig.ts'
import { humanizeWebDAVError } from '../utils/davUtils.ts'
import BreadCrumbs from '../components/BreadCrumbs.vue'
import FilesListHeader from '../components/FilesListHeader.vue'
import FilesListVirtual from '../components/FilesListVirtual.vue'
import filesSortingMixin from '../mixins/filesSorting.ts'
import logger from '../logger.ts'
import DragAndDropNotice from '../components/DragAndDropNotice.vue'
import { humanizeWebDAVError } from '../utils/davUtils.ts'
const isSharingEnabled = (getCapabilities() as { files_sharing?: boolean })?.files_sharing !== undefined
@ -193,6 +203,7 @@ export default defineComponent({
components: {
BreadCrumbs,
DragAndDropNotice,
FilesListHeader,
FilesListVirtual,
LinkIcon,
ListViewIcon,
@ -241,6 +252,7 @@ export default defineComponent({
directory,
fileId,
fileListWidth,
headers: useFileListHeaders(),
t,
filesStore,
@ -814,6 +826,13 @@ export default defineComponent({
}
}
&__before {
display: flex;
flex-direction: column;
gap: calc(var(--default-grid-baseline) * 2);
margin-inline: calc(var(--default-clickable-area) + 2 * var(--app-navigation-padding));
}
&__empty-view-wrapper {
display: flex;
height: 100%;

@ -24,6 +24,12 @@ const searchForActionInRow = (row: JQuery<HTMLElement>, actionId: string): Cypre
// Else look in the action menu
const menuButtonId = row.find('button[aria-controls]').attr('aria-controls')
if (menuButtonId === undefined) {
return cy.wrap(Cypress.$())
}
// eslint-disable-next-line no-unused-expressions
expect(menuButtonId).not.to.be.undefined
return cy.get(`#${menuButtonId} [data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
}

@ -40,6 +40,26 @@ describe('files_sharing: Note to recipient', { testIsolation: true }, () => {
.and('contain.text', 'Hello, this is the note.')
})
it('displays the note to the sharee even if the file list is empty', () => {
cy.mkdir(user, '/folder')
cy.login(user)
cy.visit('/apps/files')
// share the folder
createShare('folder', sharee.userId, { read: true, download: true, note: 'Hello, this is the note.' })
cy.logout()
// Now for the sharee
cy.login(sharee)
// visit shared files view
cy.visit('/apps/files')
navigateToFolder('folder')
cy.get('.note-to-recipient')
.should('be.visible')
.and('contain.text', 'Hello, this is the note.')
})
/**
* Regression test for https://github.com/nextcloud/server/issues/46188
*/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

260
package-lock.json generated

@ -132,15 +132,15 @@
"jasmine-core": "~2.5.2",
"jasmine-sinon": "^0.4.0",
"jsdoc": "^4.0.4",
"karma": "^6.4.3",
"karma-chrome-launcher": "^3.1.1",
"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.0.6",
"puppeteer": "^23.10.4",
"puppeteer": "^24.4.0",
"raw-loader": "^4.0.2",
"regextras": "^0.8.0",
"sass": "^1.81.1",
@ -4740,18 +4740,18 @@
"license": "BSD-3-Clause"
},
"node_modules/@puppeteer/browsers": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.6.1.tgz",
"integrity": "sha512-aBSREisdsGH890S2rQqK82qmQYU3uFpSH8wcZWHgHzl3LfzsxAKbLNiAG9mO8v1Y0UICBeClICxPJvyr0rcuxg==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.8.0.tgz",
"integrity": "sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"debug": "^4.4.0",
"extract-zip": "^2.0.1",
"progress": "^2.0.3",
"proxy-agent": "^6.5.0",
"semver": "^7.6.3",
"tar-fs": "^3.0.6",
"unbzip2-stream": "^1.4.3",
"semver": "^7.7.1",
"tar-fs": "^3.0.8",
"yargs": "^17.7.2"
},
"bin": {
@ -4766,6 +4766,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
@ -4782,13 +4783,15 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/@puppeteer/browsers/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@ -4797,17 +4800,18 @@
}
},
"node_modules/@puppeteer/browsers/node_modules/tar-fs": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz",
"integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==",
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz",
"integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==",
"dev": true,
"license": "MIT",
"dependencies": {
"pump": "^3.0.0",
"tar-stream": "^3.1.5"
},
"optionalDependencies": {
"bare-fs": "^2.1.1",
"bare-path": "^2.1.0"
"bare-fs": "^4.0.1",
"bare-path": "^3.0.0"
}
},
"node_modules/@puppeteer/browsers/node_modules/tar-stream": {
@ -4815,6 +4819,7 @@
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
"integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"b4a": "^1.6.4",
"fast-fifo": "^1.2.0",
@ -5654,7 +5659,8 @@
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
"integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node10": {
"version": "1.0.11",
@ -7848,6 +7854,7 @@
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
"integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
"dev": true,
"license": "MIT",
"dependencies": {
"tslib": "^2.0.1"
},
@ -7959,7 +7966,8 @@
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
"integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==",
"dev": true
"dev": true,
"license": "Apache-2.0"
},
"node_modules/babel-loader": {
"version": "9.2.1",
@ -8178,49 +8186,72 @@
"license": "MIT"
},
"node_modules/bare-events": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz",
"integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==",
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz",
"integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==",
"dev": true,
"license": "Apache-2.0",
"optional": true
},
"node_modules/bare-fs": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz",
"integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.0.1.tgz",
"integrity": "sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"bare-events": "^2.0.0",
"bare-path": "^2.0.0",
"bare-path": "^3.0.0",
"bare-stream": "^2.0.0"
},
"engines": {
"bare": ">=1.7.0"
}
},
"node_modules/bare-os": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz",
"integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==",
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.0.tgz",
"integrity": "sha512-BUrFS5TqSBdA0LwHop4OjPJwisqxGy6JsWVqV6qaFoe965qqtaKfDzHY5T2YA1gUL0ZeeQeA+4BBc1FJTcHiPw==",
"dev": true,
"optional": true
"license": "Apache-2.0",
"optional": true,
"engines": {
"bare": ">=1.14.0"
}
},
"node_modules/bare-path": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz",
"integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
"integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"bare-os": "^2.1.0"
"bare-os": "^3.0.1"
}
},
"node_modules/bare-stream": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.1.tgz",
"integrity": "sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==",
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz",
"integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"streamx": "^2.21.0"
},
"peerDependencies": {
"bare-buffer": "*",
"bare-events": "*"
},
"peerDependenciesMeta": {
"bare-buffer": {
"optional": true
},
"bare-events": {
"optional": true
}
}
},
"node_modules/base-64": {
@ -8264,6 +8295,7 @@
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
"integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
@ -8974,14 +9006,14 @@
}
},
"node_modules/chromium-bidi": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.8.0.tgz",
"integrity": "sha512-uJydbGdTw0DEUjhoogGveneJVWX/9YuqkWePzMmkBYwtdAqo5d3J/ovNKFr+/2hWXYmYCr6it8mSSTIj6SS6Ug==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-2.1.2.tgz",
"integrity": "sha512-vtRWBK2uImo5/W2oG6/cDkkHSm+2t6VHgnj+Rcwhb0pP74OoUb4GipyRX/T/y39gYQPhioP0DPShn+A7P6CHNw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"mitt": "3.0.1",
"urlpattern-polyfill": "10.0.0",
"zod": "3.23.8"
"mitt": "^3.0.1",
"zod": "^3.24.1"
},
"peerDependencies": {
"devtools-protocol": "*"
@ -10194,6 +10226,7 @@
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
"integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14"
}
@ -10553,6 +10586,7 @@
"resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
"integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ast-types": "^0.13.4",
"escodegen": "^2.1.0",
@ -10920,10 +10954,11 @@
}
},
"node_modules/devtools-protocol": {
"version": "0.0.1367902",
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz",
"integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==",
"dev": true
"version": "0.0.1413902",
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1413902.tgz",
"integrity": "sha512-yRtvFD8Oyk7C9Os3GmnFZLu53yAfsnyw1s+mLmHHUK0GQEc9zthHWvS1r67Zqzm5t7v56PILHIVZ7kmFMaL2yQ==",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/di": {
"version": "0.0.1",
@ -13230,7 +13265,8 @@
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/fast-glob": {
"version": "3.3.2",
@ -14106,6 +14142,7 @@
"resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz",
"integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"basic-ftp": "^5.0.2",
"data-uri-to-buffer": "^6.0.2",
@ -15156,6 +15193,7 @@
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
"dev": true,
"license": "MIT",
"dependencies": {
"jsbn": "1.1.0",
"sprintf-js": "^1.1.3"
@ -16315,7 +16353,8 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/jsdoc": {
"version": "4.0.4",
@ -18585,7 +18624,8 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/mkdirp": {
"version": "1.0.4",
@ -18801,6 +18841,7 @@
"resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
"integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4.0"
}
@ -19514,10 +19555,11 @@
}
},
"node_modules/pac-proxy-agent": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz",
"integrity": "sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
"integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@tootallnate/quickjs-emscripten": "^0.23.0",
"agent-base": "^7.1.2",
@ -19537,6 +19579,7 @@
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14"
}
@ -19546,6 +19589,7 @@
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dev": true,
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.0",
"debug": "^4.3.4"
@ -19559,6 +19603,7 @@
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
"dev": true,
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.2",
"debug": "4"
@ -19572,6 +19617,7 @@
"resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
"integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
"dev": true,
"license": "MIT",
"dependencies": {
"degenerator": "^5.0.0",
"netmask": "^2.0.2"
@ -20443,6 +20489,7 @@
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
@ -20520,6 +20567,7 @@
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
"integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
"dev": true,
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.2",
"debug": "^4.3.4",
@ -20539,6 +20587,7 @@
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14"
}
@ -20548,6 +20597,7 @@
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dev": true,
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.0",
"debug": "^4.3.4"
@ -20561,6 +20611,7 @@
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
"dev": true,
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.2",
"debug": "4"
@ -20574,6 +20625,7 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=12"
}
@ -20649,17 +20701,18 @@
}
},
"node_modules/puppeteer": {
"version": "23.10.4",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.10.4.tgz",
"integrity": "sha512-i0sYIAIjdO9MoRfFqbkoWFnQYZVmNp8msbztTgG46KbOdoYAv4f56MFzdFwtC0lyZHtkP+yl0H7tP0dNg3RQYA==",
"version": "24.4.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.4.0.tgz",
"integrity": "sha512-E4JhJzjS8AAI+6N/b+Utwarhz6zWl3+MR725fal+s3UlOlX2eWdsvYYU+Q5bXMjs9eZEGkNQroLkn7j11s2k1Q==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@puppeteer/browsers": "2.6.1",
"chromium-bidi": "0.8.0",
"@puppeteer/browsers": "2.8.0",
"chromium-bidi": "2.1.2",
"cosmiconfig": "^9.0.0",
"devtools-protocol": "0.0.1367902",
"puppeteer-core": "23.10.4",
"devtools-protocol": "0.0.1413902",
"puppeteer-core": "24.4.0",
"typed-query-selector": "^2.12.0"
},
"bin": {
@ -20670,17 +20723,18 @@
}
},
"node_modules/puppeteer-core": {
"version": "23.10.4",
"resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.10.4.tgz",
"integrity": "sha512-pQAY7+IFAndWDkDodsQGguW1/ifV5OMlGXJDspwtK49Asb7poJZ/V5rXJxVSpq57bWrJasjQBZ1X27z1oWVq4Q==",
"version": "24.4.0",
"resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.4.0.tgz",
"integrity": "sha512-eFw66gCnWo0X8Hyf9KxxJtms7a61NJVMiSaWfItsFPzFBsjsWdmcNlBdsA1WVwln6neoHhsG+uTVesKmTREn/g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@puppeteer/browsers": "2.6.1",
"chromium-bidi": "0.8.0",
"@puppeteer/browsers": "2.8.0",
"chromium-bidi": "2.1.2",
"debug": "^4.4.0",
"devtools-protocol": "0.0.1367902",
"devtools-protocol": "0.0.1413902",
"typed-query-selector": "^2.12.0",
"ws": "^8.18.0"
"ws": "^8.18.1"
},
"engines": {
"node": ">=18"
@ -20691,6 +20745,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
@ -20707,7 +20762,8 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/qjobs": {
"version": "1.2.0",
@ -20905,12 +20961,6 @@
],
"license": "MIT"
},
"node_modules/queue-tick": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
"dev": true
},
"node_modules/quote-unquote": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/quote-unquote/-/quote-unquote-1.0.0.tgz",
@ -22645,6 +22695,7 @@
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
@ -22752,10 +22803,11 @@
}
},
"node_modules/socks": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
"integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
"integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
@ -22770,6 +22822,7 @@
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
"integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
"dev": true,
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.2",
"debug": "^4.3.4",
@ -22784,6 +22837,7 @@
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14"
}
@ -23029,7 +23083,8 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
"dev": true
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/ssh2": {
"version": "1.16.0",
@ -23234,13 +23289,13 @@
}
},
"node_modules/streamx": {
"version": "2.21.1",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.21.1.tgz",
"integrity": "sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==",
"version": "2.22.0",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz",
"integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-fifo": "^1.3.2",
"queue-tick": "^1.0.1",
"text-decoder": "^1.1.0"
},
"optionalDependencies": {
@ -24342,10 +24397,11 @@
"license": "MIT"
},
"node_modules/text-decoder": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.2.tgz",
"integrity": "sha512-/MDslo7ZyWTA2vnk1j7XoDVfXsGk3tp+zFEJHJGm0UjIlQifonVFwlVbQDFh8KJzTBnT8ie115TYqir6bclddA==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz",
"integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"b4a": "^1.6.4"
}
@ -25529,7 +25585,8 @@
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz",
"integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==",
"dev": true
"dev": true,
"license": "MIT"
},
"node_modules/typescript": {
"version": "5.7.3",
@ -25624,16 +25681,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/unbzip2-stream": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
"integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
"dev": true,
"dependencies": {
"buffer": "^5.2.1",
"through": "^2.3.8"
}
},
"node_modules/underscore": {
"version": "1.13.7",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
@ -25959,12 +26006,6 @@
"integrity": "sha512-FOEojW4XReTmtZOB7xqSHmJZhrNTmClhBriwLTmle4iA7bwuCo6ldSfbtsFSb8bTf3E0a3XpfonAdaur9vqq8A==",
"license": "MIT"
},
"node_modules/urlpattern-polyfill": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz",
"integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==",
"dev": true
},
"node_modules/util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
@ -27701,9 +27742,9 @@
"license": "ISC"
},
"node_modules/ws": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
"dev": true,
"license": "MIT",
"engines": {
@ -27838,10 +27879,11 @@
}
},
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"version": "3.24.2",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
"integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}

@ -163,15 +163,15 @@
"jasmine-core": "~2.5.2",
"jasmine-sinon": "^0.4.0",
"jsdoc": "^4.0.4",
"karma": "^6.4.3",
"karma-chrome-launcher": "^3.1.1",
"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.0.6",
"puppeteer": "^23.10.4",
"puppeteer": "^24.4.0",
"raw-loader": "^4.0.2",
"regextras": "^0.8.0",
"sass": "^1.81.1",

@ -18,8 +18,11 @@
* preprocessor, which is needed to be able to debug tests properly in a browser.
*/
const { existsSync } = require('node:fs');
if (!process.env.CHROMIUM_BIN) {
process.env.CHROMIUM_BIN = require('puppeteer').executablePath()
const chrome = require('puppeteer').executablePath()
process.env.CHROMIUM_BIN = chrome
}
/* jshint node: true */
@ -243,14 +246,19 @@ module.exports = function(config) {
// - PhantomJS
// - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
// use PhantomJS_debug for extra local debug
browsers: ['ChromiumHeadless'],
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