-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[1단계 - 영화 목록 불러오기] 윤생(이윤성) 미션 제출합니다. #6
Merged
Merged
Changes from all commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
e2865f8
docs: 기능 요구 사항 작성
ksone02 7bc8633
feat: 컴포넌트 분리 구현
ksone02 294448a
feat: 이미지 밑 스타일 임포트
ksone02 cd2da9f
feat: 인기 영화 데이터 fetch 후 render 구현
ksone02 04cade7
feat: 인기 영화 더보기 기능 구현
ksone02 b55d92f
feat: 영화 검색 기능 구현
ksone02 354c7c8
feat: API 키 ignore
ksone02 1d3bb2f
refactor: 컴포넌트 폴더 분리
ksone02 0c225ea
feat: 영화 API 페이지 상태관리
ksone02 5cd6447
refactor: 중복되는 api 호출 로직 모듈화
ksone02 f7d9a32
refactor: 중복되는 렌더링 로직 모듈화
ksone02 99e1c57
refactor: initialRender 메서드 변경
ksone02 9cfe83e
feat: 에러에 따른 렌더링 구현
ksone02 9ce56fd
feat: 에러 컴포넌트 구현
ksone02 27d2315
test: 영화 리뷰 미션 e2e 테스트 작성
ksone02 4c0081f
refactor: Movie List Deprecated 된 코드 제거
ksone02 4bc7246
refactor: console.log 제거
ksone02 cef4beb
refactor: MoreButton 컴포넌트 코드 가독성 개선
ksone02 2847cc7
refactor: 코드 상수화
ksone02 52b82d7
refactor: event 위임 로직 if문 switch문으로 변경
ksone02 7671371
refactor: Movie list HTML 구조 변경
ksone02 cf4c7c0
refactor: header HTML 구조 변경
ksone02 b416e43
refactor: Movie List Title HTML 구조 변경
ksone02 042fdf2
refactor: App 내의 불필요한 document 선언 제거
ksone02 5472125
refactor: Skeleton 불필요한 li태그 제거
ksone02 f92c4ee
refactor: App 내부 변수명 통일
ksone02 188c7a8
refactor: App 불필요한 필드 제거
ksone02 8daad3f
refactor: List Method 네이밍 변경
ksone02 051e31a
refactor: API 처리 로직 구조 변경
ksone02 a76098d
feat: 로고 클릭시 input value 초기화
ksone02 e0adc38
refactor: url 생성 책임 분리
ksone02 0f334d1
refactor: App 더보기 버튼 액션 변경 메소드 분리
ksone02 4e865a7
refactor: App 컴포넌트 코드 가독성 개선
ksone02 c90298e
refactor: TITLE 상수화 객체 타입 단언
ksone02 5ba2e9b
refactor: 컴포넌트 전체적 가독성 개선
ksone02 d977044
refactor: constants 디렉토리 변경
ksone02 37dec5a
docs: README.md 작성
ksone02 2b4d446
refactor: 사용되지 않는 매개변수 선언 제거
2yunseong c320fcd
fix: html 마크업 수정
2yunseong 15c8f36
refactor: cypress 불필요한 파일 제거
2yunseong 6836501
refactor: 웹 접근성 개선
2yunseong 81241e9
refactor: 마크업 구조 변경에 따른 테스트 수정
2yunseong f3d200d
chore: 기술에 대한 정보를 제공하는 주석 추가
2yunseong 749e8f2
refactor: early return / 모호한 네이밍 수정
2yunseong fe64426
test: 검색창 공백 입력 시/ 입력이 비어있을 시 테스트 추가
2yunseong 7c81f7e
fix: 공백을 입력 시 검색을 하는 오류 수정
2yunseong 298e925
test: 테스트 명 수정
2yunseong 4e6de67
feat: 오류 메세지 페이지에 CTA 버튼 추가
2yunseong eaf2fbc
refactor: fetch 재사용화를 위한 책임 분리
2yunseong 6e07659
fix: totalPage 상태값 갱신하지 않은 오류 해결
2yunseong 2079624
test: 엘리먼트 선택자 변경
2yunseong 7563963
refactor: custom component 네이밍 변경
2yunseong File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
node_modules | ||
|
||
src/constants/key.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,45 @@ | ||
# javascript-movie-review | ||
|
||
FE 5기 레벨1 영화관 미션 | ||
|
||
## 페어프로그래밍 룰 | ||
|
||
1. 드라이버가 주도 네비게이터가 조언 | ||
2. 드라이버 변경시간 30분 | ||
3. 네비게이터는 집중을 잃지 않는다. | ||
4. 2시간마다 15분 휴식 | ||
5. 모르는 부분 / 논의가 필요한 부분 나오면 타이머 중단 | ||
6. 화장실이나 급한 사정은 유도리 있게 | ||
|
||
## 컴포넌트를 분리하려는 목적 | ||
|
||
1. 재사용성이 좋아진다. | ||
- 문제 요구사항을 분석했을 때, 재사용 되는 요소들이 많았다고 생각이 들었다.(더보기 버튼, 영화 목록 아이템, 페이지 타이틀) | ||
- 또한, 앱의 기능이 확장 되었을 때, 재사용 하려 만든 요소를 이용해 쉽게 기능을 확장할 수 있다고 판단이 들었다. | ||
2. 가독성이 좋아진다. | ||
- 파일을 컴포넌트 단위로 나누고, 컴포넌트를 UI, 기능별로 나누어 한 파일에 한 UI, 기능 단위의 로직만 들어가게 되어 개발자 입장에서 보기 좋은 프로젝트가 된다. | ||
3. 독립성이 향상된다. | ||
- 컴포넌트로 나누게 되면 각각의 다른 컴포넌트(기능)들의 간섭을 덜 받게 되어 로직의 안정성이 높아진다. | ||
|
||
## 개발 환경 | ||
|
||
- node v16.14.0 | ||
- npm 8.3.1 | ||
|
||
## API Key 설정 방법 | ||
|
||
- API 키를 숨기기 위해 레퍼지토리에서 숨김 처리 해두었습니다. | ||
|
||
1. src/constants 디렉토리 하위에 key.js 생성 | ||
2. 다음의 내용 입력 | ||
|
||
```javascript | ||
export const API_KEY = "사용할 API 키"; | ||
``` | ||
|
||
## e2e 테스트 방법 | ||
|
||
1. npm run start로 local server 구동(포트 8081 고정) | ||
2. npm run test-e2e로 cypress 구동 | ||
3. E2E-Testing -> Start E2E Testing in Chrome 클릭 | ||
4. cypress 창이 뜨면 movie-e2e.cy.ts 클릭 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { defineConfig } from "cypress"; | ||
|
||
export default defineConfig({ | ||
e2e: { | ||
setupNodeEvents(on, config) { | ||
// implement node event listeners here | ||
}, | ||
supportFile: false, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
describe("인기 영화 목록 페이지", () => { | ||
beforeEach(() => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
}); | ||
|
||
it("초기 접속 시에 인기 영화목록 상위 20개가 화면에 출력된다.", () => { | ||
cy.get("movie-list-page").find("movie-item").should("exist"); | ||
cy.get("movie-list-page").children().should("have.length", 20); | ||
}); | ||
|
||
it("헤더 로고 클릭 시 처음 인기 영화목록이 출력된다.", () => { | ||
cy.get("img[data-action='popular']").click(); | ||
|
||
cy.get("movie-list-page").find("movie-item").should("exist"); | ||
cy.get("movie-list-page").should("exist"); | ||
}); | ||
}); | ||
|
||
describe("인기 영화 목록 더보기", () => { | ||
it("사용자가 마지막 페이지에 도달했을 때, 더보기 버튼이 화면에서 보이지 않아야 한다.", () => { | ||
cy.intercept( | ||
{ | ||
method: "GET", | ||
url: /^https:\/\/api.themoviedb.org\/3\/movie\/popular*/, | ||
}, | ||
{ fixture: "movie-popular.json" } | ||
).as("getPopularMovies"); | ||
|
||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
cy.wait("@getPopularMovies").then(() => { | ||
cy.get("button[data-action='more_popular']").should("not.be.visible"); | ||
}); | ||
}); | ||
it("인기 영화 페이지에서 더보기 버튼 클릭시 영화 목록이 추가된다.", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
cy.get("button[data-action='more_popular']").click(); | ||
|
||
cy.get("movie-list-page").find("movie-item").should("exist"); | ||
cy.get("movie-list-page").should("have.length", 2); | ||
}); | ||
}); | ||
|
||
describe("검색 목록 확인", () => { | ||
it("검색창에 해리포터를 입력하고 검색버튼 클릭시, 제목에 '해리포터'가 포함된 영화 목록이 화면에 나온다.", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
cy.get(".search-box").find("input").type("해리포터"); | ||
cy.get("button[data-action='search']") | ||
.click() | ||
.then(() => { | ||
cy.get(".item-title").each(() => { | ||
cy.get("h3.item-title").contains(/해\s*리\s*포\s*터/); | ||
}); | ||
}); | ||
}); | ||
|
||
it("검색창에 해리포터를 입력하고 엔터키를 누르면, 제목에 '해리포터'가 포함된 영화 목록이 화면에 나타난다.", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
cy.get(".search-box") | ||
.find("input") | ||
.type("해리포터{enter}") | ||
.then(() => { | ||
cy.get(".item-title").each(() => { | ||
cy.get("h3.item-title").contains(/해\s*리\s*포\s*터/); | ||
}); | ||
}); | ||
}); | ||
|
||
it("검색창에 검색결과가 없는 검색어를 입력한 후 검색하는데, 결과가 존재하지 않을 시 검색결과 없음 페이지가 화면에 나타난다.", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
cy.get(".search-box") | ||
.find("input") | ||
.type("sdmnfbikrdnfivjdnfodmfhfidff{enter}") | ||
.then(() => { | ||
cy.get(".no-result-title").contains("검색 결과를 찾지 못하였습니다."); | ||
}); | ||
}); | ||
|
||
it("검색창에 입력을 하지 않고 엔터키를 누르면 사용자에게 검색어가 없다는 경고창이 화면에 나온다.", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
const stub = cy.stub(); | ||
|
||
cy.on("window:alert", stub); | ||
|
||
cy.get(".search-box") | ||
.find("input") | ||
.type("{enter}") | ||
.then(() => { | ||
expect(stub.getCall(0)).to.be.calledWith("검색어를 입력해주세요."); | ||
}); | ||
}); | ||
|
||
it("검색창에 입력을 하지 않고 검색버튼을 클릭하면 사용자에게 검색어가 없다는 경고창이 화면에 나온다.", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
const stub = cy.stub(); | ||
|
||
cy.on("window:alert", stub); | ||
|
||
cy.get(".search-button") | ||
.click() | ||
.then(() => { | ||
expect(stub.getCall(0)).to.be.calledWith("검색어를 입력해주세요."); | ||
}); | ||
}); | ||
|
||
it("검색창에 공백만을 입력하고 검색버튼을 클릭하면 사용자에게 검색어가 없다는 경고창이 화면에 나온다.", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
const stub = cy.stub(); | ||
cy.on("window:alert", stub); | ||
|
||
cy.get(".search-box").find("input").type(" "); | ||
cy.get(".search-button") | ||
.click() | ||
.then(() => { | ||
expect(stub.getCall(0)).to.be.calledWith("검색어를 입력해주세요."); | ||
}); | ||
}); | ||
|
||
it("검색창에 공백만을 입력하고 엔터키를 누르면 사용자에게 검색어가 없다는 경고창이 화면에 나온다.", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
const stub = cy.stub(); | ||
cy.on("window:alert", stub); | ||
|
||
cy.get(".search-box") | ||
.find("input") | ||
.type(" {enter}") | ||
.then(() => { | ||
expect(stub.getCall(0)).to.be.calledWith("검색어를 입력해주세요."); | ||
}); | ||
}); | ||
}); | ||
|
||
describe("검색목록 더보기 확인", () => { | ||
it("검색결과 페이지에서 더보기 버튼 클릭시 검색목록이 추가된다. ", () => { | ||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
cy.get(".search-box") | ||
.find("input") | ||
.type("전쟁{enter}") | ||
.then(() => { | ||
cy.get("button[data-action='more_search']").click(); | ||
|
||
cy.get("movie-list-page").find("movie-item").should("exist"); | ||
cy.get("movie-list-page").should("have.length", 2); | ||
}) | ||
.then(() => { | ||
cy.get("h3.item-title").each(() => { | ||
cy.get("h3.item-title").contains(/전\s*쟁/); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe("네트워크 에러 확인", () => { | ||
it("네트워크 접속 오류 시 에러 페이지가 화면에 나타난다.", () => { | ||
cy.intercept( | ||
{ | ||
method: "GET", | ||
url: /^https:\/\/api.themoviedb.org\/3\/movie\/popular*/, | ||
}, | ||
{ statusCode: 401 } | ||
).as("getErrorData"); | ||
|
||
cy.visit("http://localhost:8081/"); | ||
cy.viewport(1920, 1080); | ||
|
||
cy.wait("@getErrorData").then(() => { | ||
cy.get(".error-title").contains("오류"); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
적용안된 부분이 보이는데 적용해주시면 좋을 것 같아요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
viewport
말씀하시는건가요??intercept
를 접속 이전에 실행해야 되는걸로 알고 있어 나머지는 중복으로 작성했는데, 다시 한번 알아볼께요!