Skip to content
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

[2단계 - 음식점 목록] 윤생(이윤성) 미션 제출합니다. #53

Merged
merged 40 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
48e1f38
docs: 요구사항 목록 갱신
2yunseong Mar 8, 2023
dfe8c69
refactor: Component Interface 변경
2yunseong Mar 8, 2023
d46d6a0
feat: 탭바 UI 토글 기능 추가
2yunseong Mar 8, 2023
7a8e9a2
feat: 탭 바 메뉴별 정렬 로직 구현
2yunseong Mar 8, 2023
a4d4ec4
feat: 자주 가는 음식점 버튼 토글 기능 구현 및 저장소에 요청
2yunseong Mar 8, 2023
e888f73
fix: 좋아요 상태 변경 시 리렌더링 로직 추가
2yunseong Mar 8, 2023
32531f0
feat: Drawer 좋아요 토글 동작 구현
2yunseong Mar 8, 2023
07e7399
refactor: 이벤트 리스너 등록 로직 메서드로 묶음
2yunseong Mar 8, 2023
9b57870
refactor: export default 축약
2yunseong Mar 8, 2023
78e877d
refactor: 사용성 개선
2yunseong Mar 9, 2023
481bc98
docs: 요구사항 최신화 및 e2e테스트 기능 명세 작성
2yunseong Mar 9, 2023
7bf79aa
test: 음식점 추가 버튼 클릭 테스트
2yunseong Mar 9, 2023
92c8d10
test: 음식점 추가 창 취소하기 버튼 테스트
2yunseong Mar 9, 2023
e98102d
test: 음식 종류 별 정렬 기능 테스트
2yunseong Mar 9, 2023
aa9f6aa
refactor: 의미에 맞지 않는 html 태그 변경 및 class name 할당
2yunseong Mar 9, 2023
f19afb9
test: 음식점 이름/거리 순 정렬 기능 테스트
2yunseong Mar 9, 2023
e068708
test: 탭바 테스트
2yunseong Mar 9, 2023
aaa83f4
test: 음식정 상세 정보 창 테스트
2yunseong Mar 9, 2023
d4af145
refactor: 이벤트 핸들러 이름 일관성 부여
2yunseong Mar 9, 2023
4d1c79a
refactor: 불필요한 setState 제거
2yunseong Mar 9, 2023
fd53765
refactor: 컴포넌트에 불필한 로직 분리
2yunseong Mar 9, 2023
c72bde7
refactor: 메서드 분리
2yunseong Mar 9, 2023
1985331
refactor: 비구조화 할당 제거
2yunseong Mar 9, 2023
65b1a56
refactor: 디렉터리 구조 변경
2yunseong Mar 9, 2023
734535a
test: 음식점 목록 자주가는 음식점 토글 기능 테스트
2yunseong Mar 9, 2023
523f93e
docs: 요구사항 목록 최신화
2yunseong Mar 9, 2023
944a231
feat: 고유한 아이디를 생성하게 구현
2yunseong Mar 9, 2023
9d2bb91
refactor: 레스토랑 등록 로직 분리
2yunseong Mar 9, 2023
3e41b7a
refactor: 사용하지 않는 import 제거
2yunseong Mar 9, 2023
0b92bc4
refactor: 재사용 되는 로직 분리
2yunseong Mar 9, 2023
2bea033
refactor: img src 소스 링크 상수화
2yunseong Mar 9, 2023
aea911b
test: 코드 중복 제거
2yunseong Mar 10, 2023
0188bdd
test: 테스트 이름 변경
2yunseong Mar 10, 2023
44c14bf
refactor: 축약된 이름 변경
2yunseong Mar 10, 2023
00abc75
refactor: 불필요한 리렌더링 제거
2yunseong Mar 11, 2023
f5c12a8
refactor: 이벤트 위임으로 핸들러 일반화
2yunseong Mar 11, 2023
a3fa9b1
refactor: 이벤트 위임으로 변경
2yunseong Mar 11, 2023
8b8d4a0
refactor: DropDown 이벤트 핸들러 메서드 로직 병합
2yunseong Mar 11, 2023
959dc93
refactor: 접근 제한자 부여
2yunseong Mar 13, 2023
b6a6485
refactor: drawer html 분리
2yunseong Mar 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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',
};
170 changes: 170 additions & 0 deletions cypress/e2e/spec.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import {
CATEGORY_TEST_CASE,
FAVORITES_TEST_CASE,
SORTING_TEST_CASE,
RESTAURANT_INPUT_CASE,
} from '../data';

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

describe('음식점 추가 창', () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cypress로 e2e 테스트를 작성하셨군요 ! 👍 👍 👍

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다시보니 파일 이름이 spec.cy.js네요 더 좋은 이름은 없을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app이니 app.cy.js 가 좋아보입니다~! cypress에서 기본값으로 주어서 관례적으로 사용하는 줄 알았는데 그런건 아니였군요!!

it('음식점 추가버튼(우측 상단)을 클릭하면 음식점 추가창을 볼 수 있다.', () => {
cy.visit(TEST_URL);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cy.visit()이 반복되는데 반복되는 코드를 줄일 수는 없을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저번에 이러한 코드를 beforeEach로 줄여보았는데 한번 적용해보도록 하겠습니다!

cy.get('.gnb__button').click();
cy.contains('새로운 음식점');
});

it('음식점 추가 창에서 취소하기 버튼을 클릭하면 이전 화면으로 돌아간다.', () => {
cy.visit(TEST_URL);
cy.get('.gnb__button').click();
cy.contains('새로운 음식점');
cy.get('#modal-cancel').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('.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('음식점 상세 정보 창', () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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