Uçtan uca testleriniz için zaten Cypress kullanıyorsunuz. Şimdi doğrudan bir API'ye istek göndermek, durum kodunu kontrol etmek ve JSON gövdesinde (body) UI üzerinden tıklama yapmadan doğrulama yapmak istiyorsunuz. Cypress bunu yapabilir. cy.request() komutu, tarayıcı dışında, Node'dan gerçek HTTP istekleri gönderir, böylece bir uç noktayı kendi başına test edebilir veya bir kullanıcı arayüzü testi çalışmadan önce durumu ayarlayabilirsiniz.
Bu kılavuz size API'leri Cypress ile nasıl test edeceğinizi gösterir: cy.request()'in temelleri, yanıtları doğrulama, bir kimlik doğrulama belirtecini yeniden kullanmak için istekleri zincirleme ve cy.intercept() ile tarayıcı trafiğini taklit etme (stubbing). Ayrıca, API için Cypress'in nerelerde iyi bir seçenek olduğunu ve bir API'ye özgü aracın nerelerde daha uygun olduğunu göreceksiniz.
Neden API'leri Cypress ile test etmelisiniz?
Çoğu Cypress paketi bir tarayıcıyı yönetir. Ancak kullanıcı arayüzünde doğruladığınız şeylerin çoğu, altındaki API'dir: /login bir token döndürüyor mu, /users doğru yapıyı döndürüyor mu, bir POST beklediğiniz kaydı oluşturuyor mu?
Bu uç noktaları doğrudan test etmenin iki faydası vardır. Birincisi, API kontrolleri kullanıcı arayüzü akışlarından daha hızlı çalışır çünkü render etme (oluşturma) ve öğeleri bekleme yoktur. İkincisi, test verilerini ayarlamak için cy.request() kullanabilirsiniz. Bir kullanıcı oluşturmak için bir kayıt formunu tıklamak yerine, tek bir POST isteği gönderir ve gerçekten önemsediğiniz doğrulamaya geçersiniz.
Cypress zaten teknoloji yığınınızdaysa, API testleri eklemek yeni bir araç kurmak anlamına gelmez. Onları aynı spec dosyalarında, aynı expect doğrulamalarıyla, aynı CI çalıştırmasında yazarsınız.
cy.request() temelleri
cy.request() bir HTTP isteği yapar ve yanıtı döndürür. Tarayıcıdan değil, Cypress Node sürecinden çalışır, bu nedenle CORS veya aynı kaynak kurallarına tabi değildir.
Komut çeşitli biçimleri kabul eder:
cy.request(url)
cy.request(url, body)
cy.request(method, url)
cy.request(method, url, body)
cy.request(options)
En basit çağrı bir URL'yi iletir. Bir method belirtilmezse, Cypress varsayılan olarak GET kullanır:
cy.request('https://jsonplaceholder.typicode.com/users')
Temel bir GET isteğinin ötesindeki her şey için bir seçenekler nesnesi iletin. Bu size method, gövde (body) ve başlıklar (headers) üzerinde tam kontrol sağlar:
cy.request({
method: 'POST',
url: 'https://jsonplaceholder.typicode.com/posts',
headers: {
'Content-Type': 'application/json'
},
body: {
title: 'API test',
body: 'created from Cypress',
userId: 1
}
})
Bu nesnedeki kullanışlı seçenekler:
method: HTTP fiili (GET,POST,PUT,PATCH,DELETEve diğerleri). Varsayılan olarakGET'tir.url: uç nokta. Zorunlu.body: istek yükü (payload). Cypress nesneleri JSON'a dönüştürür.headers: istek başlıklarının bir nesnesi.auth: HTTP Temel Kimlik Doğrulaması için kimlik bilgileri.qs: bir nesne olarak sorgu dizesi parametreleri.failOnStatusCode: Bir 4xx veya 5xx yanıtını testin başarısız olması yerine doğrulamak istediğinizdefalseolarak ayarlayın.
Bu son seçenek negatif testler için önemlidir. Varsayılan olarak cy.request() 2xx veya 3xx olmayan herhangi bir durumda testi başarısız kılar. Hatalı bir isteğin 400 döndürüp döndürmediğini kontrol ediyorsanız, bu varsayılan davranışı devre dışı bırakmanız gerekir:
cy.request({
method: 'GET',
url: 'https://jsonplaceholder.typicode.com/users/99999',
failOnStatusCode: false
}).then((response) => {
expect(response.status).to.eq(404)
})
Durum ve Gövde Üzerinde Doğrulama Yapmak
cy.request() bir yanıt nesnesi döndürür. Bunu okumak için .then() zincirleme yöntemini kullanın. Yanıtın en çok kullanacağınız dört özelliği vardır:
status: HTTP durum kodu.body: yanıt yükü (payload).Content-Typejsonile bitiyorsa Cypress bunu bir JavaScript nesnesine ayrıştırır.headers: yanıt başlıkları.duration: isteğin ne kadar sürdüğü, milisaniye cinsinden.
İşte durumu, gövde şeklini ve belirli bir alanı kontrol eden eksiksiz bir test:
describe('Users API', () => {
it('returns a list of users', () => {
cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
expect(response.status).to.eq(200)
expect(response.body).to.be.an('array')
expect(response.body).to.have.length(10)
expect(response.body[0]).to.have.property('email')
})
})
})
response.body zaten ayrıştırılmış bir nesne olduğundan, üzerinde standart Chai ile doğrulama yaparsınız. Türü, uzunluğu, iç içe özelliklerini veya tam değerlerini kontrol edebilirsiniz. Bu, kullanıcı arayüzü testleri için kullandığınız doğrulama sözdizimi ile aynıdır, bu nedenle öğrenecek yeni bir şey yoktur.
Yanıt başlıklarını da doğrulayabilirsiniz, bu içerik türünü veya önbelleğe almayı kontrol etmek için kullanışlıdır:
cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
expect(response.headers['content-type']).to.include('application/json')
})
Bu kontrolleri yapılandırmaya daha derinlemesine bakmak için, API doğrulamaları ve daha geniş kapsamlı API test en iyi uygulamaları hakkındaki kılavuzumuza bakın.
İstekleri Zincirleme ve Kimlik Doğrulama Belirtecini Yeniden Kullanma
Gerçek API'ler kimlik doğrulama gerektirir. Yaygın desen, bir kez oturum açmak, belirteci almak ve ardından bunu sonraki her istekte göndermektir. cy.request() bu konuda temiz bir zincirleme sağlar.
Giriş isteğini gönderin, yanıt gövdesinden belirteci okuyun, ardından bir sonraki çağrıda kullanın:
describe('Authenticated API flow', () => {
it('logs in and fetches a protected resource', () => {
cy.request({
method: 'POST',
url: 'https://api.example.com/login',
body: {
email: 'user@example.com',
password: 'secret'
}
}).then((loginResponse) => {
expect(loginResponse.status).to.eq(200)
const token = loginResponse.body.token
cy.request({
method: 'GET',
url: 'https://api.example.com/profile',
headers: {
Authorization: `Bearer ${token}`
}
}).then((profileResponse) => {
expect(profileResponse.status).to.eq(200)
expect(profileResponse.body).to.have.property('email', 'user@example.com')
})
})
})
})
```Birkaç test aynı belirteci gerektiriyorsa, oturum açmayı bir beforeEach içine taşıyın ve belirteci Cypress.env() veya sarmalanmış bir takma ad ile saklayın, böylece her test onu kullanabilir. Bu, kimlik doğrulama kurulumunu her spec'te tekrarlamak yerine tek bir yerde tutar.
Bu giriş yap-sonra kullan deseni, bir çağrının verileri bir sonrakine beslediği herhangi bir API entegrasyon testi akışında yazacağınız şeklin aynısıdır.
Taklit Etme (Stubbing) İçin cy.intercept()
cy.request() gerçek API'ye istek gönderir. Bazen bunun tam tersini istersiniz: ön uç uygulamanızın yaptığı istekleri durdurmak ve sahte bir yanıt döndürmek. İşte bu cy.intercept()'tir.
Burada önemli bir ayrım var. cy.intercept() yalnızca ön uç uygulamanızın tarayıcıda yaptığı istekleri durdurur. cy.request()'i durdurmaz, çünkü cy.request() tarayıcıyı tamamen atlar. cy.intercept()'i, API'nin kendisini test ederken değil, kullanıcı arayüzünüzün belirli bir API yanıtına nasıl tepki verdiğini test ederken kullanın.
Bir isteği izleyebilir, statik bir yanıtla taklit edebilir veya bekleyebilirsiniz. Taklit etmek için bir yanıt nesnesi iletin:
cy.intercept('GET', '/api/users', {
statusCode: 200,
body: [{ id: 1, name: 'Ada' }]
})
Artık /api/users adresine yapılan herhangi bir tarayıcı isteği o sabit yükü döndürür. Bu, boş bir liste, 500 hatası veya yavaş bir yanıt gibi canlı bir arka uca karşı tetiklemesi zor olan uç durumları test etmenizi sağlar.
İsteğin gerçekleştiğini doğrulamak için, .as() ile bir takma ad verin ve onu bekleyin:
it('shows an error banner when the API fails', () => {
cy.intercept('GET', '/api/users', {
statusCode: 500,
body: { message: 'Server error' }
}).as('getUsers')
cy.visit('/dashboard')
cy.wait('@getUsers').its('response.statusCode').should('eq', 500)
cy.contains('Something went wrong').should('be.visible')
})
```cy.wait('@getUsers') satırı, yakalanan istek çözülene kadar testi duraklatır, ardından size doğrulama yapmak üzere isteği ve yanıtı verir. İsteği tetikleyen eylemden önce intercept'i kurun, aksi takdirde hiçbir şeyi yakalamaz. Bir yanıtı taklit etmekle (faking) tüm bir servisi taklit etmek (mocking) arasında bir değerlendirme yapıyorsanız, API mocking ve API stubbing vs API mocking hakkındaki yazılarımız bu tercihleri ayrıntılandırır.
API için Cypress'in Ne Zaman Mantıklı Olduğu ve Ne Zaman Olmadığı
Cypress, bir kullanıcı arayüzü test paketi içinde yer alan API kontrolleri için güçlü bir uyum sağlar. Zaten uçtan uca testler yazıyorsanız ve veri hazırlamanız, kullanıcı arayüzünüzün bağımlı olduğu bir uç noktayı doğrulamanız veya hata işlemeyi test etmek için bir yanıtı taklit etmeniz gerekiyorsa, cy.request() ve cy.intercept() her şeyi tek bir yerde tutar. Bağlam değişikliği yok, ikinci bir araç yok.
Cypress tek test çalıştırıcınız olduğunda ve başka bir bağımlılık eklemek istemediğinizde, birkaç bağımsız API smoke testi için de uygundur.
Ancak, büyük, bağımsız bir API test paketi söz konusu olduğunda durum karmaşıklaşır. Cypress tarayıcı için inşa edilmiştir, bu nedenle API testi temel tasarım değil, üzerine eklenmiş bir yetenektir. Paket büyüdükçe birkaç boşluk ortaya çıkar:
Görsel bir istek oluşturucu yok. Her istek koddan ibaret. Yüzlerce uç noktanız olduğunda başlıkları, gövdeleri ve sorgu parametrelerini elle oluşturmak yavaşlar.Yalnızca CI'ya yönelik bir API işlem hattı için daha zayıf. Cypress, salt API çalıştırmaları için bile bir tarayıcı bağlamı başlatır ki bu gereksiz bir yüktür.Paylaşılan bir API tanımı yok. İstek şekilleri, tasarım, belgeler ve test genelinde ekibinizin yeniden kullanabileceği bir spec'te değil, test dosyalarınızda bulunur.
İşte tam da bu noktada API'ye özgü bir araç daha uygun hale gelir. Apidog, API'nin kendisi etrafında inşa edilmiştir: bir uç noktayı bir kez tasarlar, ardından görsel bir istek oluşturucu ve görsel doğrulamalarla buna karşı test senaryoları oluşturursunuz; yaygın durumlar için kod gerekmez. İstekler, ortamlar ve kimlik doğrulama paylaşılan bir çalışma alanında yaşar, böylece ekibiniz bunları test dosyalarından yeniden türetmez.
CI için, Apidog CLI kaydettiğiniz test senaryolarınızı Node çalıştırabilen herhangi bir adımda başsız (headless) olarak çalıştırır:
npm install -g apidog-cli
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
-t bayrağı kaydedilmiş bir senaryoyu veya paketi hedefler, -e bir ortamı seçer ve -r rapor biçimlerini (cli, html, json, junit) seçer. JUnit çıktısı çoğu CI paneline doğrudan bağlanır. Bir veri dosyasından bir testi çalıştırmak için -d veya --iteration-data ekleyin ve sonuçları çalışma alanınıza geri göndermek için --upload-report kullanın. CLI, kaydedilmiş senaryoları çalıştırır; etkileşimli bir istek gönderici değildir.
Bunu düşünmenin faydalı bir yolu şudur: tarayıcı testlerinizi destekleyen API kontrolleri için cy.request() kullanın ve API testi ana iş olduğunda API'ye özgü bir araca yönelin. Seçenekleri karşılaştırıyorsanız, CI/CD'de çalışan API test otomasyon araçları ve daha geniş kapsamlı en iyi 30 API test aracı listelerimiz bu alanı kapsar.
Sıkça Sorulan Sorular
cy.request() tarayıcıda mı çalışır?
Hayır. cy.request() tarayıcı dışında, Cypress Node sürecinden çalışır. Bu yüzden CORS veya aynı kaynak politikası tarafından engellenmez ve cy.intercept() onu durduramaz. Tarayıcının yaptığı bir isteğe ihtiyacınız varsa, bunu uygulamanız aracılığıyla tetikleyin ve cy.intercept() ile yakalayın.
Bir 400 veya 404 yanıtını testi başarısız kılmadan nasıl test ederim?
Varsayılan olarak cy.request(), 2xx veya 3xx olmayan herhangi bir durumda testi başarısız kılar. Seçenekler nesnesinde failOnStatusCode: false olarak ayarlayın, ardından durumu expect(response.status).to.eq(404) ile kendiniz doğrulayın.
Bir kullanıcı arayüzü testi öncesinde oturum açmak için cy.request() kullanabilir miyim?
Evet ve bu yaygın bir desendir. cy.request() ile giriş uç noktanıza bir POST isteği gönderin, response.body'den belirteci okuyun ve kullanıcı arayüzü testinizin zaten kimliği doğrulanmış olarak başlaması için saklayın (Cypress.env() içinde, localStorage veya bir çerezde). Bu, giriş formunu atlar ve paketi hızlandırır.
cy.request() ile cy.intercept() arasındaki fark nedir?
cy.request() gerçek bir HTTP isteği gönderir ve gerçek yanıtı döndürür, bu yüzden bir API'yi test etmek için kullanırsınız. cy.intercept() ise ön ucunuzun tarayıcıda yaptığı istekleri izler veya taklit eder, bu yüzden kullanıcı arayüzünüzün ne aldığını kontrol etmek için kullanırsınız. Biri ağa istek gönderir; diğeri onu şekillendirir.
API testi için Cypress mi yoksa özel bir araç mı kullanmalıyım?
Zaten çalıştırdığınız bir tarayıcı test paketini destekleyen API kontrolleri için Cypress'i kullanın. Büyük bağımsız bir API paketi, yalnızca CI'ya yönelik API işlem hatları veya tüm ekibinizin çalıştığı paylaşılan bir API tanımı için Apidog gibi API'ye özgü bir araç daha uygundur. Nasıl karar vereceğinizi öğrenmek için API test en iyi uygulamaları makalemize bakın.
