React Test and Optimization(feat. Web Vitals)
π¦ μ‘λμ¬λ
νλμ ν€μλλ₯Ό μ‘κ³ μ’ νΈνκ² μ 리νκ³ μΆμ΄ λ§λ μ‘λμ¬λ
μ‘λμ¬λλ μ‘°μ νκΈ° νμ
μμ 볡
μ΄ νΈμ°¬νμ‘λμ°μ΄(ιεζ£η°)
μμ μ λλ λ§μ΄λ€.
μ‘λμ°μ΄λμ‘κΈ°(ιθ¨)
μ ννλ₯Ό λΉλ €μ¨ μ± μΌλ‘ ꡬ체μ μΈ μ²΄κ³κ° μ‘νμμ§ μμ νμμ΄λ€.
νλͺ©μ΄ λ€μ λμ‘νκ³ λ΄μ©μ ꡬλΆμ΄ νΌλλμ΄μλ€κ³ νλ€. π€£
λ€μ΄κ°κΈ°μ μμ
μ΄ κΈμ μν°λμμ μ£Όκ΄νλ ν리μ¨λ³΄λ© νλ‘ νΈμλ μ±λ¦°μ§ 8μ - 리μ‘νΈ λ¦¬ν©ν λ§ μ€μ κ°μ΄λ: ν μ€νΈλΆν° μ΅μ νκΉμ§ μ μ μΆν μ¬μ κ³Όμ λ₯Ό κΈ°λ°μΌλ‘ μμ±ν κΈμ λλ€.
ποΈ 1) ν μ€νΈ
1-1) μ λν μ€νΈ vs ν΅ν©ν μ€νΈ vs E2Eν μ€νΈλ₯Ό λΉκ΅νμ¬ μ€λͺ ν΄μ£ΌμΈμ
μ λν μ€νΈ
- μ€ν κ°λ₯ν κ°μ₯ μμ λ¨μμ μννΈμ¨μ΄(μ£Όλ‘
ν¨μ
)λ₯Ό ν μ€νΈ - μΌλ°μ μΌλ‘ ν¨μ, classμ method λ¨μλ‘ μ§ννλ€.
- κ°μ₯ μμ λ¨μλ₯Ό ν μ€νΈνλλ§νΌ μ’λ μ§κ΄μ μ΄κ³ λΉ λ₯Έ ν μ€νΈκ° κ°λ₯νλ€.
- μ¬μ€μ ν μ€νΈμ κΈ°λ³Έμ΄λΌκ³ ν μ μλ€.
- JS μ§μμμλ μ£Όλ‘
Jest
λ₯Ό μ¬μ©νλ€.
// sum.test.js
const sum = (a, b) => a + b;
describe('λνκΈ°', () => {
it('1κ³Ό 2λ₯Ό λνλ©΄ 3μ΄ λ°νλλ€.', () => {
expect(sum(1, 2)).toBe(3);
});
});
ν΅ν©ν μ€νΈ
- μ λν μ€νΈλ³΄λ€λ ν° λ¨μμ μννΈμ¨μ΄λ₯Ό ν μ€νΈ
- κ°λ°μκ° λ³κ²½ν μ μλ μΈλΆ μμ‘΄μ±μ κ°μ§ λͺ¨λμ ν
μ€νΈν λ μ¬μ©νλ€.
- ex) DBμ μ κ·Όνλ κ², λ€λ₯Έ λͺ¨λμ import νλ κ², μΈλΆ APIλ₯Ό νΈμΆνλ κ² λ±
- ν μ€νΈμ λ²μκ° λμ΄μ§κΈ° λλ¬Έμ μ λν μ€νΈλ³΄λ€ μλ¬ κ²μΆμ΄ μ΄λ ΅λ€.
- μ¬μ€μ μ λν μ€νΈμ νμ₯νμ΄λΌκ³ ν μ μλ€.
- JS μ§μμμλ μ£Όλ‘
Jest
λ₯Ό μ¬μ©νλ€.
// sum.test.js
import sum from './sum'; // μΈλΆμ λΌμ΄λΈλ¬λ¦¬μμ κ°μ Έμ¨ ν¨μλΌκ³ μκ°νμ
describe('λνκΈ°', () => {
it('1κ³Ό 2λ₯Ό λνλ©΄ 3μ΄ λ°νλλ€.', () => {
expect(sum(1, 2)).toBe(3);
});
});
E2Eν μ€νΈ
- End to End ν μ€νΈμ μ½μλ‘, μ¬μ©μμ μμ μμ ν μ€νΈλ₯Ό μ§ννλ€.
- μννΈμ¨μ΄μ λ΄λΆ μ½λ ꡬ쑰λ₯Ό ν μ€νΈνκΈ°λ³΄λ¨ λΉμ¦λμ€μͺ½μ μ΄μ μ λκ³ μ¬μ©μκ° μ¬μ©νλ κ΄μ μμ λμμ΄ μ λλμ§λ₯Ό ν μ€νΈνλ€.
- Acceptance Test(μΈμ ν μ€νΈ), UI TestλΌκ³ λ λΆλ¦°λ€.
- JS μ§μμμλ μ£Όλ‘
Cypress
λ₯Ό μ¬μ©νλ€.
// sum.spec.js
describe('λνκΈ°', () => {
it('1κ³Ό 2λ₯Ό λνλ©΄ 3μ΄ λ°νλλ€.', () => {
cy.visit('http://localhost:3000');
cy.get('input[name="a"]').type('1');
cy.get('input[name="b"]').type('2');
cy.get('button[type="submit"]').click();
cy.get('div[name="result"]').should('have.text', '3');
});
});
1-2) 리μ‘νΈ ν μ€νΈμ μ¬μ©λλ λꡬλ€μ λΉκ΅νμ¬ μ€λͺ ν΄μ£ΌμΈμ
ν μ€νΈλ₯Ό μ§ννλ€λ κ²μ
ν μ€νΈλ₯Ό μ§ννλ λ°©λ²μ ν¬κ² 2κ°μ§κ° μλ€.
- HTML νμ΄μ§λ₯Ό λ§λ€κ³ JS ν μ€νΈ μ½λλ₯Ό μμ±νμ¬ λΈλΌμ°μ μμ μ§μ ν μ€νΈλ₯Ό μ§ννλ λ°©λ²
- Headless λΈλΌμ°μ λ₯Ό μ¬μ©νμ¬ λΈλΌμ°μ λ₯Ό λμ°μ§ μκ³ ν
μ€νΈλ₯Ό μ§ννλ λ°©λ²
- Headless λΈλΌμ°μ : λΈλΌμ°μ μ νλ©΄μ λμ°μ§ μκ³ λΈλΌμ°μ μ κΈ°λ₯μ μ¬μ©ν μ μλ λΈλΌμ°μ (μ£Όλ‘ λΈλΌμ°μ μ Headless modeλ₯Ό μ¬μ©νλ€.)
- μ°λ¦¬κ° μΌλ°μ μΌλ‘ μ¬μ©νλ ν¬λ‘¬, νμ΄μ΄νμ€ λ±μ λΈλΌμ°μ λ Headful λΈλΌμ°μ λΌκ³ νλ€.
- λΈλΌμ°μ κ° μλ Node.js νκ²½μμ ν
μ€νΈλ₯Ό μ§ννλ λ°©λ² => λΉμ°ν μ§μ λ λλ§μ ν μλ μκ³ jsdomκ³Ό κ°μ κ°μ DOM(νΉμ κ°μ λΈλΌμ°μ )λ₯Ό μ¬μ©νλ€.
- μ΄ λ, λΈλΌμ°μ μ Headless modeμλ λ€λ₯΄λ€. Headless modeλ μ€μ λΈλΌμ°μ λ₯Ό μ¬μ©νμ§λ§ λΈλΌμ°μ μ νλ©΄μ λμ°μ§ μλ κ²μ΄λ€.
3λ²μ λ°©λ²μ μΆμ²νλ€. λν, μΌλ°μ μΌλ‘ 3λ²μ λ°©λ²μ΄ μμ£Ό μ¬μ©λλ€.
ν μ€ν ν΄ in JS
ν μ€ν ν΄λ€μ μ’ λ₯λ λ§€μ° λ§λ€. νλμ κΈ°λ₯λ§μ μ 곡νλ κ²λ€λΆν° μ¬λ¬ κΈ°λ₯μ μ‘°ν©ν΄μ μ 곡νλ κ²λ€κΉμ§ λ§μ΄λ€. 보ν΅μ νμμ ν μ€ν ν΄μ μ¬μ©νλ€.
ποΈ μ΅μ ν
CDN(Content Distributed Network)μ λν΄ μ€λͺ ν΄μ£ΌμΈμ
- μ μΈκ³ μ¬λ¬ μ§μμ λΆμ°λ μλ² λ€νΈμν¬λ‘ μ μ μκ² μΉμ¬μ΄νΈ μ½ν μΈ λ₯Ό ν¨μ¨μ μ΄κ³ λΉ λ₯΄κ² μ λ¬νλ μν μ νλ€.
- μΉμ¬μ΄νΈμ νΈλν½μ μ²λ¦¬νκ³ λ°μ΄ν° λ‘λ© μκ°μ μ΅μννκΈ° μν΄ μλ²λ€μ΄ μ¬λ¬ κ³³μ λΆμ° λ°°μΉλμ΄ μλ€.
- μΌλ°μ μΌλ‘ μ μ κ° μΉμ¬μ΄νΈμ μμΈμ€νλ €λ©΄ ν΄λΉ μΉμ¬μ΄νΈμ μ격 νΈμ€νΈ μλ²λ‘λΆν° μ 보λ₯Ό κ°μ ΈμμΌνλλ°, κ±°λ¦¬κ° λ©μλ‘ λ λ§μ μκ°μ΄ μλͺ¨λλ€.
- CDNμ μΉμ¬μ΄νΈμ μ½ν
μΈ λ₯Ό μ¬λ¬ μ§μμ μμΉν μ¬λ¬ μλ²μ 볡μ νμ¬, μ μ κ° μΉμ¬μ΄νΈμ μ μν λ κ°μ₯ κ°κΉμ΄ μλ²μμ μ½ν
μΈ λ₯Ό μ 곡νλ€.
- μ μ‘ μκ°μ΄ μ€μ΄λ λ€.
- μΉμ¬μ΄νΈμ λ‘λ© μκ°μ΄ λ¨μΆλλ€.
- νΈλν½μ΄ λΆμ°λμ΄ μ격 νΈμ€νΈ μλ²μ λΆνλ₯Ό μ€μΌ μ μλ€.
Web Vitalsμ λν΄ μ€λͺ ν΄μ£ΌμΈμ
- UX(μ¬μ©μ κ²½ν)λ₯Ό νκ°νκ³ κ°μ νκΈ° μν΄ μ¬μ©λλ μΉ μ±λ₯ μΈ‘μ μ§ν
- Googleμμ μ 곡νλ Web Vitalsλ μΉ νμ΄μ§μ λ‘λ© μλ, μνΈμμ© κ°λ₯μ±, μκ°μ μμ μ± λ±μ μΈ‘μ νμ¬ μΉ νμ΄μ§μ νμ§μ νκ°νκ³ κ°μ νλ λ° λμμ μ€λ€.
ν¬κ² 3κ°μ§ μ§νκ° μλ€.
Largest Contentful Paint(LCP)
- μ μ κ° μΉ νμ΄μ§λ₯Ό μ²μμΌλ‘ λ³Ό λ
κ°μ₯ ν° μ½ν μΈ μμκ° νλ©΄μ νμλλ μκ°
- μΌλ°μ μΌλ‘ μ΄λ―Έμ§λ ν μ€νΈ λΈλ‘κ³Ό κ°μ λν μμκ° κ°μ₯ ν° μ½ν μΈ κ° λλ€.
- μ’μ UXλ₯Ό μν΄μλ LCPκ° μΉ νμ΄μ§μ λ‘λ© μκ° λ΄μ λ°μν΄μΌ νλ©°, 2.5μ΄ μ΄λ΄λ‘ μλ£λλ κ²μ΄ κΆμ₯λλ€.
First Input Delay(FID)
- μΉ νμ΄μ§κ° λ‘λ©λ ν, μ μ μ 첫 λ²μ§Έ μνΈμμ©(ν΄λ¦, ν°μΉ λ±)κ³Ό μ€μ λ‘ λΈλΌμ°μ κ° ν΄λΉ μνΈμμ©μ μλ΅νλ μκ°
- μΉ νμ΄μ§κ° μΌλ§λ λΉ λ₯΄κ² λννμΌλ‘ μλνλμ§ λνλ΄λ©°, μ μ κ° νμ΄μ§μ μνΈμμ©νκΈ°κΉμ§ λλΌλ μ§μ° μκ°μ νκ°νλ€.
- μ’μ UXλ₯Ό μν΄μλ FIDκ° 100ms λ―Έλ§μ΄ λλλ‘ μ΅μ ννλ κ²μ΄ κΆμ₯λλ€.
Cumulative Layout Shift(CLS)
- μΉ νμ΄μ§μ λ‘λ©λ λμ μ½ν μΈ μ λ μ΄μμ λ³νμ λ°λ₯Έ μκ°μ μμ μ±μ μΈ‘μ νλ€.
- μ μ κ° λ²νΌμ ν΄λ¦νκ±°λ μ΄λ―Έμ§κ° λμ μΌλ‘ λ‘λλλ κ²½μ° νμ΄μ§μ λ μ΄μμμ΄ λ³κ²½λ μ μλ€. μ΄ λ, λ μ΄μμμ λ³νκ° μ¬μ©μ κ²½νμ λΆμ μ μΈ μν₯μ λ―ΈμΉμ§ μλλ‘ μ΅μ ννλ κ²μ΄ μ€μνλ€.
- μ’μ UXλ₯Ό μν΄μλ CLSκ° 0.1 λ―Έλ§μ΄ λλλ‘ μ΅μ ννλ κ²μ΄ κΆμ₯λλ€.
- CLSμ λν μ μ μ°μΆ λ°©λ²μ CLS μ μ μ°μΆ λ°©λ²μ μ°Έκ³ νμ!
- μ λ§ λ¨μνκ² λ§νλ©΄
λ μ΄μμ λ³νκ° μΌμ΄λ λλ§λ€ λ³νλ μμμ ν¬κΈ°μ μμΉλ₯Ό κ³±ν κ°
μ λͺ¨λ λν κ²μ΄λ€.
Web Vitalsλ μΉ νμ΄μ§ μ±λ₯ μΈ‘μ μ μν΄ Chrome λΈλΌμ°μ μ λ€λ₯Έ μ±λ₯ μΈ‘μ λꡬλ€μμ μ¬μ©ν μ μλ€. Google Search Consoleμμ μΉ νμ΄μ§μ Web Vitals λ°μ΄ν°λ₯Ό νμΈνκ³ κ°μ λ°©μμ μ μν΄ μ€λλ€. μ΄λ¬ν μΈ‘μ μ§νλ₯Ό λ°νμΌλ‘ μΉ κ°λ°μλ€μ μ¬μ©μ κ²½νμ ν₯μμν€κ³ μΉ νμ΄μ§μ μ±λ₯μ μ΅μ ννλ μμ μ μνν μ μμ΅λλ€.
Lighthouseμ λν΄ μ€λͺ ν΄μ£ΌμΈμ
- Lighthouseλ Googleμμ κ°λ°ν μ€ν μμ€λ‘, μλνλ μΉ νμ΄μ§ μ±λ₯ μΈ‘μ λꡬ
- μΉ νμ΄μ§μ μ±λ₯κ³Ό νμ§μ νκ°νκΈ° μν΄ λ€μν μΈ‘μ νλͺ©λ€μ μ€ννκ³ UXλ₯Ό κ°μ νλ λ° λμμ΄ λλ νΌλλ°±κ³Ό κΆμ₯ μ¬νμ μ 곡νλ€.
- Lighthouseλ Chrome λΈλΌμ°μ μ DevToolsμ ν¬ν¨λμ΄ μμΌλ©°, 컀맨λ λΌμΈμμλ μ€νν μ μλ€.
- μ±λ₯ μ§ν:
- First Contentful Paint(FCP): μΉ νμ΄μ§κ° λ‘λ©λ ν 첫 λ²μ§Έ μ½ν μΈ κ° νλ©΄μ νμλλ μκ°μ μΈ‘μ νλ€.
- Largest Contentful Paint(LCP): μΉ νμ΄μ§μμ κ°μ₯ ν° μ½ν μΈ μμκ° νλ©΄μ νμλλ μκ°μ μΈ‘μ νλ€. Web Vitalsμ νλλ‘λ μ¬μ©λλ€.
- Speed Index(SI): μΉ νμ΄μ§μ λ‘λ© κ³Όμ μμ μΌλ§λ 빨리 μ½ν μΈ κ° νμλλμ§μ λν μΈ‘μ μ§νμ λλ€.
- Time to Interactive(TTI): μΉ νμ΄μ§κ° λ‘λ©λ ν μνΈμμ© κ°λ₯ν μνκ° λλ μκ°μ μΈ‘μ νλ€.
- Total Blocking Time(TBT): μΉ νμ΄μ§κ° λ‘λ©λ ν μ¬μ©μμ μνΈμμ©κ³Ό λΈλΌμ°μ μ μλ΅ μ¬μ΄μ μ§μ° μκ°μ μΈ‘μ νλ€. Web Vitalsμ νλλ‘λ μ¬μ©λλ€.
- Cumulative Layout Shift(CLS): μΉ νμ΄μ§μ λ‘λ© μ€ λ°μνλ μ½ν μΈ μ μκ°μ μμ μ±μ μΈ‘μ νλ€. Web Vitalsμ νλλ‘λ μ¬μ©λλ€.
- νμ§ μΈ‘μ νλͺ©:
- Accessibility(μ κ·Όμ±): μΉ νμ΄μ§κ° μ κ·Όμ± μ§μΉ¨μ λ°λ₯΄κ³ μλμ§λ₯Ό νκ°νλ€.
- Best Practices(λͺ¨λ² μ¬λ‘): μΉ νμ΄μ§κ° λͺ¨λ² μ¬λ‘λ₯Ό λ°λ₯΄κ³ μλμ§λ₯Ό νκ°νλ€.
- SEO(κ²μ μμ§ μ΅μ ν): μΉ νμ΄μ§μ κ²μ μμ§ μ΅μ ν μνλ₯Ό νκ°νλ€.
- Progressive Web App(PWA; μ μ§μ μΉ μ±): μΉ νμ΄μ§κ° μ μ§μ μΉ μ±μΌλ‘μμ 쑰건μ μΆ©μ‘±νλμ§λ₯Ό νκ°νλ€.
Lighthouseλ μ΄λ¬ν μ±λ₯ μ§νμ νμ§ μΈ‘μ νλͺ©λ€μ μ¬μ©νμ¬ μΉ νμ΄μ§μ μ λ°μ μΈ νμ§μ νκ°νκ³ , κ°λ°μλ€μ΄ μ¬μ©μ κ²½νμ ν₯μμν€κΈ° μν΄ μ΄λ€ λΆλΆμ κ°μ ν΄μΌ νλμ§μ λν μ 보λ₯Ό μ 곡νλ€. λν, Lighthouse κ²°κ³Ό λ³΄κ³ μλ μΉ κ°λ°μλ€μ΄ μ±λ₯ μ΅μ ν μμ μ μΆμ νκ³ κ²μ¦νλ λ°λ μ μ©νκ² νμ©λ μ μλ€.
μ°Έκ³
- 벨λ‘νΌνΈμ ν¨κ»νλ 리μ‘νΈ ν μ€ν
- Unit test, Integration test, e2e test κ·Έλ¦¬κ³ TDD
- An Overview of JavaScript Testing in 2019
- An Overview of JavaScript Testing in 2022
- Web Vitals
- CLS μ μ μ°μΆ λ°©λ²