Skip to content

Commit

Permalink
[1단계 - 지하철 노선도 미션] 하루(김하루) 미션 제출합니다. (#12)
Browse files Browse the repository at this point in the history
* chore: 패키지 초기화

* chore: 코드 포맷터 설정

* chore: 린터 설정

* chore: 에디터 설정

* chore: git hook으로 커밋 전 코드포맷터 및 린터 자동실행 설정

* chore: cypress 패키지 스크립트 추가

* chore: 패키지 이름 수정

* chore: webpack 설치

* chore: webpack 설정

* chore: dist 디렉토리 eslint 적용 제외

* chore: webpack 패키지 스크립트 추가

* refactor: webpack.config.js를 ES모듈방식으로 변경

* chore: webpack에 babel 로더 설정

* style: 전체 파일에 코드포맷터, 린터 일괄 적용

* docs: 라우팅 기능 구현목록 상세화

* chore: cypress 관리하지 않을 파일 gitignore 추가

* chore: cypress 설정

* feat: querySelector 유틸함수 추가

* test: 메뉴버튼 클릭 시 해당 메뉴로 라우팅

* feat(라우팅): 경로 상수화

* test: 뒤로가기 및 앞으로가기 테스트

* fix: 3단계 구현예정 메뉴버튼 삭제

* feat(라우팅): 헤더 클릭 이벤트핸들러 구현

* feat(라우팅): 경로 유효성 검사 추가

* fix(라우팅): 동일한 origin 의 path일 경우에만 라우팅 적용

* fix:  유틸함수 hasPropertyValue 정상 작동하도록 수정

* chore: cypress plugin 에러 해결

* feat(라우팅): page별 template 작성

* refactor(라우팅): 회원가입 경로명 변경

* feat(라우팅): 헤더 클릭 핸들러 구현

* feat(라우팅): 현재 위치와 다른 경로를 클릭한 경우에만 History 추가

* feat(라우팅): 뒤로가기 앞으로가기 구현

* feat(라우팅): home 화면 template 작성

* feat(라우팅): 경로별 문서제목 설정

* fix: 3단계 구현예정 경로 관련 상수 삭제

* refactor: 불필요한 <div>태그 삭제

* fix(라우팅): 헤더 밖의 하이퍼링크도 동작하도록 설정

* refactor: 문서에 누락된 쌍따옴표 추가

* refactor: 전체 구조 변경

* chore: eslint 설정 추가

* refactor: 불필요한 HTML문서 삭제

* refactor: HTML 파일 수정, 이미지 경로 변경

* chore : html-webpack-plugin 설정

* chore: webpack-dev-server 설정

* chore: CSS 관련 webpack 설정

* chore: package.json 이메일 주소 수정

* fix: 역관리 및 노선관리 CSS 깨지는 현상 수정

* refactor: logIn => login으로 변경

* test(사용자인증): 회원가입 테스트 추가

* test(사용자인증): 로그인 테스트 추가

* feat(사용자인증): 회원가입 입력값 유효성 검사

* test(사용자인증): 유효성검사 메세지 표시 방식 변경

* fix(사용자인증): 유효성검사 함수 수정

* feat(사용자인증): 회원가입 작성 완료시에만 제출버튼 활성화

* feat(사용자인증): 회원가입 API 요청 구현

* feat(사용자인증): 회원가입 시 이메일 중복 검사 API 요청 구현

* feat(사용자인증): 로그인 기능 구현

* refactor(사용자인증): debounce관련 매직넘버 상수화

* refactor: 사용자 알림 유틸함수명 수정

* feat(사용자인증): 회원가입 성공시 로그인 화면으로 리다이렉트

* feat(사용자인증): 로그아웃 기능 구현

* chore: eslint no-cycle 옵션 해제

* refactor(사용자인증): 추상화한 로그인 함수 적용, 로그인 화면 메세지 수정

* fix(사용자인증): 로그인 상태가 변해도 화면이 바뀌지 않는 문제 해결

* feat(사용자인증): 로그인 상태에서만 정보 조회 가능

* feat(사용자인증): 로그인 폼 작성 완료시에만 제출버튼 활성화

* test(라우팅): 변경된 구조 반영

* test(사용자인증): 변경된 구조 반영

* feat(사용자인증): 입력 폼 CSS 스타일링

* fix: API Origin 변경

* chore(webpack): 함수형으로 변경, DefinePlugin 설치 및 설정

* feat(라우팅): ROUTES subpath 반영

* feat(사용자인증): 비밀번호 표시 기능 구현

* refactor(라우팅): handleLinkClick 수정

Co-authored-by: 365kim <365kim@users.noreply.github.com>

* test(라우팅): 배포용 코드의 경로(SUBPATH)와 동기화

Co-authored-by: 365kim <365kim@users.noreply.github.com>

* refactor(라우팅): router의 render부분을 views로 분리

Co-authored-by: 365kim <365kim@users.noreply.github.com>

* refactor(라우팅): 경로 상수명 변경(ROUTES -> PATHNAMES)

Co-authored-by: 365kim <365kim@users.noreply.github.com>

* refactor: 디렉토리 정리

* refactor(사용자인증): input 유효성 검사 에러 핸들링

Co-authored-by: 365kim <365kim@users.noreply.github.com>

* refactor(라우팅): pathname 유효성 검사 에러 핸들링

Co-authored-by: 365kim <365kim@users.noreply.github.com>

* chore: github pages 배포를 위한 webpack 설정

Co-authored-by: bigsaigon333 <likepeppermint@gmail.com>
Co-authored-by: 365kim <365kim@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 25, 2021
1 parent f5cb400 commit a779537
Show file tree
Hide file tree
Showing 66 changed files with 8,075 additions and 664 deletions.
1 change: 1 addition & 0 deletions .browserslistrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
defaults
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
19 changes: 19 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["airbnb-base", "prettier", "plugin:cypress/recommended"],
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
"import/extensions": ["error", "always"],
"import/no-cycle": "off",
"no-param-reassign": ["error", { "props": false }],
"no-use-before-define": ["error", "nofunc"]
},
"plugins": ["cypress"],
"ignorePatterns": ["cypress/fixtures/*", "cypress/plugins/*", "cypress/support/*", "dist"]
}
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,8 @@ dist

