๊นœ์ง€

[Cypress] ๐Ÿ“ ์›น ํ…Œ์ŠคํŠธ ์ž๋™ํ™” ์‚ฌ์šฉ๋ฒ• ๐Ÿ‘€ ํ•œ๋ˆˆ์— ์ •๋ฆฌ

์ธํŒŒ_ 2024. 3. 24. 01:19

cypress-์‚ฌ์šฉ๋ฒ•

Cypress ์†Œ๊ฐœ

์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŒ…์€ ์†Œํ”„ํŠธ์›จ์–ด์˜ ํ’ˆ์งˆ์„ ๋ณด์žฅํ•˜๊ณ  ๊ฒฐํ•จ์„ ์˜ˆ๋ฐฉํ•˜๊ณ  ์ˆ˜์ •ํ•˜๋Š” ๋ฐ ๋งค์šฐ ์ค‘์š”ํ•œ ๊ณผ์ •์ด๋‹ค. ํŠนํžˆ ์ง€์†์ ์ด๊ณ  ๋ฐ˜๋ณต์ ์ด๊ณ  ์ž์ฃผ ์ผ์–ด๋‚˜๋Š” ์ž‘์—…๋“ค์€ ๊ฐ€๋Šฅํ•œ ์ž๋™ํ™”ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. 

cypress๋Š” ์›น์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ž‘์„ฑ๋œ ๊ฐ€๋ฒผ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋™์ผํ•œ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์„ ์ทจํ•˜๊ณ  ์žˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜์˜ GUI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ์˜ ์‹คํ–‰ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ  ๋””๋ฒ„๊น…ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ํŽธ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•

์˜ˆ๋ฅผ๋“ค์–ด ์‹คํ–‰๋œ ๋ชจ๋“  ํ…Œ์ŠคํŠธ ๋ช…๋ น๊ณผ ๊ฐ ๋ช…๋ น์ด ์‹คํ–‰๋  ๋•Œ์˜ UI ์ƒํƒœ๋ฅผ ์Šค๋ƒ…์ƒท ํ˜•ํƒœ๋กœ ๋ชจ๋‘ ์ €์žฅํ•ด ํŠน์ • ์‹œ์ ์˜ UI ์ƒํƒœ๋ฅผ ๋ˆˆ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ์ „์ฒด ํ…Œ์ŠคํŠธ ์ง„ํ–‰ ๊ณผ์ •์„ ๋™์˜์ƒ์œผ๋กœ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ–ˆ์„ ๋•Œ ์ž๋™์œผ๋กœ ์Šคํฌ๋ฆฐ์ƒท์„ ๋‚จ๊ธธ ์ˆ˜ ์žˆ์–ด ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ–ˆ์„ ๋•Œ ์›์ธ์„ ํŒŒ์•…ํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ์‰ฝ๋‹ค. 

๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด ๋””๋ฒ„๊น…์„ ํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ, ๋ฌด์—‡๋ณด๋‹ค ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ž‘์„ฑ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์—ญ์‹œ ์‚ฌ์šฉ์ž๊ฐ€ ์›น ํŽ˜์ด์ง€์—์„œ ์š”์†Œ๋ฅผ ์ฐพ๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ํฐ ๋Ÿฌ๋‹์ปค๋ธŒ ์—†์ด ๋น ๋ฅด๊ฒŒ ํ•™์Šต์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 

E2E ํ…Œ์ŠคํŠธ ๋„๊ตฌ

E2E( End-to-End ) ํ…Œ์ŠคํŠธ๋ž€  '์‹œ์ž‘๋ถ€ํ„ฐ ๋๊นŒ์ง€'๋ผ๋Š” ์˜๋ฏธ๋กœ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€, ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ์‹œ์Šคํ…œ ํ๋ฆ„์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด ํ…Œ์ŠคํŠธ์˜ ๋ชฉ์ ์€ ์‹ค์ œ ์ƒ์‚ฐ ํ™˜๊ฒฝ๊ณผ ์œ ์‚ฌํ•œ ํ™˜๊ฒฝ์—์„œ ์‹œ์Šคํ…œ์ด ์ „์ฒด์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋ชฉํ‘œ์— ์ถฉ์กฑํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์‹ค์ œ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๊ณ  ํ•ด๋‹น ๊ตฌ์„ฑ ์š”์†Œ์˜ ํ†ตํ•ฉ ๋ฐ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์„ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

cypress-e2e

์‰ฝ๊ฒŒ ๋งํ•ด ์‹ค์ œ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ชจ๋ฐฉํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐœ๋ฐœํ•œ ์‹œ์Šคํ…œ์„ ์˜ค๋ฅ˜๋‚˜ ๋ฒ„๊ทธ์—†์ด ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ฒ€์ฆ์ด๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ์‡ผํ•‘๋ชฐ ์‚ฌ์ดํŠธ์— ์ ‘์†ํ•˜๊ณ , ๋กœ๊ทธ์ธํ•˜๊ณ , ์ƒํ’ˆ์„ ๊ฒ€์ƒ‰ํ•˜๊ณ , ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ณ , ๊ฒฐ์ œํ•˜๊ณ , ์ฃผ๋ฌธ ํ™•์ธํ•˜๋Š” ์ผ๋ จ์˜ ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํ…Œ์ŠคํŠธ ํ•œ๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค. 

์ด์ฒ˜๋Ÿผ, E2E ํ…Œ์ŠคํŠธ๋Š” ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•๋ก ์ด๋ฉฐ, Cypress๋Š” ์ด ๋ฐฉ๋ฒ•๋ก ์„ ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ์ธ ๊ฒƒ์ด๋‹ค.

 

Cypress vs Selenium

์›น์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ…Œ์ŠคํŠธ ์ž๋™ํ™”ํ• ๋•Œ ๊ฐ€์žฅ ์œ ๋ช…ํ•œ ๋„๊ตฌ๋ฅผ ๊ณ ๋ฅด์ž๋ฉด ์ด๊ตฌ๋™์„ฑ์œผ๋กœ Seleniun(์…€๋ ˆ๋‹ˆ์›€)์„ ๊ณ ๋ฅผ ๊ฒƒ์ด๋‹ค.

Cypress์™€ Selenium์€ ์›น ํ…Œ์ŠคํŒ…์„ ์œ„ํ•œ ๋„๊ตฌ๋กœ ๊ฐ๊ฐ ์žฅ๋‹จ์ ๊ณผ ์ฐจ์ด์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ด ๋‘˜ ์ค‘ ์–ด๋–ค ๋„๊ตฌ๋ฅผ ์„ ํƒํ•ด์•ผ ํ• ๊นŒ? ์–ด๋–ค ๋„๊ตฌ๋ฅผ ์„ ํƒํ•ด์•ผ ํ• ์ง€๋Š” ํ…Œ์ŠคํŒ…์˜ ๋ชฉ์ , ๋ฒ”์œ„, ์š”๊ตฌ์‚ฌํ•ญ, ํ™˜๊ฒฝ ๋“ฑ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค.

  cypress selenium
