瀏覽代碼

test: add team background mini program rules

Developer 3 天之前
父節點
當前提交
4b4494f9b5
共有 4 個文件被更改,包括 336 次插入6 次删除
  1. 79 0
      http/teamBackgroundFile.js
  2. 9 6
      package.json
  3. 222 0
      tests/teamBackgroundFile.test.js
  4. 26 0
      utils/teamBackgroundFile.js

+ 79 - 0
http/teamBackgroundFile.js

@@ -0,0 +1,79 @@
+import { BaseApi } from './baseApi.js'
+import api from './index.js'
+
+function parseResult(response) {
+	let result = response && response.data
+	if (typeof result === 'string') {
+		try {
+			result = JSON.parse(result)
+		} catch (error) {
+			throw new Error('上传失败,请重试')
+		}
+	}
+	if (!response || response.statusCode !== 200 || !result || result.code !== 0) {
+		throw new Error(result && result.msg ? result.msg : '上传失败,请重试')
+	}
+	return result.data
+}
+
+function unwrap(response) {
+	const result = response && response.data
+	if (!result || result.code !== 0) {
+		throw new Error(result && result.msg ? result.msg : '请求失败,请重试')
+	}
+	return result.data
+}
+
+export function uploadTeamBackgroundFile(teamId, filePath, onProgress = () => {}) {
+	return new Promise((resolve, reject) => {
+		const task = uni.uploadFile({
+			url: `${BaseApi}/core/user/team/${teamId}/background-files`,
+			filePath,
+			name: 'file',
+			header: { token: uni.getStorageSync('token') },
+			success: response => {
+				try {
+					resolve(parseResult(response))
+				} catch (error) {
+					reject(error)
+				}
+			},
+			fail: reject
+		})
+		task.onProgressUpdate(progress => onProgress(progress.progress))
+	})
+}
+
+export const listTeamBackgroundFiles = teamId => api
+	.get(`/core/user/team/${teamId}/background-files`, {}, false)
+	.then(unwrap)
+
+export const disableTeamBackgroundFile = (teamId, fileId) => api
+	.del(`/core/user/team/${teamId}/background-files/${fileId}`, {}, false)
+	.then(unwrap)
+
+export const createTeamBackgroundSession = teamId => api
+	.post(`/core/user/team/${teamId}/background-upload-session`, {}, false)
+	.then(unwrap)
+
+export function downloadTeamBackgroundFile(teamId, fileId) {
+	return new Promise((resolve, reject) => {
+		uni.downloadFile({
+			url: `${BaseApi}/core/user/team/${teamId}/background-files/${fileId}/download`,
+			header: { token: uni.getStorageSync('token') },
+			success: result => {
+				if (result.statusCode !== 200) {
+					reject(new Error('下载失败,请重试'))
+					return
+				}
+				wx.openDocument({
+					filePath: result.tempFilePath,
+					showMenu: true,
+					success: resolve,
+					fail: reject
+				})
+			},
+			fail: reject
+		})
+	})
+}

+ 9 - 6
package.json

@@ -1,6 +1,9 @@
-{
-  "dependencies": {
-    "qrcode": "^1.5.4",
-    "text-encoding-shim": "^1.0.5"
-  }
-}
+{
+  "scripts": {
+    "test:team-background": "node tests/teamBackgroundFile.test.js"
+  },
+  "dependencies": {
+    "qrcode": "^1.5.4",
+    "text-encoding-shim": "^1.0.5"
+  }
+}

+ 222 - 0
tests/teamBackgroundFile.test.js

