Vue TDD

Vue TDD - Vuex ํŽธ

2020. 7. 30. 16:38
๋ชฉ์ฐจ
  1. Table of Content
  2. ๐Ÿ“Œ00. Introduction
  3. ๐Ÿ“Œ 01. Testing State
  4. ๐Ÿ“Œ 02. Testing getters
  5. ๐Ÿ“Œ 03. Testing mutations
  6. ๐Ÿ“Œ 04. Testing actions
  7. ๐Ÿค”๋ฒˆ์™ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ mockํ•˜๊ธฐ
  8. ๐Ÿ“Œ 05. Conclusion
  9. ๐Ÿ“Œ Reference
๋ฐ˜์‘ํ˜•

Table of Content

  • Introduction
  • Testing state
  • Testing getters
  • Testing mutations
  • Testing actions
  • Conclusion
  • Reference

๐Ÿ“Œ00. Introduction

์ด๋ฒˆํŽธ์—์„œ๋Š” vuex๋ฅผ ํ…Œ์ŠคํŒ…ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ณต์œ ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์ฝ”๋“œ๋Š” vue-test-practice์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.๐ŸŽ‰

ํ•ด๋‹น ํŽธ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ComponentํŽธ์˜ counter๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์˜ˆ์ œ์—์„œ api mock์„ ์‹ค์ œ๋กœ ์‹คํ˜„ ํ•ด๋ณด๊ธฐ ์œ„ํ•ด json placeholder์— todos๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์˜ˆ์ œ๋„ ๊ฐ™์ด ์ง„ํ–‰ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ 01. Testing State

state๋Š” ๋ณดํ†ต getDefaultState ๊ฐ™์€ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ์„ ์–ธ์„ ํ•ด์ฃผ๋Š”๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ์ด์œ ๋Š” testing์„ ํ• ๋•Œ ์ข€๋” ํŽธํ•˜๊ฒŒ state์˜ ๊ฐ’์„ ์ดˆ๊ธฐํ™” ์‹œ์ผœ์ค„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

// Store.spec.js
import counterStore, { getDefaultState } from '@/store/modules/counter'; // ์Šคํ† ์–ด๋ฅผ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.
const { state, getters, mutations, actions } = counterStore; // ๋””์Šค๋Ÿญํ„ฐ๋ง์„ ์‚ฌ์šฉ

// state๋Š” ํ•ญ์ƒ ์ดˆ๊ธฐ ๊ฐ’์€ getDefaultState์˜ ๋ฆฌํ„ด ๊ฐ’์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
describe('State test', () => {
  it('state should be equal getDeFaultState()', () => {
    expect(state).toEqual(getDefaultState());
  });
});
// counter.js

export const getDefaultState = () => ({
  count: 0,
  items: [],
});

export default { namespaced: true, state: getDefaultState(), getters, mutations, actions };

๐Ÿ“Œ 02. Testing getters

getters์—๋Š” ์นด์šดํŠธ๊ฐ€ 0์ด๋ƒ ์•„๋‹ˆ๋ƒ๋Š” ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// Store.spec.js
describe('Getters test', () => {
  describe('isCountZero test', () => {
    it('count 0 should be true', () => {
      const state = { count: 0 };
      // count์˜ ๊ฐ’์ด 0์ด๊ธฐ ๋•Œ๋ฌธ์— true์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
      expect(isCountZero(state)).toBeTruthy();
    });
    it('count 1 should be false', () => {
      const state = { count: 1 };
      // count ๊ฐ’์ด 0์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— false์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
      expect(isCountZero(state)).toBeFalsy();
    });
  });
});
// counter.js
const getters = {
  isCountZero: state => state.count === 0,
};

๐Ÿ“Œ 03. Testing mutations

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‘๊ฐ€์ง€ mutations๋ฅผ ์„ ์–ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • INCREMENT: count์˜ ๊ฐ’์„ 1์ฆ๊ฐ€ ์‹œํ‚ด
  • DECREMENT: count์˜ ๊ฐ’์„ 1๊ฐ์†Œ ์‹œํ‚ด
// Store.spec.js