์–ธ์–ด JavaScript๋งŒ ์ง€์› Java, Python, JavaScript, C#, Ruby ๋“ฑ ๋‹ค์–‘ํ•œ ์–ธ์–ด ์ง€์›
์ง€์› ๋ธŒ๋ผ์šฐ์ € Chrome, Edge, Electron ์ผ๋ถ€ ๋ธŒ๋ผ์šฐ์ €๋งŒ ์ง€์› Chrome, Firefox, Edge, Safari, Opera ๋“ฑ ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ € ์ง€์›
๋‚œ์ด๋„ ๊ฐœ๋ฐœ์ž ์นœํ™”์ ์ด๊ณ , ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๊ตฌ์ถ•์ด ์‰ฌ์›€ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๊ตฌ์ถ•์ด ๋ณต์žกํ•˜๊ณ , ๋“œ๋ผ์ด๋ฒ„๋‚˜ ์„œ๋ฒ„๊ฐ€ ํ•„์š”ํ•จ
ํ…Œ์ŠคํŠธ ์†๋„ ๋ธŒ๋ผ์šฐ์ € ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ ๋น ๋ฆ„ ๋ธŒ๋ผ์šฐ์ € ๋“œ๋ผ์ด๋ฒ„๋ฅผ ํ†ตํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ ์ƒ๋Œ€์ ์œผ๋กœ ๋Š๋ฆผ
ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ์—์„œ ํ…Œ์ŠคํŠธ ๊ณผ์ •๊ณผ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธ ๊ฐ€๋Šฅ ํ…Œ์ŠคํŠธ ๊ณผ์ •๊ณผ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธํ•˜๊ธฐ ์–ด๋ ค์›€
ํ…Œ์ŠคํŠธ ๋ฒ”์œ„ ํ”„๋ก ํŠธ์—”๋“œ ํ…Œ์ŠคํŠธ์— ํŠนํ™”๋˜์–ด ์žˆ์Œ ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ ํ…Œ์ŠคํŠธ ๋ชจ๋‘ ๊ฐ€๋Šฅ

 

์ •๋ฆฌํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ๋Š” Cypress๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

  • ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ ์ž ํ•  ๋•Œ
  • ๋ชจ๋˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ UI์™€ ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๊ณ ์ž ํ•  ๋•Œ
  • ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ์‰ฝ๊ฒŒ ์„ค์ •ํ•˜๊ณ , ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•˜๊ณ , ํ…Œ์ŠคํŠธ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๊ณ ์ž ํ•  ๋•Œ
  • ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ์„ ์ˆ˜ํ–‰ํ•˜๊ณ ์ž ํ•  ๋•Œ 

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ๋Š” Selenium์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

  • ๋‹ค์–‘ํ•œ ์–ธ์–ด๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ ์ž ํ•  ๋•Œ
  • ๋‹ค์–‘ํ•œ ๋ธŒ๋ผ์šฐ์ €์™€ ํ”Œ๋žซํผ์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ ์ž ํ•  ๋•Œ
  • ์›น ์„œ๋ฒ„๋ฅผ ํ†ตํ•ด ๋ถ„์‚ฐ ํ…Œ์ŠคํŒ…์ด๋‚˜ ๋ณ‘๋ ฌ ํ…Œ์ŠคํŒ…์„ ์ˆ˜ํ–‰ํ•˜๊ณ ์ž ํ•  ๋•Œ

Cypress ์„ค์น˜ํ•˜๊ธฐ

https://www.cypress.io/ ํ™ˆํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐ€๋ฉด ์„ค์น˜๋ฅผ ์ง„ํ–‰ ํ•  ์ˆ˜๊ฐ€ ์žˆ๋‹ค. ๋‘๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ€๋Šฅํ•œ๋ฐ, ๋ชจ๋‘ ์†Œ๊ฐœํ•ด๋ณธ๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•

 

Node.js ํŒจํ‚ค์ง€ ์„ค์น˜

npm ๋ช…๋ น์œผ๋กœ cypress๋ฅผ ์„ค์น˜ํ•˜๊ณ  open ๋ช…๋ น์„ ํ†ตํ•ด cypress ์•ฑ์„ ์‹คํ–‰ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

> npm install cypress -D
> npx cypress open # cypress ์•ฑ ์˜คํ”ˆ

 

cypress๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ํ™”๋ฉด์œผ๋กœ ๋„˜์–ด๊ฐ€๊ฒŒ ๋˜๊ณ  ์‚ฌ์ง„์— ๋”ฐ๋ผ ์ง„ํ–‰ํ•ด์ค€๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•
cypress-์‚ฌ์šฉ๋ฒ•
cypress-์‚ฌ์šฉ๋ฒ•

 

exe ์„ค์น˜

๋…ธ๋“œ ์ƒํƒœ๊ณ„๊ฐ€ ์—†์–ด๋„ ๋ฐ”๋กœ ์ง์ ‘ ์‹คํ–‰ ํŒŒ์ผ๋กœ๋„ cypress ์•ฑ์„ ๋‹ค์šด ๋ฐ›์„ ์ˆ˜๊ฐ€ ์žˆ๋‹ค. ์••์ถ• ํŒŒ์ผ์„ ๋‹ค์šด๋ฐ›์œผ๋ฉด, ํŒŒ์ผ์„ ์ ์ ˆํ•œ๊ณณ์— ์••์ถ•์„ ํ’€๊ณ  ๊ฒฝ๋กœ์˜ ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๋ฉด, ๋Ÿฐ์น˜ํŒจ๋“œ(Launchpad) ํ™”๋ฉด์ด ๋„์›Œ์ง€๊ฒŒ ๋œ๋‹ค.

exe ๋ฒ„์ „์€ Cypress๋ฅผ ๋น ๋ฅด๊ฒŒ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ๋งŒ ์‹œํ—˜์ ์œผ๋กœ ์ œ์ž‘๋œ ๋„๊ตฌ์ด๋ฉฐ, ๋ช‡๊ฐ€์ง€ ๊ธฐ๋Šฅ ์ œํ•œ์ด ๋”ฐ๋ผ ๋ถ™๋Š”๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด Cypress Cloud๋กœ์˜ ๋…นํ™” ์‹คํ–‰์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•œ๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•
cypress-์‚ฌ์šฉ๋ฒ•
cypress-์‚ฌ์šฉ๋ฒ•

