Files
zszq-trs/YLErpWeb/fe-tests/swapPriceInput.component.test.js
T
hjhan 74c434bdd8 fix(swaptrade): 修复重输/重贴原值后回车不触发计算、粘贴不标记REV的静默失效
- swapPricePrecisionHelper: onKeydown 回车时无条件派发 input+enter,
  不再依赖仅值变化才触发的原生 change;onPaste 粘贴即派发 input 标 REV;
  onChange 不再派发 enter(改由 onKeydown 唯一派发,避免重复计算)
- 新增 fe-tests/swapPriceInput.component.test.js 回归守卫(6 用例,
  回退旧版即变红,锁定该 QA 高优 Bug 修复)
- bundle/bundleV2: otcDebug 调试开关改为 localStorage 持久化 +
  URL ?otcdebug=1 触发,便于排查价格计算链路
2026-07-31 09:07:08 +08:00

101 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* swapPriceInput.component.test.js — vue-swap-price-input 事件派发回归守卫
* ============================================================================
* 目的:锁定债券三字段输入组件「粘贴 / 重输原值 不派发 input/enter」的 bug。
* 症状:粘贴或重输原值后,点空白(标REV/清其他标识)与回车(触发计算)均无反应。
* 根因:组件把 input/enter 全部锁在原生 change 事件里,而 change 仅在「值相对聚焦时
* 变动」才触发;onPaste 甚至完全不派发任何事件。
*
* 做法:直接实例化组件 options 对象(createVueInputComponent),用 mock this + $emit 间谍
* 驱动 onPaste/onKeydown/onChange,断言事件派发。不依赖 Vue 运行时挂载、不改动源文件。
*
* 运行:cd YLErpWeb/fe-tests && npx jest swapPriceInput.component
* 设 SWAP_PRICE_HELPER 指向其它版本文件可做对照(如改之前的旧代码应使用例变红)。
*/
const fs = require('fs');
const path = require('path');
function loadComponent() {
const rel = process.env.SWAP_PRICE_HELPER
|| '../wwwroot/Scripts/app/swaptrade/swapPricePrecisionHelper.js';
const file = path.resolve(__dirname, rel);
const code = fs.readFileSync(file, 'utf8');
// swapPricePrecisionHelper.js: var swapPricePrecision = (function(global){...})(window);
// 在受控作用域求值并取出 createVueInputComponentIIFE 不挂 window,故用 new Function 取返回值)。
const factory = new Function('window', 'global', 'console', code + '\n;return swapPricePrecision;');
const sandbox = {};
const swapPricePrecision = factory(sandbox, sandbox, console);
return swapPricePrecision.createVueInputComponent();
}
function makeCtx(component, opts) {
opts = opts || {};
const emitted = [];
const ctx = {
text: opts.text != null ? String(opts.text) : '',
enterPressed: false,
formatSnapshot: '{}',
format: opts.format || { integerDigits: 2, precision: 4, percent: true },
$emit: function (name, payload) { emitted.push({ name: name, payload: payload }); },
};
Object.keys(component.methods).forEach(function (m) {
ctx[m] = component.methods[m].bind(ctx);
});
return { ctx: ctx, emitted: emitted };
}
describe('vue-swap-price-input 事件派发(粘贴 / 重输原值场景)', () => {
const component = loadComponent();
test('粘贴原值应派发 input(点空白标REV / 清其他标识)', () => {
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { integerDigits: 2, precision: 4, percent: true } });
const evt = { preventDefault() {}, clipboardData: { getData: () => '3.5' }, target: { value: '' } };
ctx.onPaste(evt);
const inputs = emitted.filter(e => e.name === 'input');
expect(inputs.length).toBe(1);
expect(inputs[0].payload).toBe('0.035'); // percent:true → ÷100
});
test('回车(原值未变)应派发 enter(触发自动计算)', () => {
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { integerDigits: 2, precision: 4, percent: true } });
const evt = { which: 13, keyCode: 13, key: 'Enter', target: { blur() {}, value: '3.5' } };
ctx.onKeydown(evt);
const enters = emitted.filter(e => e.name === 'enter');
expect(enters.length).toBe(1);
expect(enters[0].payload).toBe('0.035');
});
test('回车(值已改)应派发 input+enter 各一次,且不重复派发 enter', () => {
const { ctx, emitted } = makeCtx(component, { text: '3.6', format: { percent: true } });
const evt = { which: 13, keyCode: 13, key: 'Enter', target: { blur() {}, value: '3.6' } };
ctx.onKeydown(evt);
expect(emitted.filter(e => e.name === 'input').length).toBe(1);
expect(emitted.filter(e => e.name === 'enter').length).toBe(1);
});
test('非 Enter 按键不应派发 enter / input', () => {
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { percent: true } });
const evt = { which: 65, keyCode: 65, key: 'a', target: { blur() {} } };
ctx.onKeydown(evt);
expect(emitted.filter(e => e.name === 'enter').length).toBe(0);
expect(emitted.filter(e => e.name === 'input').length).toBe(0);
});
test('失焦(onChange)即使值未变也应派发 input(点空白标REV),且不再派发 enter', () => {
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { percent: true } });
const evt = { target: { value: '3.5' } };
ctx.onChange(evt);
expect(emitted.filter(e => e.name === 'input').length).toBe(1);
expect(emitted.filter(e => e.name === 'enter').length).toBe(0);
});
test('粘贴但格式为 percent:false 也应派发 input(原值透传)', () => {
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { integerDigits: 2, precision: 4, percent: false } });
const evt = { preventDefault() {}, clipboardData: { getData: () => '3.5' }, target: { value: '' } };
ctx.onPaste(evt);
expect(emitted.filter(e => e.name === 'input').length).toBe(1);
expect(emitted.filter(e => e.name === 'input')[0].payload).toBe('3.5');
});
});