Skip to content

Commit

Permalink
Merge pull request #23 from zigsong/zig-step1
Browse files Browse the repository at this point in the history
[1단계 - 행운의 로또 미션] 지그(송지은) 미션 제출합니다.
  • Loading branch information
wow9144 authored Feb 27, 2021
2 parents 6958dc9 + 2b228d3 commit 14f63a1
Show file tree
Hide file tree
Showing 20 changed files with 2,449 additions and 42 deletions.
24 changes: 24 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"plugins": ["prettier"],
"extends": [
"eslint:recommended",
"plugin:prettier/recommended",
"plugin:cypress/recommended"
],
"rules": {
"prettier/prettier": ["error", {
"endOfLine": "auto"
}],
"max-depth": ["error", 2]
},
"parser": "babel-eslint",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 12
},
"env": {
"browser": true,
"node": true,
"es6": true
}
}
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,12 @@ dist
*.code-workspace


### cypress
cypress/integration/examples/
cypress/fixtures/
cypress/plugins/
cypress/support/

### WebStorm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
Expand Down
9 changes: 9 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"bracketSpacing": true,
"arrowParens": "avoid",
"printWidth": 80
}
46 changes: 41 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,55 @@

### 🎯 step1 구입 기능

- [ ] 로꼬 구입 금액을 입력하면, 금액에 해당하는 로또를 발급해야 한다.
- [ ] 로또 1장의 가격은 1,000원이다.
- [ ] 소비자는 **자동 구매**를 할 수 있어야 한다.
- [ ] 복권 번호는 번호보기 토글 버튼을 클릭하면, 볼 수 있어야 한다.
- [x] 로또 구입 금액을 입력하면, 금액에 해당하는 로또를 발급해야 한다.
- [x] 로또 1장의 가격은 1,000원이다.
- [x] 소비자는 **자동 구매**를 할 수 있어야 한다.
- [x] 복권 번호는 번호보기 토글 버튼을 클릭하면, 볼 수 있어야 한다.

### ✅ 1단계 미션 TODO

**🎰 로또 🎰**

1번부터 45번까지의 공 중에서 6개를 추첨하고, 이어서 보너스 번호로 공 1개를 추가로 추첨한다. 즉 1번부터 45번까지 중에서 6개를 추첨한 후 또 다시 1개를 추첨하는 것이다. 물론 이 번호들은 **중복된 번호**가 없다.

**기능 구현 목록**

- [x] 프로그램을 시작하면 구입금액 입력폼이 보인다.
- [x] 프로그램을 시작 시 입력칸에 autofocus가 된다.
- [ ] 사용자가 라벨을 선택해도 입력칸에 autofocus를 해준다.
- [x] 사용자는 로또 구입 금액을 입력한다.
- [x] Enter로 금액을 입력할 수 있다.
- [x] 확인 버튼으로 금액을 입력할 수 있다.
- [x] 로또 구입 금액은 1,000원 단위여야 한다.
- [x] 로또 구입 금액은 최소 1,000원, 최대 100,000원으로 제한한다.
- [x] 로또 구입 금액을 잘못 입력했을 경우, alert로 사용자에게 알린다.
- [x] 사용자가 구매한 로또의 개수를 보여주고, 개수만큼 티켓 이모지를 가로로 보여준다.
- [x] 구매한 번호는 가려져 있는 모습을 default로 한다.
- [x] '번호 보기'를 눌렀을 때, 각 로또의 번호를 보여준다.
- [x] 로또의 각 번호는 중복이 존재하지 않는다.
- [x] 지난주 당첨 번호 입력 폼을 보여준다. (기능 구현 X)

**Cypress 테스트**

- 정상 로직

- [x] 프로그램을 시작하면 구입금액 입력폼이 보인다.
- [x] 사용자는 로또 구입 금액을 입력한다.
- [x] 사용자가 구매한 로또의 개수를 보여주고, 개수만큼 티켓 이모지를 가로로 보여준다. 지난주 당첨 번호 입력 폼을 보여준다.
- [x] '번호 보기'를 눌렀을 때, 로또 아이콘을 세로로 정렬한다.
- [x] '번호 보기'를 눌렀을 때, 각 로또의 번호를 보여준다. (로또의 번호는 중복이 없어야 한다)

- 예외상황
- 금액 입력 예외상황
- [x] 사용자가 금액을 1,000원 단위로 입력하지 않은 경우, alert로 알린다.
- [x] 구매 가능 금액은 최소 1,000원, 최대 100,000원으로 제한한다.

### 🎯🎯 step2 당첨 결과 기능

