'use strict'; const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const vm = require('node:vm'); /** * @param {string} source - 页面源码 * @param {string} name - 导出函数名 * @returns {string} 可独立执行的函数源码 */ function extractFunction(source, name) { const pattern = new RegExp('export function ' + name + '\\('); const match = pattern.exec(source); assert.ok(match, '缺少方法 ' + name); const nextExport = source.indexOf('\nexport function ', match.index + match[0].length); return source.slice(match.index, nextExport < 0 ? source.length : nextExport).replace(/^export /, ''); } const sourcePath = process.argv[2] ? path.resolve(process.argv[2]) : path.resolve(__dirname, '../src/timecard-change.oyd.jsx'); const source = fs.readFileSync(sourcePath, 'utf8'); assert.doesNotMatch(source, /window\._this/, '变更页渲染不得依赖跨页面共享的 window._this'); assert.match(source, /var _this = this;[\s\S]*if \(!_this \|\| !_this\.state/, 'renderJsx 应使用当前页面实例'); let removedEvent = null; let removedHandler = null; const methods = vm.runInNewContext( ['refreshTimecardView', 'forceUpdate', 'didUnmount'] .map((name) => extractFunction(source, name)).join('\n') + '\n({refreshTimecardView, forceUpdate, didUnmount})', { window: { removeEventListener(event, handler) { removedEvent = event; removedHandler = handler; }, }, }, ); const resizeHandler = () => {}; let setStateCount = 0; let forceUpdateCount = 0; const context = { _tcDisposed: false, _tcBeisenLeaveRequestKey: 'active-request', _tcResizeHandler: resizeHandler, setState() { setStateCount += 1; }, forceUpdate() { forceUpdateCount += 1; }, }; methods.didUnmount.call(context); assert.equal(context._tcDisposed, true); assert.equal(context._tcBeisenLeaveRequestKey, '__TIMECARD_PAGE_DISPOSED__'); assert.equal(context._tcResizeHandler, null); assert.equal(removedEvent, 'resize'); assert.equal(removedHandler, resizeHandler); methods.refreshTimecardView.call(context); methods.forceUpdate.call(context); assert.equal(forceUpdateCount, 0, '卸载后不得继续 forceUpdate'); assert.equal(setStateCount, 0, '卸载后不得继续 setState'); console.log('PASS 变更页面切换时清理实例、监听和异步刷新');