모의고사 시작 응답의 explanation 기본값 누락 해결

이 글의 목차 10개 항목

문제와 원인

모의고사 시작 응답은 제출 전 정답·해설 필드를 생략한다. 학습 화면은 explanation을 문자열로 가정해 해설 개수를 계산했고, 시험 문항을 상태에 병합한 뒤 trim()에서 TypeError가 발생했다.

수정 전 코드

StudyApp

() => data.questions.filter((question) => question.explanation.trim()).length

requestStudyMutation

읽기 응답에는 문항 정규화가 있었지만 저장 응답의 requestStudyMutation은 결과를 그대로 반환했다.

export async function requestStudyMutation<T extends object>(
  action: StudyMutationAction,
  payload: JsonRecord = {},
  signal?: AbortSignal,
) {
  return requestMutation(STUDY_MUTATION_ADAPTER, action, payload, signal) as Promise<T>;
}

수정 후 코드

requestStudyMutation

exam-start 응답에 withSafeStudyQuestionDefaults를 적용해 없는 해설은 "", 없는 배열은 []로 채웠다. 제출 응답은 서버의 정답·해설을 그대로 반환한다.

export async function requestStudyMutation<T extends object>(
  action: StudyMutationAction,
  payload: JsonRecord = {},
  signal?: AbortSignal,
) {
  const result = await requestMutation(STUDY_MUTATION_ADAPTER, action, payload, signal);
  return (action === "exam-start"
    ? withSafeStudyQuestionDefaults(result)
    : result) as T;
}

withSafeStudyQuestionDefaults · normalizeStudyPayload

정규화 함수의 문항 필드 처리:

return {
  ...row,
  correctAnswers: Array.isArray(row.correctAnswers) ? row.correctAnswers : [],
  explanation: typeof row.explanation === "string" ? row.explanation : "",
  scoringCriteria: Array.isArray(row.scoringCriteria) ? row.scoringCriteria : [],
  requiredConcepts: Array.isArray(row.requiredConcepts) ? row.requiredConcepts : [],
  acceptableAlternatives: Array.isArray(row.acceptableAlternatives) ? row.acceptableAlternatives : [],
  deductionConditions: Array.isArray(row.deductionConditions) ? row.deductionConditions : [],
  errorConditions: Array.isArray(row.errorConditions) ? row.errorConditions : [],
};

검증 결과

함수 실행

Node.js·TypeScript에서 원본 함수와 정규화기를 실행했다. ADsP·SQLD·SQLP·DAP·DAsP·BIGDATA 각각에 합성 문항 1개의 시작·제출 응답을 1회씩 넣었으며, API 로직은 대역을 사용했다. 시작 응답은 해설·정답 필드를 생략하고, 제출 응답은 Synthetic submitted explanation과 [1]을 넣었다.

비교 항목수정 전수정 후
시작 응답의 explanation.trim() 오류6/6개0/6개
시작 문항의 해설필드 없음""
시작 문항의 정답 배열필드 없음[]
제출 응답의 정답·해설 보존6/6개6/6개

현재 원본 fetch 경로의 기본값·제출 보존 회귀 테스트도 fetch 대역 조건에서 1/1개 통과했다.

시작·선택·제출 화면

로컬 원본 코드 스냅샷에 합성 SQLD 문항 1개·보기 2개와 응답 대역을 연결했다. 1280×720 CSS px·DPR 2에서 수정 전후 시작을 각 1회, 수정 후 선택·제출을 1회 실행했다. 화면은 explanation.trim() 계산과 원본 LearningError를 사용하며, 제출 payload는 [1] 고정값이다.

단계화면 결과
수정 전 시작이 학습 화면을 준비하지 못했습니다. · 라디오 0개
수정 후 시작모의고사 진행 중 · 1문항 · 라디오 2개 · 해설 0개
LEFT JOIN 선택선택한 라디오 값 1
수정 후 제출모의고사 제출 결과 · 해설 1개 · 정답 선택지: [1]

시작 응답에 해설이 없으면 오류 화면으로 전환됐다.

수정 전 시작 오류원본 보기 (새 창)

수정 전 시작 오류

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.

해설·정답의 기본값을 채운 뒤에는 문항 1개와 보기 2개가 표시됐다.

수정 후 문항과 보기 2개 표시원본 보기 (새 창)

수정 후 문항과 보기 2개 표시

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.

LEFT JOIN을 선택하고 제출하자 정답 배열 [1]과 “LEFT JOIN은 왼쪽 회원 테이블의 행을 보존합니다. 주문이 없는 회원도 결과에 남습니다.” 해설이 표시됐다.

수정 후 제출 해설과 정답 표시원본 보기 (새 창)

수정 후 제출 해설과 정답 표시

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.