์œ„ ์ฐฝ์—์„œ Drag your project directory here or browse manually ๋ฌธ๊ตฌ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ณ  ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๊ด€๋ฆฌํ•  ํ”„๋กœ์ ํŠธ ํด๋”๋ฅผ ์„ ํƒํ•ด์ค€๋‹ค. ์ฒ˜์Œ์ด๋ผ๋ฉด ๋นˆ ํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋“ฑ๋กํ•ด ์ฃผ๋ฉด ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ„์— Node.js ํŒจํ‚ค์ง€ ์„ค์น˜๋ฐฉ๋ฒ•์— ์—ฐ์žฌํ•œ ์ˆœ์„œ์™€ ๊ฐ™์ด ๋˜‘๊ฐ™์ด ์ง„ํ–‰ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.


Cypress ์‹คํ–‰ํ•˜๊ธฐ

 

ํ…Œ์ŠคํŠธ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

๋ธŒ๋ผ์šฐ์ €๋ฅผ ์„ ํƒํ•˜๋ฉด, ๋งˆ์น˜ ์›น์•ฑ๊ณผ ๊ฐ™์ด cypress ์ „์šฉ GUI์ฐฝ์ด ์ƒˆ ๋ธŒ๋ผ์šฐ์ € ์ฐฝ์œผ๋กœ ์—ด๋ฆฌ๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒˆ ํ…Œ์ŠคํŠธ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋„๋ก ํ•˜์ž.

cypress-์‚ฌ์šฉ๋ฒ•
cypress-์‚ฌ์šฉ๋ฒ•
ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ํŒŒ์ผ ์ƒ์„ฑ
cypress-์‚ฌ์šฉ๋ฒ•
์ƒ์„ฑ๋œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ํŒŒ์ผ ์‹คํ–‰
cypress-์‚ฌ์šฉ๋ฒ•

 

ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค ์ž‘์„ฑ

ํ…Œ์ŠคํŠธ ๋™์ž‘ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๋ฉด ์œ„์—์„œ ์ƒ์„ฑํ•œ spec.cy.js ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค.

์šฐ์„  ์—๋””ํ„ฐ๋กœ ๋Œ์•„์™€์„œ spec.cy.js ํŒŒ์ผ์„ ์˜คํ”ˆํ•ด๋ณด์ž. ๊ทธ๋Ÿฌ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ ํ˜€์ ธ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

describe('template spec', () => {
  it('passes', () => {
    cy.visit('https://example.cypress.io')
  })
})

์œ„์˜ api ์„ค๋ช…์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • describe() : ํ…Œ์ŠคํŠธ ํ•  ๋™์ž‘๋“ค์„ ๋ฌถ์–ด์ฃผ๋Š” ์ „์ฒด ๊ทธ๋ฃน.
  • it() : ํ…Œ์ŠคํŠธ ํ•  ๋™์ž‘์˜ ์„ธ๋ถ€ ๋‹จ์œ„ ์ผ€์ด์Šค. 
  • cy.visit() : ์›น์‚ฌ์ดํŠธ ๋ฐฉ๋ฌธ.
์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด JEST ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฝ”๋“œ ์–‘์‹๊ณผ ๊ต‰์žฅํžˆ ์œ ์‚ฌํ•˜๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

์—ฐ์Šต๊ฒธ ๊ฐ„๋‹จํ•˜๊ฒŒ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”๊ฟ”๋ณด์ž.

describe('๋„ค์ด๋ฒ„ ์‚ฌ์ดํŠธ ํ…Œ์ŠคํŠธ ์‹œํŠธ', () => {
  it('๋„ค์ด๋ฒ„ ์‚ฌ์ดํŠธ ๋ฐฉ๋ฌธ', () => {
    cy.visit('https://www.naver.com')
  })
})

๊ทธ๋ฆฌ๊ณ  cypress GUI ์•ฑ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด js ํŒŒ์ผ์„ ๋”๋ธ”ํด๋ฆญํ•˜๊ฒŒ ๋˜๋ฉด, ์ฝ”๋“œ์— ๋”ฐ๋ผ ์ž๋™ํ™” ํ…Œ์ŠคํŠธ๊ฐ€ ์ˆ˜ํ–‰๋˜๊ฒŒ ๋œ๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•
cypress-์‚ฌ์šฉ๋ฒ•

์œ„ ์ฒ˜๋Ÿผ ์‹ค์ œ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹œ๊ฐ์ ์œผ๋กœ ์ง„ํ–‰๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์™ผ์ชฝ ๋ช…๋ น ๋กœ๊ทธ ์˜์—ญ์—๋Š” ์œ„์—์„œ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์˜ ๋ช…๋ น๋“ค์ด ๋กœ๊ทธ๋กœ ๊ธฐ๋ก๋˜๋ฉฐ, ๊ฐ ๋ช…๋ น์ค„๋“ค์— ๋งˆ์šฐ์Šค๋ฅผ ํด๋ฆญํ•˜๋ฉด ํ•ด๋‹น ๋ช…๋ น์ด ์‹คํ–‰๋  ๋•Œ์˜ ํ™”๋ฉด ์ƒํƒœ๋ฅผ ๊ฐ๊ฐ ํ™•์ธ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

๋ฒ„ํŠผ ํด๋ฆญ ์ž๋™ํ™”

cypress์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋Š” jQuery ํ•จ์ˆ˜ ํ˜•์‹๊ณผ ๋˜๊ฒŒ ๋น„์Šทํ•˜๊ฒŒ ๋˜์–ด์žˆ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋‚˜ ์ œ์ด์ฟผ๋ฆฌ์—์„œ ๋ฒ„ํŠผ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ฐ,

document.querySelector('button');
$('button')

cypress๋„ ์ด์™€ ๋น„์Šทํ•˜๊ฒŒ cy ๊ฐ์ฒด์˜ get() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์•ˆ์— ์—˜๋ฆฌ๋จผํŠธ์˜ id๊ฐ’์ด๋‚˜ class๊ฐ’์„ ์ ์œผ๋ฉด ์ž๋™์œผ๋กœ html์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.

cy.get('button')

cy.get('.className');
cy.get('#idName');
cy.get('[class^="button_"]')

 

์ฐธ๊ณ ๋กœ ์—˜๋ฆฌ๋จผํŠธ์˜ id๊ฐ’์ด๋‚˜ class๊ฐ’์€ ๊ฐœ๋ฐœ์ž๋„๊ตฌ๋ฅผ ์—ด์–ด์„œ ์ง์ ‘ ์ถ”์ ํ•ด ์–ป๋Š” ๋ฐฉ์‹๋„ ์žˆ์ง€๋งŒ, cypress GUI ์•ฑ์—์„œ ๋” ๊ฐ„๋‹จํžˆ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

