Forráskód Böngészése

test: add team background frontend rules

Developer 3 napja
szülő
commit
c7c043819e
6 módosított fájl, 28834 hozzáadás és 15133 törlés
  1. 13 0
      .eslintrc.cjs
  2. 28655 15131
      package-lock.json
  3. 20 2
      package.json
  4. 25 0
      src/api/teamBackgroundFile.js
  5. 19 0
      src/utils/teamBackgroundFile.js
  6. 102 0
      tests/unit/teamBackgroundFile.spec.js

+ 13 - 0
.eslintrc.cjs

@@ -0,0 +1,13 @@
+module.exports = {
+  root: true,
+  env: { browser: true, node: true, jest: true, es2021: true },
+  extends: ['eslint:recommended', 'plugin:vue/essential'],
+  parser: 'vue-eslint-parser',
+  parserOptions: { parser: '@babel/eslint-parser', requireConfigFile: false, sourceType: 'module' },
+  globals: { defineProps: 'readonly', uni: 'readonly', wx: 'readonly' },
+  rules: {
+    'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
+    'no-empty': ['error', { allowEmptyCatch: true }],
+    'vue/multi-word-component-names': 'off'
+  }
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 28655 - 15131
package-lock.json


+ 20 - 2
package.json

@@ -3,13 +3,13 @@
   "version": "2.5.0",
   "private": true,
   "scripts": {
-    "test": "jest",
+    "test": "jest --runInBand",
     "serve": "vue-cli-service serve",
     "build": "vue-cli-service build",
     "build:sit": "vue-cli-service build --mode production.sit",
     "build:uat": "vue-cli-service build --mode production.uat",
     "build:prod": "vue-cli-service build --mode production",
-    "lint": "vue-cli-service lint",
+    "lint": "eslint --no-error-on-unmatched-pattern --ext .js,.vue src/api/teamBackgroundFile.js src/router/index.js src/utils/teamBackgroundFile.js src/components/team-background src/views/modules/wechatUser/teamManager.vue src/views/pages/team-background-upload.vue",
     "et": "node_modules/.bin/et",
     "et:init": "node_modules/.bin/et -i",
     "et:list": "gulp themes"
@@ -58,11 +58,17 @@
     "xlsx": "^0.18.5"
   },
   "devDependencies": {
+    "@babel/eslint-parser": "^7.27.5",
     "@vue/cli-plugin-babel": "~5.0.8",
     "@vue/cli-plugin-router": "~5.0.8",
     "@vue/cli-service": "~5.0.8",
+    "babel-jest": "^29.7.0",
     "element-theme-chalk": "^2.11.1",
+    "eslint": "^8.57.1",
+    "eslint-plugin-vue": "^9.33.0",
+    "jest": "^29.7.0",
     "natives": "^1.1.6",
+    "vue-eslint-parser": "^9.4.3",
     "vue-template-compiler": "^2.6.10"
   },
   "postcss": {
@@ -91,5 +97,17 @@
   },
   "overrides": {
     "node-sass": "^9.0.0"
+  },
+  "jest": {
+    "testEnvironment": "node",
+    "testMatch": [
+      "**/tests/unit/**/*.spec.js"
+    ],
+    "transform": {
+      "^.+\\.js$": "babel-jest"
+    },
+    "moduleNameMapper": {
+      "^@/(.*)$": "<rootDir>/src/$1"
+    }
   }
 }

+ 25 - 0
src/api/teamBackgroundFile.js

@@ -0,0 +1,25 @@
+import request from '@/utils/request2'
+
+export const listTeamBackgroundFiles = teamId => request({ url: `/core/userteam/${teamId}/background-files`, method: 'get' })
+export const createTeamBackgroundSession = teamId => request({ url: `/core/userteam/${teamId}/background-upload-session`, method: 'post' })
+export const disableTeamBackgroundFile = (teamId, fileId) => request({ url: `/core/userteam/${teamId}/background-files/${fileId}`, method: 'delete' })
+export const downloadTeamBackgroundFile = (teamId, fileId) => request({ url: `/core/userteam/${teamId}/background-files/${fileId}/download`, method: 'get', responseType: 'blob' })
+
+export function uploadTeamBackgroundFile(teamId, file) {
+  const data = new FormData()
+  data.append('file', file)
+  return request({ url: `/core/userteam/${teamId}/background-files`, method: 'post', data })
+}
+
+export const getPublicUploadSession = token => request({ url: '/public/team-background-upload/session', method: 'get', params: { token } })
+export const verifyPublicUploadCode = code => request({ url: '/public/team-background-upload/verify', method: 'post', data: { code } })
+export const completePublicUpload = token => request({ url: '/public/team-background-upload/complete', method: 'post', headers: { 'X-Upload-Token': token } })
+
+export function uploadPublicTeamBackgroundFile(token, file, onProgress) {
+  const data = new FormData()
+  data.append('file', file)
+  return request({
+    url: '/public/team-background-upload/files', method: 'post', data,
+    headers: { 'X-Upload-Token': token }, onUploadProgress: onProgress
+  })
+}

+ 19 - 0
src/utils/teamBackgroundFile.js

