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

[holee] typescript-racingcar #1

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
fb58e47
chore: codeformatter, cypress, tsconfig, docs
hochan222 Jun 2, 2021
a155f40
feat: λ²„νŠΌ λˆ„λ₯Όμ‹œ 이름 λ Œλ”λ§
hochan222 Jun 2, 2021
5b2e816
feat: μžλ™μ°¨ 이름 μž…λ ₯μ‹œ 화면에 이름 λ Œλ”λ§ κΈ°λŠ₯ κ΅¬ν˜„
hochan222 Jun 2, 2021
104bb69
bug: button 2κ°œκ°€ ν•œκ°œ 눌린 ν›„ μž‘λ™μ„ μ•ˆν•¨
hochan222 Jun 2, 2021
43f0526
fix: cause=> innerHTML destory eventlistener
hochan222 Jun 2, 2021
c495959
feat: add Winner
hochan222 Jun 2, 2021
02beb8c
refactor: to winner and component
hochan222 Jun 2, 2021
f36b018
refactor: naming component
hochan222 Jun 2, 2021
964800a
feat: reset button κ΅¬ν˜„ μ™„λ£Œ
hochan222 Jun 2, 2021
fa8319a
chore: prettier
hochan222 Jun 2, 2021
65c6699
chore: prettier
hochan222 Jun 2, 2021
691dfac
refactor: func to const val = ()=>{}
hochan222 Jun 3, 2021
471c156
feat: spinner κΈ°λŠ₯ κ΅¬ν˜„
hochan222 Jun 3, 2021
f66feaf
feat: add race async
hochan222 Jun 3, 2021
50e075b
feat: 각 횟수 사이에 μ§€μ—°μ‹œκ°„ 두기 async, await μ‚¬μš©
hochan222 Jun 3, 2021
af30635
feat: μŠ€ν”Όλ„ˆ λ§ˆμ§€λ§‰ 진행 νšŸμˆ˜κ°€ λλ‚˜λ©΄ μ‚­μ œν•˜λ„λ‘ λ³€κ²½
hochan222 Jun 3, 2021
978394d
feat: κΈ°λŠ₯κ΅¬ν˜„: μ •μƒμ μœΌλ‘œ κ²Œμž„μ˜ 턴이 λ‹€ λ™μž‘λœ ν›„μ—λŠ” κ²°κ³Όλ₯Ό 보여주고, 2초 후에 μΆ•ν•˜μ˜ alert 메세지λ₯Ό λ„μš΄λ‹€.
hochan222 Jun 3, 2021
36e7cb3
refactor: @share 폴더λ₯Ό 곡용으둜 λ§Œλ“€κΈ°
hochan222 Jun 3, 2021
a31cfe8
refactor: κ³΅ν†΅μœΌλ‘œ 뺼수 μžˆλŠ”κ±° λ¦¬νŽ™ν† λ§
hochan222 Jun 3, 2021
f6e5b5c
refactor: index.html에 div tag만 남기기
hochan222 Jun 3, 2021
59c0a7a
refactor: μžλ™μ°¨ 이름 μ΄ˆκΈ°ν™” ν•¨μˆ˜ 뢄리
hochan222 Jun 3, 2021
d6b60fb
feat: init νŒŒμΌμ„ λ§Œλ“€μ–΄μ„œ λ”°λ‘œ init에 κ΄€λ ¨ν•œ ν•¨μˆ˜ 둜직 뢄리
hochan222 Jun 3, 2021
543afb2
refactor: delay μ‹œκ°„ μƒμˆ˜λ‘œ λΊ΄κΈ°
hochan222 Jun 3, 2021
6230026
refactor: space before return
hochan222 Jun 3, 2021
58c3797
refactor: render ν•¨μˆ˜ ν˜•μ‹ 톡일화
hochan222 Jun 3, 2021
17f51c2
fix: car name input μž…λ ₯ν•œ λ’€μ—λ§Œ count μž…λ ₯ν•  수 있게 κ΅¬ν˜„ν•˜κΈ°.
hochan222 Jun 3, 2021
26e8f86
feat: car name input μž…λ ₯ν•œ λ’€ λΉ„ν™œμ„±ν™” ν•˜κΈ°.
hochan222 Jun 3, 2021
08476fd
feat: car name input μž…λ ₯ν•œ λ’€ λΉ„ν™œμ„±ν™” ν•˜κΈ°.
hochan222 Jun 3, 2021
e9c8da2
refactor: forwardIconDiv λ₯Ό view둜 λ‚˜λˆ„κΈ°
hochan222 Jun 3, 2021
0a5bc30
refactor: import νŒŒμΌλ“€ μˆœμ„œ λ¦¬νŽ™ν† λ§
hochan222 Jun 3, 2021
f2449fd
test: add cypress testcase
hochan222 Jun 3, 2021
a2c7c10
style: ν•¨μˆ˜μ‚¬μ΄μ— κ°œν–‰ μΆ”κ°€
hochan222 Jun 4, 2021
710237b
refactor: dom ν•¨μˆ˜ queryselector둜 톡일화 및 $, 9620둜 가독성 μ’‹κ²Œ λ°”κΏˆ
hochan222 Jun 4, 2021
581f5e6
refactor: return ν•œμ€„μœ„ κ°œν–‰κ³Ό 선언뢀와 둜직 κ°œν–‰μœΌλ‘œ ꡬ뢄
hochan222 Jun 4, 2021
9419e43
docs: μœ„ κΈ°λŠ₯듀이 μ •μƒμ μœΌλ‘œ λ™μž‘ν•˜λŠ”μ§€ Cypressλ₯Ό μ΄μš©ν•΄ ν…ŒμŠ€νŠΈν•œλ‹€.
hochan222 Jun 7, 2021
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
15 changes: 15 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["airbnb-base"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"ignorePatterns": ["dist/", "node_modules/"],
"rules": {}
}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ typings/

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
Expand Down
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 120
}
3 changes: 3 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"baseUrl": "http://127.0.0.1:5500"
}
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"
}
134 changes: 134 additions & 0 deletions cypress/integration/racingcar.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
const typeAndCheckInput = (location, content, result) => {
cy.get(location).type(content);
cy.get(location).should('have.value', result);
};

