ch18-suspense-errBoundary-concurrency
Yeni özelliklerden daha iyi anlamak için, 3 bileşen - ErrorComp, PageSpinner, Spinner - ve HeroList için yeni bir arama filtresi özelliği ekliyoruz. Suspense ve ErrorBoundary kullanım durumları için bileşenlere ihtiyacımız olacak.
// src/components/ErrorComp.cy.tsx
import ErrorComp from "./ErrorComp";
import "../styles.scss";
describe("ErrorComp", () => {
it("should render error", () => {
cy.mount(<ErrorComp />);
cy.getByCy("error").should("be.visible");
});
});// src/components/ErrorComp.test.tsx
import ErrorComp from "./ErrorComp";
import { render, screen } from "@testing-library/react";
describe("ErrorComp", () => {
it("should render error", async () => {
render(<ErrorComp />);
expect(await screen.findByTestId("error")).toBeVisible();
});
});HeroList için Arama-filtre
HeroList için Arama-filtreHeroList için kahramanların isimlerine veya açıklamalarına göre arama ve filtreleme yapabilecek yeni bir özellik istiyoruz, böylece daha sonra yeni React 18 kancaları useTransition ve useDeferredValue için bir kullanım durumu elde edebiliriz. Bunun için HeroList.cy.tsx dosyasına yeni bir test ekleyelim. Bir kahramanın adını veya açıklamasını aramak için yazdığımızda, listede sadece o kahramanı almalıyız. Tüm testler için aynı olan dağıtımı beforeEach test kancasına da taşıyabiliriz (Kırmızı 1).
Arama alanına yazarken, kahraman verilerini isim veya açıklama listesinde mevcut olanlara göre filtrelemek istiyoruz. heroes verisini zaten bir özellik olarak alırız, bunu useState ile yönetebiliriz:
const [filteredList, setFilteredList] = useState(heroes)
Şimdi bu durumu filtreleme mantığıyla ayarlamamız gerekiyor. İşte bize bunu yapmada yardımcı olan iki işlev:
heroes.map ile listeyi işlemek yerine, filteredHeroes kullanırız; bu, bir değişiklik olayında handleSearch tarafından ayarlanır.
Başka bileşenlerde kullanılan bir bileşene özellik ekledik. Büyük özellikler eklerken, gerileme olup olmadığını kontrol etmek için CT ve e2e test paketlerinin tamamını çalıştırmak önemlidir; yarn cy:run-ct, yarn cy:run-e2e. Teoride, hiçbir şey ters gitmemeli. Bileşen hataları yok. Ancak delete-hero e2e testi, silme işleminden sonra yeni eklenen kahramanı temizlemiyor; güncellenmiş kahraman listesini görmek için yenilememiz gerekiyor. Kırılgan bir ünleri olsa bile, iyi yazılmış, kararlı e2e testlerinin yüksek hata bulma yeteneği vardır ve daha küçük bir odakta fark edilmeyen hataları yakalar.
Hataları gidermek için, heroes değiştiğinde HeroListi yeniden işlememiz gerekiyor. Bu, bağımlılık dizisindeki heroes ve useEffect ile elde edilir (Yeşil 1).
useEffect(() => setFilteredHeroes(heroes), [heroes])
useDeferredValue ve useTransition ile Eşzamanlılık
useDeferredValue ve useTransition ile EşzamanlılıkEşzamanlılık kavramı, React 18'de yenidir. Birden fazla durum güncellemesi eşzamanlı olarak gerçekleşirken, Eşzamanlılık, UI tepki süresini optimize etmek amacıyla bazı durum güncellemelerinin diğerlerinden daha düşük önceliğe sahip olmasını ifade eder. useDeferredValue ve useTransition kancaları React 18'de yenidir. Uygulamamızda gerekli değiller, ancak yavaş bir bağlantıda büyük miktarda veri yüklerken nerede uygun olabileceklerini göstereceğiz.
useTransition() ile hangi durum güncellemelerinin diğer tüm durum güncellemelerinden daha düşük önceliğe sahip olduğunu belirleyebiliriz.
const [isPending, startTransition] = useTransition()
isPending boolean bir değerdir ve düşük öncelikli durum güncellemesinin hala beklemede olup olmadığını belirtir.
startTransition düşük öncelikli durum güncellemesini sarmalayan bir işlemdir.
HeroList bileşenimizde, setFilteredHeroes düşük öncelikli bir durum güncellemesi olarak kabul edilebilir. Bu, kahraman listesi çok büyük ve ağ çok yavaş olduğunda, arama filtresi girişinin listeyi hala yüklerken duyarlı kalmasını sağlar.
İlk değişiklik, handleSearchın dönüş bölümündedir. startTransition, setFilteredHeroes döndüren bir işleve sarar.
Geçiş isPending olduğunda, bileşenin tümündeki opaklığı azaltabiliriz:
İşte HeroList bileşenine yapılan useTransition güncellemeleri.
useTransition ile düşük öncelikli kod üzerinde tam kontrol sağlarız. Bazen, verinin dışarıdan bir özellik olarak veya dış koddan geldiği durumlar gibi, tam kontrol sağlayamayabiliriz. Bu tür durumlarda useDeferredValue kullanabiliriz. Durum güncelleme kodunu useTransition ile sarmalamanın aksine, useDeferredValue ile etkilenen son değeri sararız. useTransition ve useDeferredValue sonuçları aynıdır; React'e hangi düşük öncelikli durum güncellemelerinin olduğunu söyleriz.
Durum güncelleme koduna erişiminiz varsa, useTransition kullanın. Koda erişiminiz yoksa, sadece son değere erişiminiz varsa, useDeferredValue kullanın.
HeroList bileşenimizde, hero verisi bir özellik olarak gelmekte ve bu durum useDeferredValue için iyi bir adaydır.
isStale değerini CSS'te şu şekilde kullanabiliriz:
İşte güncellenmiş HeroList bileşeni (Düzenleme 1):
Koşullu işlem başka bir ipucu verir; veri yoksa arama çubuğuna ihtiyacımız var mı? Başarısız bir testle başlayarak bu özelliği ekleyelim. HeroList.cy.tsx dosyasını biraz yeniden düzenleyeceğiz, böylece testi iki bağlamda yakalayabiliriz; kahraman verisi olmadan monte etme ve kahraman verisiyle monte etme (Kırmızı 2).
Testi tatmin etmek için, arama çubuğu için koşullu işlem yapmamız yeterlidir.
İşte HeroList bileşeni son haliyle (Yeşil 2):
Suspense & ErrorBoundary
Kurulum
Uygulamanın başlangıcında yüklenen kod miktarını - başlangıç paketini - yönetmek için, UI tepki süresini artırmak amacıyla uygulamanın kodunu parçalara bölen ve yüklemeyi gerçekleştiren kod bölme işlemi kullanılabilir. React'te, Suspense ve tembel yükleme, kod bölme işlemini gerçekleştirmek için kullanılır. Genellikle ErrorBoundary ile birlikte anılırlar, çünkü Suspense ve ErrorBoundary bileşenleri, yükleme ve hata UI'sını bireysel bileşenlerden ayırmamıza olanak tanır. İşte ana fikirler:
Yükleme sırasında
Suspensebileşenini göster, hata durumundaErrorBoundarybileşenini göster, başarılı durumda ise göstermek istediğimiz bileşeni göster.İlk kez işlem gördüklerinde bileşenleri yüklemek için
React.lazykullanın.
Bir bileşeni lazy işlevi ile tembel bir bileşene dönüştürme:
Suspense ve ErrorBoundary bileşenlerini, ağacında bir veya daha fazla tembel bileşen içeren UI'ı sarmak için kullanın. İşte yüksek düzeyde nasıl birlikte çalıştıkları:
useGetHeroes kancasını, yapılandırma için üçüncü bir argüman alacak şekilde güncelleyin. {suspense: true} geçmek, react-query'deki useQuery için Suspense modunu etkinleştirir.
useGetHeroes kancasını, yapılandırma için üçüncü bir argüman alacak şekilde güncelleyin. {suspense: true} geçmek, react-query'deki useQuery için Suspense modunu etkinleştirir.
Hata durumları için testler
HeroDetail bileşeni
HeroDetail bileşeniŞimdi hata kenar durumları için başarısız testler yazmaya başlayabiliriz. Nereden başlarız? Pozitif durumları kapsayan, cy.intercept() ile ağı izlemeye alan veya ağı taklit eden herhangi bir bileşen testi iyi bir adaydır. Bunlar HeroDetail ve Heroes bileşen testleridir.
HeroList bileşen testine 200 olmayan bir senaryo için test ekleyin. İşlemcinin görünmesini sağlamak için gecikme seçeneği kullanırız (Kırmızı 3).
HeroDetail bileşenine bakarak, usePostHero ve usePutHero kancalarından status ve isUpdating elde edebiliriz, bunları kullanabiliriz. Bu durumlar görülürse, PageSpinner işlemcisini işleme alın (Yeşil 2).
Bileşen testini çalıştırarak, Cypress zaman yolculuğu hata ayıklama işleminin üzerine gelerek işlemciyi doğrulayabiliriz. Ayrıca taklit edilmiş POST isteğinin gittiğini de fark ederiz, bunu bir cy.wait() ile doğrulayabiliriz (Yeniden düzenleme 2). Cypress zaman yolculuğu hata ayıklayıcısı aracılığıyla bir bileşenin tüm geçişlerini görebilmek, testlerimizi geliştirmemize yardımcı olabilir.
Sonraki adımda, bir hatayı kontrol etmek için bir satır ekliyoruz. Durum kodu 400 ise, bu testte bir hata görmeliyiz (Kırmızı 4).
HeroDetail bileşenine bakarak, usePostHero ve usePutHero kancalarından postError ve isUpdateError elde edebiliriz, bunları kullanabiliriz (Yeşil 3).
Bileşen testinde güncelleme senaryosunu kontrol etmenin herhangi bir yolu yoktur, çünkü arka uçta bir değişikliği tetikleyecek böyle bir durumu kuramayız. Düşük düzeyde bileşen testleri ile bir testi kapsayamadığımız her durumda, ui-entegrasyon testlerine geçin. Çoğu zaman bir ui-entegrasyon testi yeterli olacak ve yeterli olmadığında arka ucu etkileyen gerçek bir e2e testi kullanabiliriz. Bizim durumumuzda, ui-entegrasyon tercih edilir, çünkü arka uç tarafından 500 yanıtı ile cevap vermenin zor olacağından. Ayrıca gerçek bir ağdan gelen yanıta ihtiyacımız yoktur. Bu nedenle, güncelleme senaryosunu kapsayan edit-hero.cy.ts e2e testine bir ui-entegrasyon testi ekleyebiliriz. Test türleri arasındaki sınırların daha ince olduğunu görüyoruz; en yüksek güveni elde etmek için en düşük maliyetli test türünü kullanırız. Piramitte nerede oldukları, yalnızca verilen bağlamda bu tür testi gerçekleştirme yeteneğiyle ilgilidir (Düzenleme 4).
Yeni test, diğer ui-entegrasyon testlerine benzerdir; ağı taklit ederiz ve ana rotayı ziyaret ederiz. Rastgele bir kahramanın düzenleme sayfasına gideriz. Güncelleme üzerinden gerçekleşecek olan ağ taklidini cy.intercept ile ayarlarız. Sonunda, bileşen testinden benzer bir işlemci -> ağı bekletme -> hata akışını tekrarlarız. Buradaki tek ayrım, PUT ve POST arasındadır.
Karşılaştırma için bileşen testiyle yan yana buradadır. Eylem ve İddia aynıdır, ağ taklidi POST ve PUT ile url'yi belirtme ihtiyacının daha az olmasıdır. Özellikle Arrange'ın kurulumu farklıdır.
İşte yeniden düzenlemenin ardından tam e2e testi.
Heroes bileşeni
Heroes bileşeniMutlu yol akışında cy.intercept kullanan diğer bileşen testi Heroes.cy.tsx'dir. /heroes rotasına bir GET çağrısını şu şekilde taklit etmektedir:
Varsayılan olarak, cy.intecept durum kodunu 200 olarak kabul eder. Durum kodu 200 değilse ne olur?
Heroes bileşeni, HeroDetail'i kullanmaktadır. Başlamadan önce, testi 2 bağlamda hafifçe yeniden düzenleyeceğiz; biri 200 akışları için ve
Yeni teste başlayalım. Ağı kurulumunu yapıyoruz, bileşeni yerleştiriyoruz ve bir hatayı görmeyi bekliyoruz.
Bileşen testini çalıştırıyoruz, hiçbir şey işlemez hale geliyor, Axios birkaç kez tekrar deniyor ve hata fırlatıyor (Kırmızı 5).