const { INCREMENT, DECREMENT } = mutations;
describe('Mutation test', () => {
  let state;
  // ๋งค ํ…Œ์ŠคํŠธ ์งํ›„ state๊ฐ’์„ ์ดˆ๊ธฐํ™” ์‹œ์ผœ์คŒ
  beforeEach(() => {
    state = getDefaultState();
  });
  describe('Increment test', () => {
    it('Increment state by 1', () => {
      INCREMENT(state);
      // ํ•œ๋ฒˆ INCREMENT๋ฅผ ํ•ด์ฃผ์—ˆ์œผ๋‹ˆ state.count์˜ ๊ฐ’์€ 1์ด ๋‚˜์™€์•ผํ•ฉ๋‹ˆ๋‹ค.
      expect(state.count).toBe(1);
    });
  });

  describe('Decrement test', () => {
    it('Decrement state by 1', () => {
      DECREMENT(state);
      // ํ•œ๋ฒˆ DECREMENT๋ฅผ ํ•ด์ฃผ์—ˆ์œผ๋‹ˆ state.count์˜ ๊ฐ’์€ -1์ด ๋‚˜์™€์•ผํ•ฉ๋‹ˆ๋‹ค.
      expect(state.count).toBe(-1);
    });
  });
});
// counter.js
const mutations = {
  [INCREMENT](state) {
    state.count += 1;
  },

  [DECREMENT](state) {
    state.count -= 1;
  },
};

๐Ÿ“Œ 04. Testing actions

์ผ๋ฐ˜์ ์œผ๋กœ actions์—๋Š” ๋ณดํ†ต api๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—…์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ json placehoder์—์„œ todos๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ž‘์—…์„ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋จผ์ € todos๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” api call์€ ์ด๋ ‡๊ฒŒ ์งค์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import * as axios from 'axios';

export const fetchData = () => {
  return axios.get('https://jsonplaceholder.typicode.com/posts/1'); // 1๊ฐœ์˜ ํฌ์ŠคํŠธ๋งŒ ๋ถˆ๋Ÿฌ์˜ค๋Š” api
};

ํ•˜์ง€๋งŒ ์‹ค์ œ ํ…Œ์ŠคํŠธ๋Š” ํ•ด๋‹น api์˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋ฐ›๋Š” ๊ฒƒ์ด ์•„๋‹Œ mock์„ ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

// Store.spec.js
import { fetchData } from '@/api/todo-service';
import { mockItems } from '../__mock__/item-mock';

// ํ•ด๋‹น ์„œ๋น„์Šค๋ฅผ jest mock ํ•ด์ค๋‹ˆ๋‹ค.
jest.mock('@/api/todo-service');


describe('Async actions test', () => {
  describe('Fetch items test', () => {
    it('get items from mock', async () => {
      // ์ด๋ถ€๋ถ„์—์„œ ๋‚ด๋ ค์˜ฌ ๊ฐ’์„ ์ง€์ •์„ ํ•ด์ค๋‹ˆ๋‹ค.
      fetchData.mockResolvedValue(mockItems);
      // mockItem์€ ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

      // export const mockItems = {
      //  data: [1, 2, 3],
      // };

      // sinon.spy()์™€ ์‚ฌ์šฉ๋ฒ•์ด ๊ฐ™์Šต๋‹ˆ๋‹ค.
      // commit์ด ์–ด๋–ป๊ฒŒ ํ˜ธ์ถœ์ด ๋˜์—ˆ๋Š”์ง€ jest์—์„œ ๊ฐ์‹œํ•ด์ค๋‹ˆ๋‹ค.
      const commit = jest.fn();
      await FETCH_ITEMS({ commit });
      expect(commit).toHaveBeenCalledWith('SET_ITEMS', mockItems.data);
    });
  });
});
// Store.spec.js

const actions = {
  async [FETCH_ITEMS]({ commit }) {
    const response = await fetchData();
    commit(SET_ITEMS, response.data);
  },
};

๐Ÿค”๋ฒˆ์™ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ mockํ•˜๊ธฐ

๋Œ€ํ‘œ์ ์œผ๋กœ ์“ฐ์ด๋Š” nanoid๋ฅผ mockํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import nanoid from 'nanoid';

/**
 * mocking nanoid
 */
jest.mock('nanoid');
let value;
// String์œผ๋กœ 1๋ถ€ํ„ฐ ์ฆ๊ฐ€๋œ๊ฒƒ์„ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค.
nanoid.mockImplementation(() => {
  return String((value += 1));
});
// ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚œํ›„ 0์œผ๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ํ•ด์ค๋‹ˆ๋‹ค.
beforeEach(() => {
  value = 0;
});
// ํ…Œ์ŠคํŠธ๊ฐ€ ๋ชจ๋‘ ๋๋‚œํ›„์— ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ์— ์˜ํ–ฅ์„ ๋ฏธ์น ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ nanoid๋ฅผ ๋˜๋Œ๋ ค ๋†“์Šต๋‹ˆ๋‹ค.
afterAll(() => {
  nanoid.mockRestore();
});