# TernJS port file
.tern-port

# cypress files
cypress/fixtures/*
cypress/plugins/*
cypress/support/*
4 changes: 4 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"printWidth": 120,
"singleQuote": true
}
11 changes: 11 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"files.autoSave": "onFocusChange",
"files.trimTrailingWhitespace": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"prettier.useEditorConfig": true,
"liveServer.settings.port": 5500
}
26 changes: 15 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,27 @@

### Webpack을 통한 번들링

- [ ] Webpack에서 babel을 설정한다.
- [ ] 기타 플러그인 및 설정은 본인이 필요에 따라 추가한다.
- [x] Webpack에서 babel을 설정한다.
- [x] 기타 플러그인 및 설정은 본인이 필요에 따라 추가한다.

### 라우팅 기능

- [ ] Browser History Api를 이용하여 SPA처럼 라우팅을 적용한다.
- [x] Browser History Api를 이용하여 SPA처럼 라우팅을 적용한다.
- [x] 메뉴를 클릭하면 새로고침이 되지 않으면서 선택한 메뉴가 표시된다.
- [x] 뒤로가기 버튼이 활성화되고, URL도 함께 변경된다.
- [x] 단, 현재 위치와 같은 메뉴를 클릭한 경우 History가 추가되지 않는다.
- [x] 뒤로가기 버튼을 클릭하면 이전 메뉴가 화면에 표시된다.
- [x] 다시 앞으로가기 버튼을 클릭하면 처음 선택한 메뉴가 화면에 표시된다.

### 회원 기능

- [ ] 유저는 회원 가입을 할 수 있다,
- [ ] 회원 가입시 받는 정보는 `email`, `name`, `password`이다.
- [ ] 유저는 로그인 할 수 있다.
- [ ] 로그인하고 나면 로그인 버튼은 로그아웃 버튼으로 변경되어야 한다.
- [ ] 로그인한 유저만, 정보의 수정이 가능하다.
- [ ] 로그인하지 않은 유저는 정보를 읽는 것만 가능하다.
- [ ] 유저는 로그아웃할 수 있다.
- [ ] 로그아웃하면 `/` 루트 페이지로 돌아온다.
- [x] 유저는 회원 가입을 할 수 있다,
- [x] 회원 가입시 받는 정보는 `name`, `email`, `password`이다.
- [x] 유저는 로그인 할 수 있다.
- [x] 로그인하지 않으면 정보를 볼 수 없다.
- [x] 로그인하고 나면 로그인 버튼은 로그아웃 버튼으로 변경되어야 한다.
- [x] 유저는 로그아웃할 수 있다.
- [x] 로그아웃하면 `/` 루트 페이지로 돌아온다.

## 🎯🎯 step2

Expand Down
11 changes: 11 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"presets": [
[
"@babel/env",
{
"useBuiltIns": "usage",
"corejs": "3.9"
}
]
]
}
5 changes: 5 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"baseUrl": "http://localhost:5500",
"watchForFileChanges": false,
"pluginsFile": false
}
133 changes: 133 additions & 0 deletions cypress/integration/auths.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { API_ENDPOINT, STATUS_CODE } from '../../src/js/constants/api.js';
import PATHNAMES from '../../src/js/constants/rawPathnames.js';

describe('회원가입 및 로그인 테스트', () => {
const oldUser = {
name: '하루',
email: '1@1',
password: '365',
};
const newUser = {
name: '동동',
email: '9@9',
password: '333',
};

beforeEach(() => {
cy.visit('/');

cy.intercept(
{
method: 'GET',
url: `${API_ENDPOINT.EMAIL_VALIDATION}`,
query: { email: /.+/ },
},
(request) => {
const url = new URL(request.url);
const parameters = new URLSearchParams(url.search);
const email = parameters.get('email');

if (oldUser.email === email) {
request.reply({ statusCode: STATUS_CODE.EMAIL_VALIDATION.DUPLICATED });
return;
}

request.reply({ statusCode: STATUS_CODE.EMAIL_VALIDATION.OK });
}
).as('checkValidation');

cy.intercept(
{
method: 'POST',
url: `${API_ENDPOINT.SIGN_UP}`,
},
(request) => {
const { email } = request.body;

if (oldUser.email === email) {
request.reply({ statusCode: STATUS_CODE.SIGN_UP.EMAIL_DUPLICATED });
return;
}

request.reply({ statusCode: STATUS_CODE.SIGN_UP.OK });
}
).as('signUp');

cy.intercept(
{
method: 'POST',
url: `${API_ENDPOINT.LOGIN}`,
},
(request) => {
const { email, password } = request.body;

if (oldUser.email === email && oldUser.password === password) {
request.reply({ statusCode: STATUS_CODE.LOGIN.OK });
return;
}

request.reply({ statusCode: STATUS_CODE.LOGIN.FAILED });
}
).as('login');
});

const goToLoginPage = () => {
cy.get(`a[href*="${PATHNAMES.LOGIN}"]`).click();
};

const goToSignUpPage = () => {
cy.get(`a[href*="${PATHNAMES.LOGIN}"]`).click();
cy.get(`a[href*="${PATHNAMES.SIGN_UP}"]`).click();
};

it('회원가입시 중복된 이메일을 입력했을 때 유효하지 않은 입력으로 표시된다.', () => {
goToSignUpPage();
cy.get('#name').type(oldUser.name);
cy.get('#email').type(oldUser.email, { delay: 1500 });
cy.wait('@checkValidation').its('response.statusCode').should('not.eq', STATUS_CODE.EMAIL_VALIDATION.OK);

cy.get('#email:invalid').should('exist');
});

it('회원가입시 모든 정보를 바르게 입력한 경우 회원가입이 정상적으로 처리된다.', () => {
goToSignUpPage();

cy.get('button[type="submit"]').should('be.disabled');

cy.get('#name').type(newUser.name);
cy.get('#email').type(newUser.email, { delay: 1500 });

cy.wait('@checkValidation').its('response.statusCode').should('eq', STATUS_CODE.EMAIL_VALIDATION.OK);

cy.get('#password').type(newUser.password);

cy.get('button[type="submit"]').should('not.be.disabled');

cy.get('button[type="submit"]').click();
cy.wait('@signUp').its('response.statusCode').should('eq', STATUS_CODE.SIGN_UP.OK);
});

it('유효하지 않은 이메일과 비밀번호를 입력하면 로그인에 실패한다.', () => {
goToLoginPage();
cy.get('#email').type(newUser.email);
cy.get('#password').type(newUser.password);
cy.get('button[type="submit"]').click();

cy.wait('@login').its('response.statusCode').should('not.eq', STATUS_CODE.LOGIN.OK);
});

it('유효한 이메일과 비밀번호를 입력하면 로그인에 성공한다', () => {
goToLoginPage();

cy.get('button[type="submit"]').should('be.disabled');

cy.get('#email').type(oldUser.email);
cy.get('#password').type(oldUser.password);

cy.get('button[type="submit"]').should('not.be.disabled');

cy.get('button[type="submit"]').click();

cy.wait('@login').its('response.statusCode').should('eq', STATUS_CODE.LOGIN.OK);
});
});
40 changes: 40 additions & 0 deletions cypress/integration/routing.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import PATHNAMES from '../../src/js/constants/rawPathnames.js';
import { API_ENDPOINT } from '../../src/js/constants/api.js';

describe('라우팅 테스트', () => {
const oldUser = {
name: '하루',
email: '365kim@gmail.com',
password: '365',
};

beforeEach(() => {
cy.intercept({
method: 'POST',
url: `${API_ENDPOINT.LOGIN}`,
}).as('login');

cy.visit('/');
cy.get(`a[href*="${PATHNAMES.LOGIN}"]`).click();
cy.get('#email').type(oldUser.email);
cy.get('#password').type(oldUser.password);
cy.get('button[type="submit"]').click();
cy.wait('@login');
});

it('역 관리 메뉴에서 뒤로가기를 하면 이전 페이지가, 앞으로 가기를 하면 다음 페이지가 표시된다.', () => {
cy.location().should(({ pathname }) => {
expect(pathname).to.match(new RegExp(`${PATHNAMES.STATIONS}$`));
});

cy.go('back');
cy.location().should(({ pathname }) => {
expect(pathname).to.match(new RegExp(`${PATHNAMES.LOGIN}$`));
});

cy.go('forward');
cy.location().should(({ pathname }) => {
expect(pathname).to.match(new RegExp(`${PATHNAMES.STATIONS}$`));
});
});
});
29 changes: 0 additions & 29 deletions index.html

This file was deleted.

63 changes: 63 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"name": "javascript-subway-mission",
"version": "0.0.1",
"main": "src/js/index.js",
"repository": "https://github.com/woowacourse/javascript-subway.git",
"contributors": [
{
"name": "Donghee Kim",
"email": "likepeppermint@gmail.com",
"url": "https://velog.io/@bigsaigon333"
},
{
"name": "Haru Kim",
"email": "365listener@gmail.com",
"url": "https://365kim.tistory.com"
}
],
"license": "MIT",
"type": "module",
"engines": {
"node": ">=14"
},
"scripts": {
"start": "webpack serve --mode=production",
"start:dev": "webpack serve --mode=development",
"build": "webpack --mode=production",
"build:dev": "webpack --mode=production",
"test": "yarn cypress open"
},
"dependencies": {
"core-js": "^3.9.1",
"regenerator-runtime": "^0.13.7"
},
"devDependencies": {
"@babel/core": "^7.13.10",
"@babel/preset-env": "^7.13.10",
"babel-loader": "^8.2.2",
"css-loader": "^5.1.3",
"cypress": "^6.7.1",
"eslint": "^7.2.0",
"eslint-config-airbnb-base": "14.2.1",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-cypress": "^2.11.2",
"eslint-plugin-import": "^2.22.1",
"html-webpack-plugin": "^5.3.1",
"husky": "=4",
"lint-staged": ">=10",
"mini-css-extract-plugin": "^1.3.9",
"prettier": "2.2.1",
"webpack": "^5.26.0",
"webpack-cli": "^4.5.0",
"webpack-dev-server": "^3.11.2"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.js": "eslint --cache",
"*.{js,css,html,json,md}": "prettier --write"
}
}
Loading

0 comments on commit a779537

Please sign in to comment.