์ƒ๋‹จ์˜ ์ €๊ฒฉ ํฌ๋กœ์Šคํ—ค์–ด ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ณ  ์•„๋ž˜์ฒ˜๋Ÿผ ํด๋ฆญ์„ ์ง„ํ–‰ํ•˜๋ฉด, ์ž๋™์œผ๋กœ cy ๊ฐ์ฒด ์ฝ”๋“œ๊ฐ€ ์™„์„ฑ๋˜๊ฒŒ ๋˜๊ณ , ์šฐ์ธก์˜ ๋ณต์‚ฌ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์ฝ”๋“œ์— ์ ์šฉํ•˜๋ฉด ๋˜๊ฒŒ ๋œ๋‹ค. ๋‹ค๋งŒ ๋ณต์žกํ•œ ํŠธ๋ฆฌ ๊ตฌ์กฐ์˜ ๊ตฌ์„ฑ์ผ ๊ฒฝ์šฐ ์ง์ ‘ ๊ฐœ๋ฐœ์ž๋„๊ตฌ๋กœ ์ฐพ๋Š”๊ฒƒ์ด ๋” ์ •ํ™•ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•

 

๊ทธ๋ ‡๊ฒŒํ•ด์„œ ์–ป์€ ์—˜๋ฆฌ๋จผํŠธ ๊ฐ์ฒด๋ฅผ ๋’ค์— ๋™์ž‘์„ ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ฒด์ด๋‹(chaining)์œผ๋กœ ๋ถ™์—ฌ์ฃผ๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฒ„ํŠผ ํด๋ฆญ ํ–‰์œ„๋ฅผ ์ž๋™ํ™” ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

cy.get('#button').click()

๋ฒ„ํŠผ ํด๋ฆญ์— ๋Œ€ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์งœ๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜ ์ฒ˜๋Ÿผ wait() ํ•จ์ˆ˜์™€ ์ ์ ˆํžˆ ์„ž์–ด์ฃผ๋ฉด ๋งˆ์น˜ ์ด๋ฅธ๋ฐ” ๋งคํฌ๋กœ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

describe('๋ฌด์‹ ์‚ฌ ์‚ฌ์ดํŠธ ํ…Œ์ŠคํŠธ ์‹œํŠธ', () => {
    it('์‡ผํ•‘๋ชฐ ๋ฒ„ํŠผ ํด๋ฆญ', () => {
        cy.visit('https://www.musinsa.com/app/'); // ๋ฌด์‹ ์‚ฌ ๋ฐฉ๋ฌธ
        cy.get('[u_cat_cd="001"] > a').click(); // ํŠน์ • ๋ฒ„ํŠผ ํด๋ฆญ
        cy.wait(1000); // 1์ดˆ ๋Œ€๊ธฐ
        cy.get('[u_cat_cd="002"] > a').click();
        cy.wait(1000);
        cy.get('[u_cat_cd="003"] > a').click();
        cy.wait(1000);
        cy.get('[u_cat_cd="004"] > a').click();
    });
});

cypress-์‚ฌ์šฉ๋ฒ•

 

ํƒ€์ดํ•‘ ์ž๋™ํ™”

์ด๋ฅธ๋ฐ” ์‡ผํ•‘๋ชฐ์˜ ๊ฒ€์ƒ‰์ฐฝ์— ๊ฒ€์ƒ‰ ํ…์ŠคํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์จ์„œ ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋งคํฌ๋กœ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž. ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜ ์—ญ์‹œ ์ง๊ด€์ ์œผ๋กœ type() ์„ ํ†ตํ•ด ์•„์ฃผ ๊ฐ„๋‹จํžˆ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

describe('๋ฌด์‹ ์‚ฌ ์‚ฌ์ดํŠธ ํ…Œ์ŠคํŠธ ์‹œํŠธ', () => {
    it('์‡ผํ•‘๋ชฐ ๋ฒ„ํŠผ ํด๋ฆญ', () => {
        // ๋ฌด์‹ ์‚ฌ ์‚ฌ์ดํŠธ ๋ฐฉ๋ฌธ
        cy.visit('https://www.musinsa.com/app/');

        // ๋ฌด์‹ ์‚ฌ ๊ฒ€์ƒ‰
        cy.get('input#commonLayoutSearchForm').type('๊ตฌ์ฐŒ ๊ฐ€๋ฐฉ'); // ๊ฒ€์ƒ‰ ์ž…๋ ฅ์ฐฝ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ€์ ธ์™€์„œ ํ…์ŠคํŠธ ํƒ€์ดํ•‘
        cy.get('.sc-1ppcy5v-5').click(); // ๋‹๋ณด๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ

    });
});

cypress-์‚ฌ์šฉ๋ฒ•

 

์ด๋ฅผ ์‘์šฉํ•ด์„œ ๊ฒ€์ƒ‰์ฐฝ์ด ์•„๋‹Œ ๋กœ๊ทธ์ธ ํ™”๋ฉด์˜ ์•„์ด๋””์™€ ํŒจ์Šค์›Œ๋“œ ์ฐฝ์— ํ…์ŠคํŠธ๋ฅผ ํƒ€์ดํ•‘ํ•˜๊ณ  ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋„๋ก ํ…Œ์ŠคํŠธ์ผ€์ด์Šค๋ฅผ ์งœ๋ฉด, ๋กœ๊ทธ์ธ ๋งคํฌ๋กœ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๊ฒƒ๊ณผ ๊ฐ™๋‹ค

describe('๋„ค์ด๋ฒ„ ํ…Œ์ŠคํŠธ', () => {
    it('๋„ค์ด๋ฒ„ ๋กœ๊ทธ์ธ', () => {
        cy.visit('https://nid.naver.com/nidlogin.login');

        cy.get('#id').type('test');
        cy.get('#pw').type('123123');

        cy.get('#log\\.login').click();
    })
})

cypress-์‚ฌ์šฉ๋ฒ•

 

๋“œ๋กญ๋ฐ•์Šค ์ž๋™ ์„ ํƒ

<select> ํƒœ๊ทธ์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์„ ํƒํ•˜๋Š” ์ž๋™ํ™” ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด์ž. ์ง๊ด€์ ์œผ๋กœ select() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฐ–์—๋„ ์ฒดํฌ๋ฐ•์Šค๋‚˜ ๋ผ๋””์˜ค๋ฒ„ํŠผ๋„ ๋น„์Šทํ•œ ๊ณผ์ •์ด๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•cypress-์‚ฌ์šฉ๋ฒ•

describe('๋ฌด์‹ ์‚ฌ ์‚ฌ์ดํŠธ ํ…Œ์ŠคํŠธ ์‹œํŠธ', () => {
    it('์ƒํ’ˆ ๋ฉ”๋‰ด ์„ ํƒํ•˜๊ธฐ', () => {
        cy.visit('https://www.musinsa.com/app/goods/3791036?loc=goods_rank');

        // ์ƒํ’ˆ ์˜ต์…˜ ์„ ํƒํ•˜๊ธฐ
        cy.get('.product-detail__sc-1d13nsy-1').select('M'); 
        cy.get('.product-detail__sc-1k1gum8-0').select('589908') 
    });
});

cypress-์‚ฌ์šฉ๋ฒ•

 

 

 

 

 

