[Cypress] ๐ ์น ํ ์คํธ ์๋ํ ์ฌ์ฉ๋ฒ ๐ ํ๋์ ์ ๋ฆฌ
Cypress ์๊ฐ
์ํํธ์จ์ด ํ ์คํ ์ ์ํํธ์จ์ด์ ํ์ง์ ๋ณด์ฅํ๊ณ ๊ฒฐํจ์ ์๋ฐฉํ๊ณ ์์ ํ๋ ๋ฐ ๋งค์ฐ ์ค์ํ ๊ณผ์ ์ด๋ค. ํนํ ์ง์์ ์ด๊ณ ๋ฐ๋ณต์ ์ด๊ณ ์์ฃผ ์ผ์ด๋๋ ์์ ๋ค์ ๊ฐ๋ฅํ ์๋ํํ๊ณ ํจ์จ์ ์ผ๋ก ์ํํ๋ ๊ฒ์ด ์ข๋ค.
cypress๋ ์น์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ๊ธฐ ์ํ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ์์ฑ๋ ๊ฐ๋ฒผ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ํ ์คํธ ์ฝ๋๋ฅผ ๋์ผํ ๋ธ๋ผ์ฐ์ ์์ ์คํํ๋ ๋ฐฉ์์ ์ทจํ๊ณ ์๋ค. ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ์ GUI๋ฅผ ์ฌ์ฉํ์ฌ ํ ์คํธ์ ์คํ ์ํ๋ฅผ ํ์ธํ๊ณ ๋๋ฒ๊น ํ ์ ์๋ ๋ค์ํ ํธ์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
์๋ฅผ๋ค์ด ์คํ๋ ๋ชจ๋ ํ ์คํธ ๋ช ๋ น๊ณผ ๊ฐ ๋ช ๋ น์ด ์คํ๋ ๋์ UI ์ํ๋ฅผ ์ค๋ ์ท ํํ๋ก ๋ชจ๋ ์ ์ฅํด ํน์ ์์ ์ UI ์ํ๋ฅผ ๋์ผ๋ก ํ์ธํ ์ ์๋ค. ๋ํ ์ ์ฒด ํ ์คํธ ์งํ ๊ณผ์ ์ ๋์์์ผ๋ก ์ ์ฅํ๊ฑฐ๋ ํ ์คํธ๊ฐ ์คํจํ์ ๋ ์๋์ผ๋ก ์คํฌ๋ฆฐ์ท์ ๋จ๊ธธ ์ ์์ด ํ ์คํธ๊ฐ ์คํจํ์ ๋ ์์ธ์ ํ์ ํ๊ธฐ๊ฐ ๋งค์ฐ ์ฝ๋ค.
๋ธ๋ผ์ฐ์ ์์ ์คํ๋๊ธฐ ๋๋ฌธ์ ํ์ํ ๊ฒฝ์ฐ ํฌ๋กฌ ๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํด ๋๋ฒ๊น ์ ํ ์๋ ์์ผ๋ฉฐ, ๋ฌด์๋ณด๋ค ์๋ฐ์คํฌ๋ฆฝํธ๋ก ์์ฑ๋์๊ธฐ ๋๋ฌธ์ ํ ์คํธ ์ฝ๋ ์ญ์ ์ฌ์ฉ์๊ฐ ์น ํ์ด์ง์์ ์์๋ฅผ ์ฐพ๋ ๋ฐฉ์๊ณผ ์ ์ฌํ ๋ฉ์๋๋ฅผ ์ ๊ณตํ์ฌ ํฐ ๋ฌ๋์ปค๋ธ ์์ด ๋น ๋ฅด๊ฒ ํ์ต์ด ๊ฐ๋ฅํ๋ค๋ ์ฅ์ ์ด ์๋ค.
E2E ํ ์คํธ ๋๊ตฌ
E2E( End-to-End ) ํ ์คํธ๋ '์์๋ถํฐ ๋๊น์ง'๋ผ๋ ์๋ฏธ๋ก, ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ๋๋ก ์๋ํ๋์ง, ์ฌ์ฉ์ ๊ด์ ์์ ์์คํ ํ๋ฆ์ ํ ์คํธํ๋ ์ํํธ์จ์ด ํ ์คํธ ๋ฐฉ๋ฒ์ด๋ค. ์ด ํ ์คํธ์ ๋ชฉ์ ์ ์ค์ ์์ฐ ํ๊ฒฝ๊ณผ ์ ์ฌํ ํ๊ฒฝ์์ ์์คํ ์ด ์ ์ฒด์ ์ธ ๋น์ฆ๋์ค ๋ชฉํ์ ์ถฉ์กฑํ๋์ง ํ์ธํ๊ธฐ ์ํด ์ค์ ์ฌ์ฉ์ ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๊ณ ํด๋น ๊ตฌ์ฑ ์์์ ํตํฉ ๋ฐ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๊ฒ์ฆํ๋ ๊ฒ์ด๋ค.
์ฝ๊ฒ ๋งํด ์ค์ ์ฌ์ฉ์ ์๋๋ฆฌ์ค๋ฅผ ๋ชจ๋ฐฉํด ์ฌ์ฉ์๊ฐ ๊ฐ๋ฐํ ์์คํ ์ ์ค๋ฅ๋ ๋ฒ๊ทธ์์ด ์์๋๋ก ์๋ํ๋์ง์ ๋ํ ๊ฒ์ฆ์ด๋ผ๊ณ ๋ณด๋ฉด ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ์ผํ๋ชฐ ์ฌ์ดํธ์ ์ ์ํ๊ณ , ๋ก๊ทธ์ธํ๊ณ , ์ํ์ ๊ฒ์ํ๊ณ , ์ฅ๋ฐ๊ตฌ๋์ ๋ด๊ณ , ๊ฒฐ์ ํ๊ณ , ์ฃผ๋ฌธ ํ์ธํ๋ ์ผ๋ จ์ ์ฌ์ฉ ์๋๋ฆฌ์ค๋ฅผ ํ ์คํธ ํ๋ค๊ณ ์ดํดํ๋ฉด ๋๋ค.
์ด์ฒ๋ผ, 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/ ํํ์ด์ง์ ๋ค์ด๊ฐ๋ฉด ์ค์น๋ฅผ ์งํ ํ ์๊ฐ ์๋ค. ๋๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ๋ฅํ๋ฐ, ๋ชจ๋ ์๊ฐํด๋ณธ๋ค.
Node.js ํจํค์ง ์ค์น
npm ๋ช ๋ น์ผ๋ก cypress๋ฅผ ์ค์นํ๊ณ open ๋ช ๋ น์ ํตํด cypress ์ฑ์ ์คํ ์ํฌ ์ ์๋ค.
> npm install cypress -D
> npx cypress open # cypress ์ฑ ์คํ
cypress๋ฅผ ์คํํ๋ฉด ์๋์ ๊ฐ์ ํ๋ฉด์ผ๋ก ๋์ด๊ฐ๊ฒ ๋๊ณ ์ฌ์ง์ ๋ฐ๋ผ ์งํํด์ค๋ค.
exe ์ค์น
๋ ธ๋ ์ํ๊ณ๊ฐ ์์ด๋ ๋ฐ๋ก ์ง์ ์คํ ํ์ผ๋ก๋ cypress ์ฑ์ ๋ค์ด ๋ฐ์ ์๊ฐ ์๋ค. ์์ถ ํ์ผ์ ๋ค์ด๋ฐ์ผ๋ฉด, ํ์ผ์ ์ ์ ํ๊ณณ์ ์์ถ์ ํ๊ณ ๊ฒฝ๋ก์ ํ์ผ์ ์คํํ๋ฉด, ๋ฐ์นํจ๋(Launchpad) ํ๋ฉด์ด ๋์์ง๊ฒ ๋๋ค.
exe ๋ฒ์ ์ Cypress๋ฅผ ๋น ๋ฅด๊ฒ ์ฌ์ฉํด ๋ณผ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก๋ง ์ํ์ ์ผ๋ก ์ ์๋ ๋๊ตฌ์ด๋ฉฐ, ๋ช๊ฐ์ง ๊ธฐ๋ฅ ์ ํ์ด ๋ฐ๋ผ ๋ถ๋๋ค. ์๋ฅผ๋ค์ด Cypress Cloud๋ก์ ๋ นํ ์คํ์ด ๋ถ๊ฐ๋ฅํ๋ค๊ณ ํ๋ค.
์ ์ฐฝ์์ Drag your project directory here or browse manually ๋ฌธ๊ตฌ ๋ฒํผ์ ํด๋ฆญํ๊ณ ํ ์คํธ ์ฝ๋๋ฅผ ๊ด๋ฆฌํ ํ๋ก์ ํธ ํด๋๋ฅผ ์ ํํด์ค๋ค. ์ฒ์์ด๋ผ๋ฉด ๋น ํด๋๋ฅผ ์์ฑํ๊ณ ๋ฑ๋กํด ์ฃผ๋ฉด ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์์ Node.js ํจํค์ง ์ค์น๋ฐฉ๋ฒ์ ์ฐ์ฌํ ์์์ ๊ฐ์ด ๋๊ฐ์ด ์งํํด์ฃผ๋ฉด ๋๋ค.
Cypress ์คํํ๊ธฐ
ํ ์คํธ ํ๋ก์ ํธ ์์ฑ
๋ธ๋ผ์ฐ์ ๋ฅผ ์ ํํ๋ฉด, ๋ง์น ์น์ฑ๊ณผ ๊ฐ์ด cypress ์ ์ฉ GUI์ฐฝ์ด ์ ๋ธ๋ผ์ฐ์ ์ฐฝ์ผ๋ก ์ด๋ฆฌ๊ฒ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์๋์ ๊ฐ์ด ์ ํ ์คํธ ํ์ผ์ ์์ฑํ๋๋ก ํ์.
ํ ์คํธ ์๋๋ฆฌ์ค ์์ฑ
ํ
์คํธ ๋์ ์ฝ๋๋ฅผ ์์ ํ๋ ค๋ฉด ์์์ ์์ฑํ 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์ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ 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 ๊ฐ์ฒด ์ฝ๋๊ฐ ์์ฑ๋๊ฒ ๋๊ณ , ์ฐ์ธก์ ๋ณต์ฌ ๋ฒํผ์ ๋๋ฌ ์ฝ๋์ ์ ์ฉํ๋ฉด ๋๊ฒ ๋๋ค. ๋ค๋ง ๋ณต์กํ ํธ๋ฆฌ ๊ตฌ์กฐ์ ๊ตฌ์ฑ์ผ ๊ฒฝ์ฐ ์ง์ ๊ฐ๋ฐ์๋๊ตฌ๋ก ์ฐพ๋๊ฒ์ด ๋ ์ ํํ ์๋ ์๋ค.
๊ทธ๋ ๊ฒํด์ ์ป์ ์๋ฆฌ๋จผํธ ๊ฐ์ฒด๋ฅผ ๋ค์ ๋์์ ํํ๋ ํจ์๋ฅผ ์ฒด์ด๋(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();
});
});
ํ์ดํ ์๋ํ
์ด๋ฅธ๋ฐ ์ผํ๋ชฐ์ ๊ฒ์์ฐฝ์ ๊ฒ์ ํ
์คํธ๋ฅผ ์๋์ผ๋ก ์จ์ ๊ฒ์์ ์ํํ๋ ๋งคํฌ๋ก๋ฅผ ๋ง๋ค์ด๋ณด์. ์ฌ์ฉํ๋ ํจ์ ์ญ์ ์ง๊ด์ ์ผ๋ก type() ์ ํตํด ์์ฃผ ๊ฐ๋จํ ๊ตฌํํ ์ ์๋ค.
describe('๋ฌด์ ์ฌ ์ฌ์ดํธ ํ
์คํธ ์ํธ', () => {
it('์ผํ๋ชฐ ๋ฒํผ ํด๋ฆญ', () => {
// ๋ฌด์ ์ฌ ์ฌ์ดํธ ๋ฐฉ๋ฌธ
cy.visit('https://www.musinsa.com/app/');
// ๋ฌด์ ์ฌ ๊ฒ์
cy.get('input#commonLayoutSearchForm').type('๊ตฌ์ฐ ๊ฐ๋ฐฉ'); // ๊ฒ์ ์
๋ ฅ์ฐฝ ์๋ฆฌ๋จผํธ๋ฅผ ๊ฐ์ ธ์์ ํ
์คํธ ํ์ดํ
cy.get('.sc-1ppcy5v-5').click(); // ๋๋ณด๊ธฐ ๋ฒํผ ํด๋ฆญ
});
});
์ด๋ฅผ ์์ฉํด์ ๊ฒ์์ฐฝ์ด ์๋ ๋ก๊ทธ์ธ ํ๋ฉด์ ์์ด๋์ ํจ์ค์๋ ์ฐฝ์ ํ ์คํธ๋ฅผ ํ์ดํํ๊ณ ๋ก๊ทธ์ธ ๋ฒํผ์ ๋๋ฅด๋๋ก ํ ์คํธ์ผ์ด์ค๋ฅผ ์ง๋ฉด, ๋ก๊ทธ์ธ ๋งคํฌ๋ก๋ฅผ ๊ตฌํํ๋๊ฒ๊ณผ ๊ฐ๋ค
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();
})
})
๋๋กญ๋ฐ์ค ์๋ ์ ํ
<select> ํ๊ทธ์ ์๋ฆฌ๋จผํธ๋ฅผ ์ ํํ๋ ์๋ํ ํ
์คํธ๋ฅผ ๊ตฌํํด ๋ณด์. ์ง๊ด์ ์ผ๋ก select() ํจ์๋ฅผ ํตํด ๋๋กญ๋ค์ด ๋ฉ๋ด๋ฅผ ์ป์ ์ ์๋ค. ์ด๋ฐ์๋ ์ฒดํฌ๋ฐ์ค๋ ๋ผ๋์ค๋ฒํผ๋ ๋น์ทํ ๊ณผ์ ์ด๋ค.
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์ ํจ์ ์ฝ๋๋ค์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋น๋๊ธฐ ํจ์๋ค์ด๋ฉฐ ์คํ ๋ฐฉ์์ ๋ง์น ์๋ฐ์คํฌ๋ฆฝํธ์ await ๋น๋๊ธฐ ๋ฐฉ์
์ผ๋ก ๋์๋๋ค. ๊ทธ๋์ ๋ณ๋๋ก Promise๋ await ์ฒ๋ฆฌ ์์ด ํ ์คํธ ์ฝ๋๋ค์ ์จ๋ด๋ ค๊ฐ๋ ์ถฉ๋์์ด ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
Cypress ๋ฌธ๋ฒ ์ ๋ฆฌ
๋ค์ํ ์ข ๋ฅ์ api ๋ฌธ๋ฒ์ ์๊ณ ํ๊ณ ์ถ๋ค๋ฉด ์๋ ๊ณต์๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด๋ณด์. ์ด๋ฒ ๊ธ์ cypress์ ๊ธฐ๋ณธ์ ์ธ ๋ผ๋ ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋๋ฐ ์ด์ ์ ๋์ด ์ค๋ช ํด๋ณธ๋ค.
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 ํ์ผ์ ์ด์ฉํ ํ์๊ฐ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ก์ด ์ฌ์ฉ์ ์ ์ ๋ช
๋ น์ด๋ฅผ ์ถ๊ฐํ๋ ค๋ฉด 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์ ์ ์ญ ์ค์ ๋ค์ ์ง์ ํ ์๊ฐ ์๋ค. ์์ธํ ์ฌ๋ฌ ์ธํ
๊ฐ๋ค์ ์๋ ๊ณต์๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ฉด ๋๋ค.
๋ธ๋ผ์ฐ์ ์ถ์ฒ ์ ์ฑ ๋นํ์ฑํ
๋ง์ผ ๋ก๊ทธ์ธ๊ณผ ๊ฐ์ ๋ธ๋ผ์ฐ์ ์ ๋ณด์ ์ ์ฑ ๊ณผ ์ฐ๊ด๋ ํ ์คํธ์ผ์ด์ค๋ฅผ ์ํํ๊ฒ ๋๋ค๋ฉด ๋์ ํ๋ฅ ๋ก ์๋์ ๊ฐ์ด ๋ธ๋ฝ๋๋ฉฐ ์ ๋๋ก ํ ์คํธ ์ฝ๋ ์ํ์ด ์๋ ๊ฒ์ด๋ค.
ํ๋ฅญํ ๋ณด์ ์ ์ฑ
์ด์ง๋ง ์๋ฌด๋๋ ํ
์คํธ ํ๋ ์
์ฅ์์๋ ๋ถํ์ํ ๋ถ๋ถ์ด๊ธฐ ๋ง๋ จ์ด๋ค. ๋ฐ๋ผ์ chromeWebSecurity ์ต์
์ ๋นํ์ฑํจ์ ๋ฐ๋ผ ๋์ผ ์ถ์ฒ ์ ์ฑ
๋ฐ ์์ ํ์ง ์์ ํผํฉ ์ฝํ
์ธ ์ ๋ํด Chromium ๊ธฐ๋ฐ ๋ธ๋ผ์ฐ์ ์ ์น ๋ณด์์ ๋ ์๊ฐ ์๋ค.
module.exports = {
e2e: {
// ํฌ๋ก๋ฏธ์ ๋์ผ ์ถ์ฒ ์ ์ฑ
๋ณด์ ๋นํ์ฑํ
chromeWebSecurity: false,
},
};
ํ์ด์ง ๋ก๋ฉ ์ ํ์๊ฐ ์ค์
๊ธฐ๋ณธ์ ์ผ๋ก ํ ์คํธ ํ์ด์ง ๋ก๋ฉ ์ ํ ์๊ฐ์ด 60์ด๋ก ์ค์ ์ด ๋์ด์๊ธฐ ๋๋ฌธ์, ๋ง์ผ ๋ก๋ฉ์ด ์ข ์ค๋๊ฑธ๋ฆฌ๋ ์ฌ์ดํธ๋ฅผ ํ ์คํธํ ์์ ์ด๋ผ๋ฉด ๋ก๋ฉ ์๊ฐ ์ด๊ณผ๋ก ํ ์คํธ๊ฐ ์คํจํ๊ธฐ ๋๋ฌธ์ ์ถ๊ฐ ์ค์ ์ ํตํด ๋ก๋ฉ ์ ํ ์๊ฐ์ ๋๋ ค์ฃผ์ด์ผ ํ๋ค.
module.exports = {
e2e: {
// ์๋ ํ
์คํธ ์ฝ๋ ์์ฑ ์ค์
experimentalStudio: true,
// ํ์ด์ง ๋ก๋ ์ ํ ์๊ฐ ์ค์
pageLoadTimeout: 120000 // 120sec
},
};
ํ์ด์ง ํฌ๊ธฐ ์ค์
๊ธฐ๋ณธ์ ์ผ๋ก ํ ์คํธํ ์นํ์ด์ง์ ํฌ๊ธฐ๋ 1000x660 ์ผ๋ก ์ค์ ํ์๊ธฐ ๋๋ฌธ์ ์๋์ ๊ฐ์ด ์นํ์ด์ง์ ์คํ์ผ์ ๋ฐ๋ผ ์งค๋ฆฌ๋ ํ์์ด ๋ฐ์ํ๊ธฐ๋ ํ๋ค. ์ถ๊ฐ ์ค์ ์ ํตํด ํ์ด์ง์ ๋ทฐํฌํธ๋ฅผ ๋ง์ถ ์ ์๋ค.
module.exports = {
e2e: {
// ํ
์คํธ ํ์ด์ง ๋ทฐํฌํธ ์ค์
viewportWidth: 1600,
viewportHeight: 900,
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
};
์ฐธ๊ณ ๋ฌธํ
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