มาเริ่มต้นใช้งาน Cypress.io ใน Next.js กันเถอะ

Pitsinee Jk
Yeeraf Co., Ltd.
Published in
4 min readJul 29, 2022

สวัสดีค่ะ หลังจากที่เป็น dev มาสักพัก ก็ตกผลึกได้อย่างนึงว่า สิ่งที่ขาดไม่ได้เลยสำหรับการพัฒนา Web Application ก็คือการทดสอบ หรือการ Test นั่นเอง Test มือมันก็ไม่แย่นะ แต่พอเจอโปรเจคที่มีช่อง input เป็นสิบ แถมต้องกดอะไรมากมายเพื่อ Test อีก ทำให้รู้ว่ามันช่างเมื่อยมือและเสียเวลาเสียจริง …ด้วยเหตุนี้จึงขอนำเสนอ เครื่องมือทุ่นแรงสำหรับการ Test ที่เปลี่ยนจาก Manual Test ให้เป็น Automated Test นั่นก็คือ Cypress นั่นเอง

Cypress คืออะไร
Cypress คือ Front end Testing Tool ที่มีทั้ง Component Testing และ End-to-End Testing หรืออธิบายแบบศัพท์บ้านๆ เลยก็คือ เครื่องมือที่เอาไว้เขียน Automated Test นั่นเอง

ติดตั้ง Cypress
ในที่นี้ขอคิดว่าทุกคนมีโปรเจค Next.js เป็นของตัวเองอยู่แล้วนะ แต่ถ้าใครยังไม่มี ไปสร้างมาก่อนโลด

สำหรับใครที่ใช้ yarn ให้รันคำสั่งนี้เลย

yarn add cypress --dev

ส่วนอันนี้สำหรับคนที่ใช้ npm นะ

npm install cypress --save-dev

หลังจากที่ install เสร็จเรียบร้อยแล้ว ให้ทุกคนไปที่ไฟล์ package.json แล้ว copy คำสั่งนี้ไปใส่ใน scripts เพื่อการเรียกเปิด cypress ที่สะดวกสบายยิ่งขึ้น

"cypress": "cypress open"

จะได้ออกมาประมาณนี้นะทุกคน

package.json

เปิด Cypress
ทีนี้เราจะมาลองเปิด cypress กัน โดยที่รันคำสั่งนี้ได้เลย

yarn cypress

สำหรับ npm ให้รันคำสั่งนี้นะ

npm run cypress

พอรันแล้วจะมี popup เด้งขึ้นมาหน้าตาประมาณนี้

cypress.io/welcome

บทความนี้จะใช้ End-to-End Testing ในการเขียน Test นะคะ เพราะฉะนั้น กดที่ E2E Testing โลด

หลังจากที่กด E2E Testing แล้ว จะขึ้นหน้า Configuration Files หน้านี้เขาจะบอกเราว่าเขาสร้างไฟล์พวกนี้ให้แล้วนะ ให้เลื่อนลงมาจนสุด แล้วกดปุ่ม Continue ได้เลย

cypress.io/config

เสร็จแล้วให้เลือก Browser ที่ต้องการให้รัน Test แล้วกด Start กันเลย

cypress.io/choose-browser

ทีนี้จะเด้งหน้าต่าง Browser ขึ้นมาอีกอันนึง หน้าตาประมาณนี้ ให้กดที่ Create new empty spec

cypress.io/index

พอกดแล้วก็ตั้งชื่อ spec แล้วกด ok จนมาถึงหน้านี้เลยนะ หน้านี้เป็นหน้ารัน spec หรือ Test ที่เราจะเขียนกันนั่นเอง อันนี้เป็น example ที่เขา gen ให้ดูก่อน

cypress.io/spec

เริ่มเขียน Test กัน!
แว๊บกลับมาที่ VSCode ของเรา สังเกตเห็นอะไรไหม เจ้า cypress เขาแอบสร้างโฟลเดอร์อะไรให้เสร็จสรรพเลย สบายละทีนี้

