Prechádzať zdrojové kódy

fix: isolate loading interceptors per request

Developer 2 mesiacov pred
rodič
commit
078cdd2d08
2 zmenil súbory, kde vykonal 61 pridanie a 7 odobranie
  1. 7 7
      http/interface.js
  2. 54 0
      tests/teamBackgroundFile.test.js

+ 7 - 7
http/interface.js

@@ -29,7 +29,9 @@ export default {
 		options.url = options.baseUrl + options.url
 		options.data = options.data || {}
 		options.method = options.method || this.config.method
-		
+		const requestInterceptor = this.interceptor.request
+		const responseInterceptor = this.interceptor.response
+
 		return new Promise((resolve, reject) => {
 			let _config = null
 			
@@ -41,9 +43,8 @@ export default {
 						////console.log("【" + _config.requestId + "】 结果:" + JSON.stringify(response.data))
 					}
 				}
-				if (this.interceptor.response) {
-					
-					let newResponse = this.interceptor.response(response)
+				if (responseInterceptor) {
+					let newResponse = responseInterceptor(response)
 					if (newResponse) {
 						response = newResponse
 					}
@@ -60,8 +61,8 @@ export default {
 			_config = Object.assign({}, this.config, options)
 			_config.requestId = new Date().getTime()
 
-			if (this.interceptor.request) {
-				this.interceptor.request(_config)
+			if (requestInterceptor) {
+				requestInterceptor(_config)
 			}
 			
 			// 统一的请求日志记录
@@ -117,4 +118,3 @@ function _reslog(res) {
 			break;
 	}
 }
-

+ 54 - 0
tests/teamBackgroundFile.test.js

@@ -141,6 +141,8 @@ for (const item of [
 console.log('team background rules: PASS')
 
 const transportPath = path.join(__dirname, '../http/teamBackgroundFile.js')
+const httpInterfacePath = path.join(__dirname, '../http/interface.js')
+const httpIndexPath = path.join(__dirname, '../http/index.js')
 
 async function loadTransport({ api = {}, uni = {}, wx = {} } = {}) {
 	const source = fs.readFileSync(transportPath, 'utf8')
@@ -166,6 +168,57 @@ async function loadTransport({ api = {}, uni = {}, wx = {} } = {}) {
 	return transportModule.namespace
 }
 
+async function loadHttpApi(uni) {
+	const context = vm.createContext({
+		uni,
+		process: { env: { NODE_ENV: 'test' } }
+	})
+	const baseApiModule = new vm.SyntheticModule(['BaseApi'], function () {
+		this.setExport('BaseApi', 'https://api.example.test/app')
+	}, { context, identifier: 'test:httpBaseApi' })
+	const interfaceModule = new vm.SourceTextModule(
+		fs.readFileSync(httpInterfacePath, 'utf8'),
+		{ context, identifier: pathToFileURL(httpInterfacePath).href }
+	)
+	const indexModule = new vm.SourceTextModule(
+		fs.readFileSync(httpIndexPath, 'utf8'),
+		{ context, identifier: pathToFileURL(httpIndexPath).href }
+	)
+	await indexModule.link((specifier, referencingModule) => {
+		if (referencingModule === indexModule && specifier === './interface') return interfaceModule
+		if (referencingModule === interfaceModule && specifier === './baseApi.js') return baseApiModule
+		throw new Error(`unexpected http import: ${specifier}`)
+	})
+	await indexModule.evaluate()
+	return indexModule.namespace.default
+}
+
+async function testConcurrentSilentRequestDoesNotStrandLoadingMask() {
+	const requests = []
+	let shown = 0
+	let hidden = 0
+	const api = await loadHttpApi({
+		showLoading() { shown += 1 },
+		hideLoading() { hidden += 1 },
+		getStorageSync() { return '' },
+		request(options) { requests.push(options) }
+	})
+
+	const visibleRequest = api.get('/visible', {}, true)
+	const silentRequest = api.get('/silent', {}, false)
+	assert.equal(shown, 1)
+	assert.equal(hidden, 0)
+	assert.equal(requests.length, 2)
+
+	requests[1].complete({ statusCode: 200, data: { code: 0, data: [] } })
+	await silentRequest
+	assert.equal(hidden, 0, 'a silent request must not hide another request loading mask')
+
+	requests[0].complete({ statusCode: 200, data: { code: 0, data: {} } })
+	await visibleRequest
+	assert.equal(hidden, 1, 'the request that displayed loading must always hide it on completion')
+}
+
 function assertNoIdentityFields(value) {
 	if (!value || typeof value !== 'object') return
 	for (const [key, child] of Object.entries(value)) {
@@ -1497,6 +1550,7 @@ async function testCloseAndBackRequirePendingUploadConfirmation() {
 async function main() {
 	const loadedTransport = await loadTransport()
 	assert.equal(typeof loadedTransport.downloadTeamBackgroundFile, 'function')
+	await testConcurrentSilentRequestDoesNotStrandLoadingMask()
 	await testUploadTransport()
 	await testApiTransport()
 	await testDownloadTransport()