ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: 조건을 보면 1에서 31까지의 수만 허용한다는 건 알지만 처음 읽는 입장에서 왜 그 사이의 수만 허용되는 지 바로 캐치하기는 어려울 수도 있습니다.
이런 부분 때문에 매직넘버를 제거하고, 변수명에 신경을 써야 하는 듯 해요. 지난 주차에 이 부분에 대해 저도 진지하게 생각하고 있었고, 아래와 같이 변경해 보았는데 이런 식으로 접목해 보시는 건 어떨까요?

```js
dayValidCheck (date) {

const date = new Date('2023-12-${date}').getDate()

if (Number.isNaN(date)) return false

return true

}
```

// 사용 예시

```js
    if (dayValidCheck(date)) {
    
     ... 정상 로직
}

// 예외 발생

      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");


```
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: 정규표현식을 변수에 담아주면 더 쉽게 이해할 수 있을 거 같아요.
예를 들면 
```js
const MenuFormat = !/^(.+)-(.+)$/

'''
'''

for (const menu of menus) {
      if (MenuFormat.test(menu)) {

'''
'''

```
이런 식으로 가급적 읽을 수 있는 문자로 변경해주면 더 좋을 듯 합니다
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: includes는 찾는 첫번째 요소를 배열 전체를 순회하며 찾아서 반환합니다. 따라서 규모가 커지면 비효율적일 수도 있습니다.
find는 찾으려는 첫번째 요소를 찾으면 true를 반환하고 종료됩니다. 저는 그래서 find를 애용하는 데 그 밖에도 다른 방법들도 있으니 여러 방면으로 생각해 보셔도 좋을 듯 합니다
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: for..of는 javascript airbnb에서 추천하지 않는 방법이라고 합니다 !
forEach()나 map()을 써보시는건 어떨까요? 
해당 함수는 for..of와 if문을 사용하는거니 `filter()`가 적합해보입니다 !

참고 : [Javascript Airbnb 11.1](https://github.com/tipjs/javascript-style-guide#11.1)
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: has를 사용하면 디테일하게 중복 처리할 수 있군요...!
저는 메뉴를 분리해서 set함수를 사용했었는데 이런 방법도 있다는 것을 배워갑니다 !!
@@ -1,7 +1,27 @@
-export default InputView = {
-    async readDate() {
-        const input = await Console.readLineAsync("12월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)");
-        // ...
-    }
-    // ...
-}
+import { MissionUtils } from "@woowacourse/mission-utils";
+import ChristmasDomain from "./ChristmasPromotion.js";
+import Order from "./Order.js";
+
+export const christmasInstance = new ChristmasDomain();
+
+const InputView = {
+  async readDate() {
+    const input = await MissionUtils.Console.readLineAsync(
+      "12월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)\n"
+    );
+    const DATE = parseInt(input, 10);
+    christmasInstance.startDateValidate(DATE);
+  },
+
+  async readOrderMenu() {
+    const input = await MissionUtils.Console.readLineAsync(
+      "주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)\n"
+    );
+    new Order(input);
+    const MENUES = input.split(",");
+    christmasInstance.startMenuValidate(MENUES);
+  },
+  // ...
+};
+
+export default InputView;

리뷰: 해당 문구는 변하지 않는 상수값이니 변하지 않은 상수값들은 따로 constant를 만들어서 한 번에 정리하는 것도 괜찮을 것 같습니다 !
@@ -1,7 +1,27 @@
-export default InputView = {
-    async readDate() {
-        const input = await Console.readLineAsync("12월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)");
-        // ...
-    }
-    // ...
-}
+import { MissionUtils } from "@woowacourse/mission-utils";
+import ChristmasDomain from "./ChristmasPromotion.js";
+import Order from "./Order.js";
+
+export const christmasInstance = new ChristmasDomain();
+
+const InputView = {
+  async readDate() {
+    const input = await MissionUtils.Console.readLineAsync(
+      "12월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)\n"
+    );
+    const DATE = parseInt(input, 10);
+    christmasInstance.startDateValidate(DATE);
+  },
+
+  async readOrderMenu() {
+    const input = await MissionUtils.Console.readLineAsync(
+      "주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)\n"
+    );
+    new Order(input);
+    const MENUES = input.split(",");
+    christmasInstance.startMenuValidate(MENUES);
+  },
+  // ...
+};
+
+export default InputView;

리뷰: 해당 미션은 우테코 라이브러리에서 Random을 사용하지 않으니 `Console`로만 선언하시면 코드가 조금 더 깔끔해 질 것 같아요 !
@@ -0,0 +1,24 @@
+import menuAndQuantity from "./utils/menuAndQuantity.js";
+
+class Order {
+  #order;
+
+  constructor(order) {
+    this.#order = Array.isArray(order) ? order : [order];
+    this.#orderQuantityValidate();
+  }
+
+  #orderQuantityValidate() {
+    this.#order.forEach((menu) => {
+      const { QUANTITY } = menuAndQuantity(menu);
+
+      if (QUANTITY > 20) {
+        throw new Error(
+          `[ERROR] 메뉴는 한 번에 최대 20개까지만 주문할 수 있습니다.`
+        );
+      }
+    });
+  }
+}
+
+export default Order;