@@ -0,0 +1,222 @@
+const assert = require('node:assert/strict')
+const fs = require('node:fs')
+const path = require('node:path')
+const vm = require('node:vm')
+const rules = require('../utils/teamBackgroundFile')
+
+assert.equal(rules.validateEnterpriseWebsite(' 无 '), '')
+assert.equal(rules.validateEnterpriseWebsite('https://example.com'), '')
+assert.match(rules.validateEnterpriseWebsite('ftp://example.com'), /http/)
+assert.equal(rules.validateBackgroundFile({ name: 'brief.PDF', size: 1 }), '')
+assert.match(rules.validateBackgroundFile({ name: 'brief.zip', size: 1 }), /类型/)
+assert.match(rules.validateBackgroundFile({ name: 'brief.pdf', size: 50 * 1024 * 1024 + 1 }), /50MB/)
+
+console.log('team background rules: PASS')
+
+const transportPath = path.join(__dirname, '../http/teamBackgroundFile.js')
+
+function loadTransport({ api = {}, uni = {}, wx = {} } = {}) {
+	const source = fs.readFileSync(transportPath, 'utf8')
+		.replace(/import\s+\{\s*BaseApi\s*\}\s+from\s+['"]\.\/baseApi\.js['"]\s*/, '')
+		.replace(/import\s+api\s+from\s+['"]\.\/index\.js['"]\s*/, '')
+		.replace(/export\s+function\s+/g, 'function ')
+		.replace(/export\s+const\s+/g, 'const ')
+		.concat(`
+			module.exports = {
+				uploadTeamBackgroundFile,
+				listTeamBackgroundFiles,
+				disableTeamBackgroundFile,
+				createTeamBackgroundSession,
+				downloadTeamBackgroundFile
+			}
+		`)
+	const module = { exports: {} }
+
+	vm.runInNewContext(source, {
+		module,
+		exports: module.exports,
+		BaseApi: 'https://api.example.test/app',
+		api,
+		uni,
+		wx
+	}, { filename: transportPath })
+
+	return module.exports
+}
+
+function assertNoIdentityFields(value) {
+	if (!value || typeof value !== 'object') return
+	for (const [key, child] of Object.entries(value)) {
+		assert.ok(!['source', 'coachId', 'uploaderId'].includes(key), `unexpected identity field: ${key}`)
+		assertNoIdentityFields(child)
+	}
+}
+
+function createUploadHarness(response, progress = 37) {
+	let request
+	const progressValues = []
+	const uni = {
+		getStorageSync(key) {
+			assert.equal(key, 'token')
+			return 'token-123'
+		},
+		uploadFile(options) {
+			request = options
+			return {
+				onProgressUpdate(callback) {
+					callback({ progress })
+					setImmediate(() => options.success(response))
+				}
+			}
+		}
+	}
+	const transport = loadTransport({ uni })
+
+	return {
+		request: () => request,
+		progressValues,
+		promise: transport.uploadTeamBackgroundFile(12, '/tmp/brief.pdf', value => progressValues.push(value))
+	}
+}
+
+async function testUploadTransport() {
+	const stringHarness = createUploadHarness({
+		statusCode: 200,
+		data: JSON.stringify({ code: 0, data: { id: 7 } })
+	})
+	assert.equal((await stringHarness.promise).id, 7)
+	assert.equal(stringHarness.request().url, 'https://api.example.test/app/core/user/team/12/background-files')
+	assert.equal(stringHarness.request().filePath, '/tmp/brief.pdf')
+	assert.equal(stringHarness.request().name, 'file')
+	assert.equal(stringHarness.request().header.token, 'token-123')
+	assert.deepEqual(stringHarness.progressValues, [37])
+	assertNoIdentityFields(stringHarness.request())
+
+	const objectHarness = createUploadHarness({ statusCode: 200, data: { code: 0, data: { id: 8 } } })
+	assert.equal((await objectHarness.promise).id, 8)
+
+	const statusHarness = createUploadHarness({ statusCode: 500, data: { code: 0 } })
+	await assert.rejects(statusHarness.promise, /上传失败,请重试/)
+
+	const codeHarness = createUploadHarness({ statusCode: 200, data: { code: 9, msg: '上传业务失败' } })
+	await assert.rejects(codeHarness.promise, /上传业务失败/)
+}
+
+async function testApiTransport() {
+	const calls = []
+	const api = {
+		get(...args) {
+			calls.push(['get', ...args])
+			return Promise.resolve({ data: { code: 0, data: [{ id: 1 }] } })
+		},
+		del(...args) {
+			calls.push(['del', ...args])
+			return Promise.resolve({ data: { code: 0, data: true } })
+		},
+		post(...args) {
+			calls.push(['post', ...args])
+			return Promise.resolve({ data: { code: 0, data: { sessionId: 'session-1' } } })
+		}
+	}
+	const transport = loadTransport({ api })
+
+	assert.deepEqual(await transport.listTeamBackgroundFiles(12), [{ id: 1 }])
+	assert.equal(await transport.disableTeamBackgroundFile(12, 34), true)
+	assert.deepEqual(await transport.createTeamBackgroundSession(12), { sessionId: 'session-1' })
+
+	assert.equal(calls[0][0], 'get')
+	assert.equal(calls[0][1], '/core/user/team/12/background-files')
+	assert.equal(calls[1][0], 'del')
+	assert.equal(calls[1][1], '/core/user/team/12/background-files/34')
+	assert.equal(calls[2][0], 'post')
+	assert.equal(calls[2][1], '/core/user/team/12/background-upload-session')
+	for (const call of calls) {
+		assert.equal(Object.keys(call[2]).length, 0)
+		assert.equal(call[3], false)
+		assertNoIdentityFields(call)
+	}
+
+	const failingTransport = loadTransport({
+		api: {
+			get: () => Promise.resolve({ data: { code: 3, msg: '列表业务失败' } })
+		}
+	})
+	await assert.rejects(failingTransport.listTeamBackgroundFiles(12), /列表业务失败/)
+
+	assert.equal(transport.uploadTeamBackgroundFile.length, 2)
+	assert.equal(transport.listTeamBackgroundFiles.length, 1)
+	assert.equal(transport.disableTeamBackgroundFile.length, 2)
+	assert.equal(transport.createTeamBackgroundSession.length, 1)
+	assert.equal(transport.downloadTeamBackgroundFile.length, 2)
+}
+
+function createDownloadHarness({ result, downloadError, openError } = {}) {
+	let request
+	let openRequest
+	const uni = {
+		getStorageSync(key) {
+			assert.equal(key, 'token')
+			return 'token-456'
+		},
+		downloadFile(options) {
+			request = options
+			setImmediate(() => {
+				if (downloadError) options.fail(downloadError)
+				else options.success(result)
+			})
+		}
+	}
+	const wx = {
+		openDocument(options) {
+			openRequest = options
+			setImmediate(() => {
+				if (openError) options.fail(openError)
+				else options.success('opened')
+			})
+		}
+	}
+	const transport = loadTransport({ uni, wx })
+
+	return {
+		request: () => request,
+		openRequest: () => openRequest,
+		promise: transport.downloadTeamBackgroundFile(12, 34)
+	}
+}
+
+async function testDownloadTransport() {
+	const successHarness = createDownloadHarness({ result: { statusCode: 200, tempFilePath: '/tmp/download.pdf' } })
+	assert.equal(await successHarness.promise, 'opened')
+	assert.equal(successHarness.request().url, 'https://api.example.test/app/core/user/team/12/background-files/34/download')
+	assert.equal(successHarness.request().header.token, 'token-456')
+	assert.equal(successHarness.openRequest().filePath, '/tmp/download.pdf')
+	assert.equal(successHarness.openRequest().showMenu, true)
+	assertNoIdentityFields(successHarness.request())
+
+	const statusHarness = createDownloadHarness({ result: { statusCode: 500 } })
+	await assert.rejects(statusHarness.promise, /下载失败,请重试/)
+	assert.equal(statusHarness.openRequest(), undefined)
+
+	const downloadError = new Error('download network error')
+	const downloadFailureHarness = createDownloadHarness({ downloadError })
+	await assert.rejects(downloadFailureHarness.promise, /download network error/)
+
+	const openError = new Error('open document error')
+	const openFailureHarness = createDownloadHarness({
+		result: { statusCode: 200, tempFilePath: '/tmp/download.pdf' },
+		openError
+	})
+	await assert.rejects(openFailureHarness.promise, /open document error/)
+}
+
+async function main() {
+	await testUploadTransport()
+	await testApiTransport()
+	await testDownloadTransport()
+	console.log('team background transport: PASS')
+}
+
+main().catch(error => {
+	console.error(error)
+	process.exitCode = 1
+})

+ 26 - 0
utils/teamBackgroundFile.js

@@ -0,0 +1,26 @@
+const ALLOWED_EXTENSIONS = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md', 'csv']
+const MAX_FILE_SIZE = 50 * 1024 * 1024
+
+function validateEnterpriseWebsite(value) {
+	const normalized = String(value || '').trim()
+	if (!normalized) return '请输入企业官网,无官网请填写“无”'
+	if (normalized === '无') return ''
+	if (!/^https?:\/\/[^/\s?#]+(?:[/?#][^\s]*)?$/i.test(normalized)) return '请输入以http://或https://开头的企业官网'
+	return ''
+}
+
+function validateBackgroundFile(file) {
+	if (!file || !file.name || !file.size) return '请选择非空文件'
+	if (file.name.length > 255) return '文件名不能超过255个字符'
+	const ext = file.name.includes('.') ? file.name.split('.').pop().toLowerCase() : ''
+	if (!ALLOWED_EXTENSIONS.includes(ext)) return '文件类型不支持'
+	if (file.size > MAX_FILE_SIZE) return '单个文件不能超过50MB'
+	return ''
+}
+
+module.exports = {
+	ALLOWED_EXTENSIONS,
+	MAX_FILE_SIZE,
+	validateEnterpriseWebsite,
+	validateBackgroundFile
+}