CI पाइपलाइन में टेस्ट चलाना
CI पाइपलाइन में टेस्ट चलाने का मतलब है एक ऐसी file में, जिसे CI server पढ़ता है, यह लिखना कि टेस्ट कब चलेंगे, किन मशीनों पर, किन dependencies के साथ और पीछे क्या छोड़ेंगे। GitHub Actions में यह file .github/workflows/ में रखा एक YAML workflow है; GitLab CI (.gitlab-ci.yml) और Jenkins (Jenkinsfile) यही विचार अपने ढंग से लिखते हैं। उदाहरण के लिए, एक ही workflow हर pull request पर Chromium में @smoke tag वाले 25 browser टेस्ट और हर रात तीन browsers में सभी 180 टेस्ट चला सकता है।
"CI/CD पाइपलाइन में टेस्टिंग" guide ने दिखाया कि pipeline क्या बनाती है: JUnit XML नतीजे, traces और screenshots जैसे artifacts, और पैरलल shards में बँटे suites। यह lesson उसका व्यावहारिक हिस्सा है: वह file जिससे यह सब होता है।
यह क्यों ज़रूरी है
CI वाली टीम में ज़्यादातर टेस्ट pipeline चलाती है, इसलिए workflow ही तय करता है कि कौन-सा सबूत मौजूद होगा। गलत set चलाने वाला check, या सिर्फ़ Chromium में चलने वाला browser suite, फिर भी हरा दिखता है; और 40 मिनट लेने वाले check का लोग इंतज़ार करना छोड़ देते हैं।
Suite क्या cover करे, यह अक्सर tester तय करता है, इसलिए उसे workflow खुद बदलना आना चाहिए: कोई browser जोड़ना, धीमे suite को nightly run में ले जाना, fail हुए job की report बचाना।
Pipeline file की बनावट
YAML के तीन building blocks हैं। Mapping key: value है; list ऐसी lines हैं जो - से शुरू होती हैं, या छोटा रूप [chromium, firefox]; nesting सिर्फ़ spaces वाले indentation से दिखती है। Indentation में tabs की अनुमति नहीं है, और एक space ज़्यादा या कम key को दूसरे block में पहुँचा सकता है। # के बाद का text comment है, और * से शुरू होने वाली value को quotes में रखना ज़रूरी है, जैसे cron '*/30 * * * *'।
on key triggers की सूची है: pull request खुलने, दोबारा खुलने या उसमें नए commits आने पर pull_request, main तक सीमित push, और cron expression के साथ schedule। Cron के पाँच fields हैं: minute, hour, day of month, month और day of week, इसलिए '0 1 * * *' का मतलब है हर दिन 01:00; schedules default branch पर चलते हैं, और UTC में, जब तक entry में timezone न दिया हो। jobs के नीचे हर job एक runner पर चलता है, यानी वह मशीन जिसका नाम runs-on देता है; GitHub-hosted runner हर job के लिए नई virtual machine है, इसलिए jobs के बीच कुछ नहीं बचता, सिवाय उसके जो आप cache या upload करें। Job के steps एक workspace में क्रम से चलते हैं: uses कोई published action चलाता है, run shell command, और non-zero exit code job को fail कर देता है।
.github/workflows/e2e.yml: एक workflow, दो jobs
# .github/workflows/e2e.yml name: e2e भाग 1:on: pull_request: push: branches: [main] schedule: - cron: '0 1 * * *' # every night, 01:00 UTC jobs: smoke: भाग 2:if: github.event_name != 'schedule' भाग 3:runs-on: ubuntu-latest timeout-minutes: 15 भाग 4:steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v7 with: node-version: 24 भाग 5:cache: npm - run: npm ci - run: npx playwright install --with-deps chromium - run: npx playwright test --project=chromium भाग 6:--grep @smoke - uses: actions/upload-artifact@v7 भाग 7:if: always() with: name: smoke-results path: results/ retention-days: 14 nightly: if: github.event_name == 'schedule' runs-on: ubuntu-latest timeout-minutes: 45 भाग 8:strategy: fail-fast: false matrix: browser: [chromium, firefox, webkit] steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v7 with: node-version: 24 cache: npm - run: npm ci - run: npx playwright install --with-deps ${{ matrix.browser }} - run: npx playwright test --project=${{ matrix.browser }} - uses: actions/upload-artifact@v7 if: always() with: भाग 9:name: nightly-${{ matrix.browser }} path: results/ retention-days: 14
- 1Triggers:
onPull requests,mainपर push और UTC में nightly cron schedule workflow शुरू करते हैं। - 2Job की condition
smokejob pull requests और pushes पर चलता है, schedule पर कभी नहीं। - 3Runnerहर job के लिए नई virtual machine; उसके बाद सिर्फ़ cache और artifacts बचते हैं।
- 4Stepsएक workspace में ऊपर से नीचे चलते हैं; non-zero exit code job को fail करता है।
- 5Dependency cacheजब तक
package-lock.jsonनहीं बदलता, npm downloads वापस लाता है। - 6Pull request का चुनावसिर्फ़
@smokeटेस्ट, Chromium में: merge रोकने लायक तेज़। - 7सबूत बचाएँTest step fail होने के बाद भी upload चलता है।
- 8Browser matrixहर browser के लिए एक पैरलल job;
fail-fast: falseतीनों को पूरा चलने देता है। - 9Unique artifact नामहर matrix job अपने नाम से upload करता है; एक run में दोहराया गया नाम fail होता है।
GitHub Actions syntax। GitLab CI और Jenkins में यही हिस्से दूसरे नामों से होते हैं।
पाठ संस्करण
# .github/workflows/e2e.yml
name: e2e
on:
pull_request:
push:
branches: [main]
schedule:
- cron: '0 1 * * *' # every night, 01:00 UTC
jobs:
smoke:
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npx playwright test --project=chromium --grep @smoke
- uses: actions/upload-artifact@v7
if: always()
with:
name: smoke-results
path: results/
retention-days: 14
nightly:
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
browser: [chromium, firefox, webkit]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npx playwright install --with-deps ${{ matrix.browser }}
- run: npx playwright test --project=${{ matrix.browser }}
- uses: actions/upload-artifact@v7
if: always()
with:
name: nightly-${{ matrix.browser }}
path: results/
retention-days: 14आज़माएँ: YAML फ़ॉर्मेटर आज़माएँ: YAML से JSON आज़माएँ: Cron एक्सप्रेशन एक्सप्लेनर
Dependency caching और browser matrix
हर job साफ़ शुरू होता है, इसलिए npm ci हर run में हर package download करेगा। Dependency cache इन downloads को lock file से बनी key के तहत सहेजता है और अगली बार वापस लाता है; package-lock.json बदलने पर key भी बदल जाती है। actions/setup-node पर cache: npm npm का download cache सहेजता है, node_modules नहीं, इसलिए npm ci अब भी ठीक वही install करता है जो lock file कहती है, बस तेज़ी से, और cache न मिलने पर भी नतीजा वही होना चाहिए। Playwright का CI documentation browser binaries cache न करने की सलाह देता है: उन्हें restore करने में लगभग उतना ही समय लगता है जितना download में।
Matrix एक job definition को values के हर combination के लिए एक job में बदलता है। browser: [chromium, firefox, webkit] तीन पैरलल jobs बनाता है, और हर job अपनी value --project को देता है, जो Playwright configuration के किसी project के नाम से मेल खानी चाहिए। shard: [1, 2] जोड़ने से छह jobs बनते हैं, इसलिए नया dimension सिर्फ़ असली risk के लिए जोड़ें, जैसे engines के बीच rendering का अंतर। fail-fast: false हर browser को पूरा चलने देता है, ताकि दिखे कि failure एक engine का है या सबका।
Worked example: pull request या nightly
एक online shop टीम के पास 1,240 unit, 310 API और 180 browser टेस्ट हैं, जिनमें से 25 पर sign-in, search, cart और payment के लिए @smoke tag है। Browser suite हर browser में लगभग 35 मिनट लेता है; pull requests का budget 15 मिनट है। टीम हर suite को उसकी speed, stability, उसके cover किए risk और fail होने पर कार्रवाई करने वाले के आधार पर छाँटती है। ऊपर का workflow browser वाली rows लागू करता है।
- Pull requests को अहम journeys पर तेज़ और stable checks मिलते हैं; लेखक इनका इंतज़ार करता है, इसलिए ये merge को रोकते (gate) हैं।
mainपर push वही set दोहराता है: अलग-अलग pass हुए दो pull requests मिलकर टूट सकते हैं।- Nightly run धीमे और व्यापक suites संभालता है; एक तय owner हर सुबह उसे पढ़ता है और पिछली हरी रात के बाद के commits जाँचता है।
- Quarantined flaky टेस्ट pull request set से बाहर होकर सिर्फ़ रात में चलते हैं, और किसी को रोके बिना report करते हैं। Nightly job में main test step
--grep-invert @quarantineजोड़ता है, जो उस tag वाले टेस्ट छोड़ देता है; दूसरा step--grep @quarantineकोcontinue-on-error: trueके साथ चलाता है, ताकि उसका fail होना job को fail न करे, औरif: always()के साथ, ताकि main step fail होने के बाद भी वह चले।
Suite Tests Time* Pull request Push to main Nightly 01:00 UTC
Lint + unit 1,240 3 min gate run run
API tests 310 6 min gate run run
E2E @smoke, Chromium 25 4 min gate run -
E2E full, 3 browsers 3 x 180 35 min - - run, 3 parallel jobs
gate: must pass before the merge
* wall-clock time per job; illustrative figuresTest reports, artifacts और पैरलल jobs
Test runner को मशीनों और लोगों के लिए नतीजे लिखने के लिए configure करें, फिर पक्का करें कि job उन्हें बचाए। नीचे का excerpt CI server के लिए JUnit XML, लोगों के लिए HTML report, और fail हुए टेस्ट के traces और screenshots लिखता है। GitLab XML को artifacts:reports:junit से पढ़ता है, Jenkins JUnit plugin के junit step से; बाकी जगह platform का documentation देखें।
Artifacts वे files हैं जिन्हें job upload करता है ताकि वे runner के बाद भी बचें। इन्हें if: always() के साथ upload करें: default रूप से fail हुए step के बाद का step skip होता है, और ज़रूरत fail हुए runs में ही पड़ती है। GitHub Actions में artifact के नाम एक run में unique होने चाहिए, इसीलिए nightly-${{ matrix.browser }}; retention-days तय करता है कि वे कितने दिन रहें। Personal data और secrets इनसे बाहर रखें।
जिन jobs में needs नहीं है वे पैरलल चलते हैं, matrix jobs भी, जितने runners उपलब्ध हों; max-parallel matrix की सीमा तय करता है। Job के अंदर Playwright की CI guidance stable runs के लिए एक worker पसंद करती है, और फैलाव shards से। हर job की reports merge करें, जैसे Playwright के blob reporter और npx playwright merge-reports से, ताकि gate एक ही नतीजा देखे।
// playwright.config.ts (excerpt)
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
workers: process.env.CI ? 1 : undefined,
outputDir: 'results/artifacts', // traces, screenshots
reporter: [
['junit', { outputFile: 'results/junit.xml' }], // for the CI server
['html', { outputFolder: 'results/html', open: 'never' }], // for people
],
use: { trace: 'retain-on-failure', screenshot: 'only-on-failure' },
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
});आम गलतियाँ
- Tabs से indent करना, जिसे YAML नहीं मानता, या गलत संख्या के spaces से, जिससे file valid YAML रहकर भी कुछ और मतलब दे सकती है। Push से पहले file को format करें और JSON के रूप में पढ़ें।
if: always()के बिना reports upload करना, जिससे artifacts सिर्फ़ हरे runs के लिए बचते हैं।- हर pull request पर हर browser में हर टेस्ट चलाना, जब तक लोग बिना इंतज़ार merge न करने लगें।
- बिना owner का nightly run: हफ़्ते भर बाद पढ़ी गई लाल रात safety net नहीं है।
- टेस्ट की संख्या जाँचे बिना हरे job पर भरोसा करना: गलती से
@smoektag वाला टेस्ट चुपचाप--grep @smokeset से बाहर हो जाता है। - नतीजा तय करने वाली कोई भी चीज़ cache करना, जैसे test output, या ऐसी cache key जो lock file को नज़रअंदाज़ करे।
QA का नज़रिया
Workflow file का review pull requests में code की तरह करें। हर बदलाव पर पूछें: कौन-से events इसे चलाते हैं, कौन-से टेस्ट pull request पर चलते हैं और कौन-से सिर्फ़ रात में, क्या हर test job failure पर अपनी reports बचाता है, और क्या check अब भी budget में है?
बँटवारा test strategy या README में nightly owner के साथ दर्ज करें, और suite बढ़ने पर टेस्ट को columns के बीच खिसकाएँ। Nightly run fail हो तो report में run, browser और जाँचे जाने वाले commits की range लिखें।
अभ्यास
Test workflow का review करें और suites बाँटें
आपके browser suite में 140 टेस्ट हैं: 20 पर @smoke tag, 110 सामान्य, और @quarantine tag वाले 10 flaky टेस्ट। एक browser job smoke set के लिए 2 मिनट और सब कुछ के लिए 28 मिनट लेता है; pull request checks को 10 मिनट में पूरा होना चाहिए। पिछले दो defects सिर्फ़ WebKit में दिखे थे। टीम रियाद (UTC+3) में काम करती है।
तय करें कि pull requests पर, main पर push होने पर और रात में क्या चलेगा, फिर नीचे के workflow का review करें।
name: e2e
on:
pull_request:
schedule:
- cron: '0 13 * * *'
jobs:
e2e:
runs-on: ubuntu-latest
strategy:
matrix:
browser: [chromium, firefox, webkit]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
- run: npm ci
- run: npx playwright install --with-deps ${{ matrix.browser }}
- run: npx playwright test --project=${{ matrix.browser }}
- uses: actions/upload-artifact@v7
with:
name: e2e-report
path: results/- Suites को तीनों triggers के सामने table में रखें: merge रोकता है, सिर्फ़ report, या नहीं चलता।
- Triggers, cron का समय और jobs की conditions जाँचें।
- Caching, matrix और artifacts जाँचें।
मॉडल उत्तर दिखाएँ
जैसा लिखा है, हर pull request लगभग 28 मिनट इंतज़ार करता है और quarantined टेस्ट पर merge रोकता है। इसके बजाय pull requests और main पर push Chromium और WebKit में @smoke टेस्ट चलाते हैं, लगभग 2 मिनट के दो पैरलल jobs, और merge रोकते हैं। Nightly run तीन browsers में सभी 130 non-quarantined टेस्ट (--grep-invert @quarantine) और continue-on-error: true व if: always() वाले एक step में quarantined टेस्ट (--grep @quarantine) चलाता है, ताकि वे job को fail किए बिना report करें और main step लाल होने पर भी चलें। एक तय owner हर सुबह run पढ़ता है।
branches: [main] के साथ push जोड़ें। '0 13 * * *' रियाद में 16:00 है, यानी रात नहीं, दोपहर बाद; '0 22 * * *' local समय से 01:00 पर चलता है, और timezone: Asia/Riyadh के साथ '0 1 * * *' भी।
इसे smoke job (if: github.event_name != 'schedule', matrix [chromium, webkit], --grep @smoke) और nightly job (if: github.event_name == 'schedule', तीनों browsers) में बाँटें; timeout-minutes, fail-fast: false (वरना पहला failure बाकी browsers cancel कर देता है) और cache: npm जोड़ें।
Upload में if: always() जोड़ें और उसका नाम job और browser पर रखें, जैसे nightly-${{ matrix.browser }}: e2e-report upload करने वाले तीन jobs टकराते हैं।
अक्सर पूछे जाने वाले सवाल
क्या pipelines के साथ काम करने के लिए YAML अच्छी तरह आना ज़रूरी है?
इस lesson की बुनियाद काफ़ी है: mappings, lists, indentation और quoting। Tester workflow में जो ज़्यादातर बदलाव करता है वे हैं कोई step, matrix value या trigger जोड़ना। Push से पहले file को YAML formatter से validate करें, और जो key पहले इस्तेमाल नहीं की उसके लिए platform का syntax reference पढ़ें।
क्या E2E टेस्ट हर pull request पर चलने चाहिए?
Critical journeys को cover करने वाला एक छोटा, stable set चलना चाहिए, आम तौर पर एक browser में, क्योंकि वह सबसे नुकसानदेह regressions तब पकड़ता है जब लेखक अभी बदलाव पर काम कर रहा होता है। पूरा suite और बाकी browsers आम तौर पर merge या nightly run में जाते हैं, जब तक suite इतना तेज़ न हो कि pull request budget में आ जाए।
मेरा scheduled workflow उम्मीद के समय पर क्यों नहीं चला?
GitHub Actions में schedule default branch पर चलता है और UTC इस्तेमाल करता है, जब तक entry में timezone न दिया हो, इसलिए feature branch में जोड़ा गया schedule merge होने तक कुछ नहीं करता, और समय आपकी local घड़ी से घंटों अलग हो सकता है। Platform पर ज़्यादा load के समय scheduled runs देर से शुरू हो सकते हैं या छूट भी सकते हैं; हर घंटे की शुरुआत व्यस्त समय है, इसलिए 0 की जगह 17 जैसा minute देरी की संभावना घटाता है। Public repository में 60 दिन तक कोई activity न हो तो schedules बंद हो जाते हैं।
Cache और artifact में क्या अंतर है?
Cache runs के बीच साझा एक optimisation है, जैसे lock file से बनी key वाली downloaded dependencies; यह गायब भी हो सकता है, और job को फिर भी चलना चाहिए। Artifact एक run का output है, जैसे reports, traces और screenshots, जिसे लोगों के download करने और बाद के jobs के इस्तेमाल के लिए रखा जाता है।
संदर्भ
- GitHub Actions documentationGitHub Actions में workflows, jobs, runners और artifacts कैसे परिभाषित होते हैं — जहाँ हर push या pull request पर ऑटोमेटेड टेस्ट चलते हैं।
- Playwright DocumentationPlaywright का आधिकारिक दस्तावेज़ — Chromium, WebKit और Firefox चलाने वाला end-to-end टेस्ट फ़्रेमवर्क।
- YAML Ain't Markup Language (YAML™) version 1.2.2YAML 1.2 का डेटा मॉडल और सिंटैक्स, और JSON से उसका संबंध (हर JSON दस्तावेज़ वैध YAML 1.2 है)।
- Unit test reports — GitLab CI/CDJUnit XML नतीजों को pipeline artifact के रूप में प्रकाशित करना ताकि फ़ेल टेस्ट merge request में दिखें और रनों के बीच तुलना हो सके।
Mutqan tools से अभ्यास करें
YAML को एकसमान इंडेंटेशन और quoting के साथ फ़ॉर्मेट और वैलिडेट करें।
YAML डॉक्यूमेंट को JSON में बदलें, एरर रिपोर्टिंग के साथ।
किसी भी cron एक्सप्रेशन को आसान भाषा में समझें और आने वाली रन टाइम देखें।
cron एक्सप्रेशन विज़ुअल तरीक़े से बनाएँ और अगली रन टाइम पहले से देखें।
XML को मनचाहे इंडेंटेशन के साथ प्रिटी-प्रिंट करें और वापस मिनिफ़ाई भी करें।
और गहराई से
इस topic में आपकी प्रगति
प्रगति ट्रैक करने के लिए साइन इन करें
Topics पूर्ण चिह्नित करें, जहाँ छोड़ा था वहीं से जारी रखें और specialisation परीक्षाएँ खोलें।