Skip to content

Commit

Permalink
Merge pull request #53 from sunhpark42/sunny-step2
Browse files Browse the repository at this point in the history
[2단계 - 행운의 로또 미션] 서니(박선희) 미션 제출합니다.
  • Loading branch information
Vallista authored Feb 28, 2021
2 parents 9f76f06 + 2afcf5a commit 164fe5a
Show file tree
Hide file tree
Showing 17 changed files with 544 additions and 143 deletions.
31 changes: 28 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ src/js
### step1 테스트 항목

- [x] 사용자가 로또 구입 금액을 입력하고 확인 버튼을 누르면 금액에 맞는 로또가 화면에 보여진다.
- [x] 구입 금액 입력 폼에 autoFocus가 되는지 확인한다.
- [x] 구입 금액 입력 후, 당첨 번호 입력 폼에 autoFocus가 되는지 확인한다.
- [x] 사용자가 토글 버튼을 누르면 로또의 번호를 볼 수 있다.
- [x] 각 로또 안의 번호가 중복되지 않았는지 확인한다.

Expand All @@ -99,9 +101,32 @@ src/js

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

- [ ] 결과 확인하기 버튼을 누르면 당첨 통계, 수익률을 모달로 확인할 수 있다.
- [ ] 로또 당첨 금액은 고정되어 있는 것으로 가정한다.
- [ ] 다시 시작하기 버튼을 누르면 초기화 되서 다시 구매를 시작할 수 있다.
- [x] 페이지를 처음 로드했을 때, 구입할 금액 입력 폼에 autoFocus되도록 수정 구현 (step1 보완)
- [x] 구입할 금액 입력 후, 당첨 번호 입력 폼에 autoFocus되도록 구현
- [x] 당첨 번호 입력 중, 2자리 숫자가 입력되면 바로 다음 입력 폼으로 넘어가도록 구현
- [x] 결과 확인하기 버튼을 누르면 당첨 통계, 수익률을 모달로 확인할 수 있다.
- [x] 결과 확인하기 버튼을 누르면 모달이 뜨도록 구현
- [x] 입력된 당첨 번호가 1 ~ 45 사이의 중복되지 않는 숫자인지 확인한다.
- [x] 모달이 떴을 때, 당첨금의 당첨 개수와 총 수익률이 계산되어 보여지도록 구현
- [x] 모달이 뜬 상태에서 닫기를 눌렀을 때, 기존 화면에 변화가 없도록 한다.
- [x] 로또 당첨 금액은 고정되어 있는 것으로 가정한다.
- [x] 다시 시작하기 버튼을 누르면 초기화 되서 다시 구매를 시작할 수 있다.
- [x] 처음 접속했을 때의 화면(구입할 금액 입력 폼만 보이는 상태)처럼 초기화한다.

### step2 테스트 항목

- [x] 로또 구입 후, 당첨 번호를 입력하고 결과 확인하기 버튼을 누르면, 모달에서 당첨 개수와 총 수익률을 확인할 수 있다.
- [x] 모달이 잘 뜨는지 확인한다.
- [x] 당첨금과 수익률이 정상 출력되는지 확인한다.
- [x] (Assertion) 로또 번호와 당첨 번호를 비교하여 일치하는 갯수가 정확하게 나오는지 확인한다.
- [x] 다시 시작하기 버튼을 눌렀을 때, 구입할 금액 입력 폼만 보이는지 확인한다.
- [x] 닫기 버튼을 눌렀을 때, 모달이 잘 닫히는지 확인한다.
- [x] 당첨 번호를 입력할 때, 2자리 숫자가 입력되면, 자동으로 다음 폼으로 focus되는지 확인한다.

#### 예외사항(테스트)

- [x] 입력된 당첨 번호가 1 ~ 45 사이의 숫자가 아니거나, 중복되면
- [x] '1 ~ 45 사이의 숫자를 중복되지 않게 입력해주세요' 라는 경고창을 띄운다.

### 🎯🎯🎯 step3 수동 구매

Expand Down
149 changes: 143 additions & 6 deletions cypress/integration/lotto.spec.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import { ALERT_MESSAGE } from '../../src/js/constants.js';
import { ALERT_MESSAGE, VALUE } from '../../src/js/constants.js';
import Lotto from '../../src/js/models/Lotto.js';

