const { updateMemo } = require("../../src/memo/updateMemo");
describe("updateMemo", () => {
test("정상 id와 수정값이면 memo 수정에 성공한다", async () => {
const result = await updateMemo(1, {
title: "수정된 메모 제목",
content: "수정된 메모 내용",
priority: 5,
isSuccess: true,
});
expect(result).toMatchObject({
id: 1,
title: "수정된 메모 제목",
content: "수정된 메모 내용",
priority: 5,
isSuccess: true,
});
});
test("id가 없으면 에러 발생", async () => {
await expect(
updateMemo(undefined, {
title: "수정 제목",
}),
).rejects.toThrow("id");
});
test("id가 문자열이면 에러 발생", async () => {
await expect(
updateMemo("1", {
title: "수정 제목",
}),
).rejects.toThrow("id");
});
test("id가 0이면 에러 발생", async () => {
await expect(
updateMemo(0, {
title: "수정 제목",
}),
).rejects.toThrow("id");
});
test("update data가 없으면 에러 발생", async () => {
await expect(updateMemo(1)).rejects.toThrow("data");
});
test("존재하지 않는 id이면 에러 발생", async () => {
await expect(
updateMemo(999, {
title: "수정 제목",
}),
).rejects.toThrow("memo");
});
test("title이 빈 문자열이면 에러 발생", async () => {
await expect(
updateMemo(1, {
title: "",
}),
).rejects.toThrow("title");
});
test("content가 공백만 있으면 에러 발생", async () => {
await expect(
updateMemo(1, {
content: " ",
}),
).rejects.toThrow("content");
});
test("priority가 범위를 벗어나면 에러 발생", async () => {
await expect(
updateMemo(1, {
priority: 6,
}),
).rejects.toThrow("priority");
});
test("isSuccess가 boolean이 아니면 에러 발생", async () => {
await expect(
updateMemo(1, {
isSuccess: "true",
}),
).rejects.toThrow("isSuccess");
});
test("period 시작일이 종료일보다 뒤면 에러 발생", async () => {
await expect(
updateMemo(1, {
period: {
startDate: "2026-03-20",
endDate: "2026-03-10",
},
}),
).rejects.toThrow("period");
});
});
hongseongchae@hongseongchaeui-MacBookPro tdd_study % npm test
> tdd_study@1.0.0 test
> jest
FAIL __test__/memo/updateMemoList.test.js
● updateMemo › 정상 id와 수정값이면 memo 수정에 성공한다
TypeError: updateMemo is not a function
3 | describe("updateMemo", () => {
4 | test("정상 id와 수정값이면 memo 수정에 성공한다", async () => {
> 5 | const result = await updateMemo(1, {
| ^
6 | title: "수정된 메모 제목",
7 | content: "수정된 메모 내용",
8 | priority: 5,
at Object.updateMemo (__test__/memo/updateMemoList.test.js:5:26)
● updateMemo › id가 없으면 에러 발생
TypeError: updateMemo is not a function
21 | test("id가 없으면 에러 발생", async () => {
22 | await expect(
> 23 | updateMemo(undefined, {
| ^
24 | title: "수정 제목",
25 | }),
26 | ).rejects.toThrow("id");
at Object.updateMemo (__test__/memo/updateMemoList.test.js:23:7)
● updateMemo › id가 문자열이면 에러 발생
TypeError: updateMemo is not a function
29 | test("id가 문자열이면 에러 발생", async () => {
30 | await expect(
> 31 | updateMemo("1", {
| ^
32 | title: "수정 제목",
33 | }),
34 | ).rejects.toThrow("id");
at Object.updateMemo (__test__/memo/updateMemoList.test.js:31:7)
● updateMemo › id가 0이면 에러 발생
TypeError: updateMemo is not a function
37 | test("id가 0이면 에러 발생", async () => {
38 | await expect(
> 39 | updateMemo(0, {
| ^
40 | title: "수정 제목",
41 | }),
42 | ).rejects.toThrow("id");
at Object.updateMemo (__test__/memo/updateMemoList.test.js:39:7)
● updateMemo › update data가 없으면 에러 발생
TypeError: updateMemo is not a function
44 |
45 | test("update data가 없으면 에러 발생", async () => {
> 46 | await expect(updateMemo(1)).rejects.toThrow("data");
| ^
47 | });
48 |
49 | test("존재하지 않는 id이면 에러 발생", async () => {
at Object.updateMemo (__test__/memo/updateMemoList.test.js:46:18)
● updateMemo › 존재하지 않는 id이면 에러 발생
TypeError: updateMemo is not a function
49 | test("존재하지 않는 id이면 에러 발생", async () => {
50 | await expect(
> 51 | updateMemo(999, {
| ^
52 | title: "수정 제목",
53 | }),
54 | ).rejects.toThrow("memo");
at Object.updateMemo (__test__/memo/updateMemoList.test.js:51:7)
● updateMemo › title이 빈 문자열이면 에러 발생
TypeError: updateMemo is not a function
57 | test("title이 빈 문자열이면 에러 발생", async () => {
58 | await expect(
> 59 | updateMemo(1, {
| ^
60 | title: "",
61 | }),
62 | ).rejects.toThrow("title");
at Object.updateMemo (__test__/memo/updateMemoList.test.js:59:7)
● updateMemo › content가 공백만 있으면 에러 발생
TypeError: updateMemo is not a function
65 | test("content가 공백만 있으면 에러 발생", async () => {
66 | await expect(
> 67 | updateMemo(1, {
| ^
68 | content: " ",
69 | }),
70 | ).rejects.toThrow("content");
at Object.updateMemo (__test__/memo/updateMemoList.test.js:67:7)
● updateMemo › priority가 범위를 벗어나면 에러 발생
TypeError: updateMemo is not a function
73 | test("priority가 범위를 벗어나면 에러 발생", async () => {
74 | await expect(
> 75 | updateMemo(1, {
| ^
76 | priority: 6,
77 | }),
78 | ).rejects.toThrow("priority");
at Object.updateMemo (__test__/memo/updateMemoList.test.js:75:7)
● updateMemo › isSuccess가 boolean이 아니면 에러 발생
TypeError: updateMemo is not a function
81 | test("isSuccess가 boolean이 아니면 에러 발생", async () => {
82 | await expect(
> 83 | updateMemo(1, {
| ^
84 | isSuccess: "true",
85 | }),
86 | ).rejects.toThrow("isSuccess");
at Object.updateMemo (__test__/memo/updateMemoList.test.js:83:7)
● updateMemo › period 시작일이 종료일보다 뒤면 에러 발생
TypeError: updateMemo is not a function
89 | test("period 시작일이 종료일보다 뒤면 에러 발생", async () => {
90 | await expect(
> 91 | updateMemo(1, {
| ^
92 | period: {
93 | startDate: "2026-03-20",
94 | endDate: "2026-03-10",
at Object.updateMemo (__test__/memo/updateMemoList.test.js:91:7)
PASS __test__/memo/deleteMemo.test.js
PASS __test__/memo/createMemo.test.js
PASS __test__/memo/readMemo.test.js
PASS __test__/memo/readMemoList.test.js
Test Suites: 1 failed, 4 passed, 5 total
Tests: 11 failed, 43 passed, 54 total
Snapshots: 0 total
Time: 0.696 s, estimated 1 s
Ran all test suites.const mockMemos = [
{
id: 1,
title: "TDD 메모 작성",
period: {
startDate: "2026-03-06",
endDate: "2026-03-10",
},
content: "첫 번째 메모",
priority: 3,
isSuccess: false,
},
{
id: 2,
title: "두 번째 메모",
period: {
startDate: "2026-03-07",
endDate: "2026-03-12",
},
content: "두 번째 내용",
priority: 2,
isSuccess: true,
},
{
id: 3,
title: "세 번째 메모",
period: {
startDate: "2026-03-08",
endDate: "2026-03-15",
},
content: "세 번째 내용",
priority: 3,
isSuccess: true,
},
{
id: 4,
title: "네 번째 메모",
period: {
startDate: "2026-03-09",
endDate: "2026-03-18",
},
content: "네 번째 내용",
priority: 1,
isSuccess: false,
},
];
async function updateMemo(id, data) {
if (typeof id !== "number" || id <= 0) {
throw new Error("id");
}
if (!data) {
throw new Error("data");
}
const index = mockMemos.findIndex((item) => item.id === id);
if (index === -1) {
throw new Error("memo");
}
if (data.title !== undefined) {
if (typeof data.title !== "string" || data.title.trim() === "") {
throw new Error("title");
}
}
if (data.content !== undefined) {
if (typeof data.content !== "string" || data.content.trim() === "") {
throw new Error("content");
}
}
if (data.priority !== undefined) {
if (
typeof data.priority !== "number" ||
data.priority < 1 ||
data.priority > 5
) {
throw new Error("priority");
}
}
if (data.isSuccess !== undefined) {
if (typeof data.isSuccess !== "boolean") {
throw new Error("isSuccess");
}
}
if (data.period !== undefined) {
if (
!data.period ||
typeof data.period.startDate !== "string" ||
typeof data.period.endDate !== "string"
) {
throw new Error("period");
}
const start = new Date(data.period.startDate);
const end = new Date(data.period.endDate);
if (
Number.isNaN(start.getTime()) ||
Number.isNaN(end.getTime()) ||
start > end
) {
throw new Error("period");
}
}
mockMemos[index] = {
...mockMemos[index],
...data,
};
return mockMemos[index];
}
module.exports = { updateMemo };
hongseongchae@hongseongchaeui-MacBookPro tdd_study % npm test
> tdd_study@1.0.0 test
> jest
PASS __test__/memo/updateMemoList.test.js
PASS __test__/memo/createMemo.test.js
PASS __test__/memo/readMemo.test.js
PASS __test__/memo/readMemoList.test.js
PASS __test__/memo/deleteMemo.test.js
Test Suites: 5 passed, 5 total
Tests: 54 passed, 54 total
Snapshots: 0 total
Time: 0.599 s, estimated 1 s
Ran all test suites.const mockMemos = [
{
id: 1,
title: "TDD 메모 작성",
period: {
startDate: "2026-03-06",
endDate: "2026-03-10",
},
content: "첫 번째 메모",
priority: 3,
isSuccess: false,
},
{
id: 2,
title: "두 번째 메모",
period: {
startDate: "2026-03-07",
endDate: "2026-03-12",
},
content: "두 번째 내용",
priority: 2,
isSuccess: true,
},
{
id: 3,
title: "세 번째 메모",
period: {
startDate: "2026-03-08",
endDate: "2026-03-15",
},
content: "세 번째 내용",
priority: 3,
isSuccess: true,
},
{
id: 4,
title: "네 번째 메모",
period: {
startDate: "2026-03-09",
endDate: "2026-03-18",
},
content: "네 번째 내용",
priority: 1,
isSuccess: false,
},
];
function validateId(id) {
if (typeof id !== "number" || id <= 0) {
throw new Error("id");
}
}
function validateUpdateData(data) {
if (!data) {
throw new Error("data");
}
}
function validateTitle(title) {
if (typeof title !== "string" || title.trim() === "") {
throw new Error("title");
}
}
function validateContent(content) {
if (typeof content !== "string" || content.trim() === "") {
throw new Error("content");
}
}
function validatePriority(priority) {
if (typeof priority !== "number" || priority < 1 || priority > 5) {
throw new Error("priority");
}
}
function validateIsSuccess(isSuccess) {
if (typeof isSuccess !== "boolean") {
throw new Error("isSuccess");
}
}
function validatePeriod(period) {
if (
!period ||
typeof period.startDate !== "string" ||
typeof period.endDate !== "string"
) {
throw new Error("period");
}
const start = new Date(period.startDate);
const end = new Date(period.endDate);
if (
Number.isNaN(start.getTime()) ||
Number.isNaN(end.getTime()) ||
start > end
) {
throw new Error("period");
}
}
function validateUpdateFields(data) {
if (data.title !== undefined) {
validateTitle(data.title);
}
if (data.content !== undefined) {
validateContent(data.content);
}
if (data.priority !== undefined) {
validatePriority(data.priority);
}
if (data.isSuccess !== undefined) {
validateIsSuccess(data.isSuccess);
}
if (data.period !== undefined) {
validatePeriod(data.period);
}
}
async function updateMemo(id, data) {
validateId(id);
validateUpdateData(data);
const index = mockMemos.findIndex((item) => item.id === id);
if (index === -1) {
throw new Error("memo");
}
validateUpdateFields(data);
mockMemos[index] = {
...mockMemos[index],
...data,
};
return mockMemos[index];
}
module.exports = { updateMemo };
hongseongchae@hongseongchaeui-MacBookPro tdd_study % npm test
> tdd_study@1.0.0 test
> jest
PASS __test__/memo/updateMemoList.test.js
PASS __test__/memo/createMemo.test.js
PASS __test__/memo/readMemoList.test.js
PASS __test__/memo/readMemo.test.js
PASS __test__/memo/deleteMemo.test.js
Test Suites: 5 passed, 5 total
Tests: 54 passed, 54 total
Snapshots: 0 total
Time: 0.586 s, estimated 1 s
Ran all test suites.