- [ ] 결과 확인하기 버튼을 누르면 당첨 통계, 수익률을 모달로 확인할 수 있다.
- [ ] 로또 당첨 금액은 고정되어 있는 것으로 가정한다.
- [ ] 다시 시작하기 버튼을 누르면 초기화 되서 다시 구매를 시작할 수 있다.


### 🎯🎯🎯 step3 수동 구매

- [ ] 소비자는 수동 구매(스스로 구매 번호를 입력)를 할 수 있어야 한다.
Expand Down
1 change: 1 addition & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
60 changes: 60 additions & 0 deletions cypress/integration/lottoTest/lottoTest.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
describe('로또 게임 테스트', () => {
beforeEach(() => {
cy.visit('http://127.0.0.1:5500/');
});

const price = 10000;
const lottoTotalCount = price / 1000;

function clickAfterTypePrice() {
cy.get('#input-price').type(price);
cy.get('#input-price-btn').click();
}

it('프로그램을 시작하면 구입금액 입력폼만 보인다.', () => {
cy.get('#input-price-form').should('be.visible');
cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
});

it('사용자는 로또 구입 금액을 입력하면, 확인 버튼을 누르면 사용자가 구매한 로또와 지난 주 당첨 로또 입력폼이 보인다.', () => {
clickAfterTypePrice();
cy.get('#purchased-lottos').should('be.visible');
cy.get('#input-lotto-nums').should('be.visible');
});

it('사용자는 로또 구입 금액을 입력하면, Enter를 누르면 사용자가 구매한 로또와 지난 주 당첨 로또 입력폼이 보인다.', () => {
cy.get('#input-price').type(`${price}{enter}`);
cy.get('#purchased-lottos').should('be.visible');
cy.get('#input-lotto-nums').should('be.visible');
});

it('사용자가 구매한 로또의 개수와 개수 만큼의 로또 이모지를 보여준다.', () => {
clickAfterTypePrice();

cy.get('#purchased-lottos').should('be.visible');
cy.get('#total-purchased').should('have.text', lottoTotalCount);
cy.get('#lotto-icons')
.children('.lotto-wrapper')
.should('have.length', lottoTotalCount);
cy.get('#input-lotto-nums').should('be.visible');
});

it('번호 보기 스위치 off 상태에서는 로또 아이콘들이 가로로, on에서는 세로로 정렬된다.', () => {
clickAfterTypePrice();

cy.get('.switch').click();
cy.get('#lotto-icons').should('have.class', 'flex-col');
cy.get('.switch').click();
cy.get('#lotto-icons').should('not.have.class', 'flex-col');
});

it('번호 보기 스위치가 off이면 구매한 로또의 번호가 보이지 않고, on이면 번호가 보인다.', () => {
clickAfterTypePrice();

cy.get('.switch').click();
cy.get('.lotto-wrapper').children('.lotto-detail').should('be.visible');
cy.get('.switch').click();
cy.get('.lotto-wrapper').children('.lotto-detail').should('not.be.visible');
});
});
47 changes: 47 additions & 0 deletions cypress/integration/lottoTest/lottoValidation.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
describe('로또 금액 입력 예외 처리 테스트', () => {
beforeEach(() => {
cy.visit('http://127.0.0.1:5500/');
});

function exceptionAlert(wrongPrice, alertMessage) {
const alertStub = cy.stub();
cy.on('window:alert', alertStub);

cy.get('#input-price').type(wrongPrice);
cy.get('#input-price-btn')
.click()
.then(() => {
expect(alertStub.getCall(0)).to.be.calledWith(alertMessage);
});
}

function checkInvalid(wrongPrice, errorMessage) {
cy.get('#input-price').type(wrongPrice);
cy.get('#input-price-btn').click();

cy.get('input:invalid').should('have.length', 1);
cy.get('#input-price').then($input => {
expect($input[0].validationMessage).to.eq(errorMessage);
});
}

it('로또 구입 금액은 최소 1,000원으로 제한한다.', () => {
checkInvalid(200, '값은 1000 이상이어야 합니다.');

cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
});

it('로또 구입 금액은 최대 100,000원으로 제한한다.', () => {
checkInvalid(120000, '값은 100000 이하여야 합니다.');

cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
});

it('로또 구입 금액은 1,000원 단위여야 한다.', () => {
exceptionAlert(1200, '로또 구입 금액을 1,000원 단위로 입력해 주세요.');
cy.get('#purchased-lottos').should('not.be.visible');
cy.get('#input-lotto-nums').should('not.be.visible');
});
});
39 changes: 20 additions & 19 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,41 @@
<body>
<div id="app" class="p-3">
<div class="d-flex justify-center mt-5">
<div class="w-100">
<section class="w-100">
<h1 class="text-center">🎱 행운의 로또</h1>
<form class="mt-5">
<label class="mb-2 d-inline-block"
>구입할 금액을 입력해주세요.
<form id="input-price-form" class="mt-5">
<label for="input-price" class="mb-2 d-inline-block">
구입할 금액을 입력해주세요.
</label>
<div class="d-flex">
<input
type="number"
id="input-price"
class="w-100 mr-2 pl-2"
name="inputPrice"
placeholder="구입 금액"
required
min="1000"
max="100000"
/>
<button type="button" class="btn btn-cyan">확인</button>
<button type="submit" id="input-price-btn" class="btn btn-cyan">확인</button>
</div>
</form>
<section class="mt-9">

