From 372ac8ad7830c5e7ed755fc0a33e80fbfa879ffb Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Wed, 22 Oct 2025 23:13:35 +0200 Subject: [PATCH] chore: adjust Vue 3 based frontend vite config for multiple apps Signed-off-by: Ferdinand Thiessen --- build/frontend/package.json | 8 +- build/frontend/vite.config.mts | 49 +++-- build/frontend/vitest.config.mts | 58 ------ package-lock.json | 345 +++++++++++++++++++++++++++++++ package.json | 11 +- vitest.config.ts | 57 ++++- 6 files changed, 446 insertions(+), 82 deletions(-) delete mode 100644 build/frontend/vitest.config.mts diff --git a/build/frontend/package.json b/build/frontend/package.json index 3573eabfc99..c0e4b728268 100644 --- a/build/frontend/package.json +++ b/build/frontend/package.json @@ -11,10 +11,10 @@ "dev": "NODE_ENV=development vite build --mode development", "lint": "eslint --suppressions-location ../eslint-baseline.json --no-error-on-unmatched-pattern ./apps/*/ ./core/", "lint:fix": "eslint --suppressions-location ../eslint-baseline.json --fix --no-error-on-unmatched-pattern ./apps/*/ ./core/", - "test": "vitest run --passWithNoTests", - "test:coverage": "vitest run --passWithNoTests --coverage --reporter=default", - "test:update-snapshots": "vitest run --update", - "test:watch": "vitest watch", + "test": "vitest -c ../../vitest.config.ts run", + "test:coverage": "vitest -c ../../vitest.config.ts run --coverage --reporter=default", + "test:update-snapshots": "vitest -c ../../vitest.config.ts run --update", + "test:watch": "vitest -c ../../vitest.config.ts watch", "watch": "NODE_ENV=development vite build --mode development --watch" }, "browserslist": [ diff --git a/build/frontend/vite.config.mts b/build/frontend/vite.config.mts index 20ba69403cc..18e1c2de3c6 100644 --- a/build/frontend/vite.config.mts +++ b/build/frontend/vite.config.mts @@ -6,9 +6,21 @@ import { createAppConfig } from '@nextcloud/vite-config' import { resolve } from 'node:path' -export default createAppConfig({ - 'admin-settings': resolve(import.meta.dirname, 'apps/sharebymail/src', 'settings-admin.ts'), -}, { +const modules = { + sharebymail: { + 'admin-settings': resolve(import.meta.dirname, 'apps/sharebymail/src', 'settings-admin.ts'), + }, +} + +// convert modules to modules entries prefied with the app id +const viteModuleEntries = Object.entries(modules) + .map(([appId, entries]) => ( + Object.entries(entries) + .map(([entryName, entryPath]) => [`${appId}-${entryName}`, entryPath]) + )) + .flat(1) + +export default createAppConfig(Object.fromEntries(viteModuleEntries), { emptyOutputDirectory: { additionalDirectories: [resolve(import.meta.dirname, '../..', 'dist')], }, @@ -23,11 +35,11 @@ export default createAppConfig({ build: { outDir: 'dist', rollupOptions: { + experimental: { + strictExecutionOrder: true, + }, output: { - entryFileNames({ facadeModuleId }) { - const [, appId] = facadeModuleId!.match(/apps\/([^/]+)\//)! - return `${appId}-[name].mjs` - }, + entryFileNames: '[name].mjs', chunkFileNames: '[name]-[hash].chunk.mjs', assetFileNames({ originalFileNames }) { const [name] = originalFileNames @@ -37,16 +49,25 @@ export default createAppConfig({ } return '[name]-[hash][extname]' }, - /* advancedChunks: { - groups: [{ name: 'common', test: /[\\/]node_modules[\\/]/ }], + advancedChunks: { + groups: [ + // one group for common dependencies + { name: 'common', test: /[\\/]node_modules[\\/]/ }, + // one group per app with a lower minShareCount to encourage sharing within the app + ...Object.keys(modules).map((name) => ({ + name, + test: new RegExp(`[\\\\/]apps[\\\\/]${name}[\\\\/]`), + minShareCount: 2, + })), + ], // only include modules in the groups if they are used at least by 3 different chunks minShareCount: 3, - // only include modules in the groups if they are smaller than 200kb on its own - maxModuleSize: 200 * 1024, + // only include modules in the groups if they are smaller than 400kb on its own + // maxModuleSize: 400 * 1024, // define the groups output size (not too small but also not too big!) - minSize: 50 * 1024, - maxSize: 500 * 1024, - }, */ + minSize: 100 * 1024, + maxSize: 800 * 1024, + }, }, }, }, diff --git a/build/frontend/vitest.config.mts b/build/frontend/vitest.config.mts deleted file mode 100644 index 48ab1275bdb..00000000000 --- a/build/frontend/vitest.config.mts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: CC0-1.0 - */ - -import vue from '@vitejs/plugin-vue' -import { exec } from 'node:child_process' -import { promisify } from 'node:util' -import { defaultExclude, defineConfig } from 'vitest/config' - -const gitIgnore: string[] = [] -// get all files ignored in the apps directory (e.g. if putting `view` app there). -try { - const execAsync = promisify(exec) - const { stdout } = await execAsync('git check-ignore apps/*', { cwd: __dirname }) - gitIgnore.push(...stdout.split('\n').filter(Boolean)) - // eslint-disable-next-line no-console - console.log('Git ignored files excluded from tests: ', gitIgnore) -} catch (error) { - // we can ignore error code 1 as this just means there are no ignored files - if (error.code !== 1) { - // but otherwise something bad is happening and we should re-throw - throw error - } -} - -export default defineConfig({ - plugins: [vue()], - test: { - include: ['./apps/sharebymail/**/*.{test,spec}.?(c|m)[jt]s?(x)'], - environment: 'jsdom', - environmentOptions: { - jsdom: { - url: 'http://nextcloud.local', - }, - }, - coverage: { - include: ['apps/*/src/**', 'core/src/**'], - exclude: ['**.spec.*', '**.test.*', '**.cy.*', 'core/src/tests/**'], - provider: 'v8', - reporter: ['lcov', 'text'], - }, - setupFiles: [ - '__tests__/mock-window.js', - '__tests__/setup-testing-library.js', - ], - exclude: [ - ...defaultExclude, - ...gitIgnore, - ], - globalSetup: '__tests__/setup-global.js', - server: { - deps: { - inline: [/@nextcloud\//], - }, - }, - }, -}) diff --git a/package-lock.json b/package-lock.json index 823363b8d4c..f641a40779d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,9 +24,12 @@ "@nextcloud/stylelint-config": "^3.1.1", "@nextcloud/vite-config": "^2.5.2", "@testing-library/cypress": "^10.1.0", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/vue": "^8.1.0", "@types/dockerode": "^3.3.44", "@types/wait-on": "^5.3.4", "@vitest/coverage-v8": "^3.2.4", + "@vue/test-utils": "^2.4.6", "@vue/tsconfig": "^0.8.1", "@zip.js/zip.js": "^2.8.8", "concurrently": "^9.2.1", @@ -109,6 +112,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT" + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -2565,6 +2575,13 @@ "node": ">= 8" } }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true, + "license": "MIT" + }, "node_modules/@parcel/watcher": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", @@ -3555,6 +3572,87 @@ "node": ">=18" } }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/vue": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/vue/-/vue-8.1.0.tgz", + "integrity": "sha512-ls4RiHO1ta4mxqqajWRh8158uFObVrrtAPoxk7cIp4HrnQUj/ScKzqz53HxYpG3X6Zb7H2v+0eTGLSoy8HQ2nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@testing-library/dom": "^9.3.3", + "@vue/test-utils": "^2.4.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@vue/compiler-sfc": ">= 3", + "vue": ">= 3" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + } + } + }, + "node_modules/@testing-library/vue/node_modules/@testing-library/dom": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", + "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@testing-library/vue/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, "node_modules/@tokenizer/token": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", @@ -4472,6 +4570,17 @@ "integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==", "license": "MIT" }, + "node_modules/@vue/test-utils": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.4.6.tgz", + "integrity": "sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-beautify": "^1.14.9", + "vue-component-type-helpers": "^2.0.0" + } + }, "node_modules/@vue/tsconfig": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.8.1.tgz", @@ -4569,6 +4678,16 @@ "node": ">=18.0.0" } }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -5995,6 +6114,24 @@ "dev": true, "license": "MIT" }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, "node_modules/console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", @@ -6230,6 +6367,13 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -7122,6 +7266,61 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.238", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.238.tgz", @@ -9987,6 +10186,85 @@ "node": ">= 20" } }, + "node_modules/js-beautify": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-beautify/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/js-beautify/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11651,6 +11929,16 @@ "node": ">=6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -11976,6 +12264,22 @@ "node": ">= 6" } }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -12816,6 +13120,13 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, "node_modules/protobufjs": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", @@ -13059,6 +13370,20 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -14450,6 +14775,19 @@ "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -16206,6 +16544,13 @@ } } }, + "node_modules/vue-component-type-helpers": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-2.2.12.tgz", + "integrity": "sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==", + "dev": true, + "license": "MIT" + }, "node_modules/vue-eslint-parser": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.2.0.tgz", diff --git a/package.json b/package.json index 5ec6b688cff..a2a83673115 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,10 @@ "sass:watch": "sass --watch --load-path core/css core/css/ $(for cssdir in $(find apps -mindepth 2 -maxdepth 2 -name \"css\"); do if ! $(git check-ignore -q $cssdir); then printf \"$cssdir \"; fi; done)", "stylelint": "stylelint $(for appdir in $(ls apps); do if ! $(git check-ignore -q \"apps/$appdir\"); then printf \"'apps/$appdir/**/*.{scss,vue}' \"; fi; done) 'core/**/*.{scss,vue}'", "stylelint:fix": "npm run stylelint -- --fix", - "test": "build/demi.sh test", - "test:coverage": "build/demi.sh test:coverage", - "test:update-snapshots": "build/demi.sh test:update-snapshots", - "test:watch": "build/demi.sh --parallel test:watch", + "test": "vitest run; cd build/frontend-legacy && npm run test", + "test:coverage": "vitest run --coverage --reporter=default", + "test:update-snapshots": "vitest run --update; cd build/frontend-legacy && npm run test:update-snapshots", + "test:watch": "concurrently 'vitest watch' 'cd build/frontend-legacy && npm run test:watch'", "watch": "build/demi.sh --parallel watch" }, "browserslist": [ @@ -53,9 +53,12 @@ "@nextcloud/stylelint-config": "^3.1.1", "@nextcloud/vite-config": "^2.5.2", "@testing-library/cypress": "^10.1.0", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/vue": "^8.1.0", "@types/dockerode": "^3.3.44", "@types/wait-on": "^5.3.4", "@vitest/coverage-v8": "^3.2.4", + "@vue/test-utils": "^2.4.6", "@vue/tsconfig": "^0.8.1", "@zip.js/zip.js": "^2.8.8", "concurrently": "^9.2.1", diff --git a/vitest.config.ts b/vitest.config.ts index d0c1805bc08..663acfe3cd3 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,6 +1,59 @@ -/*! +/** * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: CC0-1.0 */ -// temporary see build/frontend/vitest.config.mts +import vue from '@vitejs/plugin-vue' +import { exec } from 'node:child_process' +import { resolve } from 'node:path' +import { promisify } from 'node:util' +import { defaultExclude, defineConfig } from 'vitest/config' + +const gitIgnore: string[] = [] +// get all files ignored in the apps directory (e.g. if putting `view` app there). +try { + const execAsync = promisify(exec) + const { stdout } = await execAsync('git check-ignore apps/*', { cwd: __dirname }) + gitIgnore.push(...stdout.split('\n').filter(Boolean)) + // eslint-disable-next-line no-console + console.log('Git ignored files excluded from tests: ', gitIgnore) +} catch (error) { + // we can ignore error code 1 as this just means there are no ignored files + if (error.code !== 1) { + // but otherwise something bad is happening and we should re-throw + throw error + } +} + +export default defineConfig({ + plugins: [vue()], + test: { + include: ['build/frontend/apps/**/*.{test,spec}.?(c|m)[jt]s?(x)'], + environment: 'jsdom', + environmentOptions: { + jsdom: { + url: 'http://nextcloud.local', + }, + }, + coverage: { + include: ['build/frontend/apps/*/src/**', 'build/frontend/core/src/**'], + exclude: ['**.spec.*', '**.test.*', '**.cy.*', 'core/src/tests/**'], + provider: 'v8', + reporter: ['lcov', 'text'], + }, + setupFiles: [ + resolve(import.meta.dirname, '__tests__/mock-window.js'), + resolve(import.meta.dirname, '__tests__/setup-testing-library.js'), + ], + exclude: [ + ...defaultExclude, + ...gitIgnore, + ], + globalSetup: resolve(import.meta.dirname, '__tests__/setup-global.js'), + server: { + deps: { + inline: [/@nextcloud\//], + }, + }, + }, +})