선택할 수 있는 시간이 없습니다.
';
- return;
- }
- times.forEach(time => {
- const div = createSlot('time', time.time, time.timeId, time.booked);
- timeSlots.appendChild(div);
- });
+ const timeSection = document.getElementById("time-section");
+ if (timeSection.classList.contains("disabled")) {
+ timeSection.classList.remove("disabled");
+ }
+
+ const timeSlots = document.getElementById('time-slots');
+ timeSlots.innerHTML = '';
+ if (times.length === 0) {
+ timeSlots.innerHTML = '선택할 수 있는 시간이 없습니다.
';
+ return;
+ }
+ times.forEach(time => {
+ const div = createSlot('time', time.time, time.timeId, time.booked);
+ timeSlots.appendChild(div);
+ });
}
function checkDateAndThemeAndTime() {
- const selectedDate = document.getElementById("datepicker").value;
- const selectedThemeElement = document.querySelector('.theme-slot.active');
- const selectedTimeElement = document.querySelector('.time-slot.active');
- const reserveButton = document.getElementById("reserve-button");
- const waitButton = document.getElementById("wait-button"); // '예약 대기 버튼'의 ID 가정
-
- if (selectedDate && selectedThemeElement && selectedTimeElement) {
- if (selectedTimeElement.getAttribute('data-time-booked') === 'true') {
- // 선택된 시간이 이미 예약된 경우
- reserveButton.classList.add("disabled");
- waitButton.classList.remove("disabled"); // 예약 대기 버튼 활성화
+ const selectedDate = document.getElementById("datepicker").value;
+ const selectedThemeElement = document.querySelector('.theme-slot.active');
+ const selectedTimeElement = document.querySelector('.time-slot.active');
+ const reserveButton = document.getElementById("reserve-button");
+ const waitButton = document.getElementById("wait-button"); // '예약 대기 버튼'의 ID 가정
+
+ if (selectedDate && selectedThemeElement && selectedTimeElement) {
+ if (selectedTimeElement.getAttribute('data-time-booked') === 'true') {
+ // 선택된 시간이 이미 예약된 경우
+ reserveButton.classList.add("disabled");
+ waitButton.classList.remove("disabled"); // 예약 대기 버튼 활성화
+ } else {
+ // 선택된 시간이 예약 가능한 경우
+ reserveButton.classList.remove("disabled");
+ waitButton.classList.add("disabled"); // 예약 대기 버튼 비활성화
+ }
} else {
- // 선택된 시간이 예약 가능한 경우
- reserveButton.classList.remove("disabled");
- waitButton.classList.add("disabled"); // 예약 대기 버튼 비활성화
+ // 날짜, 테마, 시간 중 하나라도 선택되지 않은 경우
+ reserveButton.classList.add("disabled");
+ waitButton.classList.add("disabled");
}
- } else {
- // 날짜, 테마, 시간 중 하나라도 선택되지 않은 경우
- reserveButton.classList.add("disabled");
- waitButton.classList.add("disabled");
- }
}
function onReservationButtonClick() {
- const selectedDate = document.getElementById("datepicker").value;
- const selectedThemeId = document.querySelector('.theme-slot.active')?.getAttribute('data-theme-id');
- const selectedTimeId = document.querySelector('.time-slot.active')?.getAttribute('data-time-id');
-
- if (selectedDate && selectedThemeId && selectedTimeId) {
- const reservationData = {
- date: selectedDate,
- theme: selectedThemeId,
- time: selectedTimeId
- };
-
- fetch('/reservations', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(reservationData)
- })
- .then(response => {
- if (!response.ok) throw new Error('Reservation failed');
- return response.json();
+ const selectedDate = document.getElementById("datepicker").value;
+ const selectedThemeId = document.querySelector('.theme-slot.active')?.getAttribute('data-theme-id');
+ const selectedTimeId = document.querySelector('.time-slot.active')?.getAttribute('data-time-id');
+
+ if (selectedDate && selectedThemeId && selectedTimeId) {
+ const reservationData = {
+ date: selectedDate,
+ theme: selectedThemeId,
+ time: selectedTimeId
+ };
+
+ fetch('/reservations', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(reservationData)
})
- .then(data => {
- alert("Reservation successful!");
- window.location.href = "/";
- })
- .catch(error => {
- alert("An error occurred while making the reservation.");
- console.error(error);
- });
- } else {
- alert("Please select a date, theme, and time before making a reservation.");
- }
+ .then(response => {
+ if (!response.ok) throw new Error('Reservation failed');
+ return response.json();
+ })
+ .then(data => {
+ alert("Reservation successful!");
+ window.location.href = "/";
+ })
+ .catch(error => {
+ alert("An error occurred while making the reservation.");
+ console.error(error);
+ });
+ } else {
+ alert("Please select a date, theme, and time before making a reservation.");
+ }
}
function onWaitButtonClick() {
- const selectedDate = document.getElementById("datepicker").value;
- const selectedThemeId = document.querySelector('.theme-slot.active')?.getAttribute('data-theme-id');
- const selectedTimeId = document.querySelector('.time-slot.active')?.getAttribute('data-time-id');
-
- if (selectedDate && selectedThemeId && selectedTimeId) {
- const reservationData = {
- date: selectedDate,
- theme: selectedThemeId,
- time: selectedTimeId
- };
-
- fetch('/waitings', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(reservationData)
- })
- .then(response => {
- if (!response.ok) throw new Error('Reservation failed');
- return response.json();
- })
- .then(data => {
- alert("대기 순서" + data.waitingNumber + "번째");
- window.location.href = "/";
+ const selectedDate = document.getElementById("datepicker").value;
+ const selectedThemeId = document.querySelector('.theme-slot.active')?.getAttribute('data-theme-id');
+ const selectedTimeId = document.querySelector('.time-slot.active')?.getAttribute('data-time-id');
+
+ if (selectedDate && selectedThemeId && selectedTimeId) {
+ const reservationData = {
+ date: selectedDate,
+ theme: selectedThemeId,
+ time: selectedTimeId
+ };
+
+ fetch('/waitings', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(reservationData)
})
- .catch(error => {
- alert("An error occurred while making the reservation.");
- console.error(error);
- });
- } else {
- alert("Please select a date, theme, and time before making a reservation.");
- }
+ .then(response => {
+ if (!response.ok) throw new Error('Reservation failed');
+ return response.json();
+ })
+ .then(data => {
+ alert("대기 순서" + data.waitingNumber + "번째");
+ window.location.href = "/";
+ })
+ .catch(error => {
+ alert("An error occurred while making the reservation.");
+ console.error(error);
+ });
+ } else {
+ alert("Please select a date, theme, and time before making a reservation.");
+ }
}
function requestRead(endpoint) {
- return fetch(endpoint)
- .then(response => {
- if (response.status === 200) return response.json();
- throw new Error('Read failed');
- });
+ return fetch(endpoint)
+ .then(response => {
+ if (response.status === 200) return response.json();
+ throw new Error('Read failed');
+ });
}
diff --git a/src/main/resources/static/js/user-scripts.js b/src/main/resources/static/js/user-scripts.js
index 758f4f53..aaf3edf0 100644
--- a/src/main/resources/static/js/user-scripts.js
+++ b/src/main/resources/static/js/user-scripts.js
@@ -1,150 +1,150 @@
document.addEventListener('DOMContentLoaded', function () {
- updateUIBasedOnLogin();
+ updateUIBasedOnLogin();
});
document.getElementById('logout-btn').addEventListener('click', function () {
- fetch('/logout', {
- method: 'POST', // 또는 서버 설정에 따라 GET 일 수도 있음
- credentials: 'include' // 쿠키를 포함시키기 위해 필요
- })
- .then(response => {
- if(response.ok) {
- // 로그아웃 성공, 페이지 새로고침 또는 리다이렉트
- window.location.reload();
- } else {
- // 로그아웃 실패 처리
- console.error('Logout failed');
- }
- })
- .catch(error => {
- console.error('Error:', error);
- });
+ fetch('/logout', {
+ method: 'POST', // 또는 서버 설정에 따라 GET 일 수도 있음
+ credentials: 'include' // 쿠키를 포함시키기 위해 필요
+ })
+ .then(response => {
+ if (response.ok) {
+ // 로그아웃 성공, 페이지 새로고침 또는 리다이렉트
+ window.location.reload();
+ } else {
+ // 로그아웃 실패 처리
+ console.error('Logout failed');
+ }
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ });
});
function updateUIBasedOnLogin() {
- fetch('/login/check') // 로그인 상태 확인 API 호출
- .then(response => {
- if (!response.ok) { // 요청이 실패하거나 로그인 상태가 아닌 경우
- throw new Error('Not logged in or other error');
- }
- return response.json(); // 응답 본문을 JSON으로 파싱
- })
- .then(data => {
- // 응답에서 사용자 이름을 추출하여 UI 업데이트
- document.getElementById('profile-name').textContent = data.name; // 프로필 이름 설정
- document.querySelector('.nav-item.dropdown').style.display = 'block'; // 드롭다운 메뉴 표시
- document.querySelector('.nav-item a[href="/login"]').parentElement.style.display = 'none'; // 로그인 버튼 숨김
- })
- .catch(error => {
- // 에러 처리 또는 로그아웃 상태일 때 UI 업데이트
- console.error('Error:', error);
- document.getElementById('profile-name').textContent = 'Profile'; // 기본 텍스트로 재설정
- document.querySelector('.nav-item.dropdown').style.display = 'none'; // 드롭다운 메뉴 숨김
- document.querySelector('.nav-item a[href="/login"]').parentElement.style.display = 'block'; // 로그인 버튼 표시
- });
+ fetch('/login/check') // 로그인 상태 확인 API 호출
+ .then(response => {
+ if (!response.ok) { // 요청이 실패하거나 로그인 상태가 아닌 경우
+ throw new Error('Not logged in or other error');
+ }
+ return response.json(); // 응답 본문을 JSON으로 파싱
+ })
+ .then(data => {
+ // 응답에서 사용자 이름을 추출하여 UI 업데이트
+ document.getElementById('profile-name').textContent = data.name; // 프로필 이름 설정
+ document.querySelector('.nav-item.dropdown').style.display = 'block'; // 드롭다운 메뉴 표시
+ document.querySelector('.nav-item a[href="/login"]').parentElement.style.display = 'none'; // 로그인 버튼 숨김
+ })
+ .catch(error => {
+ // 에러 처리 또는 로그아웃 상태일 때 UI 업데이트
+ console.error('Error:', error);
+ document.getElementById('profile-name').textContent = 'Profile'; // 기본 텍스트로 재설정
+ document.querySelector('.nav-item.dropdown').style.display = 'none'; // 드롭다운 메뉴 숨김
+ document.querySelector('.nav-item a[href="/login"]').parentElement.style.display = 'block'; // 로그인 버튼 표시
+ });
}
// 드롭다운 메뉴 토글
document.getElementById("navbarDropdown").addEventListener('click', function (e) {
- const dropdownMenu = e.target.closest('.nav-item.dropdown').querySelector('.dropdown-menu');
- dropdownMenu.classList.toggle('show'); // Bootstrap 4에서는 data-toggle 사용, Bootstrap 5에서는 JS로 처리
+ const dropdownMenu = e.target.closest('.nav-item.dropdown').querySelector('.dropdown-menu');
+ dropdownMenu.classList.toggle('show'); // Bootstrap 4에서는 data-toggle 사용, Bootstrap 5에서는 JS로 처리
});
function login() {
- const email = document.getElementById('email').value;
- const password = document.getElementById('password').value;
+ const email = document.getElementById('email').value;
+ const password = document.getElementById('password').value;
- // 입력 필드 검증
- if (!email || !password) {
- alert('Please fill in all fields.');
- return; // 필수 입력 필드가 비어있으면 여기서 함수 실행을 중단
- }
+ // 입력 필드 검증
+ if (!email || !password) {
+ alert('Please fill in all fields.');
+ return; // 필수 입력 필드가 비어있으면 여기서 함수 실행을 중단
+ }
- fetch('/login', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- email: email,
- password: password
+ fetch('/login', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ email: email,
+ password: password
+ })
})
- })
- .then(response => {
- if (200 === !response.status) {
- alert('Login failed'); // 로그인 실패 시 경고창 표시
- throw new Error('Login failed');
- }
- })
- .then(() => {
- updateUIBasedOnLogin(); // UI 업데이트
- window.location.href = '/';
- })
- .catch(error => {
- console.error('Error during login:', error);
- });
+ .then(response => {
+ if (200 === !response.status) {
+ alert('Login failed'); // 로그인 실패 시 경고창 표시
+ throw new Error('Login failed');
+ }
+ })
+ .then(() => {
+ updateUIBasedOnLogin(); // UI 업데이트
+ window.location.href = '/';
+ })
+ .catch(error => {
+ console.error('Error during login:', error);
+ });
}
function signup() {
- // Redirect to signup page
- window.location.href = '/signup';
+ // Redirect to signup page
+ window.location.href = '/signup';
}
function register(event) {
- // 폼 데이터 수집
- const email = document.getElementById('email').value;
- const password = document.getElementById('password').value;
- const name = document.getElementById('name').value;
+ // 폼 데이터 수집
+ const email = document.getElementById('email').value;
+ const password = document.getElementById('password').value;
+ const name = document.getElementById('name').value;
- // 입력 필드 검증
- if (!email || !password || !name) {
- alert('Please fill in all fields.');
- return; // 필수 입력 필드가 비어있으면 여기서 함수 실행을 중단
- }
+ // 입력 필드 검증
+ if (!email || !password || !name) {
+ alert('Please fill in all fields.');
+ return; // 필수 입력 필드가 비어있으면 여기서 함수 실행을 중단
+ }
- // 요청 데이터 포맷팅
- const formData = {
- email: email,
- password: password,
- name: name
- };
+ // 요청 데이터 포맷팅
+ const formData = {
+ email: email,
+ password: password,
+ name: name
+ };
- // AJAX 요청 생성 및 전송
- fetch('/members', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(formData)
- })
- .then(response => {
- if (!response.ok) {
- alert('Signup request failed');
- throw new Error('Signup request failed');
- }
- return response.json(); // 여기서 응답을 JSON 형태로 변환
- })
- .then(data => {
- // 성공적인 응답 처리
- console.log('Signup successful:', data);
- window.location.href = '/login';
- })
- .catch(error => {
- // 에러 처리
- console.error('Error during signup:', error);
- });
+ // AJAX 요청 생성 및 전송
+ fetch('/members', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(formData)
+ })
+ .then(response => {
+ if (!response.ok) {
+ alert('Signup request failed');
+ throw new Error('Signup request failed');
+ }
+ return response.json(); // 여기서 응답을 JSON 형태로 변환
+ })
+ .then(data => {
+ // 성공적인 응답 처리
+ console.log('Signup successful:', data);
+ window.location.href = '/login';
+ })
+ .catch(error => {
+ // 에러 처리
+ console.error('Error during signup:', error);
+ });
- // 폼 제출에 의한 페이지 리로드 방지
- event.preventDefault();
+ // 폼 제출에 의한 페이지 리로드 방지
+ event.preventDefault();
}
function base64DecodeUnicode(str) {
- // Base64 디코딩
- const decodedBytes = atob(str);
- // UTF-8 바이트를 문자열로 변환
- const encodedUriComponent = decodedBytes.split('').map(function (c) {
- return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
- }).join('');
- return decodeURIComponent(encodedUriComponent);
-}
\ No newline at end of file
+ // Base64 디코딩
+ const decodedBytes = atob(str);
+ // UTF-8 바이트를 문자열로 변환
+ const encodedUriComponent = decodedBytes.split('').map(function (c) {
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
+ }).join('');
+ return decodeURIComponent(encodedUriComponent);
+}
diff --git a/src/main/resources/templates/admin/index.html b/src/main/resources/templates/admin/index.html
index 8c2de6ad..dcac3ea3 100644
--- a/src/main/resources/templates/admin/index.html
+++ b/src/main/resources/templates/admin/index.html
@@ -1,56 +1,56 @@
-
-
예약 페이지
-
-
-
+
+
예약 페이지
+
-
-
-
+
+
+
-
\ No newline at end of file
+
diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html
index 8965f2dd..de0e0812 100644
--- a/src/main/resources/templates/signup.html
+++ b/src/main/resources/templates/signup.html
@@ -1,65 +1,65 @@
-
-
-
Signup
-
-
-
+
+
+
Signup
+
+
+
diff --git a/src/test/java/roomescape/JpaTest.java b/src/test/java/roomescape/JpaTest.java
new file mode 100644
index 00000000..06e9ad9b
--- /dev/null
+++ b/src/test/java/roomescape/JpaTest.java
@@ -0,0 +1,37 @@
+package roomescape;
+
+import org.junit.jupiter.api.DisplayNameGeneration;
+import org.junit.jupiter.api.DisplayNameGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
+import org.springframework.test.context.ActiveProfiles;
+import roomescape.time.Time;
+import roomescape.time.TimeRepository;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+@SuppressWarnings("NonAsciiCharacters")
+@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
+@DataJpaTest
+@ActiveProfiles("test")
+public class JpaTest {
+
+ @Autowired
+ private TestEntityManager entityManager;
+
+ @Autowired
+ private TimeRepository timeRepository;
+
+ @Test
+ void 사단계() {
+ Time time = new Time("10:00");
+ entityManager.persist(time);
+ entityManager.flush();
+
+ Time persistTime = timeRepository.findById(time.getId()).orElse(null);
+
+ assertThat(persistTime.getValue()).isEqualTo(time.getValue());
+ }
+}
diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java
index 6add784b..a1bf072c 100644
--- a/src/test/java/roomescape/MissionStepTest.java
+++ b/src/test/java/roomescape/MissionStepTest.java
@@ -4,19 +4,31 @@
import io.restassured.http.ContentType;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
+import jwt.JwtUtils;
import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.stereotype.Component;
import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+import roomescape.reservation.dto.MyReservationResponse;
+import roomescape.reservation.dto.ReservationResponse;
+import roomescape.waiting.dto.WaitingResponse;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
+@ActiveProfiles("test")
public class MissionStepTest {
+ @Value("${jwt.secret}")
+ private String secretKey;
+
@Test
void 일단계() {
Map
params = new HashMap<>();
@@ -32,7 +44,155 @@ public class MissionStepTest {
.extract();
String token = response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1];
-
assertThat(token).isNotBlank();
+
+ ExtractableResponse checkResponse = RestAssured.given().log().all()
+ .contentType(ContentType.JSON)
+ .cookie("token", token)
+ .when().get("/login/check")
+ .then().log().all()
+ .statusCode(200)
+ .extract();
+
+ assertThat(checkResponse.body().jsonPath().getString("name")).isEqualTo("어드민");
+ }
+
+ private String createToken(String email, String password) {
+ Map params = new HashMap<>();
+ params.put("email", email);
+ params.put("password", password);
+
+ ExtractableResponse response = RestAssured.given().log().all()
+ .contentType(ContentType.JSON)
+ .body(params)
+ .when().post("/login")
+ .then().log().all()
+ .statusCode(200)
+ .extract();
+
+ return response.headers().get("Set-Cookie").getValue().split(";")[0].split("=")[1];
+ }
+
+ @Test
+ void 이단계() {
+ String token = createToken("admin@email.com", "password");
+
+ Map params1 = new HashMap<>();
+ params1.put("date", "2024-01-01");
+ params1.put("time", "1");
+ params1.put("theme", "1");
+
+ Map params2 = new HashMap<>();
+ params2.put("date", "2024-01-02");
+ params2.put("time", "1");
+ params2.put("theme", "1");
+
+ ExtractableResponse response = RestAssured.given().log().all()
+ .body(params1)
+ .cookie("token", token)
+ .contentType(ContentType.JSON)
+ .post("/reservations")
+ .then().log().all()
+ .extract();
+
+ assertThat(response.statusCode()).isEqualTo(201);
+ assertThat(response.as(ReservationResponse.class).getName()).isEqualTo("어드민");
+
+ params2.put("name", "브라운");
+
+ ExtractableResponse adminResponse = RestAssured.given().log().all()
+ .body(params2)
+ .cookie("token", token)
+ .contentType(ContentType.JSON)
+ .post("/reservations")
+ .then().log().all()
+ .extract();
+
+ assertThat(adminResponse.statusCode()).isEqualTo(201);
+ assertThat(adminResponse.as(ReservationResponse.class).getName()).isEqualTo("브라운");
+ }
+
+ @Test
+ void 삼단계() {
+ String brownToken = createToken("brown@email.com", "password");
+
+ RestAssured.given().log().all()
+ .cookie("token", brownToken)
+ .get("/admin")
+ .then().log().all()
+ .statusCode(401);
+
+ String adminToken = createToken("admin@email.com", "password");
+
+ RestAssured.given().log().all()
+ .cookie("token", adminToken)
+ .get("/admin")
+ .then().log().all()
+ .statusCode(200);
+ }
+
+ @Test
+ void 오단계() {
+ String adminToken = createToken("admin@email.com", "password");
+
+ List reservations = RestAssured.given().log().all()
+ .cookie("token", adminToken)
+ .get("/reservations-mine")
+ .then().log().all()
+ .statusCode(200)
+ .extract().jsonPath().getList(".", MyReservationResponse.class);
+
+ assertThat(reservations).hasSize(3);
+ }
+
+ @Test
+ void 육단계() {
+ String brownToken = createToken("brown@email.com", "password");
+
+ Map params = new HashMap<>();
+ params.put("date", "2024-03-01");
+ params.put("time", "1");
+ params.put("theme", "1");
+
+ // 예약 대기 생성
+ WaitingResponse waiting = RestAssured.given().log().all()
+ .body(params)
+ .cookie("token", brownToken)
+ .contentType(ContentType.JSON)
+ .post("/waitings")
+ .then().log().all()
+ .statusCode(201)
+ .extract().as(WaitingResponse.class);
+
+ // 내 예약 목록 조회
+ List myReservations = RestAssured.given().log().all()
+ .body(params)
+ .cookie("token", brownToken)
+ .contentType(ContentType.JSON)
+ .get("/reservations-mine")
+ .then().log().all()
+ .statusCode(200)
+ .extract().jsonPath().getList(".", MyReservationResponse.class);
+
+ // 예약 대기 상태 확인
+ String status = myReservations.stream()
+ .filter(it -> it.getId() == waiting.getId())
+ .filter(it -> !it.getStatus().equals("예약"))
+ .findFirst()
+ .map(it -> it.getStatus())
+ .orElse(null);
+
+ assertThat(status).isEqualTo("1번째 예약대기");
+ }
+
+ @Test
+ void 칠단계() {
+ Component componentAnnotation = JwtUtils.class.getAnnotation(Component.class);
+ assertThat(componentAnnotation).isNull();
+ }
+
+ @Test
+ void 팔단계() {
+ assertThat(secretKey).isNotBlank();
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/roomescape/initializer/TestDataLoader.java b/src/test/java/roomescape/initializer/TestDataLoader.java
new file mode 100644
index 00000000..b79910b3
--- /dev/null
+++ b/src/test/java/roomescape/initializer/TestDataLoader.java
@@ -0,0 +1,51 @@
+package roomescape.initializer;
+
+import jakarta.persistence.EntityManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@Profile("test")
+public class TestDataLoader implements ApplicationRunner {
+
+ @Autowired
+ private EntityManager entityManager;
+
+ @Override
+ @Transactional
+ public void run(ApplicationArguments args) throws Exception {
+ loadTestData();
+ }
+
+ private void loadTestData() {
+ entityManager.createNativeQuery(
+ "INSERT INTO member (name, email, password, role) VALUES " +
+ "('어드민', 'admin@email.com', 'password', 'ADMIN'),\n" +
+ "('브라운', 'brown@email.com', 'password', 'USER')"
+ ).executeUpdate();
+
+ entityManager.createNativeQuery(
+ "INSERT INTO theme (name, description) VALUES " +
+ "('테마1', '테마1입니다.'), ('테마2', '테마2입니다.'), ('테마3', '테마3입니다.')"
+ ).executeUpdate();
+
+ entityManager.createNativeQuery(
+ "INSERT INTO time (time_value) VALUES ('10:00'), ('12:00'), ('14:00'), ('16:00'), ('18:00'), ('20:00')"
+ ).executeUpdate();
+
+ entityManager.createNativeQuery(
+ "INSERT INTO reservation (member_id, name, date, time_id, theme_id) VALUES \n" +
+ "(1, '어드민', '2024-03-01', 1, 1), \n" +
+ "(1, '어드민', '2024-03-01', 2, 2), \n" +
+ "(1, '어드민', '2024-03-01', 3, 3)"
+ ).executeUpdate();
+
+ entityManager.createNativeQuery(
+ "INSERT INTO reservation (name, date, time_id, theme_id) VALUES ('브라운', '2024-03-01', 1, 2)"
+ ).executeUpdate();
+ }
+}