<section id="purchased-lottos" class="mt-9">
<div class="d-flex">
<label class="flex-auto my-0">5개를 구매하였습니다.</label>
<label class="flex-auto my-0"><span id="total-purchased">5</span>개를 구매하였습니다.</label>
<div class="flex-auto d-flex justify-end pr-1">
<label class="switch">
<input type="checkbox" class="lotto-numbers-toggle-button" />
<input id="lotto-switch" type="checkbox" class="lotto-numbers-toggle-button" />
<span class="text-base font-normal">번호보기</span>
</label>
</div>
</div>
<div class="d-flex flex-wrap">
<span class="mx-1 text-4xl">🎟️ </span>
<span class="mx-1 text-4xl">🎟️ </span>
<span class="mx-1 text-4xl">🎟️ </span>
<span class="mx-1 text-4xl">🎟️ </span>
<span class="mx-1 text-4xl">🎟️ </span>
</div>
<ul id="lotto-icons" class="d-flex flex-wrap"></ul>
</section>
<form class="mt-9">

<form class="mt-9" id="input-lotto-nums">
<label class="flex-auto d-inline-block mb-3"
>지난 주 당첨번호 6개와 보너스 넘버 1개를 입력해주세요.</label
>
Expand Down Expand Up @@ -90,10 +91,10 @@ <h4 class="mt-0 mb-3 text-center">보너스 번호</h4>
결과 확인하기
</button>
</form>
</div>
</section>
</div>

<div class="modal">
<!-- <div class="modal">
<div class="modal-inner p-10">
<div class="modal-close">
<svg viewbox="0 0 40 40">
Expand Down Expand Up @@ -145,7 +146,7 @@ <h2 class="text-center">🏆 당첨 통계 🏆</h2>
<button type="button" class="btn btn-cyan">다시 시작하기</button>
</div>
</div>
</div>
</div> -->
</div>
<script type="module" src="./src/js/index.js"></script>
</body>
Expand Down
15 changes: 13 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
"main": "index.js",
"license": "MIT",
"devDependencies": {
"cypress": "^6.3.0"
}
"babel-eslint": "^10.1.0",
"cypress": "^6.3.0",
"eslint": "^7.20.0",
"eslint-config-prettier": "^7.2.0",
"eslint-plugin-cypress": "^2.11.2",
"eslint-plugin-prettier": "^3.3.1",
"prettier": "^2.2.1"
},
"repository": "https://github.com/devhyun637/javascript-lotto",
"contributors": [
"Zig <wldms5764@gmail.com>",
"Tyche <kgshdgeh@gmail.com>"
]
}
4 changes: 4 additions & 0 deletions src/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ body {
width: 30px;
height: 36px;
}

ul {
padding: 0;
}
9 changes: 9 additions & 0 deletions src/css/shared/modules/flex.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
flex-wrap: wrap;
}

.flex-wrap > .lotto-wrapper {
display: flex;
}

.flex-wrap > .lotto-wrapper > .lotto-detail {
font-size: 1.25rem;
margin-left: 12px;
}

.flex-wrap-reverse {
flex-wrap: wrap-reverse;
}
Expand Down
20 changes: 20 additions & 0 deletions src/js/Lotto.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import getRandomNumber from './utils/utils.js';

export default class Lotto {
static LOTT0_LENGTH = 6;

constructor() {
this.numbers = new Set();
this.initNumbers();
}

initNumbers() {
while (this.numbers.size < Lotto.LOTT0_LENGTH) {
this.numbers.add(getRandomNumber());
}
}

get numberDetail() {
return [...this.numbers.values()].join(', ');
}
}
Loading

0 comments on commit 14f63a1

Please sign in to comment.