cypress์˜ ํ•จ์ˆ˜ ์ฝ”๋“œ๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋“ค์ด๋ฉฐ ์‹คํ–‰ ๋ฐฉ์‹์€ ๋งˆ์น˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ await ๋น„๋™๊ธฐ ๋ฐฉ์‹
์œผ๋กœ ๋™์ž‘๋œ๋‹ค. ๊ทธ๋ž˜์„œ ๋ณ„๋„๋กœ Promise๋‚˜ await ์ฒ˜๋ฆฌ ์—†์ด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋“ค์„ ์จ๋‚ด๋ ค๊ฐ€๋„ ์ถฉ๋Œ์—†์ด ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

Cypress ๋ฌธ๋ฒ• ์ •๋ฆฌ

๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ api ๋ฌธ๋ฒ•์„ ์•Œ๊ณ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด๋ณด์ž. ์ด๋ฒˆ ๊ธ€์€ cypress์˜ ๊ธฐ๋ณธ์ ์ธ ๋ผˆ๋Œ€ ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๋Š”๋ฐ ์ดˆ์ ์„ ๋‘์–ด ์„ค๋ช…ํ•ด๋ณธ๋‹ค.

 

Table of Contents | Cypress Documentation

Commands

docs.cypress.io

 

Cypress.io: Kitchen Sink

Cypress API The Cypress API enables you to configure the behavior of how Cypress works internally. You can do things like access Environment Variables, change configuration, create custom commands, and more.

example.cypress.io

 

Cypress ๊ทธ๋ฃนํ•‘

๊ฐ ๋ช…๋ น์–ด๋“ค์„ ๋ณด๊ธฐ์ข‹๊ฒŒ ๋ชจ๋“ˆํ™”ํ•˜์—ฌ ๋ฌถ๋Š” ๊ทธ๋ฃน ํ•จ์ˆ˜๋“ค์ด๋‹ค.

  • describe() : ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ฌถ๋Š” ๊ฐ€์žฅ ํฐ ๋‹จ์œ„. ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ
  • context() : describe ๋‚ด๋ถ€์—์„œ ์ƒˆ๋กœ์šด ํ…Œ์ŠคํŠธ ๊ทธ๋ฃน์„ ์ •์˜ํ•˜๋Š” ํ•จ์ˆ˜ (context๋Š” describe์™€ ๊ธฐ๋Šฅ์ ์œผ๋กœ๋Š” ์ฐจ์ด๊ฐ€ ์—†๊ฑฐ ๋‹จ์ง€, ์˜๋ฏธ์ ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ์ƒ๋žตํ•ด๋„ ๋ฌธ์ œ ์—†๋‹ค)
  • it() : ์‹ค์ œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ •์˜ํ•˜๋Š” ํ•จ์ˆ˜
// 'My App'์ด๋ผ๋Š” ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
describe('My App', () => {

  // 'Login'์ด๋ผ๋Š” ํ…Œ์ŠคํŠธ ๊ทธ๋ฃน์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ…Œ์ŠคํŠธ ๊ทธ๋ฃน์€ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จ๋œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋“ค์„ ๋ฌถ์–ด์ค๋‹ˆ๋‹ค.
  context('Login', () => {
  
    // 'Valid user'๋ผ๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋Š” ์œ ํšจํ•œ ์‚ฌ์šฉ์ž ์ •๋ณด๋กœ ๋กœ๊ทธ์ธํ•˜๋Š” ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค.
    it('Valid user', () => {
      // ํ…Œ์ŠคํŠธํ•  ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
      cy.visit('/login'); // ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์— ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค.
      cy.get('#username').type('test'); // ์•„์ด๋”” ์ž…๋ ฅ์ฐฝ์— 'test'๋ผ๊ณ  ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
      cy.get('#password').type('1234'); // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ์ฐฝ์— '1234'๋ผ๊ณ  ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
      cy.get('#login-button').click(); // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
      cy.url().should('include', '/dashboard'); // ๋กœ๊ทธ์ธ์ด ์„ฑ๊ณตํ•˜๋ฉด ๋Œ€์‹œ๋ณด๋“œ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
    });
    
    // 'Invalid user'๋ผ๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋Š” ์œ ํšจํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž ์ •๋ณด๋กœ ๋กœ๊ทธ์ธํ•˜๋Š” ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค.
    it('Invalid user', () => {
      // ํ…Œ์ŠคํŠธํ•  ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
      cy.visit('/login'); // ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์— ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค.
      cy.get('#username').type('wrong'); // ์•„์ด๋”” ์ž…๋ ฅ์ฐฝ์— 'wrong'์ด๋ผ๊ณ  ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
      cy.get('#password').type('4321'); // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ์ฐฝ์— '4321'์ด๋ผ๊ณ  ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.
      cy.get('#login-button').click(); // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
      cy.contains('Invalid username or password'); // ๋กœ๊ทธ์ธ์ด ์‹คํŒจํ•˜๋ฉด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
    });
  });
  
  // 'Logout'์ด๋ผ๋Š” ํ…Œ์ŠคํŠธ ๊ทธ๋ฃน์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ…Œ์ŠคํŠธ ๊ทธ๋ฃน์€ ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จ๋œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋“ค์„ ๋ฌถ์–ด์ค๋‹ˆ๋‹ค.
  context('Logout', () => {
  
    // 'Logout from dashboard'๋ผ๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋Š” ๋Œ€์‹œ๋ณด๋“œ ํŽ˜์ด์ง€์—์„œ ๋กœ๊ทธ์•„์›ƒํ•˜๋Š” ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค.
    it('Logout from dashboard', () => {
      // ํ…Œ์ŠคํŠธํ•  ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
      cy.login('test', '1234'); // cy.login()์€ ์ปค์Šคํ…€ ์ปค๋งจ๋“œ๋กœ, ๋กœ๊ทธ์ธ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
      cy.visit('/dashboard'); // ๋Œ€์‹œ๋ณด๋“œ ํŽ˜์ด์ง€์— ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค.
      cy.get('#logout-button').click(); // ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
      cy.url().should('include', '/login'); // ๋กœ๊ทธ์•„์›ƒ์ด ์„ฑ๊ณตํ•˜๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
    });
    
  });
  
});

 

Cypress Hook

Cypress hook๋Š” ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์˜ ์‹คํ–‰ ์ „ํ›„์— ํŠน์ •ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ์ด๋ฅผ ์ด์šฉํ•ด ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ์„ค์ •ํ•˜๊ฑฐ๋‚˜, ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๊ฑฐ๋‚˜, ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์ •๋ฆฌํ•˜๊ฑฐ๋‚˜, ํ…Œ์ŠคํŠธ ๋กœ๊ทธ๋ฅผ ๊ธฐ๋กํ•˜๊ฑฐ๋‚˜, ํ…Œ์ŠคํŠธ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ๋“ฑ์˜ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • before() : ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰
  • after() : ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์˜ ๋งˆ์ง€๋ง‰ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์‹คํ–‰๋œ ํ›„์— ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰
  • beforeEach() : ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์˜ ๊ฐ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ๋งค๋ฒˆ ์‹คํ–‰๋ฉ
  • afterEach() : ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์˜ ๊ฐ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์‹คํ–‰๋œ ํ›„์— ๋งค๋ฒˆ ์‹คํ–‰
