راهنمای جامع سایپرس، فریمورک قدرتمند تست end-to-end، شامل نصب، نوشتن تست، دیباگینگ، یکپارچهسازی با CI/CD و بهترین شیوهها.
سایپرس: راهنمای جامع تست End-to-End برای اپلیکیشنهای وب
در چشمانداز توسعه وب که به سرعت در حال تحول است، تضمین کیفیت و قابلیت اطمینان اپلیکیشنهای وب از اهمیت بالایی برخوردار است. تست End-to-End (E2E) نقشی حیاتی در تأیید اینکه تمام اجزای یک اپلیکیشن از دیدگاه کاربر به طور یکپارچه با هم کار میکنند، ایفا میکند. سایپرس به عنوان یک فریمورک پیشرو در تست E2E ظهور کرده است که تجربهای کاربرپسند برای توسعهدهندگان، ویژگیهای قدرتمند و عملکرد عالی ارائه میدهد. این راهنمای جامع شما را با هر آنچه برای شروع کار با سایپرس و تست مؤثر اپلیکیشنهای وب خود نیاز دارید، آشنا میکند.
سایپرس چیست؟
سایپرس یک ابزار تست فرانتاند نسل جدید است که برای وب مدرن ساخته شده است. برخلاف فریمورکهای تست سنتی که تستها را در یک مرورگر اجرا میکنند، سایپرس مستقیماً در مرورگر عمل میکند و به شما کنترل و دید بینظیری بر رفتار اپلیکیشنتان میدهد. این ابزار طوری طراحی شده که سریع، قابل اعتماد و آسان برای استفاده باشد، و همین امر آن را به انتخابی محبوب در میان توسعهدهندگان و مهندسان تضمین کیفیت در سراسر جهان تبدیل کرده است. سایپرس با جاوا اسکریپت نوشته شده و در داخل مرورگر اجرا میشود، که آن را بسیار کارآمد کرده و دسترسی بینظیری به اجزای داخلی اپلیکیشن فراهم میکند.
مزایای کلیدی استفاده از سایپرس
- کاربرپسند برای توسعهدهندگان: سایپرس یک API تمیز و شهودی ارائه میدهد که نوشتن و دیباگ کردن تستها را آسان میکند.
- سفر در زمان: سایپرس در طول هر دستور تست، از وضعیت اپلیکیشن شما اسنپشات میگیرد و به شما این امکان را میدهد که در زمان به عقب برگردید و ببینید دقیقاً در هر نقطه چه اتفاقی افتاده است.
- بارگذاری مجدد لحظهای: سایپرس با ایجاد تغییرات در تستهای شما به طور خودکار بارگذاری مجدد میشود و بازخورد فوری ارائه میدهد.
- انتظار خودکار: سایپرس به طور خودکار منتظر میماند تا عناصر قابل مشاهده یا تعامل شوند قبل از انجام اقدامات، که نیاز به انتظارهای صریح را از بین میبرد.
- کنترل شبکه: سایپرس به شما امکان میدهد درخواستها و پاسخهای شبکه را شبیهسازی (stub) کنید، که به شما امکان میدهد سناریوهای مختلف را شبیهسازی کرده و مدیریت خطای اپلیکیشن خود را تست کنید.
- قابلیت دیباگ بالا: سایپرس ابزارهای دیباگینگ عالی، از جمله یک دیباگر قدرتمند و پیامهای خطای دقیق ارائه میدهد.
- تست بین مرورگری: سایپرس از چندین مرورگر از جمله کروم، فایرفاکس، اج و الکترون پشتیبانی میکند.
- تست Headless: تستها را در حالت headless برای اجرای سریعتر در محیطهای CI/CD اجرا کنید.
- Assertions داخلی: سایپرس مجموعه غنی از assertions داخلی برای تأیید رفتار مورد انتظار اپلیکیشن شما فراهم میکند.
نصب و راهاندازی
شروع کار با سایپرس ساده است. در اینجا نحوه نصب آن آمده است:
- پیشنیازها: اطمینان حاصل کنید که Node.js و npm (مدیر بسته نود) روی سیستم شما نصب شده باشند. میتوانید آنها را از وبسایت رسمی Node.js دانلود کنید.
- نصب سایپرس: ترمینال یا خط فرمان خود را باز کنید، به دایرکتوری پروژه خود بروید و دستور زیر را اجرا کنید:
- باز کردن سایپرس: پس از اتمام نصب، میتوانید Cypress Test Runner را با اجرای دستور زیر باز کنید:
npm install cypress --save-dev
npx cypress open
این دستور Cypress Test Runner را راهاندازی میکند، که یک رابط گرافیکی برای اجرا و دیباگ کردن تستهای شما فراهم میکند.
نوشتن اولین تست سایپرس
بیایید یک تست ساده برای تأیید اینکه صفحه اصلی یک وبسایت به درستی بارگذاری میشود، ایجاد کنیم. یک فایل جدید به نام `example.cy.js` در دایرکتوری `cypress/e2e` پروژه خود ایجاد کنید.
// cypress/e2e/example.cy.js
describe('اولین تست من', () => {
it('از Kitchen Sink بازدید میکند', () => {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
cy.url().should('include', '/commands/actions')
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
بیایید این تست را تحلیل کنیم:
- `describe()`: یک مجموعه تست (test suite) را تعریف میکند که مجموعهای از تستهای مرتبط است.
- `it()`: یک مورد تست (test case) جداگانه را در داخل مجموعه تست تعریف میکند.
- `cy.visit()`: به URL مشخص شده میرود.
- `cy.contains()`: عنصری را که حاوی متن مشخص شده است پیدا میکند.
- `.click()`: روی عنصر انتخاب شده کلیک میکند.
- `cy.url()`: URL فعلی صفحه را دریافت میکند.
- `.should()`: یک ادعا (assertion) در مورد وضعیت اپلیکیشن ایجاد میکند.
- `cy.get()`: یک عنصر را با استفاده از یک انتخابگر CSS انتخاب میکند.
- `.type()`: متنی را در عنصر انتخاب شده تایپ میکند.
- `.should('have.value', 'fake@email.com')`: ادعا میکند که مقدار عنصر برابر با 'fake@email.com' است.
این تست را در Cypress Test Runner اجرا کنید تا عملکرد آن را ببینید. باید ببینید که مرورگر به وبسایت Cypress Kitchen Sink میرود، روی لینک "type" کلیک میکند و URL را تأیید میکند.
دستورات سایپرس
سایپرس طیف گستردهای از دستورات را برای تعامل با اپلیکیشن شما فراهم میکند. در اینجا برخی از رایجترین دستورات مورد استفاده آورده شده است:
- `cy.visit(url)`: به URL مشخص شده میرود.
- `cy.get(selector)`: یک عنصر را با استفاده از یک انتخابگر CSS انتخاب میکند.
- `cy.contains(content)`: عنصری را که حاوی متن مشخص شده است انتخاب میکند.
- `cy.click()`: روی عنصر انتخاب شده کلیک میکند.
- `cy.type(text)`: متنی را در عنصر انتخاب شده تایپ میکند.
- `cy.clear()`: محتویات یک عنصر input یا textarea را پاک میکند.
- `cy.submit()`: یک فرم را ارسال میکند.
- `cy.check()`: یک چکباکس یا دکمه رادیویی را علامت میزند.
- `cy.uncheck()`: علامت یک چکباکس را برمیدارد.
- `cy.select(value)`: یک گزینه از یک منوی کشویی انتخاب میکند.
- `cy.scrollTo(position)`: صفحه را به موقعیت مشخص شده اسکرول میکند.
- `cy.trigger(event)`: یک رویداد DOM را روی عنصر انتخاب شده فعال میکند.
- `cy.request(url, options)`: یک درخواست HTTP به URL مشخص شده ارسال میکند.
- `cy.intercept(route, handler)`: درخواستهای HTTP مطابق با مسیر مشخص شده را رهگیری میکند.
- `cy.wait(time)`: برای مدت زمان مشخصی منتظر میماند.
- `cy.reload()`: صفحه فعلی را دوباره بارگذاری میکند.
- `cy.go(direction)`: به صفحه قبلی یا بعدی در تاریخچه مرورگر میرود.
- `cy.url()`: URL فعلی صفحه را دریافت میکند.
- `cy.title()`: عنوان صفحه را دریافت میکند.
- `cy.window()`: آبجکت window را دریافت میکند.
- `cy.document()`: آبجکت document را دریافت میکند.
- `cy.viewport(width, height)`: اندازه viewport را تنظیم میکند.
اینها تنها تعدادی از دستورات متعدد موجود در سایپرس هستند. برای لیست کامل دستورات و گزینههای آنها به مستندات سایپرس مراجعه کنید.
Assertions در سایپرس
Assertions برای تأیید رفتار مورد انتظار اپلیکیشن شما استفاده میشوند. سایپرس مجموعه غنی از assertions داخلی را فراهم میکند که میتوانید برای بررسی وضعیت عناصر، URL، عنوان و موارد دیگر از آنها استفاده کنید. Assertions پس از دستورات سایپرس با استفاده از متد `.should()` زنجیر میشوند.
در اینجا چند نمونه از assertionهای رایج آورده شده است:
- `.should('be.visible')`: ادعا میکند که یک عنصر قابل مشاهده است.
- `.should('not.be.visible')`: ادعا میکند که یک عنصر قابل مشاهده نیست.
- `.should('be.enabled')`: ادعا میکند که یک عنصر فعال است.
- `.should('be.disabled')`: ادعا میکند که یک عنصر غیرفعال است.
- `.should('have.text', 'expected text')`: ادعا میکند که یک عنصر متن مشخص شده را دارد.
- `.should('contain', 'expected text')`: ادعا میکند که یک عنصر حاوی متن مشخص شده است.
- `.should('have.value', 'expected value')`: ادعا میکند که یک عنصر مقدار مشخص شده را دارد.
- `.should('have.class', 'expected class')`: ادعا میکند که یک عنصر کلاس مشخص شده را دارد.
- `.should('have.attr', 'attribute name', 'expected value')`: ادعا میکند که یک عنصر ویژگی و مقدار مشخص شده را دارد.
- `.should('have.css', 'css property', 'expected value')`: ادعا میکند که یک عنصر خاصیت CSS و مقدار مشخص شده را دارد.
- `.should('have.length', expected length)`: ادعا میکند که یک عنصر طول مشخصی دارد (به عنوان مثال، تعداد عناصر در یک لیست).
شما همچنین میتوانید assertionهای سفارشی برای نیازهای خاص خود ایجاد کنید.
بهترین شیوهها برای نوشتن تستهای سایپرس
پیروی از بهترین شیوهها میتواند به شما در نوشتن تستهای سایپرس قابل نگهداریتر، قابل اعتمادتر و کارآمدتر کمک کند. در اینجا چند توصیه آورده شده است:
- تستهای واضح و مختصر بنویسید: هر تست باید بر روی یک عملکرد یا سناریوی خاص تمرکز کند. از نوشتن تستهای بیش از حد پیچیده که درک و نگهداری آنها دشوار است، خودداری کنید.
- از نامهای تست معنادار استفاده کنید: به تستهای خود نامهای توصیفی بدهید که به وضوح نشان میدهد چه چیزی را تست میکنند.
- از کدگذاری سخت مقادیر خودداری کنید: از متغیرها یا فایلهای پیکربندی برای ذخیره مقادیری که ممکن است در طول زمان تغییر کنند، استفاده کنید.
- از دستورات سفارشی استفاده کنید: دستورات سفارشی برای کپسوله کردن منطق قابل استفاده مجدد و خواناتر کردن تستهای خود ایجاد کنید.
- تستها را ایزوله کنید: هر تست باید مستقل از سایر تستها باشد. از اتکا به وضعیت اپلیکیشن از تستهای قبلی خودداری کنید.
- پس از تستها پاکسازی کنید: وضعیت اپلیکیشن را پس از هر تست بازنشانی کنید تا اطمینان حاصل شود که تستهای بعدی از یک وضعیت تمیز شروع میشوند.
- از ویژگیهای داده (Data Attributes) استفاده کنید: از ویژگیهای داده (مانند `data-testid`) برای انتخاب عناصر در تستهای خود استفاده کنید. احتمال تغییر ویژگیهای داده نسبت به کلاسهای CSS یا IDها کمتر است، که تستهای شما را در برابر تغییرات در UI مقاومتر میکند.
- از انتظارهای صریح خودداری کنید: سایپرس به طور خودکار منتظر میماند تا عناصر قابل مشاهده یا تعامل شوند. از استفاده از انتظارهای صریح (مانند `cy.wait()`) خودداری کنید مگر اینکه کاملاً ضروری باشد.
- جریانهای کاربری را تست کنید: بر روی تست جریانهای کاربری به جای اجزای فردی تمرکز کنید. این به شما کمک میکند تا اطمینان حاصل کنید که اپلیکیشن شما از دیدگاه کاربر به درستی کار میکند.
- تستها را به طور منظم اجرا کنید: تستهای سایپرس را در پایپلاین CI/CD خود ادغام کرده و آنها را به طور منظم اجرا کنید تا باگها را در مراحل اولیه فرآیند توسعه پیدا کنید.
تکنیکهای پیشرفته سایپرس
Stubbing و Mocking
سایپرس به شما امکان میدهد درخواستها و پاسخهای شبکه را شبیهسازی کنید، که به شما امکان میدهد سناریوهای مختلف را شبیهسازی کرده و مدیریت خطای اپلیکیشن خود را تست کنید. این به ویژه برای تست ویژگیهایی که به APIها یا سرویسهای خارجی متکی هستند، مفید است.
برای شبیهسازی یک درخواست شبکه، میتوانید از دستور `cy.intercept()` استفاده کنید. به عنوان مثال، کد زیر یک درخواست GET به `/api/users` را شبیهسازی کرده و یک پاسخ ساختگی برمیگرداند:
cy.intercept('GET', '/api/users', {
statusCode: 200,
body: [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' }
]
}).as('getUsers')
سپس میتوانید با استفاده از `cy.wait('@getUsers')` منتظر درخواست رهگیری شده بمانید و تأیید کنید که اپلیکیشن شما پاسخ ساختگی را به درستی مدیریت میکند.
کار با Local Storage و کوکیها
سایپرس دستوراتی برای تعامل با local storage و کوکیها فراهم میکند. شما میتوانید از این دستورات برای تنظیم، دریافت و پاک کردن local storage و کوکیها در تستهای خود استفاده کنید.
برای تنظیم یک آیتم در local storage، میتوانید از دستور `cy.window()` برای دسترسی به آبجکت window و سپس از متد `localStorage.setItem()` استفاده کنید. برای مثال:
cy.window().then((win) => {
win.localStorage.setItem('myKey', 'myValue')
})
برای دریافت یک آیتم از local storage، میتوانید از دستور `cy.window()` و سپس از متد `localStorage.getItem()` استفاده کنید. برای مثال:
cy.window().then((win) => {
const value = win.localStorage.getItem('myKey')
expect(value).to.equal('myValue')
})
برای تنظیم یک کوکی، میتوانید از دستور `cy.setCookie()` استفاده کنید. برای مثال:
cy.setCookie('myCookie', 'myCookieValue')
برای دریافت یک کوکی، میتوانید از دستور `cy.getCookie()` استفاده کنید. برای مثال:
cy.getCookie('myCookie').should('have.property', 'value', 'myCookieValue')
مدیریت آپلود فایل
سایپرس یک پلاگین به نام `cypress-file-upload` ارائه میدهد که آپلود فایل در تستهای شما را ساده میکند. برای نصب پلاگین، دستور زیر را اجرا کنید:
npm install -D cypress-file-upload
سپس، خط زیر را به فایل `cypress/support/commands.js` خود اضافه کنید:
import 'cypress-file-upload';
سپس میتوانید از دستور `cy.uploadFile()` برای آپلود یک فایل استفاده کنید. برای مثال:
cy.get('input[type="file"]').attachFile('example.txt')
کار با IFrameها
تست IFrameها میتواند چالشبرانگیز باشد، اما سایپرس راهی برای تعامل با آنها فراهم میکند. شما میتوانید از دستور `cy.frameLoaded()` برای منتظر ماندن برای بارگذاری یک IFrame، و سپس از دستور `cy.iframe()` برای دریافت آبجکت document آن IFrame استفاده کنید.
cy.frameLoaded('#myIframe')
cy.iframe('#myIframe').find('button').click()
سایپرس و یکپارچهسازی/استقرار مداوم (CI/CD)
ادغام سایپرس در پایپلاین CI/CD شما برای تضمین کیفیت اپلیکیشنتان ضروری است. شما میتوانید تستهای سایپرس را در حالت headless در محیط CI/CD خود اجرا کنید. در اینجا نحوه انجام آن آمده است:
- نصب سایپرس: اطمینان حاصل کنید که سایپرس به عنوان یک dependency در پروژه شما نصب شده است.
- پیکربندی CI/CD: پایپلاین CI/CD خود را طوری پیکربندی کنید که تستهای سایپرس را پس از هر بیلد اجرا کند.
- اجرای سایپرس به صورت Headless: از دستور `cypress run` برای اجرای تستهای سایپرس در حالت headless استفاده کنید.
مثال پیکربندی CI/CD (با استفاده از GitHub Actions):
name: تستهای سایپرس
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: نصب وابستگیها
run: npm install
- name: اجرای سایپرس
uses: cypress-io/github-action@v5
with:
start: npm start
wait-on: 'http://localhost:3000'
این پیکربندی تستهای سایپرس را هر زمان که کدی به شاخه `main` پوش شود یا یک pull request در برابر شاخه `main` ایجاد شود، اجرا میکند. اکشن `cypress-io/github-action` فرآیند اجرای تستهای سایپرس در GitHub Actions را ساده میکند.
دیباگ کردن تستهای سایپرس
سایپرس ابزارهای دیباگینگ عالی برای کمک به شما در شناسایی و رفع مشکلات تستهایتان فراهم میکند. در اینجا چند نکته برای دیباگ کردن تستهای سایپرس آورده شده است:
- از Cypress Test Runner استفاده کنید: Cypress Test Runner یک رابط بصری برای اجرا و دیباگ کردن تستهای شما فراهم میکند. شما میتوانید تستهای خود را دستور به دستور طی کنید، وضعیت اپلیکیشن را بررسی کنید و پیامهای خطای دقیق را مشاهده کنید.
- از دستور `cy.pause()` استفاده کنید: دستور `cy.pause()` اجرای تست شما را متوقف کرده و به شما امکان میدهد وضعیت اپلیکیشن را در ابزارهای توسعهدهنده مرورگر بررسی کنید.
- از دستور `cy.debug()` استفاده کنید: دستور `cy.debug()` عنصر انتخاب شده را در کنسول چاپ میکند و به شما امکان میدهد ویژگیها و صفات آن را بررسی کنید.
- از ابزارهای توسعهدهنده مرورگر استفاده کنید: ابزارهای توسعهدهنده مرورگر اطلاعات فراوانی درباره اپلیکیشن شما، از جمله DOM، درخواستهای شبکه و لاگهای کنسول فراهم میکنند.
- پیامهای خطا را با دقت بخوانید: سایپرس پیامهای خطای دقیقی ارائه میدهد که میتواند به شما در شناسایی علت خطا کمک کند. به پیام خطا و stack trace توجه کنید.
مقایسه سایپرس با سایر فریمورکهای تست
در حالی که سایپرس یک فریمورک قدرتمند تست end-to-end است، درک نحوه مقایسه آن با سایر گزینههای محبوب ضروری است. در اینجا یک نمای کلی مختصر آورده شده است:
- سلنیوم: سلنیوم یک فریمورک تست اتوماسیون پرکاربرد است. در حالی که انعطافپذیر است و از چندین زبان پشتیبانی میکند، راهاندازی و نگهداری آن میتواند پیچیده باشد. سایپرس تجربهای سادهتر و کاربرپسندتر برای توسعهدهندگان، به ویژه برای اپلیکیشنهای مبتنی بر جاوا اسکریپت، ارائه میدهد.
- Puppeteer: Puppeteer یک کتابخانه Node است که یک API سطح بالا برای کنترل Chrome یا Chromium در حالت headless فراهم میکند. این ابزار برای اسکرپینگ و خودکارسازی وظایف مرورگر عالی است اما ممکن است در مقایسه با سایپرس برای تست end-to-end به پیکربندی دستی بیشتری نیاز داشته باشد.
- Playwright: Playwright یک فریمورک اتوماسیون بین مرورگری دیگر است که توسط مایکروسافت توسعه یافته است. شباهتهایی با Puppeteer دارد اما پشتیبانی وسیعتری از مرورگرها ارائه میدهد. سایپرس دارای یک دیباگر سفر در زمان منحصر به فرد و تجربه تست یکپارچهتری است.
انتخاب فریمورک به نیازها و الزامات خاص پروژه شما بستگی دارد. سایپرس یک انتخاب عالی برای اپلیکیشنهای وب مدرن است که به تست end-to-end سریع، قابل اعتماد و کاربرپسند برای توسعهدهندگان نیاز دارند.
مثالهای واقعی از سایپرس در عمل
بیایید چند مثال واقعی از نحوه استفاده از سایپرس برای تست انواع مختلف اپلیکیشنهای وب را بررسی کنیم:
تست یک اپلیکیشن تجارت الکترونیک
شما میتوانید از سایپرس برای تست جریانهای کاربری مختلف در یک اپلیکیشن تجارت الکترونیک استفاده کنید، مانند:
- جستجوی محصولات
- افزودن محصولات به سبد خرید
- پرداخت و ثبت سفارش
- مدیریت تنظیمات حساب کاربری
در اینجا نمونهای از یک تست سایپرس است که تأیید میکند کاربر میتواند با موفقیت محصولی را به سبد خرید خود اضافه کند:
it('یک محصول را به سبد خرید اضافه میکند', () => {
cy.visit('/products')
cy.get('.product-card').first().find('button').click()
cy.get('.cart-count').should('have.text', '1')
})
تست یک اپلیکیشن شبکه اجتماعی
شما میتوانید از سایپرس برای تست تعاملات کاربر در یک اپلیکیشن شبکه اجتماعی استفاده کنید، مانند:
- ایجاد یک پست جدید
- لایک کردن یک پست
- نظر دادن روی یک پست
- دنبال کردن کاربران دیگر
در اینجا نمونهای از یک تست سایپرس است که تأیید میکند کاربر میتواند با موفقیت یک پست جدید ایجاد کند:
it('یک پست جدید ایجاد میکند', () => {
cy.visit('/profile')
cy.get('#new-post-textarea').type('سلام، دنیا!')
cy.get('#submit-post-button').click()
cy.get('.post').first().should('contain', 'سلام، دنیا!')
})
تست یک اپلیکیشن بانکی
برای اپلیکیشنهای بانکی، سایپرس میتواند برای تست عملکردهای حیاتی مانند موارد زیر استفاده شود:
- ورود امن
- بررسی موجودی حساب
- انتقال وجه
- مدیریت ذینفعان
یک تست برای تأیید انتقال وجه ممکن است به این شکل باشد (با شبیهسازی مناسب برای امنیت):
it('وجه را با موفقیت منتقل میکند', () => {
cy.visit('/transfer')
cy.get('#recipient-account').type('1234567890')
cy.get('#amount').type('100')
cy.intercept('POST', '/api/transfer', { statusCode: 200, body: { success: true } }).as('transfer')
cy.get('#transfer-button').click()
cy.wait('@transfer')
cy.get('.success-message').should('be.visible')
})
نتیجهگیری
سایپرس یک فریمورک تست end-to-end قدرتمند و همهکاره است که میتواند به شما در تضمین کیفیت و قابلیت اطمینان اپلیکیشنهای وب کمک کند. API کاربرپسند آن برای توسعهدهندگان، ویژگیهای قدرتمند و عملکرد عالی، آن را به انتخابی محبوب در میان توسعهدهندگان و مهندسان تضمین کیفیت در سراسر جهان تبدیل کرده است. با پیروی از بهترین شیوههای ذکر شده در این راهنما، میتوانید تستهای سایپرس مؤثری بنویسید که به شما در شناسایی باگها در مراحل اولیه فرآیند توسعه و ارائه نرمافزار با کیفیت بالا به کاربرانتان کمک میکند.
همچنان که اپلیکیشنهای وب به تکامل خود ادامه میدهند، اهمیت تست end-to-end تنها افزایش خواهد یافت. پذیرش سایپرس و ادغام آن در جریان کاری توسعه شما، شما را قادر میسازد تا تجربیات وب قویتر، قابل اعتمادتر و کاربرپسندتری بسازید.