브라우저의 Ctrl+S 는 "페이지를 파일로 저장"이다. 글을 쓰다가 그 손버릇이 나오면 저장 대화상자가 뜨고 편집한 내용은 그대로 남는다 — 저장한 줄 알고 창을 닫으면 잃는다. 문서·프로젝트·릴리즈 세 편집기에서 기본 동작을 막고 그 화면의 저장으로 돌린다. 저장할 것이 없을 때도 기본 동작은 막는다. 막지 않으면 "저장할 것이 없다"는 화면 상태와 브라우저의 저장 대화상자가 동시에 나와, 무엇이 일어났는지 알 수 없다. Ctrl+Shift+S 와 Alt 조합은 가로채지 않는다 — 다른 뜻으로 쓰는 곳이 있다. 버튼에 단축키를 적어 둔다. 단축키는 알려 주지 않으면 없는 것과 같다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XEHXspz4rv5pB5wiiSsVDu
92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import { strict as assert } from "node:assert";
|
|
import { afterEach, test } from "vitest";
|
|
import { renderHook } from "@testing-library/react";
|
|
|
|
import { useSaveShortcut } from "../../../src/features/tech-log/presentation/studio/components/use-save-shortcut.ts";
|
|
|
|
function pressSave(overrides: Partial<KeyboardEventInit> = {}) {
|
|
const event = new KeyboardEvent("keydown", {
|
|
key: "s",
|
|
ctrlKey: true,
|
|
cancelable: true,
|
|
bubbles: true,
|
|
...overrides,
|
|
});
|
|
window.dispatchEvent(event);
|
|
return event;
|
|
}
|
|
|
|
afterEach(() => {
|
|
document.body.innerHTML = "";
|
|
});
|
|
|
|
/*
|
|
브라우저의 Ctrl+S 는 "페이지를 파일로 저장"이다. 글을 쓰다가 그 손버릇이 나오면 저장 대화상자가
|
|
뜨고 편집한 내용은 그대로 남는다 — 저장한 줄 알고 창을 닫으면 잃는다. 그래서 기본 동작을 막는
|
|
것까지가 이 훅의 일이다.
|
|
*/
|
|
test("Ctrl+S saves and keeps the browser from offering the page as a file", () => {
|
|
let saved = 0;
|
|
const { unmount } = renderHook(() => useSaveShortcut(() => { saved += 1; }));
|
|
|
|
const event = pressSave();
|
|
|
|
assert.equal(saved, 1);
|
|
assert.equal(event.defaultPrevented, true);
|
|
unmount();
|
|
});
|
|
|
|
test("Cmd+S does the same, because the habit is the same on a Mac", () => {
|
|
let saved = 0;
|
|
const { unmount } = renderHook(() => useSaveShortcut(() => { saved += 1; }));
|
|
|
|
pressSave({ ctrlKey: false, metaKey: true });
|
|
|
|
assert.equal(saved, 1);
|
|
unmount();
|
|
});
|
|
|
|
/*
|
|
저장할 것이 없을 때도 기본 동작은 막는다. 막지 않으면 "저장할 것이 없다"는 화면 상태와
|
|
브라우저의 저장 대화상자가 동시에 나와, 무엇이 일어났는지 알 수 없다.
|
|
*/
|
|
test("a disabled shortcut still swallows the browser default", () => {
|
|
let saved = 0;
|
|
const { unmount } = renderHook(() =>
|
|
useSaveShortcut(() => { saved += 1; }, false),
|
|
);
|
|
|
|
const event = pressSave();
|
|
|
|
assert.equal(saved, 0);
|
|
assert.equal(event.defaultPrevented, true);
|
|
unmount();
|
|
});
|
|
|
|
test("modified chords are left to whoever else wants them", () => {
|
|
let saved = 0;
|
|
const { unmount } = renderHook(() => useSaveShortcut(() => { saved += 1; }));
|
|
|
|
const shift = pressSave({ shiftKey: true });
|
|
const alt = pressSave({ altKey: true });
|
|
const plain = pressSave({ ctrlKey: false });
|
|
|
|
assert.equal(saved, 0);
|
|
assert.equal(shift.defaultPrevented, false);
|
|
assert.equal(alt.defaultPrevented, false);
|
|
assert.equal(plain.defaultPrevented, false);
|
|
unmount();
|
|
});
|
|
|
|
test("the listener goes away with the screen", () => {
|
|
let saved = 0;
|
|
const { unmount } = renderHook(() => useSaveShortcut(() => { saved += 1; }));
|
|
unmount();
|
|
|
|
pressSave();
|
|
|
|
assert.equal(saved, 0);
|
|
});
|