Cypress hook์€ describe()๋‚˜ context() ์•ˆ์— ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, it()์•ˆ์—๋Š” ์ž‘์„ฑํ•  ์ˆ˜ ์—†๋‹ค
describe('Test E2E by Cypress', () => {

  context('Mobile Version', () => {
  
    // ์ด hook์€ Mobile Version ํ…Œ์ŠคํŠธ ๊ทธ๋ฃน์˜ ๊ฐ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ๋งค๋ฒˆ ์‹คํ–‰. 
    beforeEach(() => {
      // ... Codes executed before each test case inside it() hooks ...
    });
    
    // ์ด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋Š” beforeEach() hook์ด ์‹คํ–‰๋œ ํ›„์— ์‹คํ–‰
    it('Login Button Should be Somewhere', () => {
      // ... Real Executing test codes for some application ...
    }); 
    
  });
});

 

Cypress Assertion

Cypress Assertion์ด๋ž€ Cypress์—์„œ ํ…Œ์ŠคํŠธ์˜ ๊ฒฐ๊ณผ๊ฐ€ ์˜ˆ์ƒํ•œ ๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋งํ•œ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด ์–ด๋Š ์ œ๋ชฉ์˜ ํ…์ŠคํŠธ๊ฐ€ ํŠน์ • ๋ฌธ์ž์—ด๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š”๋ฐ ์ด์šฉ๋œ๋‹ค.

// h2ํƒœ๊ทธ์˜ text๊ฐ€ ํŠน์ • ์ œ๋ชฉ์ธ์ง€ ํ™•์ธ
cy.get('h2').should('have.text', 'ํŠน์ • ์ œ๋ชฉ');

// button์„ ํด๋ฆญํ•˜๊ณ  ๋‚˜๋ฉด class์— active๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
cy.get('button').click().should('have.class', 'active')

// ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ์—†์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
cy.get('button').should('not.exist')

// ๋‘ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ (and)
cy.get('#header a')
  .should('have.class', 'active') // ํด๋ž˜์Šค๋ช…์ด active ์ผ ๊ฒฝ์šฐ
  .and('have.attr', 'href', '/users') // href ์†์„ฑ ๊ฐ’์ด /users ์ผ๊ฒฝ์šฐ

// ์ฒดํฌ๋ฐ•์Šค๊ฐ€ disabled๋œ ๊ฒฝ์šฐ
cy.get(':checkbox').should('be.disabled')

// input์— ํŠน์ • ๊ฐ’์ด ์—†์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
cy.get('input').should('not.have.value', 'US')

// URL ๋กœ ํ˜ธ์ถœ์„ ํ•˜๊ณ , ํ•ด๋‹น ์ฃผ์†Œ RETURN BODY์— {name: 'inpa'}์ด ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
cy.request('/users/1').its('body').should('deep.eq', { name: 'inpa' })

Cypress Assertion์€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์ด ์กฐ๊ฑด์„ ๋งŒ์กฑํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. ๋งŒ์•ฝ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜์ง€ ๋ชปํ•˜๋ฉด, Cypress๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ฒŒ ๋œ๋‹ค. ๋˜ํ•œ ์ฒด์ด๋‹(chaining)์—ญ์‹œ ๊ฐ€๋Šฅํ•˜๋ฉฐ, and๋‚˜ or๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์กฐ๊ฑด์„ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.   

 

Cypress Commands

ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์ด๋ฅผ ํ•จ์ˆ˜๋กœ ๋ฌถ์–ด ๋ชจ๋“ˆํ™” ํ•˜๋Š”๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค. cypress ์—ญ์‹œ ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™ํ™”์‹œํ‚ด์— ๋”ฐ๋ผ ์ฆ๋น„ํ•˜๊ฒŒ ์ค‘๋ณต ๋ฐ ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋“ค์ด ๋งŽ์•„์งˆ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ์—ญ์‹œ ํ•จ์ˆ˜ ๋‹จ์œ„๋กœ ๋ฌถ์–ด ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์„ '์‚ฌ์šฉ์ž ์ •์˜ ๋ช…๋ น์–ด' ๋ผ๊ณ  ํ•œ๋‹ค.

์šฐ์„  ์‚ฌ์šฉ์ž ์ •์˜ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, cypress ํ”„๋กœ์ ํŠธ์˜ support ํด๋” ๋‚ด์˜ commands.js ํŒŒ์ผ์„ ์ด์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค. 

cypress-์‚ฌ์šฉ๋ฒ•

๊ทธ๋ฆฌ๊ณ  ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž ์ •์˜ ๋ช…๋ น์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด commands.js ํŒŒ์ผ ์•ˆ์— Cypress.Commands.add ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด ๋กœ๊ทธ์ธ ํ”„๋กœ์„ธ์Šค๋Š” ์•„์ด๋”” ์ž…๋ ฅ, ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ, ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ ‡๊ฒŒ 3๊ฐœ์˜ ํ”„๋กœ์„ธ์Šค๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋Š”๋ฐ, ๋งŒ์ผ ๋กœ๊ทธ์ธ์„ ํ…Œ์ŠคํŠธํ•˜๋Š”๋ฐ ์žˆ์–ด ์ž์ฃผ ์ด์šฉํ•˜์—ฌ ๋ชจ๋“ˆํ™”๋ฅผ ์‹œํ‚จ๋‹ค๊ณ  ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

Cypress.Commands.add('login', (email, password) => {
  cy.get('input[name=email]').type(email);
  cy.get('input[name=password]').type(password);
  cy.get('form').submit();
});

/*
์–ด๋ ต๊ฒŒ ์ƒ๊ฐํ•  ํ•„์š”์—†์ด ์•„๋ž˜์˜ ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

const login = (email, password) => {
  cy.get('input[name=email]').type(email);
  cy.get('input[name=password]').type(password);
  cy.get('form').submit();
}
*/

์ด๋ ‡๊ฒŒ ์ถ”๊ฐ€๋œ ์‚ฌ์šฉ์ž ์ •์˜ ๋ช…๋ น์–ด๋Š” ๋ณ„๋„์˜ require๋‚˜ import ์—†์ด๋„, Cypress์—์„œ ์ž๋™์œผ๋กœ ์ธ์‹ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ ํŒŒ์ผ ์–ด๋””์—์„œ๋‚˜ ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