const typeAndClickCarNameSubmit = (content) => {
typeAndCheckInput('.w-100[type=text]', content, content);
cy.get('#car-name-submit').click();
cy.get('#car-name-submit').should('be.disabled');
cy.get('.w-100[type=text]').should('be.disabled');
};

const typeAndClickCountSubmit = (count) => {
typeAndCheckInput('.w-100[type=number]', count, count);
cy.get('#car-count-submit').click();
cy.get('#car-count-submit').should('be.disabled');
cy.get('.w-100[type=number]').should('be.disabled');
};

const checkSpinnerCount = (length) => {
cy.get('.spinner-container').should('exist');
cy.get('.mr-2').find('.spinner').should('have.length', length);
};

describe('initial page behavior', () => {
beforeEach(() => {
cy.visit('/javascript-racingcar/');
});
it('inputκ°’ μž…λ ₯ ν–ˆμ„λ•Œ 잘 λ“€μ–΄κ°€λŠ”μ§€ 확인', () => {
cy.get('.w-100[type=text]').type('holee');
cy.get('.w-100[type=text]').should('have.value', 'holee');
cy.get('.w-100[type=number]').type(1);
cy.get('.w-100[type=number]').should('have.value', 1);
});
});

describe('racing-game base behavior', () => {
beforeEach(() => {
cy.visit('/javascript-racingcar/');
});
const basicInput = 'EAST, WEST, SOUTH, NORTH';
const basicCount = 2;

it('μžλ™μ°¨ 이름 μž…λ ₯ ν–ˆμ„ λ•Œ, car name input/button λΉ„ν™œμ„±ν™”', () => {
typeAndClickCarNameSubmit(basicInput);
});
it('μžλ™μ°¨ 이름 μž…λ ₯ ν–ˆμ„ λ•Œ, 이름에 λ§žλŠ” μžλ™μ°¨/μŠ€ν”Όλ„ˆ 생성', () => {
typeAndClickCarNameSubmit(basicInput);
basicInput.split(', ').map((x, i) => {
cy.get('.car-player').eq(i).should('have.text', x);
});
checkSpinnerCount(basicInput.split(', ').length);
});
it('μ‹œλ„ 횟수 μž…λ ₯ ν–ˆμ„ λ•Œ, count input/button λΉ„ν™œμ„±ν™”', () => {
typeAndClickCarNameSubmit(basicInput);
typeAndClickCountSubmit(basicCount);
});
it('μ‹œλ„ 횟수 μž…λ ₯ ν–ˆμ„ λ•Œ, μ•Œλ§žμ€ ⬇️️ 생성 및 spinner μ‚­μ œ', () => {
typeAndClickCarNameSubmit(basicInput);
typeAndClickCountSubmit(basicCount);
cy.clock();
checkSpinnerCount(basicInput.split(', ').length);
cy.tick(2000);
cy.get('.forward-icon').should('exist');
checkSpinnerCount(0);
});
it('μ‹œλ„ 횟수 μž…λ ₯ ν–ˆμ„ λ•Œ, κ²°κ³Ό ν™”λ©΄ 좜λ ₯', () => {
typeAndClickCarNameSubmit(basicInput);
typeAndClickCountSubmit(basicCount);
cy.wait(2000);
cy.get('section').eq(2).should('exist');
});
it('μ‹œλ„ 횟수 μž…λ ₯ ν–ˆμ„ λ•Œ, μ•Œλ§žμ€ alert 생성', () => {
typeAndClickCarNameSubmit(basicInput);
typeAndClickCountSubmit(basicCount);
cy.wait(2000);
cy.get('section').eq(2).should('exist');
cy.wait(1500);
cy.on('window:alert', (txt) => {
expect(txt).to.contains('πŸ† 우승 μΆ•ν•˜ν•©λ‹ˆλ‹€ γ…Žγ…Ž πŸ†');
});
});
it('λ‹€μ‹œ μ‹œμž‘ν•˜κΈ° λ²„νŠΌ λΆˆλ €μ„ λ•Œ, html μ΄ˆκΈ°ν™” 확인', () => {
typeAndClickCarNameSubmit(basicInput);
typeAndClickCountSubmit(basicCount);
cy.wait(3500);
cy.get('button').eq(2).click();
cy.get('section').eq(1).should('not.exist');
cy.get('section').eq(2).should('not.exist');
cy.get('#car-name-submit').should('not.disabled');
cy.get('.w-100[type=text]').should('not.disabled');
cy.get('#car-count-submit').should('not.disabled');
cy.get('.w-100[type=number]').should('not.disabled');
});
});