@@ -0,0 +1,19 @@
+export const ALLOWED_EXTENSIONS = ['pdf','doc','docx','xls','xlsx','ppt','pptx','txt','md','csv']
+export const ACCEPT = ALLOWED_EXTENSIONS.map(ext => `.${ext}`).join(',')
+export const MAX_FILE_SIZE = 50 * 1024 * 1024
+
+export function validateBackgroundFile(file) {
+  if (!file || !file.name || file.size === 0) 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 ''
+}
+
+export function formatFileSize(bytes) {
+  if (!bytes) return '0 B'
+  if (bytes < 1024) return `${bytes} B`
+  if (bytes < 1024 * 1024) return `${Number((bytes / 1024).toFixed(1))} KB`
+  return `${Number((bytes / 1024 / 1024).toFixed(1))} MB`
+}

+ 102 - 0
tests/unit/teamBackgroundFile.spec.js

@@ -0,0 +1,102 @@
+import { formatFileSize, validateBackgroundFile } from '@/utils/teamBackgroundFile'
+import request from '@/utils/request2'
+import {
+  completePublicUpload,
+  createTeamBackgroundSession,
+  disableTeamBackgroundFile,
+  downloadTeamBackgroundFile,
+  getPublicUploadSession,
+  listTeamBackgroundFiles,
+  uploadPublicTeamBackgroundFile,
+  uploadTeamBackgroundFile,
+  verifyPublicUploadCode
+} from '@/api/teamBackgroundFile'
+
+jest.mock('@/utils/request2', () => jest.fn())
+
+class TestFormData {
+  constructor() {
+    this.entries = []
+  }
+
+  append(name, value) {
+    this.entries.push([name, value])
+  }
+}
+
+global.FormData = TestFormData
+
+beforeEach(() => {
+  request.mockReset()
+})
+
+test('accepts all approved extensions case-insensitively', () => {
+  for (const ext of ['pdf','doc','docx','xls','xlsx','ppt','pptx','txt','md','csv']) {
+    expect(validateBackgroundFile({ name: `file.${ext.toUpperCase()}`, size: 1 })).toBe('')
+  }
+})
+
+test('rejects archives, 50MB overflow and names over 255 chars', () => {
+  expect(validateBackgroundFile({ name: 'file.zip', size: 1 })).toContain('文件类型')
+  expect(validateBackgroundFile({ name: 'file.pdf', size: 50 * 1024 * 1024 + 1 })).toContain('50MB')
+  expect(validateBackgroundFile({ name: `${'a'.repeat(252)}.pdf`, size: 1 })).toContain('255')
+})
+
+test('formats byte counts for the table', () => {
+  expect(formatFileSize(0)).toBe('0 B')
+  expect(formatFileSize(1536)).toBe('1.5 KB')
+})
+
+test('uses backend-controlled authenticated file routes', () => {
+  listTeamBackgroundFiles(7)
+  createTeamBackgroundSession(7)
+  disableTeamBackgroundFile(7, 12)
+  downloadTeamBackgroundFile(7, 12)
+
+  expect(request.mock.calls).toEqual([
+    [{ url: '/core/userteam/7/background-files', method: 'get' }],
+    [{ url: '/core/userteam/7/background-upload-session', method: 'post' }],
+    [{ url: '/core/userteam/7/background-files/12', method: 'delete' }],
+    [{ url: '/core/userteam/7/background-files/12/download', method: 'get', responseType: 'blob' }]
+  ])
+})
+
+test('uploads authenticated files without client-supplied identity fields', () => {
+  const file = { name: 'brief.pdf' }
+
+  uploadTeamBackgroundFile(7, file)
+
+  const config = request.mock.calls[0][0]
+  expect(config).toEqual({
+    url: '/core/userteam/7/background-files',
+    method: 'post',
+    data: expect.any(TestFormData)
+  })
+  expect(config.data.entries).toEqual([['file', file]])
+})
+
+test('uses fixed public routes and sends only server-issued credentials', () => {
+  const file = { name: 'brief.pdf' }
+  const onProgress = jest.fn()
+
+  getPublicUploadSession('session-token')
+  verifyPublicUploadCode('123456')
+  completePublicUpload('upload-token')
+  uploadPublicTeamBackgroundFile('upload-token', file, onProgress)
+
+  const uploadData = request.mock.calls[3][0].data
+  expect(request.mock.calls).toEqual([
+    [{ url: '/public/team-background-upload/session', method: 'get', params: { token: 'session-token' } }],
+    [{ url: '/public/team-background-upload/verify', method: 'post', data: { code: '123456' } }],
+    [{ url: '/public/team-background-upload/complete', method: 'post', headers: { 'X-Upload-Token': 'upload-token' } }],
+    [{
+      url: '/public/team-background-upload/files',
+      method: 'post',
+      data: uploadData,
+      headers: { 'X-Upload-Token': 'upload-token' },
+      onUploadProgress: onProgress
+    }]
+  ])
+  expect(uploadData).toEqual(expect.any(TestFormData))
+  expect(uploadData.entries).toEqual([['file', file]])
+})