describe('๋„ค์ด๋ฒ„ ํ…Œ์ŠคํŠธ', () => {
    it('๋„ค์ด๋ฒ„ ๋กœ๊ทธ์ธ', () => {
        cy.visit('https://nid.naver.com/nidlogin.login');
		
        // commands.js์— ์ •์˜๋œ ์‚ฌ์šฉ์ž ์ •์˜ ๋ช…๋ น์–ด ์ˆ˜ํ–‰
        cy.login('test', '123123')
    })
})

 

Cypress then

cypress then() ๋ฉ”์†Œ๋“œ๋Š” ๋ช…๋ น์–ด์™€ ๊ฒฐ๊ณผ๋ฅผ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌํ•ด, ๋ช…๋ น ๊ฒฐ๊ณผ์— ์•ก์„ธ์Šคํ•˜๊ณ  ์ด์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

cy.get('.list-item').then(($listItem) => {
  // $listItem์€ .list-item์˜ ์ฒซ ๋ฒˆ์งธ DOM ์š”์†Œ๋ฅผ jQuery ๊ฐ์ฒด๋กœ ๊ฐ์‹ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  // ์—ฌ๊ธฐ์„œ ์ถ”๊ฐ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  $listItem.css('color', 'red');
});

cy.get('.element').then(($el) => {
  if ($el.hasClass('active')) {
    // .element๊ฐ€ 'active' ํด๋ž˜์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ์ถ”๊ฐ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  }
});

 cy.request('https://jsonplaceholder.typicode.com/posts/1').then((response) => {
    cy.log(response)
    
    expect(response.status).to.equal(200);
    expect(response.status).to.eq(200);
});

 

cypress then ๊ณผ promise then ์€ ์„œ๋กœ ์—ฐ๊ด€ ์—†๋‹ค

๋‹ค๋งŒ ์œ ์˜ํ• ์ ์€, Cypress์˜ then ํ‚ค์›Œ๋“œ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ Promise.then ๊ณผ ์ „ํ˜€ ์•„๋ฌด๋Ÿฐ ๊ด€๋ จ์ด ์—†๋‹ค๋Š” ์ ์ด๋‹ค. ์•„๋ฌด๋ž˜๋„ ์ฝ”๋“œ ๊ตฌ๋ฌธ ์ƒ๊น€์ƒˆ๊ฐ€ ๋งค์šฐ ๋น„์Šทํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์ฐฉ๊ฐ์„ ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, Cypress์˜ then ํ‚ค์›Œ๋“œ๋Š” ๋™๊ธฐ/๋น„๋™๊ธฐ์™€ ๊ด€๋ จ์ด ์—†๋Š” ๋ช…๋ น์–ด์ด๋‹ค. ์‹ค์ง€๋กœ catch ๋ฌธ์€ ํ†ตํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š”๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌํ•˜์ž๋ฉด, Cypress์˜ then ์€ ๋‹จ์ˆœํžˆ ๋ช…๋ น ๊ฒฐ๊ณผ์— ์•ก์„ธ์Šคํ•˜๊ณ  ์ด์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์ผ ๋ฟ์ด๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด cy ๊ฐ์ฒด์—์„œ ์ง€์›ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ์ฒด์ด๋‹ํ•ด์„œ ์‚ฌ์šฉํ•ด๋„ ์ถฉ๋ถ„ํ•˜์ง€๋งŒ, ๊ฐ€์ ธ์˜จ ๊ฐ’์— ๋ญ˜ ๋”ํ•˜๊ฑฐ๋‚˜ ํ•˜๋Š” ๋“ฑ ๋ณ„๋„์˜ ์ถ”๊ฐ€ ์—ฐ์‚ฐ ์ž‘์—…์ด ํ•„์š”ํ• ๋•Œ ์—ฐ์‚ฐ ์ฝ”๋“œ๋ฅผ then ๋ธ”๋ก ์•ˆ์— ์“ฐ๋Š” ์šฉ๋„์ธ ๊ฒƒ์ด๋‹ค.

cy.get('option:first')
  .should('be.selected')
  .then(($option) => {
    // $option is yielded
  })

 

Cypress Wrapping

cy.wrap() ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋‚˜ ๊ฐ’์„ Cypress ๋ช…๋ น์–ด ์ฒด์ธ์— ํฌํ•จ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.

์‰ฝ๊ฒŒ ์ƒ๊ฐํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋น„์œ ๋ฅผ ๋“ค์ž๋ฉด ์ œ์ด์ฟผ๋ฆฌ์—์„œ ์ œ์ด์ฟผ๋ฆฌ ์ „์šฉ ์ฒด์ด๋‹ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” $(obj) ์™€ ๊ฐ™์ด $ ๊ด„ํ˜ธ ์•ˆ์— ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ๋‹ค. ์ด์™€ ๋˜‘๊ฐ™์€ ์›๋ฆฌ๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

// JavaScript ๊ฐ์ฒด๋ฅผ cy.wrap()์œผ๋กœ ๊ฐ์‹ธ๊ณ , .should() ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด์˜ ์†์„ฑ์„ ๊ฒ€์‚ฌ
const object = { name: 'Cypress' };
cy.wrap(object).should('have.property', 'name', 'Cypress');

์ด๋Ÿฌํ•œ ๋ž˜ํ•‘ ๊ธฐ๋Šฅ์€ ์ฃผ๋กœ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ˜ํ™˜๋œ ๊ฐ’๋“ค์„ cy ๊ฐ์ฒด๋กœ ๊ฐ์‹ธ Cypress ๋ช…๋ น์–ด ์ฒด์ธ์— ํฌํ•จ์‹œ์ผœ ํ…Œ์ŠคํŠธ์˜ ์œ ์—ฐ์„ฑ์„ ๋†’์ผ ์ˆ˜๊ฐ€ ์žˆ๋‹ค.

cy.get('button').then(($button) => {
  if ($button.hasClass('active')) {
    cy.wrap($button).click();
  }
});

 

Cypress Window

ํ…Œ์ŠคํŠธํ•  ์›นํŽ˜์ด์ง€์˜ DOM์— ์ ‘๊ทผํ•ด์„œ ์กฐ์ž‘์„ ํ•˜๊ณ  ์‹ถ์„ ์ƒํ™ฉ์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์ด๋•Œ cy.window ๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ํ…Œ์ŠคํŠธ ์ค‘์ธ ํŽ˜์ด์ง€์˜ window ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. cy.window ๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฏ€๋กœ, ์—ญ์‹œ ์œ„์—์„œ ๋ฐฐ์šด .then() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.

cy.window().then((win) => {

  // win์€ ํ˜„์žฌ ํŽ˜์ด์ง€์˜ window ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
  console.log('Window object:', win);
  
  // DOM ์š”์†Œ์— ์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ ์กฐ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  win.document.querySelector('button').click();
  
  // ํŽ˜์ด์ง€์— ์ •์˜๋œ ์ „์—ญ ๋ณ€์ˆ˜๋‚˜ ํ•จ์ˆ˜์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.
  console.log('Page title:', win.title);
});

 

Cypress Cookie

ํ…Œ์ŠคํŠธ ์ค‘์— ์‚ฌ์šฉ์ž ์ธ์ฆ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ฑฐ๋‚˜, ํŠน์ • ์ฟ ํ‚ค ๊ฐ’์„ ๊ฒ€์‚ฌํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ง€์›ํ•œ๋‹ค. cy.getCookies() ๋ช…๋ น์–ด๋Š” ํ˜„์žฌ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ชจ๋“  ์ฟ ํ‚ค๋ฅผ ๊ฐ€์ ธ์™€ ์ฟ ํ‚ค ๊ฐ์ฒด ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ฐ ๊ฐ์ฒด๋Š” ์ฟ ํ‚ค์˜ ์ด๋ฆ„, ๊ฐ’, ๋„๋ฉ”์ธ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ๋‹ค.

cy.getCookies().then((cookies) => {
  // cookies๋Š” ์ฟ ํ‚ค ๊ฐ์ฒด ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค.
});

cy.setCookie('auth_key', '123key');
cy.getCookie('auth_key').should('have.property', 'value', '123key');
Cypress๋Š” ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์ฟ ํ‚ค๋ฅผ ์ง€์šฐ๋ฏ€๋กœ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ์ „์— ์ฟ ํ‚ค๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Cypress ์„ค์ • ์˜ต์…˜

Cypress๋ฅผ ์ฒ˜์Œ ์‹œ์ž‘ํ•˜๋ฉด Cypress ๊ตฌ์„ฑ ํŒŒ์ผ์ธ cypress.config.js์ด ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๊ฒŒ ๋˜๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ ์ „๋ฐ˜์ ์€ cypress์˜ ์ „์—ญ ์„ค์ •๋“ค์„ ์ง€์ •ํ•  ์ˆ˜๊ฐ€ ์žˆ๋‹ค. ์ž์„ธํ•œ ์—ฌ๋Ÿฌ ์„ธํŒ…๊ฐ’๋“ค์€ ์•„๋ž˜ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค.

 

Configuration | Cypress Documentation

This guide is for Cypress 10+ and the new JavaScript configuration file format.

docs.cypress.io

 

๋ธŒ๋ผ์šฐ์ € ์ถœ์ฒ˜ ์ •์ฑ… ๋น„ํ™œ์„ฑํ™”

๋งŒ์ผ ๋กœ๊ทธ์ธ๊ณผ ๊ฐ™์€ ๋ธŒ๋ผ์šฐ์ €์˜ ๋ณด์•ˆ ์ •์ฑ…๊ณผ ์—ฐ๊ด€๋œ ํ…Œ์ŠคํŠธ์ผ€์ด์Šค๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ๋†’์€ ํ™•๋ฅ ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ธ”๋ฝ๋˜๋ฉฐ ์ œ๋Œ€๋กœ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ˆ˜ํ–‰์ด ์•ˆ๋  ๊ฒƒ์ด๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•

ํ›Œ๋ฅญํ•œ ๋ณด์•ˆ ์ •์ฑ…์ด์ง€๋งŒ ์•„๋ฌด๋ž˜๋„ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” ๋ถˆํ•„์š”ํ•œ ๋ถ€๋ถ„์ด๊ธฐ ๋งˆ๋ จ์ด๋‹ค. ๋”ฐ๋ผ์„œ chromeWebSecurity ์˜ต์…˜์„ ๋น„ํ™œ์„ฑํ•จ์— ๋”ฐ๋ผ ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ… ๋ฐ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ํ˜ผํ•ฉ ์ฝ˜ํ…์ธ ์— ๋Œ€ํ•ด Chromium ๊ธฐ๋ฐ˜ ๋ธŒ๋ผ์šฐ์ €์˜ ์›น ๋ณด์•ˆ์„ ๋Œ ์ˆ˜๊ฐ€ ์žˆ๋‹ค.

module.exports = {
    e2e: {
        // ํฌ๋กœ๋ฏธ์›€ ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ… ๋ณด์•ˆ ๋น„ํ™œ์„ฑํ™”
        chromeWebSecurity: false,
    },
};

 

ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์ œํ•œ์‹œ๊ฐ„ ์„ค์ •

๊ธฐ๋ณธ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์ œํ•œ ์‹œ๊ฐ„์ด 60์ดˆ๋กœ ์„ค์ •์ด ๋˜์–ด์ž‡๊ธฐ ๋•Œ๋ฌธ์—, ๋งŒ์ผ ๋กœ๋”ฉ์ด ์ข€ ์˜ค๋ž˜๊ฑธ๋ฆฌ๋Š” ์‚ฌ์ดํŠธ๋ฅผ ํ…Œ์ŠคํŠธํ•  ์˜ˆ์ •์ด๋ผ๋ฉด ๋กœ๋”ฉ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ ์„ค์ •์„ ํ†ตํ•ด ๋กœ๋”ฉ ์ œํ•œ ์‹œ๊ฐ„์„ ๋Š˜๋ ค์ฃผ์–ด์•ผ ํ•œ๋‹ค.

module.exports = {
  e2e: {
    // ์ž๋™ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ƒ์„ฑ ์„ค์ •
    experimentalStudio: true,

    // ํŽ˜์ด์ง€ ๋กœ๋“œ ์ œํ•œ ์‹œ๊ฐ„ ์„ค์ •
    pageLoadTimeout: 120000 // 120sec
  },
};

 

ํŽ˜์ด์ง€ ํฌ๊ธฐ ์„ค์ •

๊ธฐ๋ณธ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•  ์›นํŽ˜์ด์ง€์˜ ํฌ๊ธฐ๋Š” 1000x660 ์œผ๋กœ ์„ค์ •ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์›นํŽ˜์ด์ง€์˜ ์Šคํƒ€์ผ์— ๋”ฐ๋ผ ์งค๋ฆฌ๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ์ถ”๊ฐ€ ์„ค์ •์„ ํ†ตํ•ด ํŽ˜์ด์ง€์˜ ๋ทฐํฌํŠธ๋ฅผ ๋งž์ถœ ์ˆ˜ ์žˆ๋‹ค.

cypress-์‚ฌ์šฉ๋ฒ•

module.exports = {
  e2e: {
     // ํ…Œ์ŠคํŠธ ํŽ˜์ด์ง€ ๋ทฐํฌํŠธ ์„ค์ •
     viewportWidth: 1600, 
     viewportHeight: 900,

    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
  },
};

cypress-์‚ฌ์šฉ๋ฒ•


์ฐธ๊ณ ๋ฌธํ—Œ

https://microsoft.github.io/code-with-engineering-playbook/automated-testing/e2e-testing/

https://docs.cypress.io/guides/overview/why-cypress

ttps://rae-gi.tistory.com/23

https://blog.naver.com/o_zak/222671883835