๐Ÿ“Œ 05. Conclusion

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ง ๋‹ค๋Š”๊ฒƒ์„ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋ฅผ ์ง ๋‹ค๋Š”๊ฒƒ์€ ๊ฐ๊ฐ์˜ ์ฝ”๋“œ๋ฅผ ์งœ๋Š” ๊ฒƒ์˜ ์‹œ๊ฐ„์ด ๋” ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์ด ์‚ฌ์‹ค์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ •ํ™•ํ•œ ์ฝ”๋“œ๋“ค๋กœ ํ•˜๋‚˜ํ•˜๋‚˜ ์Œ“์•„๊ฐ„๋‹ค๋ฉด ์ „๋ฐ˜์ ์ธ ์‹œ๊ฐ„์„ ํ›จ์”ฌ ๋” ๋‹จ์ถ•์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ„ํ˜น mutations์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ๊ฒƒ๋“ค์€ ์™œ test code๋ฅผ ์งœ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค๋Š” ์‚ฌ๋žŒ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‘๊ฐ€์ง€ ๊ด€์ ์—์„œ ์ข€๋” ์‚ดํŽด๋ด์•ผํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ๊ด€์ ์€ test code๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ฌธ์„œ์˜ ์—ญํ• ์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. mutations์— ์ •ํ™•ํ•˜๊ฒŒ ์–ด๋– ํ•œ ๊ฐ’๋“ค์ด ๋“ค์–ด๊ฐ€๋Š”์ง€ ์–ด๋–ค ํƒ€์ž…๋“ค์ด ๋“ค์–ด๊ฐ€๋Š”์ง€ ์ •ํ™•ํ•˜๊ฒŒ ์•Œ์•„์•ผ ํ•  ํ•„์š”์„ฑ์ด ์žˆ์„ ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ๋Œ๋ ค์„œ ํ™•์ธํ•˜๊ธฐ์—๋Š” ๋‹จ๊ณ„๊ฐ€ ๋ณต์žกํ•œ ๊ฒฝ์šฐ๋„ ์žˆ๊ณ  ํ•œ๋ˆˆ์— ๋ณด๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ ์ง‘๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ๊ด€์ ์€ test code๊ฐ€ ์‚ฌ์†Œํ•œ ๋ฒ„๊ทธ๋ฅผ ์žก์•„์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ฐ„ํ˜น ์ €๋Š” ์ด๋Ÿฐ ์‹ค์ˆ˜๋ฅผ ํ•˜๊ณค ํ•ฉ๋‹ˆ๋‹ค. state์— tset๋ผ๊ณ  ์„ ์–ธ์ด๋ ‡๊ฒŒ ์„ค์ •์„ ํ•˜๊ณ 
mutations์—๋Š” ๋˜ ์ •ํ™•ํ•˜๊ฒŒ state.test = 1; ์ด๋ ‡๊ฒŒ ํ•ด๋†“๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ๋ฒ„๊ทธ๋ฅผ ์žก๋Š”๋ฐ ์‹œ๊ฐ„์ด ์ •๋ง ๋งŽ์ด ์†Œ์š”๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ž์ž˜ํ•œ ๋ฒ„๊ทธ๋“ค์„ ์žก์•„์ฃผ๊ธฐ ๋•Œ๋ฌธ์— testcode๋ฅผ ์”๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ชจ๋“  ์ฝ”๋“œ๋“ค์„ 100% tdd๋กœ ๊ฐ€๋Š”๊ฒƒ์€ ๋ถ€์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  100% test code๋ฅผ ์‹ ๋ขฐํ•˜๋Š”๊ฒƒ ๋˜ํ•œ ์œ„ํ—˜ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.(test case์˜ ๋ถ€์žฌ ํ˜น์€ test case๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—) ํ•˜์ง€๋งŒ ๋งˆ์น˜ mutations type์„ ์ƒ์ˆ˜ํ™”๋ฅผ ํ•ด๋†“๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ž์ž˜ํ•œ ๋ฒ„๊ทธ๋ถ€ํ„ฐ ์น˜๋ช…์ ์ธ ๋ฒ„๊ทธ๋Š” ๊ฝค๋งŽ์ด ์žก์•„์ค„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•„์š”์— ๋”ฐ๋ผ tdd๋ฅผ ์“ฐ๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ test์˜ ์ข…๋ฅ˜๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ž…๋‹ˆ๋‹ค. unit test๋กœ๋งŒ ๋ชจ๋“  test๋ฅผ ์ปค๋ฒ„ํ•˜๋ ค๊ณ  ํ•˜์ง€ ๋งˆ์„ธ์šฉ... ๐Ÿ˜…

์ด๋ฒˆ ํฌ์ŠคํŒ… ๊นŒ์ง€๋Š” vue์˜ logic์ ์ธ ๊ฒƒ์„ ์‚ดํŽด ๋ณด์•˜๋‹ค๋ฉด ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” vue์˜ view์ ์ธ ๊ฒƒ์„ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.(Story Book)

๐Ÿ“Œ Reference

  • Vuex ๊ณต์‹ ๋ฌธ์„œ
  • Vue test utils
