teamBackgroundFile.test.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. const assert = require('node:assert/strict')
  2. const fs = require('node:fs')
  3. const path = require('node:path')
  4. const { pathToFileURL } = require('node:url')
  5. const vm = require('node:vm')
  6. const rules = require('../utils/teamBackgroundFile')
  7. assert.equal(rules.validateEnterpriseWebsite(' 无 '), '')
  8. assert.equal(rules.validateEnterpriseWebsite('https://example.com'), '')
  9. assert.match(rules.validateEnterpriseWebsite('ftp://example.com'), /http/)
  10. assert.equal(rules.validateBackgroundFile({ name: 'brief.PDF', size: 1 }), '')
  11. assert.match(rules.validateBackgroundFile({ name: 'brief.zip', size: 1 }), /类型/)
  12. assert.match(rules.validateBackgroundFile({ name: 'brief.pdf', size: 50 * 1024 * 1024 + 1 }), /50MB/)
  13. assert.equal(rules.validateBackgroundFile({ name: 'brief.pdf', size: 50 * 1024 * 1024 }), '')
  14. assert.equal(rules.validateBackgroundFile({ name: `${'a'.repeat(251)}.pdf`, size: 1 }), '')
  15. assert.match(rules.validateBackgroundFile({ name: `${'a'.repeat(252)}.pdf`, size: 1 }), /255/)
  16. assert.match(rules.validateBackgroundFile({ name: 'empty.pdf', size: 0 }), /非空/)
  17. console.log('team background rules: PASS')
  18. const transportPath = path.join(__dirname, '../http/teamBackgroundFile.js')
  19. async function loadTransport({ api = {}, uni = {}, wx = {} } = {}) {
  20. const source = fs.readFileSync(transportPath, 'utf8')
  21. const context = vm.createContext({ uni, wx })
  22. const baseApiModule = new vm.SyntheticModule(['BaseApi'], function () {
  23. this.setExport('BaseApi', 'https://api.example.test/app')
  24. }, { context, identifier: 'test:baseApi' })
  25. const apiModule = new vm.SyntheticModule(['default'], function () {
  26. this.setExport('default', api)
  27. }, { context, identifier: 'test:api' })
  28. const transportModule = new vm.SourceTextModule(source, {
  29. context,
  30. identifier: pathToFileURL(transportPath).href
  31. })
  32. await transportModule.link(specifier => {
  33. if (specifier === './baseApi.js') return baseApiModule
  34. if (specifier === './index.js') return apiModule
  35. throw new Error(`unexpected transport import: ${specifier}`)
  36. })
  37. await transportModule.evaluate()
  38. return transportModule.namespace
  39. }
  40. function assertNoIdentityFields(value) {
  41. if (!value || typeof value !== 'object') return
  42. for (const [key, child] of Object.entries(value)) {
  43. assert.ok(!['source', 'coachId', 'uploaderId'].includes(key), `unexpected identity field: ${key}`)
  44. assertNoIdentityFields(child)
  45. }
  46. }
  47. async function createUploadHarness(response, progress = 37) {
  48. let request
  49. const progressValues = []
  50. const uni = {
  51. getStorageSync(key) {
  52. assert.equal(key, 'token')
  53. return 'token-123'
  54. },
  55. uploadFile(options) {
  56. request = options
  57. return {
  58. onProgressUpdate(callback) {
  59. callback({ progress })
  60. setImmediate(() => options.success(response))
  61. }
  62. }
  63. }
  64. }
  65. const transport = await loadTransport({ uni })
  66. return {
  67. request: () => request,
  68. progressValues,
  69. promise: transport.uploadTeamBackgroundFile(12, '/tmp/brief.pdf', value => progressValues.push(value))
  70. }
  71. }
  72. async function testUploadTransport() {
  73. const stringHarness = await createUploadHarness({
  74. statusCode: 200,
  75. data: JSON.stringify({ code: 0, data: { id: 7 } })
  76. })
  77. assert.equal((await stringHarness.promise).id, 7)
  78. assert.equal(stringHarness.request().url, 'https://api.example.test/app/core/user/team/12/background-files')
  79. assert.equal(stringHarness.request().filePath, '/tmp/brief.pdf')
  80. assert.equal(stringHarness.request().name, 'file')
  81. assert.equal(stringHarness.request().header.token, 'token-123')
  82. assert.deepEqual(stringHarness.progressValues, [37])
  83. assertNoIdentityFields(stringHarness.request())
  84. const objectHarness = await createUploadHarness({ statusCode: 200, data: { code: 0, data: { id: 8 } } })
  85. assert.equal((await objectHarness.promise).id, 8)
  86. const statusHarness = await createUploadHarness({ statusCode: 500, data: { code: 0 } })
  87. await assert.rejects(statusHarness.promise, /上传失败,请重试/)
  88. const codeHarness = await createUploadHarness({ statusCode: 200, data: { code: 9, msg: '上传业务失败' } })
  89. await assert.rejects(codeHarness.promise, /上传业务失败/)
  90. const invalidJsonHarness = await createUploadHarness({ statusCode: 200, data: '<invalid-json>' })
  91. await assert.rejects(invalidJsonHarness.promise, /上传失败,请重试/)
  92. }
  93. async function testApiTransport() {
  94. const calls = []
  95. const api = {
  96. get(...args) {
  97. calls.push(['get', ...args])
  98. return Promise.resolve({ data: { code: 0, data: [{ id: 1 }] } })
  99. },
  100. del(...args) {
  101. calls.push(['del', ...args])
  102. return Promise.resolve({ data: { code: 0, data: true } })
  103. },
  104. post(...args) {
  105. calls.push(['post', ...args])
  106. return Promise.resolve({ data: { code: 0, data: { sessionId: 'session-1' } } })
  107. }
  108. }
  109. const transport = await loadTransport({ api })
  110. assert.deepEqual(await transport.listTeamBackgroundFiles(12), [{ id: 1 }])
  111. assert.equal(await transport.disableTeamBackgroundFile(12, 34), true)
  112. assert.deepEqual(await transport.createTeamBackgroundSession(12), { sessionId: 'session-1' })
  113. assert.equal(calls[0][0], 'get')
  114. assert.equal(calls[0][1], '/core/user/team/12/background-files')
  115. assert.equal(calls[1][0], 'del')
  116. assert.equal(calls[1][1], '/core/user/team/12/background-files/34')
  117. assert.equal(calls[2][0], 'post')
  118. assert.equal(calls[2][1], '/core/user/team/12/background-upload-session')
  119. for (const call of calls) {
  120. assert.equal(Object.keys(call[2]).length, 0)
  121. assert.equal(call[3], false)
  122. assertNoIdentityFields(call)
  123. }
  124. const failingTransport = await loadTransport({
  125. api: {
  126. get: () => Promise.resolve({ data: { code: 3, msg: '列表业务失败' } })
  127. }
  128. })
  129. await assert.rejects(failingTransport.listTeamBackgroundFiles(12), /列表业务失败/)
  130. assert.equal(transport.uploadTeamBackgroundFile.length, 2)
  131. assert.equal(transport.listTeamBackgroundFiles.length, 1)
  132. assert.equal(transport.disableTeamBackgroundFile.length, 2)
  133. assert.equal(transport.createTeamBackgroundSession.length, 1)
  134. assert.equal(transport.downloadTeamBackgroundFile.length, 2)
  135. }
  136. async function createDownloadHarness({ result, responseHeaders, downloadError, openError,
  137. withHeadersListener = true } = {}) {
  138. let request
  139. let openRequest
  140. const uni = {
  141. getStorageSync(key) {
  142. assert.equal(key, 'token')
  143. return 'token-456'
  144. },
  145. downloadFile(options) {
  146. request = options
  147. setImmediate(() => {
  148. if (downloadError) options.fail(downloadError)
  149. else options.success(result)
  150. })
  151. if (!withHeadersListener) return {}
  152. return {
  153. onHeadersReceived(callback) {
  154. if (responseHeaders) callback({ header: responseHeaders })
  155. }
  156. }
  157. }
  158. }
  159. const wx = {
  160. openDocument(options) {
  161. openRequest = options
  162. setImmediate(() => {
  163. if (openError) options.fail(openError)
  164. else options.success('opened')
  165. })
  166. }
  167. }
  168. const transport = await loadTransport({ uni, wx })
  169. return {
  170. request: () => request,
  171. openRequest: () => openRequest,
  172. promise: transport.downloadTeamBackgroundFile(12, 34)
  173. }
  174. }
  175. async function testDownloadTransport() {
  176. const successHarness = await createDownloadHarness({
  177. result: { statusCode: 200, tempFilePath: '/tmp/download.pdf' },
  178. responseHeaders: {
  179. 'cOnTeNt-TyPe': 'application/pdf',
  180. 'CONTENT-disPOSITION': 'attachment; filename="download.pdf"'
  181. }
  182. })
  183. assert.equal(await successHarness.promise, 'opened')
  184. assert.equal(successHarness.request().url, 'https://api.example.test/app/core/user/team/12/background-files/34/download')
  185. assert.equal(successHarness.request().header.token, 'token-456')
  186. assert.equal(successHarness.openRequest().filePath, '/tmp/download.pdf')
  187. assert.equal(successHarness.openRequest().showMenu, true)
  188. assertNoIdentityFields(successHarness.request())
  189. const resultHeaderHarness = await createDownloadHarness({
  190. result: {
  191. statusCode: 200,
  192. tempFilePath: '/tmp/result-header.docx',
  193. header: {
  194. 'content-type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  195. 'content-disposition': 'attachment; filename="result-header.docx"'
  196. }
  197. },
  198. withHeadersListener: false
  199. })
  200. assert.equal(await resultHeaderHarness.promise, 'opened')
  201. const resultHeadersHarness = await createDownloadHarness({
  202. result: {
  203. statusCode: 200,
  204. tempFilePath: '/tmp/result-headers.txt',
  205. headers: {
  206. 'Content-Type': 'text/plain; charset=UTF-8',
  207. 'Content-Disposition': 'attachment; filename="result-headers.txt"'
  208. }
  209. },
  210. withHeadersListener: false
  211. })
  212. assert.equal(await resultHeadersHarness.promise, 'opened')
  213. const jsonHarness = await createDownloadHarness({
  214. result: { statusCode: 200, tempFilePath: '/tmp/error.json' },
  215. responseHeaders: {
  216. 'Content-Type': 'application/json;charset=UTF-8',
  217. 'Content-Disposition': 'attachment; filename="error.json"'
  218. }
  219. })
  220. await assert.rejects(jsonHarness.promise, /下载失败,请重试/)
  221. assert.equal(jsonHarness.openRequest(), undefined)
  222. const htmlHarness = await createDownloadHarness({
  223. result: { statusCode: 200, tempFilePath: '/tmp/error.html' },
  224. responseHeaders: { 'content-type': 'text/html; charset=UTF-8' }
  225. })
  226. await assert.rejects(htmlHarness.promise, /下载失败,请重试/)
  227. assert.equal(htmlHarness.openRequest(), undefined)
  228. const missingHeadersHarness = await createDownloadHarness({
  229. result: { statusCode: 200, tempFilePath: '/tmp/unknown.pdf' },
  230. withHeadersListener: false
  231. })
  232. await assert.rejects(missingHeadersHarness.promise, /下载失败,请重试/)
  233. assert.equal(missingHeadersHarness.openRequest(), undefined)
  234. const statusHarness = await createDownloadHarness({ result: { statusCode: 500 } })
  235. await assert.rejects(statusHarness.promise, /下载失败,请重试/)
  236. assert.equal(statusHarness.openRequest(), undefined)
  237. const downloadError = new Error('download network error')
  238. const downloadFailureHarness = await createDownloadHarness({ downloadError })
  239. await assert.rejects(downloadFailureHarness.promise, /download network error/)
  240. const openError = new Error('open document error')
  241. const openFailureHarness = await createDownloadHarness({
  242. result: { statusCode: 200, tempFilePath: '/tmp/download.pdf' },
  243. responseHeaders: {
  244. 'Content-Type': 'application/pdf',
  245. 'Content-Disposition': 'attachment; filename="download.pdf"'
  246. },
  247. openError
  248. })
  249. await assert.rejects(openFailureHarness.promise, /open document error/)
  250. }
  251. async function main() {
  252. const loadedTransport = await loadTransport()
  253. assert.equal(typeof loadedTransport.downloadTeamBackgroundFile, 'function')
  254. await testUploadTransport()
  255. await testApiTransport()
  256. await testDownloadTransport()
  257. console.log('team background transport: PASS')
  258. }
  259. main().catch(error => {
  260. console.error(error)
  261. process.exitCode = 1
  262. })