Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"env": {
"browser": true,
"es2021": true,
"cypress/globals": true
},
"extends": [
"airbnb-base",
"plugin:cypress/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"cypress"
],
"rules": {
"lines-between-class-members": "off",
"import/extensions": "off",
"import/no-unresolved": "off",
"no-console": "warn",
"no-alert": "off",
"no-param-reassign": "off"
},
"ignorePatterns": ["src/js/*"]
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
src/js/*

# Created by https://www.toptal.com/developers/gitignore/api/node,vscode,intellij,webstorm
# Edit at https://www.toptal.com/developers/gitignore?templates=node,vscode,intellij,webstorm

Expand Down Expand Up @@ -351,3 +353,4 @@ dist
# https://plugins.jetbrains.com/plugin/12206-codestream

# End of https://www.toptal.com/developers/gitignore/api/node,vscode,intellij,webstorm
docs/README.md
12 changes: 12 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"baseUrl": "http://localhost:5500",
"env": {
"BUY_INPUT": "#buy-container > div > input",
"BUY_BUTTON": "#buy-container > div > button",
"TICKET_CONTAINER": "#ticket-container",
"TICKET_SIZE_LABEL": "#ticket-container > div > label",
"TICKET_NUMBER_TOGGLE": ".switch",
"TICKET_RENDER_CONTAINER": "#ticket-container > div.flex-wrap",
"RESULT_CONTAINER": "#result-container"
}
}
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"
}
101 changes: 101 additions & 0 deletions cypress/integration/container/buy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/* eslint-disable no-undef */
describe('Buy container', () => {
function inputMoneyString(money: string): Cypress.Chainable<JQuery<any>> {
return (
cy.get(Cypress.env('BUY_INPUT')).type(money)
.get(Cypress.env('BUY_BUTTON')).click()
);
}

it('change visibility of ticket and result container', () => {
cy.visit('/');
inputMoneyString('3000')
.get(Cypress.env('TICKET_CONTAINER'))
.should('be.visible')
.get(Cypress.env('RESULT_CONTAINER'))
.should('be.visible');
});

it('alert and fixable when user input money is less than 1000', () => {
let alertMessage: String;
cy.on('window:alert', (str) => {
alertMessage = str;
});

cy.reload().then(() => {
alertMessage = undefined;
});
inputMoneyString('5').then(() => {
expect(alertMessage).to.equal('🚨 1000원 이상을 입력해야 합니다 🚨');
alertMessage = undefined;
}).get(Cypress.env('BUY_INPUT')).should('not.be.disabled');

inputMoneyString('999').then(() => {
expect(alertMessage).to.equal('🚨 1000원 이상을 입력해야 합니다 🚨');
}).get(Cypress.env('BUY_INPUT')).should('not.be.disabled');
});

it('calculate ticket size and render tickets', () => {
function checkTickets(money: number): Cypress.Chainable<JQuery<any>> {
const ticketSize = Math.floor(money / 1000);
return (
inputMoneyString(money.toString())
.get(Cypress.env('BUY_INPUT'))
.should('be.disabled')
.get(Cypress.env('BUY_BUTTON'))
.should('be.disabled')
.get(Cypress.env('TICKET_SIZE_LABEL'))
.should('have.text', `총 ${ticketSize}개를 구매하였습니다.`)
.get(Cypress.env('TICKET_RENDER_CONTAINER'))
.find('span')
.should('have.length', ticketSize)
);
}

cy.reload();
checkTickets(5000);

cy.reload();
checkTickets(50000);

cy.reload();
checkTickets(27000);
});

it('alert when user input money value with remainder', () => {
let alertMessage: String;
cy.on('window:alert', (str) => {
alertMessage = str;
});

cy.reload().then(() => {
alertMessage = undefined;
});
inputMoneyString('5500').then(() => {
expect(alertMessage).to.equal('잔돈으로 500원이 남았습니다');
});

cy.reload().then(() => {
alertMessage = undefined;
});
inputMoneyString('1234').then(() => {
expect(alertMessage).to.equal('잔돈으로 234원이 남았습니다');
});
});

it('show numbers when number toggle enable', () => {
cy.reload();
inputMoneyString('4672')
.get(Cypress.env('TICKET_NUMBER_TOGGLE')).click()
.get(Cypress.env('TICKET_RENDER_CONTAINER'))
.find('span')
.each(($el) => {
const numArr = $el.text().substr(4).split(', ').map((val) => Number(val));
expect(numArr).to.be.an('array')
.and.to.be.lengthOf(6)
.and.to.satisfy((nums) => (
nums.every((num) => (num >= 1 && num <= 45))
));
});
});
});
5 changes: 5 additions & 0 deletions cypress/integration/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
describe('Lotto module', () => {
it('can test itself', () => {
cy.visit('/');
});
});
22 changes: 22 additions & 0 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
25 changes: 25 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
20 changes: 20 additions & 0 deletions cypress/support/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands'