describe('LOTTO 테스트', () => {
beforeEach(() => {
cy.visit('http://localhost:5500/');
});

it('사용자가 로또 구입 금액을 입력하고 확인 버튼을 누르면 금액에 맞는 로또가 화면에 보여진다.', () => {
cy.get('.lotto-list-container').should('not.be.visible');
cy.get('.winning-number-form-container').should('not.be.visible');
cy.get('.lotto-list-section').should('not.be.visible');
cy.get('.winning-number-form-section').should('not.be.visible');

cy.get('#money-input').type('10000');
// Note: Cypress 체크 시 autofocus가 잡히지 않는 문제가 있어 수동으로 focus를 잡아둠
cy.get('#money-input').should('have.attr', 'autofocus', 'autofocus').focus();

cy.focused().should('have.attr', 'id', 'money-input').type('10000');
cy.get('#money-submit-button').click();

cy.get('.lotto-list-container').should('be.visible');
cy.get('.winning-number-form-container').should('be.visible');
cy.get('.lotto-list-section').should('be.visible');
cy.get('.winning-number-form-section').should('be.visible');

cy.get('.lotto-count').should('have.text', '10');
cy.get('.lotto').should('have.length', '10');

cy.get('.winning-number').first().should('be.focused');
});

it('사용자가 토글 버튼을 누르면 로또의 번호를 볼 수 있다.', () => {
Expand Down Expand Up @@ -72,4 +78,135 @@ describe('LOTTO 테스트', () => {

cy.get('.lotto-list').children().should('have.length', 5);
});

it('로또 구입 후, 당첨 번호를 입력하고 결과 확인하기 버튼을 누르면, 모달에서 당첨 개수와 총 수익률을 확인할 수 있다.', () => {
const winningNumbers = [9, 11, 3, 25, 21, 2];
cy.get('#money-input').type('10000');
cy.get('#money-submit-button').click();

cy.get('.winning-number').each((winningNumberInput, index) => {
cy.wrap(winningNumberInput).type(winningNumbers[index]);
});
cy.get('.bonus-number').type(45);
cy.get('.open-result-modal-button').click();

cy.get('.modal').should('be.visible');

cy.get('.winning-count').each((count) => {
cy.wrap(count)
.invoke('text')
.should('match', /^[0-9]+$/);
});

cy.get('.winning-rate')
.first()
.invoke('text')
.should('match', /^[0-9]+\.[0-9]+$/);
});

it('다시 시작하기 버튼을 눌렀을 때, 구입할 금액 입력 폼만 보이는지 확인한다.', () => {
const winningNumbers = [9, 11, 3, 25, 21, 2];
cy.get('#money-input').type('10000');
cy.get('#money-submit-button').click();

cy.get('.winning-number').each((winningNumberInput, index) => {
cy.wrap(winningNumberInput).type(winningNumbers[index]);
});
cy.get('.bonus-number').type(45);
cy.get('.open-result-modal-button').click();

cy.get('.modal').should('be.visible');

cy.get('.restart-button').click();

cy.get('#money-input').should('have.value', '').and('be.focused');
cy.get('.lotto-list-section').should('not.be.visible');
cy.get('.winning-number-form-section').should('not.be.visible');
cy.get('.modal').should('not.be.visible');
});

it('닫기 버튼을 눌렀을 때, 모달이 잘 닫히는지 확인한다.', () => {
const winningNumbers = [9, 11, 3, 25, 21, 2];
cy.get('#money-input').type('10000');
cy.get('#money-submit-button').click();

cy.get('.winning-number').each((winningNumberInput, index) => {
cy.wrap(winningNumberInput).type(winningNumbers[index]);
});
cy.get('.bonus-number').type(45);
cy.get('.open-result-modal-button').click();

cy.get('.modal').should('be.visible');
cy.get('.modal-close').click();

cy.get('.modal').should('not.be.visible');
});

it('당첨 번호를 입력할 때, 2자리 숫자가 입력되면, 자동으로 다음 폼으로 focus되는지 확인한다.', () => {
const winningNumbers = [10, 11, 30, 25, 21, 20];
cy.get('#money-input').type('10000');
cy.get('#money-submit-button').click();

cy.get('.winning-number').each((winningNumberInput, index) => {
cy.wrap(winningNumberInput)
.should('have.value', '')
.and('be.focused')
.type(winningNumbers[index]);
});
cy.get('.bonus-number').should('have.value', '').and('be.focused').type(45);
});

it('(Assertion) 로또 번호와 당첨 번호를 비교하여 일치하는 갯수가 정확하게 나오는지 확인한다.', () => {
const winningNumbers = [3, 9, 11, 20, 21, 25];
const bonusNumber = 45;

const lottos = [
{
sample: new Lotto([3, 9, 11, 20, 21, 25]),
rank: VALUE.RANK.FIRST,
},
{
sample: new Lotto([3, 9, 11, 20, 21, 45]),
rank: VALUE.RANK.SECOND,
},
{
sample: new Lotto([3, 9, 11, 20, 21, 44]),
rank: VALUE.RANK.THIRD,
},
{
sample: new Lotto([3, 9, 11, 20, 22, 44]),
rank: VALUE.RANK.FOURTH,
},
{
sample: new Lotto([3, 9, 11, 19, 22, 44]),
rank: VALUE.RANK.FIFTH,
},
];

lottos.forEach(({ sample, rank }) => {
expect(sample.getWinningRank(winningNumbers, bonusNumber)).to.be.equal(rank);
});
});

it('입력된 당첨 번호가 중복되면 경고창을 띄운다.', () => {
const winningNumbers = [9, 11, 9, 1, 21, 45];
const bonusNumber = 10;
const alertStub = cy.stub();

cy.get('#money-input').type('10000');
cy.get('#money-submit-button').click();

cy.get('.winning-number').each((winningNumberInput, index) => {
cy.wrap(winningNumberInput).type(winningNumbers[index]);
});

cy.get('.bonus-number').type(bonusNumber);

cy.on('window:alert', alertStub);
cy.get('.open-result-modal-button')
.click()
.then(() => {
expect(alertStub.getCall(0)).to.be.calledWith(ALERT_MESSAGE.INVALID_WINNING_NUMBER_INPUT);
});
});
});
68 changes: 39 additions & 29 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,63 +9,73 @@
</head>

<body>
<div id="app" class="p-3">
<main id="app" class="p-3">
<div class="d-flex justify-center mt-5">
<div class="w-100">
<h1 class="text-center">🎱 행운의 로또</h1>
<form class="mt-5" id="money-input-form">
<label class="mb-2 d-inline-block">구입할 금액을 입력해주세요.</label>
<label for="money-input" class="mb-2 d-inline-block">구입할 금액을 입력해주세요.</label>
<div class="d-flex">
<input id="money-input" type="number" min="0" class="w-100 mr-2 pl-2" placeholder="구입 금액" />
<input id="money-input" type="number" min="0" class="w-100 mr-2 pl-2" placeholder="구입 금액" autofocus
required />
<button id="money-submit-button" type="submit" class="btn btn-cyan">확인</button>
</div>
</form>
<section class="lotto-list-container mt-9 hidden">
<section class="lotto-list-section mt-9 hidden">
<div class="d-flex">
<label class="flex-auto my-0"><span class="lotto-count">
<!--로또 개수--></span>개를 구매하였습니다.</label>
<div class="flex-auto d-flex justify-end pr-1">
<label class="switch" id="lotto-numbers-toggle">
<input type="checkbox" class="lotto-numbers-toggle-button" />
<label for="lotto-numbers-toggle-button" class="switch" id="lotto-numbers-toggle">
<input type="checkbox" id="lotto-numbers-toggle-button" class="lotto-numbers-toggle-button" />
<span class="text-base font-normal">번호보기</span>
</label>
</div>
</div>
<div class="lotto-list d-flex flex-wrap">
<div class="lotto-list-container d-flex flex-wrap">
<!-- 로또 목록 -->
</div>
</section>
<section class="winning-number-form-container hidden">
<form class="mt-9">
<label class="flex-auto d-inline-block mb-3">지난 주 당첨번호 6개와 보너스 넘버 1개를 입력해주세요.</label>
<section class="winning-number-form-section hidden">
<form class="mt-9" id="winning-number-form">
<label class="flex-auto d-inline-block mb-3">지난 주 당첨번호 6개와 보너스 넘버 1개를
입력해주세요.</label>
<div class="d-flex">
<div>
<h4 class="mt-0 mb-3 text-center">당첨 번호</h4>
<label for="first-winning-number" class="mt-0 mb-3 text-center text-base d-block font-semibold">당첨
번호</label>
<div>
<input type="number" class="winning-number mx-1 text-center" />
<input type="number" class="winning-number mx-1 text-center" />
<input type="number" class="winning-number mx-1 text-center" />
<input type="number" class="winning-number mx-1 text-center" />
<input type="number" class="winning-number mx-1 text-center" />
<input type="number" class="winning-number mx-1 text-center" />
<input type="number" name="winning-number" aria-label="winning-number1" id="first-winning-number"
class="winning-number mx-1 text-center" min="1" max="45" required />
<input type="number" name="winning-number" aria-label="winning-number2"
class="winning-number mx-1 text-center" min="1" max="45" required />
<input type="number" name="winning-number" aria-label="winning-number3"
class="winning-number mx-1 text-center" min="1" max="45" required />
<input type="number" name="winning-number" aria-label="winning-number4"
class="winning-number mx-1 text-center" min="1" max="45" required />
<input type="number" name="winning-number" aria-label="winning-number5"
class="winning-number mx-1 text-center" min="1" max="45" required />
<input type="number" name="winning-number" aria-label="winning-number6"
class="winning-number mx-1 text-center" min="1" max="45" required />
</div>
</div>
<div class="bonus-number-container flex-grow">
<h4 class="mt-0 mb-3 text-center">보너스 번호</h4>
<label for="bonus-number" class="mt-0 mb-3 text-center text-base d-block font-semibold">보너스 번호</label>
<div class="d-flex justify-center">
<input type="number" class="bonus-number text-center" />
<input type="number" name="bonus-number" id="bonus-number" aria-label="bonus-number"
class="bonus-number text-center" min="1" max="45" required />
</div>
</div>
</div>
<button type="button" class="open-result-modal-button mt-5 btn btn-cyan w-100">
<button type="submit" class="open-result-modal-button mt-5 btn btn-cyan w-100">
결과 확인하기
</button>
</form>
</section>
</div>
</div>

<div class="modal">
<div class="modal hidden">
<div class="modal-inner p-10">
<div class="modal-close">
<svg viewbox="0 0 40 40">
Expand All @@ -87,38 +97,38 @@ <h2 class="text-center">🏆 당첨 통계 🏆</h2>
<tr class="text-center">
<td class="p-3">3개</td>
<td class="p-3">5,000</td>
<td class="p-3">n개</td>
<td class="p-3"><span class="winning-count" data-rank="5"></span></td>
</tr>
<tr class="text-center">
<td class="p-3">4개</td>
<td class="p-3">50,000</td>
<td class="p-3">n개</td>
<td class="p-3"><span class="winning-count" data-rank="4"></span></td>
</tr>
<tr class="text-center">
<td class="p-3">5개</td>
<td class="p-3">1,500,000</td>
<td class="p-3">n개</td>
<td class="p-3"><span class="winning-count" data-rank="3"></span></td>
</tr>
<tr class="text-center">
<td class="p-3">5개 + 보너스볼</td>
<td class="p-3">30,000,000</td>
<td class="p-3">n개</td>
<td class="p-3"><span class="winning-count" data-rank="2"></span></td>
</tr>
<tr class="text-center">
<td class="p-3">6개</td>
<td class="p-3">2,000,000,000</td>
<td class="p-3">n개</td>
<td class="p-3"><span class="winning-count" data-rank="1"></span></td>
</tr>
</tbody>
</table>
</div>
<p class="text-center font-bold">당신의 총 수익률은 %입니다.</p>
<p class="text-center font-bold">당신의 총 수익률은 <span class="winning-rate"></span>%입니다.</p>
<div class="d-flex justify-center mt-5">
<button type="button" class="btn btn-cyan">다시 시작하기</button>
<button type="button" class="btn btn-cyan restart-button">다시 시작하기</button>
</div>
</div>
</div>
</div>
</main>
<script type="module" src="./src/js/index.js"></script>
</body>

Expand Down
21 changes: 2 additions & 19 deletions src/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,10 @@ button:disabled {

.hidden {
visibility: hidden;
}

.lotto-numbers {
font-size: 1rem;
}

.lotto-list .lotto {
display: flex;
flex-direction: row;
align-items: center;
opacity: 0;
}

.lotto-list .lotto .lotto-numbers {
display: none;
font-size: 1rem;
padding-left: 5px;
}

.lotto-list.show-number {
flex-direction: column;
}

.lotto-list.show-number .lotto .lotto-numbers {
display: inline;
}
4 changes: 4 additions & 0 deletions src/css/shared/modules/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
display: inline-block;
}

.d-none {
display: none;
}

/* Layout - Top / Right / Bottom / Left */

.mt-2 {
Expand Down
Loading

0 comments on commit 164fe5a

Please sign in to comment.