Skip to content

Commit

Permalink
[1단계 - 영화 목록 불러오기] 윤생(이윤성) 미션 제출합니다. (#6)
Browse files Browse the repository at this point in the history
* docs: 기능 요구 사항 작성

Co-authored-by: 2yunseong <2yunseong@users.noreply.github.com>

* feat: 컴포넌트 분리 구현

* feat: 이미지 밑 스타일 임포트

* feat: 인기 영화 데이터 fetch 후 render 구현

* feat: 인기 영화 더보기 기능 구현

* feat: 영화 검색 기능 구현

* feat: API 키 ignore

* refactor: 컴포넌트 폴더 분리

* feat: 영화 API 페이지 상태관리

* refactor: 중복되는 api 호출 로직 모듈화

* refactor: 중복되는 렌더링 로직 모듈화

* refactor: initialRender 메서드 변경

* feat: 에러에 따른 렌더링 구현

* feat: 에러 컴포넌트 구현

* test: 영화 리뷰 미션 e2e 테스트 작성

Co-authored-by: 2yunseong <2yunseong@users.noreply.github.com>

* refactor: Movie List Deprecated 된 코드 제거

* refactor: console.log 제거

* refactor: MoreButton 컴포넌트 코드 가독성 개선

* refactor: 코드 상수화

* refactor: event 위임 로직 if문 switch문으로 변경

* refactor: Movie list HTML 구조 변경

* refactor: header HTML 구조 변경

* refactor: Movie List Title HTML 구조 변경

* refactor: App 내의 불필요한 document 선언 제거

* refactor: Skeleton 불필요한 li태그 제거

* refactor: App 내부 변수명 통일

* refactor: App 불필요한 필드 제거

* refactor: List Method 네이밍 변경

* refactor: API 처리 로직 구조 변경

* feat: 로고 클릭시 input value 초기화

* refactor: url 생성 책임 분리

* refactor: App 더보기 버튼 액션 변경 메소드 분리

* refactor: App 컴포넌트 코드 가독성 개선

* refactor: TITLE 상수화 객체 타입 단언

* refactor: 컴포넌트 전체적 가독성 개선

* refactor: constants 디렉토리 변경

* docs: README.md 작성

* refactor: 사용되지 않는 매개변수 선언 제거

* fix: html 마크업 수정

* refactor: cypress 불필요한 파일 제거

* refactor: 웹 접근성 개선

* refactor: 마크업 구조 변경에 따른 테스트 수정

* chore: 기술에 대한 정보를 제공하는 주석 추가

* refactor: early return / 모호한 네이밍 수정

* test: 검색창 공백 입력 시/ 입력이 비어있을 시 테스트 추가

* fix: 공백을 입력 시 검색을 하는 오류 수정

* test: 테스트 명 수정

* feat: 오류 메세지 페이지에 CTA 버튼 추가

* refactor: fetch 재사용화를 위한 책임 분리

* fix: totalPage 상태값 갱신하지 않은 오류 해결

* test: 엘리먼트 선택자 변경

* refactor: custom component 네이밍 변경

---------

Co-authored-by: SangwonKang <72087183+ksone02@users.noreply.github.com>
Co-authored-by: 2yunseong <2yunseong@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 25, 2023
1 parent 965a557 commit 3f9c0b0
Show file tree
Hide file tree
Showing 27 changed files with 1,219 additions and 16 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules

src/constants/key.js
42 changes: 42 additions & 0 deletions README.md
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 클릭
10 changes: 10 additions & 0 deletions cypress.config.ts
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,
},
});
190 changes: 190 additions & 0 deletions cypress/e2e/movie-e2e.cy.ts
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("오류");
});
});
});
Loading

0 comments on commit 3f9c0b0

Please sign in to comment.