// Alternatively you can use CommonJS syntax:
// require('./commands')
8 changes: 8 additions & 0 deletions cypress/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
}
19 changes: 19 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## 기능 구현 목록
- [x] 프로젝트 개발 환경 설정
- [x] eslint + typescript 설정
- [x] cypress 설정
- [x] 구입 기능
- [x] 구입할 금액에 맞는 갯수를 구매할수 있어야 함
- [x] 딱 떨어지는 금액이 아닐때 가능한 금액만 구매해야 함
- [x] 자동으로 번호를 배정받아야 함
- [x] 확인버튼을 누른 이후에는 구입 금액을 수정할 수 없어야 함
- [x] 복권 번호를 번호보기를 통해 볼 수 있어야 함
- [x] 당첨 결과 기능
- [x] 결과 확인하기 버튼을 눌렀을 때 결과 모달이 떠야 함
- [x] 올바르지 않는 당첨 번호, 보너스 번호가 들어왔을 때 처리되지 않아야 함
- [x] 당첨 통계, 수익률을 계산해야 함
- [x] 다시 시작 버튼을 통해 초기화해야 함
- [x] 수동 구입 기능
- [x] 입력에 따라 자동 / 수동을 구분해야 함
- [x] 수동 구입에 대한 UI를 구현해야 함
- [x] 수동 구입이 끝난 이후 나머지 금액만큼 자동으로 구매해야 함
53 changes: 45 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<div class="d-flex justify-center mt-5">
<div class="w-100">
<h1 class="text-center">🎱 행운의 로또</h1>
<form class="mt-5">
<form class="mt-5" id="buy-container">
<label class="mb-2 d-inline-block"
>구입할 금액을 입력해주세요.
</label>
Expand All @@ -24,7 +24,49 @@ <h1 class="text-center">🎱 행운의 로또</h1>
<button type="button" class="btn btn-cyan">확인</button>
</div>
</form>
<section class="mt-9">
<form class="mt-9 d-flex flex-col justify-center" id="manual-container">
<label class="flex-auto d-inline-block mb-3"
>수동으로 구매할 번호를 입력해주세요.</label
>
<div class="d-flex">
<div>
<div>
<input
type="number"
class="manual-number mx-1 text-center"
/>
<input
type="number"
class="manual-number mx-1 text-center"
/>
<input
type="number"
class="manual-number mx-1 text-center"
/>
<input
type="number"
class="manual-number mx-1 text-center"
/>
<input
type="number"
class="manual-number mx-1 text-center"
/>
<input
type="number"
class="manual-number mx-1 text-center"
/>
<button type="button" class="buy-manual-button mx-2 btn btn-cyan">한장 구매</button>
</div>
</div>
</div>
<button
type="button"
class="buy-left-button mt-5 btn btn-cyan w-100"
>
남은 돈으로 자동 구매하기
</button>
</form>
<section class="mt-9" id="ticket-container">
<div class="d-flex">
<label class="flex-auto my-0">총 5개를 구매하였습니다.</label>
<div class="flex-auto d-flex justify-end pr-1">
Expand All @@ -35,14 +77,9 @@ <h1 class="text-center">🎱 행운의 로또</h1>
</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>
</section>
<form class="mt-9">
<form class="mt-9" id="result-container">
<label class="flex-auto d-inline-block mb-3"
>지난 주 당첨번호 6개와 보너스 넘버 1개를 입력해주세요.</label
>
Expand Down
16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
{
"name": "racingcar",
"name": "lotto",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"cypress": "^6.3.0"
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
"cypress": "^7.6.0",
"eslint": "^7.29.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-cypress": "^2.11.3",
"eslint-plugin-import": "^2.23.4",
"typescript": "^4.3.4"
},
"scripts": {
"build": "yarn tsc --watch",
"lint": "yarn eslint src/ts/**/*.ts --fix",
"test": "yarn cypress open"
}
}
17 changes: 17 additions & 0 deletions src/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,20 @@ body {
width: 30px;
height: 36px;
}

.manual-number {
width: 30px;
height: 36px;
}

#ticket-container {
visibility: hidden;
}

#result-container {
visibility: hidden;
}

#manual-container {
display: none;
}
Loading