const checkValidInit = () => {
cy.get('#car-count-submit').should('not.disabled');
cy.get('.w-100[type=number]').should('not.disabled');
cy.get('section').eq(1).should('not.exist');
cy.get('section').eq(2).should('not.exist');
cy.get('.w-100[type=text]').focus();
};

describe('racing-game exception behavior', () => {
beforeEach(() => {
cy.visit('/javascript-racingcar/');
});
const basicInput = 'EAST, WEST, SOUTH, NORTH';
const basicCount = 2;

it('μžλ™μ°¨ 이름을 μž…λ ₯ν•˜μ§€ μ•Šμ•˜μ„ λ•Œ, μ‹œλ„ν•  횟수 λ²„νŠΌ 클릭', () => {
cy.get('#car-name-submit').click();
cy.get('#car-count-submit').click();
checkValidInit();
});
it('μžλ™μ°¨ 이름을 μž…λ ₯ν•˜μ§€ μ•Šμ•˜μ„ λ•Œ, μ‹œλ„ν•  횟수 μž…λ ₯ ν›„ λ²„νŠΌ 클릭', () => {
typeAndCheckInput('.w-100[type=number]', basicCount, basicCount);
cy.get('#car-name-submit').click();
cy.get('#car-count-submit').click();
checkValidInit();
});
it('μžλ™μ°¨ 이름을 μž…λ ₯ν•œ ν›„ 확인 λ²„νŠΌμ„ λˆ„λ₯΄μ§€μ•Šμ•˜μ„ λ•Œ, μ‹œλ„ν•  횟수 λ²„νŠΌ 클릭', () => {
typeAndCheckInput('.w-100[type=text]', basicInput, basicInput);
cy.get('#car-count-submit').click();
checkValidInit();
});
it('μžλ™μ°¨ 이름을 μž…λ ₯ν•œ ν›„ 확인 λ²„νŠΌμ„ λˆ„λ₯΄μ§€μ•Šμ•˜μ„ λ•Œ, μ‹œλ„ν•  횟수 μž…λ ₯ ν›„ λ²„νŠΌ 클릭', () => {
typeAndCheckInput('.w-100[type=text]', basicInput, basicInput);
typeAndCheckInput('.w-100[type=number]', basicCount, basicCount);
cy.get('#car-count-submit').click();
checkValidInit();
});
});
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')
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions dist/js/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Game from './modules/Game.js';
export default function App() {
Game({
$app: document.querySelector('#app'),
});
}
App();
13 changes: 13 additions & 0 deletions dist/js/modules/@share/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const ERROR_MESSAGE = {
INVALID_CAR_NAME_INPUT: 'μœ νš¨ν•˜μ§€ μ•Šμ€ μžλ™μ°¨ μ΄λ¦„μž…λ‹ˆλ‹€. λ‹€μ‹œ μž…λ ₯ ν•΄μ£Όμ„Έμš”.',
INVALID_INPUT_PROCEDURE: 'μžλ™μ°¨ 이름 λ¨Όμ € μž…λ ₯ν•΄μ£Όμ„Έμš”!',
INVALID_COUNT_INPUT: 'μœ νš¨ν•˜μ§€ μ•Šμ€ 횟수 μž…λ ₯μž…λ‹ˆλ‹€. λ‹€μ‹œ μž…λ ₯ ν•΄μ£Όμ„Έμš”.',
};
const MESSAGE = {
CELEBRATE_WINNER: 'πŸ† 우승 μΆ•ν•˜ν•©λ‹ˆλ‹€ γ…Žγ…Ž πŸ†',
};
const DELAY = {
RACE: 1000,
ALERT: 1500,
};
export { ERROR_MESSAGE, MESSAGE, DELAY };
38 changes: 38 additions & 0 deletions dist/js/modules/@share/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import CarNameComponent from '../CarName.js';
import RaceComponent from '../Race.js';
import { $, $$, disable, initEnable } from './utils.js';
import { ERROR_MESSAGE } from './constants.js';
import { carNameInputInit } from './init.js';
const carNameInputEvent = () => {
var _a;
const carNamesInput = $('#car-name-input');
disable(carNamesInput);
disable((_a = carNamesInput.parentElement) === null || _a === void 0 ? void 0 : _a.children[1]);
if (carNamesInput) {
CarNameComponent({ $app: $('#app'), carNames: carNamesInput.value });
}
};
const raceCountInputEvent = () => {
var _a;
const raceCountInput = $('input[type="number"]');
const carNamesInput = $('input[type="text"]');
disable(raceCountInput);
disable((_a = raceCountInput.parentElement) === null || _a === void 0 ? void 0 : _a.children[1]);
if (raceCountInput && carNamesInput.value !== '') {
RaceComponent({
$app: $('#app'),
count: Number(raceCountInput.value),
});
}
else {
alert(ERROR_MESSAGE.INVALID_INPUT_PROCEDURE);
carNameInputInit();
initEnable();
}
};
const inputController = () => {
const gameButton = $$('button');
gameButton[0].onclick = carNameInputEvent;
gameButton[1].onclick = raceCountInputEvent;
};
export { inputController };
15 changes: 15 additions & 0 deletions dist/js/modules/@share/dom-dataset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { $ } from './utils.js';
const setCarNameDataset = (data) => {
const carNamesInput = $('input[type="text"]');
if (carNamesInput) {
carNamesInput.dataset.click = data;
}
};
const checkCarNameDataset = () => {
const carNamesInput = $('input[type="text"]');
if (carNamesInput) {
return carNamesInput.dataset.click === 'click';
}
return false;
};
export { setCarNameDataset, checkCarNameDataset };
12 changes: 12 additions & 0 deletions dist/js/modules/@share/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { $ } from './utils.js';
const carNameInputInit = () => {
const carNameInput = $('#car-name-input');
carNameInput.value = '';
carNameInput.focus();
};
const racingCountInputInit = () => {
const racingCountInput = $('#racing-count-input');
racingCountInput.value = '';
racingCountInput.focus();
};
export { carNameInputInit, racingCountInputInit };
8 changes: 8 additions & 0 deletions dist/js/modules/@share/message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const ERROR_MESSAGE = {
INVALID_CAR_NAME_INPUT: 'μœ νš¨ν•˜μ§€ μ•Šμ€ μžλ™μ°¨ μ΄λ¦„μž…λ‹ˆλ‹€. λ‹€μ‹œ μž…λ ₯ ν•΄μ£Όμ„Έμš”.',
INVALID_INPUT_PROCEDURE: 'μžλ™μ°¨ 이름 λ¨Όμ € μž…λ ₯ν•΄μ£Όμ„Έμš”!',
INVALID_COUNT_INPUT: 'μœ νš¨ν•˜μ§€ μ•Šμ€ 횟수 μž…λ ₯μž…λ‹ˆλ‹€. λ‹€μ‹œ μž…λ ₯ ν•΄μ£Όμ„Έμš”.'
};
export const MESSAGE = {
CELEBRATE_WINNER: 'πŸ† μΆ•ν•˜ν•©λ‹ˆλ‹€ γ…Žγ…Ž μ΅œμ’… 우승자: EAST, WEST, SOUTH, NORTH πŸ†'
};
7 changes: 7 additions & 0 deletions dist/js/modules/@share/spinner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const removeSpinner = (carPlayer) => {
var _a, _b, _c, _d;
if (((_b = (_a = carPlayer.parentNode) === null || _a === void 0 ? void 0 : _a.lastElementChild) === null || _b === void 0 ? void 0 : _b.className) === 'd-flex justify-center mt-3') {
(_d = (_c = carPlayer.parentNode) === null || _c === void 0 ? void 0 : _c.lastElementChild) === null || _d === void 0 ? void 0 : _d.remove();
}
};
export { removeSpinner };
Loading