리뷰: forEach()로 선언하신 이유를 알 수 있을까요??
@@ -1,5 +1,29 @@
+import { MissionUtils } from "@woowacourse/mission-utils";
+import InputView from "./InputView.js";
+import OutputView from "./OutputView.js";
+
 class App {
-  async run() {}
+  async run() {
+    await christmasPromotionProcess();
+  }
+}
+
+async function christmasPromotionProcess() {
+  try {
+    OutputView.printIntroduction();
+    await InputView.readDate();
+    await InputView.readOrderMenu();
+    OutputView.printBenefitIntroduction();
+    OutputView.printMenu();
+    OutputView.printTotalPrice();
+    OutputView.printChampagnePromotion();
+    OutputView.printReceivedPromotion();
+    OutputView.printReceivedTotalBenefitPrice();
+    OutputView.printTotalPriceAfterDiscount();
+    OutputView.printEventBadge();
+  } catch (error) {
+    MissionUtils.Console.print(error.message);
+  }
 }
 
 export default App;

리뷰: 호출 메서드가 많아 길어진 걸 정리하지 않았었는데  printResult () 메서드를 생성하는 방식 좋아요!
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: 지금까지 상수라는 개념은 알았지만 상수를 왜 사용하는지에 고민이 없었던 것 같아요. 🥲🙌
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: 무작정 해결해보고 본다 스타일이었는데, 정말 해결하고 끝이었네요. 작성할 때부터 상황에 맞는 효율적인 메서드를 택하는 것이 좋겠지만, 하고 나서 확인했을 때 '여기에 맞는 더 좋은 메서드가 있나?'  고민해 봐야겠어요!
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: 매직넘버를 제가 사용했던 거군요! 의미있게 코드 길이가 길어진 것 같아요.
또, 생성자 함수 사용(객체...!)을 적극적으로 앞으로 사용해야 겠어요.
@@ -0,0 +1,78 @@
+import {
+  ChampagnePromotionAvailable,
+  receivedD_dayPromotion,
+  toTalPriceLogic,
+} from "../src/DomainLogic";
+import menuAndQuantity from "../src/utils/menuAndQuantity";
+
+jest.mock("../src/InputView", () => ({
+  christmasInstance: {
+    getMenus: jest.fn(),
+    getDate: jest.fn(),
+  },
+}));
+
+jest.mock("../src/utils/menuAndQuantity", () => ({
+  __esModule: true,
+  default: jest.fn(),
+}));
+
+jest.mock("../src/DomainLogic", () => ({
+  ...jest.requireActual("../src/DomainLogic"),
+  toTalPriceLogic: jest.fn(),
+}));
+
+describe("DomainLogic 기능 테스트", () => {
+  test("할인 전 총주문 금액", () => {
+    const mockedMenus = ["양송이수프-2", "양송이수프-1", "티본스테이크-3"];
+    require("../src/InputView").christmasInstance.getMenus.mockReturnValue(
+      mockedMenus
+    );
+
+    menuAndQuantity
+      .mockReturnValueOnce({ MENU_NAME: "양송이수프", QUANTITY: 2 })
+      .mockReturnValueOnce({ MENU_NAME: "초코케이크", QUANTITY: 1 })
+      .mockReturnValueOnce({ MENU_NAME: "티본스테이크", QUANTITY: 3 });
+
+    const MENUS_PRICE = {
+      양송이수프: 6000,
+      초코케이크: 15000,
+      티본스테이크: 55000,
+    };
+
+    toTalPriceLogic.mockReturnValueOnce(192000);
+
+    const result = toTalPriceLogic(MENUS_PRICE);
+    const expectedTotalPrice = 2 * 6000 + 1 * 15000 + 3 * 55000;
+
+    expect(result).toBe(expectedTotalPrice);
+  });
+
+  test("증정 메뉴", () => {
+    const mockedMenus = ["아이스크림-2", "초코케이크-1"];
+    require("../src/InputView").christmasInstance.getMenus.mockReturnValue(
+      mockedMenus
+    );
+
+    toTalPriceLogic.mockReturnValueOnce(25000);
+
+    const result = ChampagnePromotionAvailable();
+    expect(result).toBe(false);
+  });
+
+  test("크리스마스 디데이 할인", () => {
+    require("../src/InputView").christmasInstance.getDate.mockReturnValue(25);
+
+    const result = receivedD_dayPromotion();
+
+    expect(result).toBe(3400);
+  });
+
+  test("크리스마스 디데이 할인 예외", () => {
+    require("../src/InputView").christmasInstance.getDate.mockReturnValue(26);
+
+    const result = receivedD_dayPromotion();
+
+    expect(result).toBe(0);
+  });
+});