cypress folder

ทีนี้เราจะมาโฟกัสที่ 3 ส่วนที่สำคัญกัน

  1. e2e เป็นโฟลเดอร์ที่เอาไว้เก็บ Test case ต่างๆ โดยจะเก็บไฟล์ประมาณนี้
cypress/e2e

2. fixtures เป็นโฟลเดอร์ที่เอาไว้เก็บข้อมูลต่างๆ ที่ใช้สำหรับการ Test เช่น ตัวแปรข้อมูลที่เป็น json, รูปภาพ

3. support เป็นโฟลเดอร์สำหรับเขียน commands เพิ่มเติมจากที่ cypress มีอยู่ คือเราสามารถ custom ได้อิสระเลยที่ไฟล์ commands.ts ตัวอย่างก็อย่างเช่น ถ้าในทุกๆ Test case เราจำเป็นต้อง login ก่อนทุกครั้ง เราก็สามารถสร้าง command login ไว้เพื่อเรียกใช้ได้แบบสั้นๆ ไม่ต้องเขียนใหม่ทุกรอบ

พอรู้ concept คร่าวๆ แล้วก็มาเริ่มกันเลยเต้อะ เราจะลองเขียน Test หน้า login กันนะ เริ่มจากสร้างไฟล์ชื่อ login.cy.ts ไว้ข้างในโฟลเดอร์ e2e แล้วเขียน Test case ใส่ไปตามนี้เลย

describe('Login', () => {
beforeEach(() => {
cy.visit('/auth/login-test')
})

it('visit login page', () => {
cy.contains('Sign in')
})
})

ขออธิบายสิ่งที่เราเขียนลงไปก่อนนะ
describe จะเป็นหัวข้อใหญ่ของ Test case ทั้งหมด ให้ตั้งชื่อเพื่อระบุว่าเราต้องการจะ Test อะไร อันนี้เรากำลังเขียน Test สำหรับหน้า Login เราก็ใส่คำว่า Login ไปได้เลย
beforeEach ในตอนที่รัน Test ตัว cypress จะเข้ามาทำคำสั่งข้างใน beforeEach ทุกครั้งก่อนที่จะเข้า Test case แต่ละ case ในที่นี้เราใส่คำสั่ง cy.visit เพื่อให้เข้าหน้า /auth/login-test
it ก็คือ Test case ให้ตั้งชื่อ case ว่าเราต้องการจะ Test อะไร ในที่นี้เราเช็คว่าเข้ามาหน้า Login ได้ไหม ด้วยการใช้คำสั่ง cy.contains เพื่อดูว่าในหน้าที่อยู่ตอนนี้มี text ว่า Sign in อยู่ไหม

ลองไปรัน Test กัน เปิด Browser สำหรับ run test ที่เราเลือกไว้ในตอนแรกขึ้นมา แล้วกดไฟล์ login.cy.ts

cypress.io/specs

เจ๊งจ้า เพราะเราเขียน path ไม่เต็มนั่นเอง ถ้าเราต้องการเขียน path ย่อๆ แบบเดิม แต่ไม่เจ๊งแบบนี้ เราต้องไปแก้ config กันก่อน

cypress.io/path-error

ไปที่ไฟล์ cypress.config.ts ที่ cypress แอบสร้างมาให้ในตอนแรก (ถ้าไม่มีก็สร้างเองเลยนะ) แล้วก็ใส่ baseUrl ให้ตรงกับ project ของเรา อันนี้ใช้ port 3000 ก็ใส่ไปแบบนี้ได้เลย

import { defineConfig } from 'cypress'export default defineConfig({
e2e: {
baseUrl: 'http://localhost:3000/',
},
})

พอ save ปุ๊บ cypress จะเปิดหน้า Browser ให้ใหม่อัตโนมัติ (แต่ถ้ามันไม่เปิดให้เอง เราต้องปิดเปิดใหม่แบบอัตโนมือนะจ๊ะ) เสร็จแล้วกดเข้าไปในไฟล์เดิม เย้ รันผ่านแล้ว

