const { test } = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const Module = require('node:module') const ts = require('typescript') const root = path.resolve(__dirname, '..') function loadRuntime() { const filename = path.join(root, 'src/sheep/utils/file-access.ts') const corePath = path.join(path.dirname(filename), 'file-access-core.ts') const compile = source => ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 } }).outputText const core = new Module(corePath, module); core.filename = corePath; core.paths = Module._nodeModulePaths(path.dirname(corePath)) core._compile(compile(fs.readFileSync(corePath, 'utf8')), corePath) const appId = root.endsWith('pj_mini_app_cloud') ? 'mini' : 'h5' const env = { VITE_FILE_ACCESS_APP_ID: appId, VITE_FILE_ACCESS_KEY_ID: 'v1', VITE_FILE_ACCESS_KEY: JSON.parse(fs.readFileSync(path.join(root, 'test-vectors/file-access.json'), 'utf8'))[0].key, VITE_IMAGE_DEV_PATH: 'https://files.example/api', VITE_APP_DEV_SERVICE: 'https://files.example/api' } const runtime = new Module(filename, module); runtime.filename = filename; runtime.paths = core.paths runtime.require = name => name === './file-access-core' ? core.exports : name === './app' ? { isDevEnv: () => true } : core.require(name) runtime._compile(compile(fs.readFileSync(filename, 'utf8').replace(/import\.meta\.env/g, '(' + JSON.stringify(env) + ')')), filename) return { api: runtime.exports, appId } } test('rich-text file links use signed downloads and local files instead of browser navigation', () => { const previousUni = global.uni, previousDocument = global.document const downloads = [], documents = [], previews = [], browserDownloads = [] global.uni = { downloadFile: options => { downloads.push(options); options.success({ statusCode: 200, tempFilePath: 'blob:local-file' }) }, openDocument: options => documents.push(options), previewImage: options => previews.push(options), onNetworkStatusChange() {}, } global.document = undefined try { const { api, appId } = loadRuntime() api.openFileLink('/admin/sys-file/oss/file?fileName=report.pdf') assert.equal(new URL(downloads[0].url).searchParams.get('appId'), appId) assert.ok(new URL(downloads[0].url).searchParams.has('sign')) assert.equal(documents[0].filePath, 'blob:local-file') let appended = 0, removed = 0 let onClick global.document = { addEventListener(name, handler, capture) { assert.equal(name, 'click'); assert.equal(capture, true); onClick = handler }, body: { appendChild() { appended++ } }, createElement: () => ({ click() { browserDownloads.push({ href: this.href, name: this.download }) }, remove() { removed++ } }), } api.openFileLink('/admin/sys-file/oss/file?fileName=' + encodeURIComponent('附件 +.pdf')) assert.deepEqual(browserDownloads, [{ href: 'blob:local-file', name: '附件 +.pdf' }]) assert.equal(appended, 1); assert.equal(removed, 1) api.openFileLink('/admin/sys-file/oss/file?fileName=photo.png') assert.equal(previews.length, 1) assert.ok(new URL(previews[0].urls[0]).searchParams.has('sign')) assert.equal(downloads.length, 2) api.installFileAccess({ config: { globalProperties: {} }, mixin() {} }) let prevented = false onClick({ target: { closest: () => ({ getAttribute: () => '/admin/sys-file/oss/file?fileName=linked.pdf' }) }, preventDefault() { prevented = true }, stopImmediatePropagation() {}, }) assert.equal(prevented, true) assert.equal(browserDownloads.at(-1).name, 'linked.pdf') let outsidePrevented = false onClick({ target: { closest: () => ({ getAttribute: () => 'https://other.example/report.pdf' }) }, preventDefault() { outsidePrevented = true }, stopImmediatePropagation() {}, }) assert.equal(outsidePrevented, false) } finally { global.uni = previousUni; global.document = previousDocument } }) test('the actual rich-text component routes owned links through the file helper', () => { const filename = path.join(root, 'src/uni_modules/tm-ui/components/tm-html/mp-node.vue') const script = fs.readFileSync(filename, 'utf8').match(/