리뷰: christmasInstance를 제외하면 함수라 mock를 적용했던 것 같습니다.
@@ -0,0 +1,86 @@
+class ChristmasPromotion {
+  #date;
+  #menus;
+
+  constructor(date, menus) {
+    this.#date = date;
+    this.#menus = menus;
+  }
+
+  #dateValidate(date) {
+    if (!(date >= 1 && date <= 31)) {
+      throw new Error("[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.");
+    }
+  }
+
+  startDateValidate(date) {
+    this.#dateValidate(date);
+    this.#date = date;
+  }
+
+  #menusValidate(menus) {
+    const SEENMENUS = new Set();
+
+    for (const menu of menus) {
+      if (!/^(.+)-(.+)$/.test(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      const MENU_LIST = [
+        "양송이수프",
+        "타파스",
+        "시저샐러드",
+        "티본스테이크",
+        "바비큐립",
+        "해산물파스타",
+        "크리스마스파스타",
+        "초코케이크",
+        "아이스크림",
+        "제로콜라",
+        "레드와인",
+        "샴페인",
+      ];
+
+      const [MENU_PART, QUANTITY] = menu.split("-");
+      const QUANTITY_PART = parseInt(QUANTITY, 10);
+
+      if (!MENU_LIST.includes(MENU_PART)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      if (isNaN(QUANTITY_PART) || QUANTITY_PART <= 0) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      // 중복 디테일하게 에러 처리 필요
+      if (SEENMENUS.has(menu)) {
+        throw new Error(
+          `[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.`
+        );
+      }
+
+      SEENMENUS.add(menu);
+    }
+  }
+
+  startMenuValidate(menus) {
+    this.#menusValidate(menus);
+    this.#menus = menus;
+  }
+
+  getDate() {
+    return this.#date;
+  }
+
+  getMenus() {
+    return this.#menus;
+  }
+}
+
+export default ChristmasPromotion;

리뷰: ````js
 menus.forEach((menu) => { . . . 
````
이런 식으로 코드를 고치겠습니다. `for..of`는 사용을 지양하도록 하겠습니다!
@@ -1,7 +1,27 @@
-export default InputView = {
-    async readDate() {
-        const input = await Console.readLineAsync("12월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)");
-        // ...
-    }
-    // ...
-}
+import { MissionUtils } from "@woowacourse/mission-utils";
+import ChristmasDomain from "./ChristmasPromotion.js";
+import Order from "./Order.js";
+
+export const christmasInstance = new ChristmasDomain();
+
+const InputView = {
+  async readDate() {
+    const input = await MissionUtils.Console.readLineAsync(
+      "12월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)\n"
+    );
+    const DATE = parseInt(input, 10);
+    christmasInstance.startDateValidate(DATE);
+  },
+
+  async readOrderMenu() {
+    const input = await MissionUtils.Console.readLineAsync(
+      "주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)\n"
+    );
+    new Order(input);
+    const MENUES = input.split(",");
+    christmasInstance.startMenuValidate(MENUES);
+  },
+  // ...
+};
+
+export default InputView;

리뷰: 오호!
```js
import { Console } from "@woowacourse/mission-utils";
```
import 해오는 것도 선언했다고 표현하는 것도 처음 알았어요! 감사합니다.