Heroes içinde HeroDetailde yapılan iyileştirmeyi yansıtabiliriz.
İşte Suspense ve ErrorBoundary ile Heroes bileşeni için yapılan geliştirme.
Yine de Axios yeniden denemeleri uzun sürüyor ve hiçbir şey işlemiyor. Ağ hatalarını cy.clock ve cy.tick kullanarak hızlandırabiliriz. Ayrıca Cypress'e yakalanmamış istisnaların beklendiğini Cypress.on('uncaught:exception', () => false) kullanarak söylüyoruz.
Bu değişiklikten sonra, kalan tek başarısızlık data-cy işlememesidir.

Bileşen testinin bağımsız, küçük ölçekli bir uygulama olduğunu unutmamalıyız. Uygulamamız temel düzeyde sarılıyor ve bununla birlikte ErrorBoundary ve Suspense, App altındaki her bileşene uygulanabiliyor. Bu nedenle, monte edilmiş bileşenimizi de sarmamız gerekiyor (Yeşil 5).
Yeni monte ile karşılaştırın:
Testimiz bununla çalışabilir, ancak büyük olasılıkla başka yerlerde de ayrıntılılık gerekecektir. Bunun yerine şöyle bir özel işlev kullanabiliriz:
Bunu, herhangi bir bileşende içe aktarmadan kullanabileceğimiz bir Cypress komutu olarak yapmak en iyisidir. App.cy.tsx dışındaki bileşen test süitindeki çoğu cy.mountı değiştirebiliriz. Özel montaj gerekmeyen durumlar bile olsa, ek sargılar zarar vermez. ./cypress/support/component.ts dosyasını tsx dosyasına değiştirin. Komut sürümündeki wrappedMount ile cy.mountı daha iyi hizalıyoruz.
cypress.d.ts. dosyasına tanımı ekleyin.
İşte cy.wrappedMount ile yapılan testin nihai sürümü. Hata öncesinde dönen çarkı kontrol etmeyi de ekledik (Yeniden Düzenleme 5). İsteğe bağlı olarak cy.wrappedMount düzenlemesini bazı bileşen testlerine uygulayabilirsiniz:
src/components/Heroes.cy.tsxsrc/components/HeroList.cy.tsxsrc/components/HeroDetail.cy.tsxKullanışlı olmasa da hâlâ mümkün (sadece
BrowserRouter'ı kılıf olarak kullanırlar):src/components/HeaderBar.cy.tsxsrc/components/HeaderBarBrand.cy.tsxsrc/components/ListHeader.cy.tsxsrc/components/NavBar.cy.tsx
RTL testlerini güncelleme
RTL'de başlangıçta dönen çarkı ele almak biraz farklıdır. Asenkron olarak beklemek için act kullanmamız gerekiyor. İşte güncellenmiş birim testi:
RTL'deki cy.wrappedMount'ı yansıtmak için, src/test-utils.tsx'de özel bir render oluşturun. Bu dosya ayrıca '@testing-library/react'i dışa aktarır, böylece wrappedRender'ı kullanıyorsak buradan screen, userEvent, waitFor'i içe aktarabiliriz. Bileşen testlerine benzer şekilde, wrappedRender heroes klasöründeki 3 bileşende en yararlı olanıdır.
HeroList.test.tsx, HeroList.cy.tsx'in RTL yansımasıdır.
msw ile - RTL kullanımı için cy.intercept düşünün - uygulamadan çıkan XHR çağrılarını doğrulamak önerilmez. Bunun yerine, kullanıcı arayüzündeki değişiklikleri doğrulamak önerilir. Ne yazık ki, bazen bileşende kendisinde değişiklik olmaz, bu nedenle her Cypress bileşen testini RTL ile 1:1 yansıtamayız. İşte HeroDetail.cy.tsx'in RTL yansıması.
Alternatif olarak,
react-querykancalarını takip etmeyi ve çağrıldıklarını doğrulamayı düşünebiliriz. Bu, çoğu geliştiricinin alışkın olduğu şey olsa da, durum yönetimi yaklaşımımızda yapılan değişiklikler testlerin başarısız olmasına neden olacağı için uygulama ayrıntısıdır.
Heroes.test.tsx, Heroes.cy.tsx'in RTL yansımasıdır.
Özet
Bu bölümde kullanılacak yeni bileşenler ekledik.
Kahraman arama / filtreleme özelliği için yeni bir test ekledik (Kırmızı 1).
HeroList bileşenine uygulamayı ekledik ve CT veya e2e regresyonlarının olmadığından emin olduk (Yeşil 1).
Bileşeni, üzerinde kontrol sahibi olduğumuz kodu (setFilteredHeroes) sarmak için useTransition ve üzerinde kontrol sahibi olmadığımız değeri sarmak için (heroes değeri prop olarak geçirilir) useDeferredValue ile geliştirdik (Yeniden düzenleme 1).
Arama-filtreleme için koşullu render ekledik (Kırmızı 2, Yeşil 2)
Uygulamayı Suspense ve ErrorBoundary için yapılandırdık
HeroDetail bileşeni için 200 olmayan / ağ hatası kenar durumu yazdık. Bu, cy.intercept gecikme seçeneğini kullanarak Suspense kodunu da vurur (Kırmızı 3, Kırmızı 4).
HeroDetail'e, POST isteğiyle meydana gelebilecek yükleme ve hata koşulları için koşullu render ekledik (Yeşil 3, Yeşil 4)
PUT isteği yükleme ve hata koşulunu kapsamak için, gerçek bir ağdan 500 yanıtı almak zorunda olmamasına rağmen arka uç değişikliği tetikleyebilecek bir durumun farkında olan bir ui-entegrasyon testi kullandık (Yeniden düzenleme 4)
HeroDetail'in üst bileşeni olan Heroes bileşeni için 200 olmayan / ağ hatası kenar durumu yazdık. Verileri almak için GET isteğini kullanır (Kırmızı 5).
Bileşen testini monte etmeyi, kök uygulamanın ErrorBoundary ve Suspense ile sarılma şeklinde gerçekleştirdik. cy.clock, cy.tick'i kullanarak ve beklenen hata atılırken test başarısızlığını kapatarak avantaj sağladık (Yeşil 5).
Dönen çarkı kontrol etmek için bileşen testini geliştirdik. POST isteği hata durumuna benzer şekilde, gerçek bir ağdan 500 yanıtı almak zorunda olmamasına rağmen arka uç değişikliği tetikleyebilecek bir durumun farkında olan bir ui-entegrasyon testinde DELETE için ağ hatası durumunu kapsadık (Yeniden düzenleme 5).
RTL birim testini Suspense ile çalışacak şekilde değiştirdik.
Çıkarılacak Dersler
Büyük özellikler eklerken, regresyon olmadığından emin olmak için CT ve e2e test süitlerini çalıştırmak önemlidir. Küçük artımlı adımlar ve güvenilir testler, hata teşhisini kolaylaştırır.
"Kırılgan" olarak ünleri olsa da, iyi yazılmış, kararlı e2e veya ui-entegrasyon testlerinin yüksek hata bulma yeteneği vardır ve izole bileşenlerde ya da birim testlerde fark edilmeyen hataları yakalar.
Eşzamanlı olarak birden fazla durum güncellemesi gerçekleşirken, Concurrency (Eşzamanlılık), UI yanıt verme hızını optimize etmek amacıyla bazı durum güncellemelerinin diğerlerine göre daha düşük önceliğe sahip olmasını ifade eder.
useTransitionveuseDeferredValue, daha düşük öncelikli olanı belirtmek için kullanılabilir. Durum güncelleme koduna erişiminiz varsa,useTransition'ı tercih edin ve kodu onunla sarın. Kod erişiminiz yoksa, ancak son değere erişiminiz varsa, değeri sarmak içinuseDeferredValuekullanın.Suspenseilelazyyükleme, başlangıç uygulama paketini kod bölme amacıyla kullanılır ve UI yanıt verme hızını artırır.ErrorBoundaryile birlikte, yükleme ve hata UI'sini bireysel bileşenlerden ayırırlar. Yükleme sırasındaSuspensebileşenini gösterin, hata durumundaErrorBoundarybileşenini gösterin, başarı durumunda render etmek istediğimiz bileşeni gösterin.Hata durumları için test yazmaya başlarken, ağ üzerinde casusluk etmek veya
cy.intercept()ile ağı taklit etmek amacıyla pozitif akışları kapsayan herhangi bir test, başlamak için iyi bir adaydır. Bileşen düzeyinde başlayın ve daha fazla test mümkün olmadığında ui-entegrasyona geçin.Bir bileşen testi ile düşük düzeyde bir testi kapsayamadığımız her zaman, ui-entegrasyon testlerine geçin. Çoğu zaman bir ui-entegrasyon testi yeterli olacak ve yeterli olmadığında, arka ucu etkileyen gerçek bir e2e kullanabiliriz. En yüksek güveni elde etmek için en düşük maliyetli test türünü kullanın; piramitte nerede oldukları, yalnızca verilen bağlamda o tür testi gerçekleştirme yeteneğiyle ilgilidir.
Bir bileşen testinin bağımsız, küçük ölçekli bir uygulama olduğunu unutmayın. Temel
Appbileşenini saran ne varsa, bir bileşen testi montajını da sarması gerekebilir (Providers,ErrorBoundary,Suspense,Routervb.).
Last updated