๋ฐ˜์‘ํ˜•

'Vue TDD' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Vue TDD - ํšŒ๊ณ ํŽธ  (0) 2020.08.10
Test code ์‰ฝ๊ฒŒ ์“ฐ๊ธฐ - 1  (0) 2020.08.06
Vue TDD - E2E ํŽธ  (0) 2020.08.02
Vue TDD - Storybook ํŽธ  (0) 2020.07.31
Vue TDD - Component ํŽธ  (0) 2020.07.25
  1. Table of Content
  2. ๐Ÿ“Œ00. Introduction
  3. ๐Ÿ“Œ 01. Testing State
  4. ๐Ÿ“Œ 02. Testing getters
  5. ๐Ÿ“Œ 03. Testing mutations
  6. ๐Ÿ“Œ 04. Testing actions
  7. ๐Ÿค”๋ฒˆ์™ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ mockํ•˜๊ธฐ
  8. ๐Ÿ“Œ 05. Conclusion
  9. ๐Ÿ“Œ Reference
'Vue TDD' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Test code ์‰ฝ๊ฒŒ ์“ฐ๊ธฐ - 1
  • Vue TDD - E2E ํŽธ
  • Vue TDD - Storybook ํŽธ
  • Vue TDD - Component ํŽธ
eddie0329
eddie0329
Front-end Developer
Eddie Sunny's BlogFront-end Developer
๋ฐ˜์‘ํ˜•
eddie0329
Eddie Sunny's Blog
eddie0329
์ „์ฒด
์˜ค๋Š˜
์–ด์ œ
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (100)
    • Summary of Book (0)
    • Vue Study (11)
    • Vue TDD (9)
    • Vue BDD (5)
    • Design Pattern (9)
    • Javascript Study (3)
    • React Study (15)
    • React TDD (1)
    • Vue Storybook (2)
    • Refactoring (0)
    • Graphql_Apollo (3)
    • Svelte (8)
    • Open Source (1)
    • D3 (4)
    • Typescript (1)
    • CSS (2)
    • Android (0)
    • Java (0)
    • Kotlin (0)
    • ์žก๋‹ด (0)
    • Swift (19)
    • Rust (2)
    • ํšŒ์‚ฌ์ด์•ผ๊ธฐ (2)
    • ReactNative Study (2)
    • Vitest (0)

๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

  • Home

๊ณต์ง€์‚ฌํ•ญ

์ธ๊ธฐ ๊ธ€

ํƒœ๊ทธ

  • D3
  • client only
  • Vue
  • apollo
  • vue3
  • storybook6
  • react useRef
  • Javascript
  • javascript pattern
  • BDD
  • swift5
  • vue bdd
  • Design Pattern
  • vue storybook
  • slot ํŒจํ„ด
  • Nextjs
  • Kotlin
  • Cypress
  • react
  • swift
  • react-component-slot
  • TDD
  • vue cypress
  • TypeScript
  • jest
  • svelte
  • CSS
  • vue tdd
  • React Native
  • Vue test

์ตœ๊ทผ ๋Œ“๊ธ€

์ตœ๊ทผ ๊ธ€

hELLO ยท Designed By ์ •์ƒ์šฐ.
eddie0329
Vue TDD - Vuex ํŽธ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”

๋‹จ์ถ•ํ‚ค

๋‚ด ๋ธ”๋กœ๊ทธ

๋‚ด ๋ธ”๋กœ๊ทธ - ๊ด€๋ฆฌ์ž ํ™ˆ ์ „ํ™˜
Q
Q
์ƒˆ ๊ธ€ ์“ฐ๊ธฐ
W
W

๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๊ธ€

๊ธ€ ์ˆ˜์ • (๊ถŒํ•œ ์žˆ๋Š” ๊ฒฝ์šฐ)
E
E
๋Œ“๊ธ€ ์˜์—ญ์œผ๋กœ ์ด๋™
C
C

๋ชจ๋“  ์˜์—ญ

์ด ํŽ˜์ด์ง€์˜ URL ๋ณต์‚ฌ
S
S
๋งจ ์œ„๋กœ ์ด๋™
T
T
ํ‹ฐ์Šคํ† ๋ฆฌ ํ™ˆ ์ด๋™
H
H
๋‹จ์ถ•ํ‚ค ์•ˆ๋‚ด
Shift + /
โ‡ง + /

* ๋‹จ์ถ•ํ‚ค๋Š” ํ•œ๊ธ€/์˜๋ฌธ ๋Œ€์†Œ๋ฌธ์ž๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ‹ฐ์Šคํ† ๋ฆฌ ๊ธฐ๋ณธ ๋„๋ฉ”์ธ์—์„œ๋งŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.