cypress.io/case-visit-success

เราจะมาเพิ่มความเท่ห์ให้มันด้วยการสั่งให้พิมพ์อัตโนมัติกัน กลับไปที่ไฟล์ login.cy.ts เพิ่ม case login failed

it('login failed', () => {
cy.get('[data-cy="login-email"]').type('hello@cypress.io')
cy.get('[data-cy="login-password"]').type('hello@cy')
cy.get('[data-cy="login-submit"]').click()
cy.contains('login failed.')
})

แวะอธิบายนิดนึง
cy.get เป็นคำสั่งที่เอาไว้ get element อย่างเช่น
ถ้าต้องการ get element ที่ถูกระบุด้วย id จะใส่คำสั่ง cy.get(‘#login-submit’)
ถ้าต้องการ get element ที่ถูกระบุด้วย class จะใส่คำสั่ง cy.get(‘.login-submit’)
ส่วนในตัวอย่างใช้ cy.get(‘[data-cy=”login-submit”]’) แปลว่าจะ get element ที่ถูกระบุด้วย data-cy …งงล่ะสิ รอแปป เก็บไว้ก่อนนะ
.type คำสั่งนี้จะสั่งให้พิมพ์ข้อความ ลงไปใน element

data-cy อธิบายง่ายๆ ได้ว่ามันคือการตั้งชื่อ element เพื่อเขียน Test นั่นเอง ถ้าเราจะ get element โดยการระบุด้วย data-cy เราต้องไปตั้งชื่อให้ element ก่อน เช่น

<button data-cy="login-submit">Login</button>

ตั้งชื่อ element ครบแล้วใช่ไหม ถ้างั้นเราไปรัน Test กัน

cypress.io/case-login-failed-success

case login failed ของเราผ่านไปได้ด้วยดี เหลือ case สุดท้ายแล้ว ก็คือ login successful นั่นเอง กลับไปเขียนเพิ่มในไฟล์ login.cy.ts โลด

it('login successful', () => {
cy.get('[data-cy="login-email"]').type('test@test.com')
cy.get('[data-cy="login-password"]').type('test1234')
cy.get('[data-cy="login-submit"]').click()
cy.location('pathname').should('eq', '/welcome')
})

ใน case นี้เราจะให้พิมพ์ข้อมูลที่ถูกต้อง แล้วถ้า login สำเร็จ จะไปที่หน้า welcome โดยคำสั่ง cy.location(‘pathname’).should(‘eq’, ‘/welcome’) คือการเช็คว่า pathname เท่ากับ /welcome หรือไม่

และพอเอาทั้งหมดมารวมกัน ไฟล์ login.cy.ts จะได้แบบนี้

describe('Login', () => {
beforeEach(() => {
cy.visit('/auth/login-test')
})

it('visit login page', () => {
cy.contains('Sign in')
})
it('login failed', () => {
cy.get('[data-cy="login-email"]').type('hello@cypress.io')
cy.get('[data-cy="login-password"]').type('hello@cy')
cy.get('[data-cy="login-submit"]').click()
cy.contains('login failed.')
})
it('login successful', () => {
cy.get('[data-cy="login-email"]').type('test@test.com')
cy.get('[data-cy="login-password"]').type('test1234')
cy.get('[data-cy="login-submit"]').click()
cy.location('pathname').should('eq', '/welcome')
})
})

มาลองรันครั้งสุดท้ายกัน

cypress.io/run-all-spec

เสร็จเรียบร้อยยย เท่านี้เราก็มี Automated test ไว้ใช้แทนการเทสมือแล้ว จริงๆ cypress เขามีคำสั่งให้เล่นอีกเยอะเลยนะ ลองไปหาเล่นกันจาก doc เขาได้เลย
https://docs.cypress.io/api/table-of-contents

บทความนี้คงจะจบลงตรงนี้แล้ว ขอบคุณทุกคนที่อ่านมาจนจบนะคะ สวัสดีค่า 😊

--

--