Skip to content

Commit

Permalink
[2단계 - 음식점 목록] 윤생(이윤성) 미션 제출합니다. (#53)
Browse files Browse the repository at this point in the history
* docs: 요구사항 목록 갱신

* refactor: Component Interface 변경

- render와 setState를 강제하지 않음

* feat: 탭바 UI 토글 기능 추가

* feat: 탭 바 메뉴별 정렬 로직 구현

* feat: 자주 가는 음식점 버튼 토글 기능 구현 및 저장소에 요청

* fix: 좋아요 상태 변경 시 리렌더링 로직 추가

* feat: Drawer 좋아요 토글 동작 구현

* refactor: 이벤트 리스너 등록 로직 메서드로 묶음

* refactor: export default 축약

* refactor: 사용성 개선

* docs: 요구사항 최신화 및 e2e테스트 기능 명세 작성

* test: 음식점 추가 버튼 클릭 테스트

* test: 음식점 추가 창 취소하기 버튼 테스트

* test: 음식 종류 별 정렬 기능 테스트

* refactor: 의미에 맞지 않는 html 태그 변경 및 class name 할당

* test: 음식점 이름/거리 순 정렬 기능 테스트

* test: 탭바 테스트

* test: 음식정 상세 정보 창 테스트

* refactor: 이벤트 핸들러 이름 일관성 부여

* refactor: 불필요한 setState 제거

* refactor: 컴포넌트에 불필한 로직 분리

* refactor: 메서드 분리

* refactor: 비구조화 할당 제거

* refactor: 디렉터리 구조 변경

* test: 음식점 목록 자주가는 음식점 토글 기능 테스트

* docs: 요구사항 목록 최신화

* feat: 고유한 아이디를 생성하게 구현

* refactor: 레스토랑 등록 로직 분리

* refactor: 사용하지 않는 import 제거

* refactor: 재사용 되는 로직 분리

* refactor: img src 소스 링크 상수화

* test: 코드 중복 제거

* test: 테스트 이름 변경

* refactor: 축약된 이름 변경

* refactor: 불필요한 리렌더링 제거

* refactor: 이벤트 위임으로 핸들러 일반화

* refactor: 이벤트 위임으로 변경

* refactor: DropDown 이벤트 핸들러 메서드 로직 병합

* refactor: 접근 제한자 부여

* refactor: drawer html 분리
  • Loading branch information
2yunseong authored Mar 13, 2023
1 parent c71f3a0 commit e299419
Show file tree
Hide file tree
Showing 31 changed files with 1,024 additions and 306 deletions.
6 changes: 3 additions & 3 deletions __tests__/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('컴포넌트 랜더링 테스트', () => {

describe('GNB 테스트', () => {
test('GNB를 화면에 잘 나타내는지 테스트', () => {
new GNB({ $parent: document.body, toggleAddRestaurantDrawer: () => {} }).render();
new GNB({ $parent: document.body, onToggleAddRestaurantDrawer: () => {} }).render();
expect(screen.getByText('점심 뭐 먹지')).toBeInTheDocument();
});
});
Expand All @@ -82,7 +82,7 @@ describe('컴포넌트 랜더링 테스트', () => {
test('select 태그 렌더링 테스트: 카테고리', () => {
new AddRestaurantDrawer({
$parent: document.body,
toggleAddRestaurantDrawer: () => {},
onToggleAddRestaurantDrawer: () => {},
}).render();
const categoryElement = document.getElementById('category');
const categories = ['한식', '중식', '일식', '양식', '아시안', '기타'];
Expand All @@ -94,7 +94,7 @@ describe('컴포넌트 랜더링 테스트', () => {
test('select 태그 렌더링 테스트: 거리(도보 x분)', () => {
new AddRestaurantDrawer({
$parent: document.body,
toggleAddRestaurantDrawer: () => {},
onToggleAddRestaurantDrawer: () => {},
}).render();
const distanceElement = document.getElementById('distance');
const distances = [5, 10, 15, 20, 30];
Expand Down
9 changes: 9 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineConfig } from "cypress";

export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});
151 changes: 151 additions & 0 deletions cypress/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
export const CATEGORY_TEST_CASE = [
{
id: 0,
category: '한식',
name: '가_한식',
distance: '30',
description: '가_한식입니다.',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 1,
category: '한식',
name: '나_한식',
distance: '15',
description: '나_한식입니다.',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 2,
category: '중식',
name: '다_중식',
distance: '10',
description: '다_중식입니다.',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 3,
category: '일식',
name: '라_일식',
distance: '5',
description: '라_일식입니다',
link: '',
isFavorite: false,
},
{
id: 4,
category: '양식',
name: '하_오분거리 양식',
distance: '5',
description: '5분거리',
link: '',
isFavorite: false,
},
{
id: 5,
category: '아시안',
name: '하_오분거리 아시안',
distance: '5',
description: '5분거리',
link: '',
isFavorite: false,
},
];

export const SORTING_TEST_CASE = [
{
id: 0,
category: '한식',
name: '다섯번째 거리',
distance: '30',
description: '한식입니다.',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 1,
category: '한식',
name: '세번째 거리',
distance: '15',
description: '한식입니다.',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 2,
category: '한식',
name: '두번째 거리',
distance: '10',
description: '한식입니다.',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 3,
category: '한식',
name: '네번째 거리',
distance: '20',
description: '한식입니다.',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 4,
category: '한식',
name: '첫번째 거리',
distance: '5',
description: '한식입니다.',
link: 'http://www.naver.com',
isFavorite: false,
},
];

export const FAVORITES_TEST_CASE = [
{
id: 0,
category: '한식',
name: '매우_좋아요',
distance: '5',
description: 'good',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 1,
category: '한식',
name: '안좋아요',
distance: '5',
description: 'good',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 2,
category: '한식',
name: '안좋아요',
distance: '5',
description: 'good',
link: 'http://www.naver.com',
isFavorite: false,
},
{
id: 3,
category: '한식',
name: '안좋아요',
distance: '5',
description: 'good',
link: 'http://www.naver.com',
isFavorite: false,
},
];

export const RESTAURANT_INPUT_CASE = {
category: '한식',
name: '얌샘김밥',
distance: '5',
description: 'good',
link: 'http://www.naver.com',
};
171 changes: 171 additions & 0 deletions cypress/e2e/app.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import {
CATEGORY_TEST_CASE,
FAVORITES_TEST_CASE,
SORTING_TEST_CASE,
RESTAURANT_INPUT_CASE,
} from '../data';

const TEST_URL = 'http://localhost:8080/';

describe('음식점 추가 창', () => {
beforeEach('beforeEach', () => {
cy.visit(TEST_URL);
});

it('음식점 추가버튼(우측 상단)을 클릭하면 음식점 추가창을 볼 수 있다.', () => {
cy.get('.gnb__button').click();
cy.contains('새로운 음식점');
});

it('음식점 추가 창에서 취소하기 버튼을 클릭하면 이전 화면으로 돌아간다.', () => {
cy.get('.gnb__button').click();
cy.contains('새로운 음식점');
cy.get('#modal-cancel').click();
cy.get('.modal').should('not.exist');
});

it('카테고리, 이름, 거리, 설명, 링크 `입력창`을 작성하고 `추가하기 버튼`을 `클릭`하면 음식점이 목록에 추가된다. (음식점 목록 추가)', () => {
cy.get('.gnb__button').click();
cy.contains('새로운 음식점');
cy.get('#category').select(RESTAURANT_INPUT_CASE.category);
cy.get('#name').type(RESTAURANT_INPUT_CASE.name);
cy.get('#distance').select(RESTAURANT_INPUT_CASE.distance);
cy.get('#description').type(RESTAURANT_INPUT_CASE.description);
cy.get('#link').type(RESTAURANT_INPUT_CASE.link);
cy.get('.button-container').contains('추가하기').click();
cy.get('.app').contains('5분 내');
});
});

describe('음식점 목록, 드롭다운 메뉴/탭바', () => {
it('드롭다운 메뉴를 통해 음식점 목록을 음식 종류 별로 정렬할 수 있다.', () => {
cy.visit(TEST_URL, {
onBeforeLoad(win) {
win.localStorage.setItem('restaurants', JSON.stringify(CATEGORY_TEST_CASE));
},
});
cy.get('#category-filter').select('한식');
cy.get('.app').should('contain.text', '가_한식');
cy.get('.app').should('contain.text', '가_한식');
cy.get('.app').contains('다_중식').should('not.exist');
cy.get('.app').contains('라_일식').should('not.exist');
cy.get('.app').contains('하_오분거리 양식').should('not.exist');
cy.get('.app').contains('하_오분거리 아시안').should('not.exist');
});

it('드롭다운 메뉴를 통해 음식점 목록을 이름/거리 순으로 정렬할 수 있다.', () => {
cy.visit(TEST_URL, {
onBeforeLoad(win) {
win.localStorage.setItem('restaurants', JSON.stringify(SORTING_TEST_CASE));
},
});
cy.get('#sorting-filter').select('distance');
cy.get('.restaurant-list li.restaurant')
.first()
.should('contain', '첫번째 거리')
.next()
.should('contain', '두번째 거리')
.next()
.should('contain', '세번째 거리')
.next()
.should('contain', '네번째 거리')
.next()
.should('contain', '다섯번째 거리');

cy.get('#sorting-filter').select('name');
cy.get('.restaurant-list li.restaurant')
.first()
.should('contain', '네번째 거리')
.next()
.should('contain', '다섯번째 거리')
.next()
.should('contain', '두번째 거리')
.next()
.should('contain', '세번째 거리')
.next()
.should('contain', '첫번째 거리');
});

it('탭바를 통해 음식점 목록을 모든 음식점/자주 가는 음식점 으로 분류하여 볼 수 있다.', () => {
cy.visit(TEST_URL, {
onBeforeLoad(win) {
win.localStorage.setItem('restaurants', JSON.stringify(FAVORITES_TEST_CASE));
},
});
cy.get('.restaurant-list li.restaurant .favorite__button').first().click();
cy.get('.tab-bar-select[data-type="favorite"]').click();
cy.get('.app').contains('매우_좋아요');
cy.get('.app').contains('안좋아요').should('not.exist');
});

it('음식점 목록에서 `별표 버튼`을 `클릭`해 자주 가는 음식점으로 `등록/해제` 할 수 있다.', () => {
cy.visit(TEST_URL, {
onBeforeLoad(win) {
win.localStorage.setItem('restaurants', JSON.stringify(FAVORITES_TEST_CASE));
},
});
cy.get('.restaurant-list li.restaurant .favorite__button').first().click();
cy.get('.favorite__button>img')
.first()
.should('have.attr', 'src', `./favorite-icon-filled.png`);
});
});

describe('음식점 상세 정보 창', () => {
it('음식점 목록을 클릭해 음식점 상세 정보창을 열 수 있다.', () => {
cy.visit(TEST_URL, {
onBeforeLoad(win) {
win.localStorage.setItem('restaurants', JSON.stringify(FAVORITES_TEST_CASE));
},
});
cy.get('.restaurant-list li.restaurant').first().click();
cy.get('.modal').contains(FAVORITES_TEST_CASE[0].name);
cy.get('.modal').contains(FAVORITES_TEST_CASE[0].description);
cy.get('.modal').contains(FAVORITES_TEST_CASE[0].link);
});

it('음식점 상세 정보창에서 `별표 버튼`을 `클릭`해 자주 가는 음식점으로 `등록/해제` 할 수 있다.', () => {
cy.visit(TEST_URL, {
onBeforeLoad(win) {
win.localStorage.setItem('restaurants', JSON.stringify(FAVORITES_TEST_CASE));
},
});

cy.get('.restaurant-list li.restaurant').first().click();
cy.get('.modal .favorite__button').click();
cy.get('.modal #drawer-close__button').click();

cy.get('.tab-bar-select[data-type="favorite"]').click();
cy.get('.app').contains('매우_좋아요');
});

it('음식점 상세 정보창에서 `닫기 버튼`을 `클릭`해 음식점 상세 정보 창을 닫을 수 있다.', () => {
cy.visit(TEST_URL, {
onBeforeLoad(win) {
win.localStorage.setItem('restaurants', JSON.stringify(FAVORITES_TEST_CASE));
},
});

cy.get('.restaurant-list li.restaurant').first().click();
cy.get('.modal #drawer-close__button').click();
cy.get('.modal').should('not.exist');
});

it('음식점 상세 정보창에서 `삭제 버튼`을 `클릭`해 음식점을 목록에서 삭제할 수 있다.', () => {
cy.visit(TEST_URL);
// 음식점 추가
cy.get('.gnb__button').click();
cy.contains('새로운 음식점');
cy.get('#category').select(RESTAURANT_INPUT_CASE.category);
cy.get('#name').type(RESTAURANT_INPUT_CASE.name);
cy.get('#distance').select(RESTAURANT_INPUT_CASE.distance);
cy.get('#description').type(RESTAURANT_INPUT_CASE.description);
cy.get('#link').type(RESTAURANT_INPUT_CASE.link);
cy.get('.button-container').contains('추가하기').click();

// 삭제 버튼
cy.get('.restaurant-list li.restaurant').first().click();
cy.get('#restaurant-delete__button').click();
cy.get('.app').contains(RESTAURANT_INPUT_CASE.name).should('not.exist');
});
});
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
Loading

0 comments on commit e299419

Please sign in to comment.