네이버 SmartEditor 붙여넣기: 성공 이벤트보다 본문 일치가 먼저다
답부터 말하면 붙여넣기 이벤트가 받아들여졌는지가 아니라, 편집기 본문이 넣으려던 전체 글과 같아졌는지를 완료 조건으로 삼아야 한다.
이벤트를 보내기 전에 변경 감시를 시작하고, 제한 시간 안에 정규화한 누적 본문이 정확히 일치할 때만 다음 단계로 넘어가는 방식이다.
2026년 9월 27일 한 번의 SmartEditor 자동화 기록에서 첫 구간은 48ms, 두 번째 구간은 239ms 뒤 반영됐다.
이후 다시 연 예약 글에서는 원고·주입 대상·편집기 본문이 각각 2800자로 일치했다.
그 예약은 이 실행이 아니라 동시에 돌던 다른 작업이 저장한 것이다.
48ms와 239ms는 속도 기준이나 성공률이 아니라 한 실행의 관찰값이다.
왜 paste 이벤트 성공만으로는 부족했나?
조사 중 합성 paste 이벤트는
defaultPrevented:true를 반환했다.
그런데 직후 본문은 여전히 한 문단이었고, 조금 뒤에는 시험용 두 문단이 들어와 있었다.
문제는 이벤트 수락과 화면 반영이 같은 순간이 아니라는 점이다.
dispatchEvent() 반환값, iframe 포커스, 즉시 읽은 문단 수는
모두 완료 조건이 아니었다.
선택 영역이 iframe 루트에 잡힌 관찰도 과거 60초 지연의 원인으로 확정할 수 없었다.
그렇다면 무엇을 기다려야 할까.
편집기가 실제로 만들어 낸 최종 상태를 기다려야 한다.
고정 sleep 대신 무엇을 기다렸나?
성공한 경로는 MutationObserver를 붙여넣기 전에 등록했다.
그 다음 clipboard 이벤트를 보낸 뒤, 공백과 제로폭 문자를 정규화한 전체 본문을 매 변경마다 비교했다.
아래는 실제 코드를 줄인 형태다.
const done = new Promise((resolve, reject) => {
const timer = setTimeout(() => {
observer.disconnect();
reject(new Error("paste timeout"));
}, 20000);
const observer = new MutationObserver(() => {
if (normalize(readBody()) === normalize(expected)) {
clearTimeout(timer);
observer.disconnect();
resolve();
}
});
observer.observe(editorBody, {
childList: true,
characterData: true,
subtree: true
});
});
dispatchPaste(html);
await done;순서가 중요하다.
이벤트를 먼저 보내고 감시를 붙이면 빠른 변경을 놓칠 수 있다.
제한 시간은 성공을 만드는 대기 시간이 아니라, 끝나지 않은 작업을 실패로 돌리는 안전장치다.
실제 기록에서는 첫 구간이 48ms 뒤 16문단·260자로, 두 번째 구간이 239ms 뒤 142문단·2310자로 반영됐다.
세 번째 구간도 일치 검사를 통과했다.
이 실행은 저장까지 가지 않았다.
동시에 돌던 다른 작업이 같은 예약을 먼저 저장했고, 그 글을 다시 열었을 때 정규화한 세 본문이 2800/2800/2800자로 같았다.
어떤 완료 신호를 믿어야 하나?
비교하면 차이가 분명하다.
| 확인 신호 | 알 수 있는 것 | 완료 판정 |
|---|---|---|
dispatchEvent() 반환 |
이벤트 취소 여부 | 부족하다 |
| iframe 포커스·선택 영역 | 입력 대상의 현재 위치 | 부족하다 |
| 문단 수 증가 | 일부 구조가 생김 | 내용 누락을 잡지 못한다 |
| 고정 sleep 종료 | 시간이 지남 | 느린 실행과 빠른 실행을 구분하지 못한다 |
| 정규화한 누적 본문 일치 | 의도한 텍스트가 모두 반영됨 | 본문 완료 조건으로 쓸 수 있다 |
| HTTPS 이미지 로드·decode | 실제 이미지가 준비됨 | 이미지 완료 조건으로 쓸 수 있다 |
| 저장 후 재열기 일치 | 저장된 결과가 유지됨 | 최종 검증으로 쓸 수 있다 |
문단 수만 맞추는 검사는 특히 약하다.
같은 문단 수에서도 글자가 빠지거나 순서가 달라질 수 있다.
완료 조건은 가능하면 개수가 아니라 값의 정확한 일치여야 한다.
이미지는 왜 별도 상태 검사가 필요한가?
본문이 맞아도 이미지는 아직 끝나지 않을 수 있다.
같은 실행에서 두
번째 이미지 요소는 실제 파일이 아니라 1200×1550 크기의
data:image/svg+xml placeholder를 먼저 보여 줬다.
이 상태에서 컴포넌트가 생겼다는 이유만으로 저장하면 안 된다.
실제
HTTPS src, load, 양수인
naturalWidth, 이미지 decode()까지 확인해야
한다.
지연 로딩된 이미지는 화면 안으로 스크롤해야 실제 URL이 붙을 수도 있다.
저장 전 검사는 이 placeholder를 보고 저장을 막았다.
이후 다시 연 예약 글에서 그 이미지를 화면 안으로 스크롤하자 실제 HTTPS 이미지가 1200×1550으로 로드됐다.
기대한 PNG 두 장은 1200×1200, 1200×1550이었다.
중복 예약은 어느 순간 막아야 하나?
붙여넣기가 성공해도 같은 글을 두 번 예약하면 자동화는 실패다.
실제 조사에서는 편집기를 다시 열었을 때 같은 제목과 시간의 예약이 이미 목록에 있었다.
동시에 돌던 다른 작업이 먼저 저장한 것이다.
이 실행은 첫 목록 검사에서 멈췄고 저장 버튼을 누르지 않았다.
목록에는 해당 제목과 시간의 예약이 정확히 한 건만 남았다.
내가 확인한 실행 코드는 저장 전후를 다음 순서로 막고 있었다.
- 편집기를 열자마자 예약 제목과 시간 슬롯을 검사한다.
- 본문·이미지·메타데이터를 채운 뒤 예약 목록을 다시 읽는다.
- 공개 RSS에 같은 제목이 이미 있는지 확인한다.
- 저장 직전에 폼이 앞선 검증 상태와 같은지 다시 비교한다.
- 저장 뒤 예약 목록에서 제목과 시간 슬롯이 각각 한 건인지 확인한다.
- 예약 글을 다시 열어 본문·이미지·설정을 재검증한다.
이 구조는 경주에서 결승선만 보는 것과 다르다.
출발 전과 피트인 직전에도 차 상태를 보는 셈이다.
다만 경주 비유와 달리 브라우저 자동화에서는 각 검사를 정확한 값 비교로 표현할 수 있다.
예전의 Claude Code와 Blogger 자동화가 발행 흐름을 다뤘다면, 이번 기록은 그 안의 완료 조건을 좁혀 본 것이다.
테스트 통과와 실제 표면이 다를 수 있다는 문제는 테스트 113개가 통과했지만 실제 수집은 0개였던 기록과도 이어진다.
언제 이 결론이 달라지나?
이번 기록은 한 글을 예약하던 하루의 관찰이다.
여러 글의 성공률, 반영 시간 p50·p95, 브라우저와 SmartEditor 버전별 차이는 측정하지 않았다.
과거의 60초 전송 지연이 왜 생겼는지도 이번 관찰만으로 확정하지 않았다.
편집기가 공식 완료 API와 저장 결과 식별자를 제공한다면 DOM 감시보다 그 계약을 먼저 쓸 수 있다.
그래도 API 응답만 믿지 않고, 저장 후 다시 연 본문과 메타데이터가 맞는지는 확인하는 편이 낫다고 생각한다.
결국 기준은 이벤트의 성공이 아니라 사용자가 다시 보게 될 상태다.
붙여넣기 전에 감시를 구독하고, 전체 본문 일치와 실제 이미지 준비를 기다린 뒤, 저장 후 같은 글을 다시 열어 확인하면 된다.
결론 · 이벤트가 아니라 상태를 본다
붙여넣기 성공은 이벤트가 받아들여졌다는 뜻으로 끝내면 안 된다.
판단 기준은 정규화한 전체 본문과 실제 이미지가 준비됐는지, 저장 뒤 다시 연 결과까지 맞는지다.
먼저 트리거 전에 감시를 구독하고, 제목과 시간 슬롯의 중복도 저장 직전에 다시 확인하면 된다.
확인한 자료와 범위
2026년 9월 27일 작성된 SmartEditor 조사 기록, 예약 실행 로그, 예약 자동화 실행 코드를 2026년 9월 28일 다시 확인했다.
파일별 경로와 확인한
주장, 측정하지 않은 항목은 이 초안의 evidence.md에
적었다.


댓글
댓글 쓰기