verify-repair-lifecycle.cjs 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. 'use strict';
  2. const assert = require('node:assert/strict');
  3. const fs = require('node:fs');
  4. const path = require('node:path');
  5. const vm = require('node:vm');
  6. /**
  7. * @param {string} source - 页面源码
  8. * @param {string} name - 导出函数名
  9. * @returns {string} 可独立执行的函数源码
  10. */
  11. function extractFunction(source, name) {
  12. const pattern = new RegExp('export function ' + name + '\\(');
  13. const match = pattern.exec(source);
  14. assert.ok(match, '缺少方法 ' + name);
  15. const nextExport = source.indexOf('\nexport function ', match.index + match[0].length);
  16. return source.slice(match.index, nextExport < 0 ? source.length : nextExport).replace(/^export /, '');
  17. }
  18. const defaultSource = path.resolve(__dirname, '../src/timecard-repair-lifecycle.oyd.jsx');
  19. const sourcePath = process.argv[2] ? path.resolve(process.argv[2]) : defaultSource;
  20. const source = fs.readFileSync(sourcePath, 'utf8');
  21. assert.doesNotMatch(source, /window\._this/, '渲染不得依赖跨页面共享的 window._this');
  22. assert.match(source, /var _this = this;[\s\S]*if \(!_this \|\| !_this\.state/, 'renderJsx 应使用当前页面实例');
  23. let removedEvent = null;
  24. let removedHandler = null;
  25. let clearedTimer = null;
  26. let releasedTimer = false;
  27. const methods = vm.runInNewContext(
  28. ['refreshTimecardView', 'forceUpdate', 'didUnmount']
  29. .map((name) => extractFunction(source, name)).join('\n')
  30. + '\n({refreshTimecardView, forceUpdate, didUnmount})',
  31. {
  32. window: {
  33. removeEventListener(event, handler) {
  34. removedEvent = event;
  35. removedHandler = handler;
  36. },
  37. },
  38. clearTimeout(timer) {
  39. clearedTimer = timer;
  40. },
  41. },
  42. );
  43. const resizeHandler = () => {};
  44. let setStateCount = 0;
  45. let forceUpdateCount = 0;
  46. const context = {
  47. _tcDisposed: false,
  48. _tcBeisenLeaveRequestKey: 'active-request',
  49. _tcRepairContextRequestKey: 'active-repair-request',
  50. _tcRepairContextPollTimers: [{
  51. timerId: 123,
  52. resolve() { releasedTimer = true; },
  53. }],
  54. _tcResizeHandler: resizeHandler,
  55. setState() { setStateCount += 1; },
  56. forceUpdate() { forceUpdateCount += 1; },
  57. };
  58. methods.didUnmount.call(context);
  59. assert.equal(context._tcDisposed, true);
  60. assert.equal(context._tcBeisenLeaveRequestKey, '__TIMECARD_PAGE_DISPOSED__');
  61. assert.equal(context._tcRepairContextRequestKey, '__TIMECARD_PAGE_DISPOSED__');
  62. assert.equal(context._tcRepairContextPollTimers.length, 0);
  63. assert.equal(clearedTimer, 123);
  64. assert.equal(releasedTimer, true);
  65. assert.equal(context._tcResizeHandler, null);
  66. assert.equal(removedEvent, 'resize');
  67. assert.equal(removedHandler, resizeHandler);
  68. methods.refreshTimecardView.call(context);
  69. methods.forceUpdate.call(context);
  70. assert.equal(forceUpdateCount, 0, '卸载后不得继续 forceUpdate');
  71. assert.equal(setStateCount, 0, '卸载后不得继续 setState');
  72. console.log('PASS 补填页面切换时清理实例、监听和异步刷新');