mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
fix: try to fix test case failures on Windows
This commit is contained in:
@@ -127,9 +127,11 @@ interface AppProps {
|
|||||||
|
|
||||||
export const AppWrapper = (props: AppProps) => {
|
export const AppWrapper = (props: AppProps) => {
|
||||||
const kittyProtocolStatus = useKittyKeyboardProtocol();
|
const kittyProtocolStatus = useKittyKeyboardProtocol();
|
||||||
|
const nodeMajorVersion = parseInt(process.versions.node.split('.')[0], 10);
|
||||||
return (
|
return (
|
||||||
<KeypressProvider
|
<KeypressProvider
|
||||||
kittyProtocolEnabled={kittyProtocolStatus.enabled}
|
kittyProtocolEnabled={kittyProtocolStatus.enabled}
|
||||||
|
pasteWorkaround={process.platform === 'win32' || nodeMajorVersion < 20}
|
||||||
config={props.config}
|
config={props.config}
|
||||||
>
|
>
|
||||||
<SessionStatsProvider>
|
<SessionStatsProvider>
|
||||||
|
|||||||
@@ -66,11 +66,16 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const wrapper = ({
|
const wrapper = ({
|
||||||
children,
|
children,
|
||||||
kittyProtocolEnabled = true,
|
kittyProtocolEnabled = true,
|
||||||
|
pasteWorkaround = false,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
kittyProtocolEnabled?: boolean;
|
kittyProtocolEnabled?: boolean;
|
||||||
|
pasteWorkaround?: boolean;
|
||||||
}) => (
|
}) => (
|
||||||
<KeypressProvider kittyProtocolEnabled={kittyProtocolEnabled}>
|
<KeypressProvider
|
||||||
|
kittyProtocolEnabled={kittyProtocolEnabled}
|
||||||
|
pasteWorkaround={pasteWorkaround}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</KeypressProvider>
|
</KeypressProvider>
|
||||||
);
|
);
|
||||||
@@ -389,17 +394,15 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('paste mode markers', () => {
|
describe('paste mode markers', () => {
|
||||||
beforeEach(() => {
|
// These tests use pasteWorkaround=true to force passthrough mode for raw keypress testing
|
||||||
// Force passthrough mode for raw keypress testing
|
|
||||||
vi.stubEnv('PASTE_WORKAROUND', '1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle complete paste sequence with markers', async () => {
|
it('should handle complete paste sequence with markers', async () => {
|
||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
const pastedText = 'pasted content';
|
const pastedText = 'pasted content';
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) =>
|
||||||
|
wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -429,7 +432,8 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) =>
|
||||||
|
wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -459,7 +463,8 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) =>
|
||||||
|
wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -515,7 +520,8 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) =>
|
||||||
|
wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -554,7 +560,8 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) =>
|
||||||
|
wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -658,7 +665,8 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) =>
|
||||||
|
wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -689,7 +697,8 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const multilineContent = 'line1\nline2\nline3';
|
const multilineContent = 'line1\nline2\nline3';
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) =>
|
||||||
|
wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -721,7 +730,8 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) =>
|
||||||
|
wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -754,7 +764,7 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) => wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -789,17 +799,14 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Raw keypress pipeline', () => {
|
describe('Raw keypress pipeline', () => {
|
||||||
beforeEach(() => {
|
// These tests use pasteWorkaround=true to force passthrough mode for raw keypress testing
|
||||||
// Force passthrough mode for raw keypress testing
|
|
||||||
vi.stubEnv('PASTE_WORKAROUND', '1');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should buffer input data and wait for timeout', () => {
|
it('should buffer input data and wait for timeout', () => {
|
||||||
vi.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) => wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -829,7 +836,7 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) => wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -892,7 +899,7 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) => wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -934,7 +941,7 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) => wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -987,7 +994,7 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) => wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
@@ -1036,7 +1043,7 @@ describe('KeypressContext - Kitty Protocol', () => {
|
|||||||
const keyHandler = vi.fn();
|
const keyHandler = vi.fn();
|
||||||
|
|
||||||
const { result } = renderHook(() => useKeypressContext(), {
|
const { result } = renderHook(() => useKeypressContext(), {
|
||||||
wrapper,
|
wrapper: ({ children }) => wrapper({ children, pasteWorkaround: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
|
|||||||
@@ -69,10 +69,12 @@ export function useKeypressContext() {
|
|||||||
export function KeypressProvider({
|
export function KeypressProvider({
|
||||||
children,
|
children,
|
||||||
kittyProtocolEnabled,
|
kittyProtocolEnabled,
|
||||||
|
pasteWorkaround = false,
|
||||||
config,
|
config,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
kittyProtocolEnabled: boolean;
|
kittyProtocolEnabled: boolean;
|
||||||
|
pasteWorkaround?: boolean;
|
||||||
config?: Config;
|
config?: Config;
|
||||||
}) {
|
}) {
|
||||||
const { stdin, setRawMode } = useStdin();
|
const { stdin, setRawMode } = useStdin();
|
||||||
@@ -97,18 +99,8 @@ export function KeypressProvider({
|
|||||||
|
|
||||||
const keypressStream = new PassThrough();
|
const keypressStream = new PassThrough();
|
||||||
let usePassthrough = false;
|
let usePassthrough = false;
|
||||||
const nodeMajorVersion = parseInt(process.versions.node.split('.')[0], 10);
|
// Use passthrough mode when pasteWorkaround is enabled,
|
||||||
const isWindows = process.platform === 'win32';
|
if (pasteWorkaround) {
|
||||||
// On Windows, Node's readline keypress stream often loses bracketed paste
|
|
||||||
// boundaries, causing multi-line pastes to be delivered as plain Return
|
|
||||||
// key events. This leads to accidental submits on Enter within pasted text.
|
|
||||||
// Force passthrough on Windows to parse raw bytes and detect ESC[200~...201~.
|
|
||||||
if (
|
|
||||||
nodeMajorVersion < 20 ||
|
|
||||||
isWindows ||
|
|
||||||
process.env['PASTE_WORKAROUND'] === '1' ||
|
|
||||||
process.env['PASTE_WORKAROUND'] === 'true'
|
|
||||||
) {
|
|
||||||
usePassthrough = true;
|
usePassthrough = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +492,14 @@ export function KeypressProvider({
|
|||||||
pasteBuffer = Buffer.alloc(0);
|
pasteBuffer = Buffer.alloc(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [stdin, setRawMode, kittyProtocolEnabled, config, subscribers]);
|
}, [
|
||||||
|
stdin,
|
||||||
|
setRawMode,
|
||||||
|
kittyProtocolEnabled,
|
||||||
|
pasteWorkaround,
|
||||||
|
config,
|
||||||
|
subscribers,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeypressContext.Provider value={{ subscribe, unsubscribe }}>
|
<KeypressContext.Provider value={{ subscribe, unsubscribe }}>
|
||||||
|
|||||||
@@ -105,7 +105,28 @@ describe('useKeypress', () => {
|
|||||||
let originalNodeVersion: string;
|
let originalNodeVersion: string;
|
||||||
|
|
||||||
const wrapper = ({ children }: { children: React.ReactNode }) =>
|
const wrapper = ({ children }: { children: React.ReactNode }) =>
|
||||||
React.createElement(KeypressProvider, null, children);
|
React.createElement(
|
||||||
|
KeypressProvider,
|
||||||
|
{
|
||||||
|
kittyProtocolEnabled: false,
|
||||||
|
pasteWoraround: false,
|
||||||
|
},
|
||||||
|
children,
|
||||||
|
);
|
||||||
|
|
||||||
|
const wrapperWithWindowsWorkaround = ({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) =>
|
||||||
|
React.createElement(
|
||||||
|
KeypressProvider,
|
||||||
|
{
|
||||||
|
kittyProtocolEnabled: false,
|
||||||
|
pasteWoraround: true,
|
||||||
|
},
|
||||||
|
children,
|
||||||
|
);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
@@ -187,21 +208,17 @@ describe('useKeypress', () => {
|
|||||||
description: 'Modern Node (>= v20)',
|
description: 'Modern Node (>= v20)',
|
||||||
setup: () => setNodeVersion('20.0.0'),
|
setup: () => setNodeVersion('20.0.0'),
|
||||||
isLegacy: false,
|
isLegacy: false,
|
||||||
|
pasteWoraround: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'Legacy Node (< v20)',
|
description: 'PasteWorkaround Environment Variable',
|
||||||
setup: () => setNodeVersion('18.0.0'),
|
|
||||||
isLegacy: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: 'Workaround Env Var',
|
|
||||||
setup: () => {
|
setup: () => {
|
||||||
setNodeVersion('20.0.0');
|
setNodeVersion('20.0.0');
|
||||||
vi.stubEnv('PASTE_WORKAROUND', 'true');
|
|
||||||
},
|
},
|
||||||
isLegacy: true,
|
isLegacy: false,
|
||||||
|
pasteWoraround: true,
|
||||||
},
|
},
|
||||||
])('in $description', ({ setup, isLegacy }) => {
|
])('in $description', ({ setup, isLegacy, pasteWoraround }) => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
setup();
|
setup();
|
||||||
stdin.setLegacy(isLegacy);
|
stdin.setLegacy(isLegacy);
|
||||||
@@ -209,7 +226,7 @@ describe('useKeypress', () => {
|
|||||||
|
|
||||||
it('should process a paste as a single event', async () => {
|
it('should process a paste as a single event', async () => {
|
||||||
renderHook(() => useKeypress(onKeypress, { isActive: true }), {
|
renderHook(() => useKeypress(onKeypress, { isActive: true }), {
|
||||||
wrapper,
|
wrapper: pasteWoraround ? wrapperWithWindowsWorkaround : wrapper,
|
||||||
});
|
});
|
||||||
const pasteText = 'hello world';
|
const pasteText = 'hello world';
|
||||||
act(() => stdin.paste(pasteText));
|
act(() => stdin.paste(pasteText));
|
||||||
@@ -230,7 +247,7 @@ describe('useKeypress', () => {
|
|||||||
|
|
||||||
it('should handle keypress interspersed with pastes', async () => {
|
it('should handle keypress interspersed with pastes', async () => {
|
||||||
renderHook(() => useKeypress(onKeypress, { isActive: true }), {
|
renderHook(() => useKeypress(onKeypress, { isActive: true }), {
|
||||||
wrapper,
|
wrapper: pasteWoraround ? wrapperWithWindowsWorkaround : wrapper,
|
||||||
});
|
});
|
||||||
|
|
||||||
const keyA = { name: 'a', sequence: 'a' };
|
const keyA = { name: 'a', sequence: 'a' };
|
||||||
@@ -266,7 +283,9 @@ describe('useKeypress', () => {
|
|||||||
it('should emit partial paste content if unmounted mid-paste', async () => {
|
it('should emit partial paste content if unmounted mid-paste', async () => {
|
||||||
const { unmount } = renderHook(
|
const { unmount } = renderHook(
|
||||||
() => useKeypress(onKeypress, { isActive: true }),
|
() => useKeypress(onKeypress, { isActive: true }),
|
||||||
{ wrapper },
|
{
|
||||||
|
wrapper: pasteWoraround ? wrapperWithWindowsWorkaround : wrapper,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const pasteText = 'incomplete paste';
|
const pasteText = 'incomplete paste';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user