PageSourceSearch

https://dev-mountain.vercel.app/assets/js/1cf2cd57.c31eded7.js

js dev-mountain.vercel.app collected 2026-10-03 07:14:21 UTC 24,021 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdev_mountain=globalThis.webpackChunkdev_mountain||[]).push([[3782],{28453(e,t,n){n.d(t,{R:()=>a,x:()=>o});var s=n(96540);const i={},r=s.createContext(i);function a(e){const t=s.useContext(r);return s.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:a(e.components),s.createElement(r.Provider,{value:t},e.children)}},67176(e,t,n){n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"quality-testing-performance/software-testing","title":"Software Testing \u2014 Fundamentals, Playwright & AI-Powered Testing","description":"Personal notes from a course on modern software testing \u2014 covering why testing matters, hands-on browser automation with Playwright, and the emerging role of AI-powered testing tools like KaneAI.","source":"@site/resources/quality-testing-performance/software-testing.md","sourceDirName":"quality-testing-performance","slug":"/quality-testing-performance/software-testing","permalink":"/resources/quality-testing-performance/software-testing","draft":false,"unlisted":false,"editUrl":"https://github.com/AbdulDevHub/Docusaurus/tree/main/resources/quality-testing-performance/software-testing.md","tags":[{"inline":true,"label":"testing","permalink":"/resources/tags/testing"},{"inline":true,"label":"playwright","permalink":"/resources/tags/playwright"},{"inline":true,"label":"qa","permalink":"/resources/tags/qa"},{"inline":true,"label":"ai","permalink":"/resources/tags/ai"},{"inline":true,"label":"automation","permalink":"/resources/tags/automation"}],"version":"current","frontMatter":{"id":"software-testing","title":"Software Testing \u2014 Fundamentals, Playwright & AI-Powered Testing","sidebar_label":"Software Testing","tags":["testing","playwright","qa","ai","automation"]},"sidebar":"resourcesSidebar","previous":{"title":"Prompt Engineering","permalink":"/resources/ai-systems/prompt-engineering-fundamentals"},"next":{"title":"Accessibility Tools","permalink":"/resources/quality-testing-performance/accessibility-tools"}}');var i=n(74848),r=n(28453);const a={id:"software-testing",title:"Software Testing \u2014 Fundamentals, Playwright & AI-Powered Testing",sidebar_label:"Software Testing",tags:["testing","playwright","qa","ai","automation"]},o=void 0,l={},c=[{value:"1. Why Testing Matters",id:"1-why-testing-matters",level:2},{value:"Knight Capital (2012)",id:"knight-capital-2012",level:3},{value:"Boeing 737 MAX (MCAS)",id:"boeing-737-max-mcas",level:3},{value:"2. The Testing Pyramid",id:"2-the-testing-pyramid",level:2},{value:"3. Hands-on Automation with Playwright",id:"3-hands-on-automation-with-playwright",level:2},{value:"3.1 Setup",id:"31-setup",level:3},{value:"3.2 Core Test Writing",id:"32-core-test-writing",level:3},{value:"3.3 Advanced Techniques",id:"33-advanced-techniques",level:3},{value:"Edge case & security testing (XSS)",id:"edge-case--security-testing-xss",level:4},{value:"API mocking (simulating network failures)",id:"api-mocking-simulating-network-failures",level:4},{value:"Accessibility testing with Axe Core",id:"accessibility-testing-with-axe-core",level:4},{value:"4. AI-Powered Testing",id:"4-ai-powered-testing",level:2},{value:"4.1 KaneAI",id:"41-kaneai",level:3},{value:"4.2 Exporting to Professional Frameworks",id:"42-exporting-to-professional-frameworks",level:3},{value:"4.3 AI as a Multiplier, Not a Replacement",id:"43-ai-as-a-multiplier-not-a-replacement",level:3},{value:"5. Final Takeaways",id:"5-final-takeaways",level:2}];function d(e){const t={admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",hr:"hr",li:"li",mermaid:"mermaid",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Personal notes from a course on modern software testing \u2014 covering ",(0,i.jsx)(t.em,{children:"why"})," testing matters, hands-on browser automation with ",(0,i.jsx)(t.strong,{children:"Playwright"}),", and the emerging role of ",(0,i.jsx)(t.strong,{children:"AI-powered testing tools"})," like KaneAI."]}),"\n",(0,i.jsx)(t.admonition,{title:"Why this page exists",type:"tip",children:(0,i.jsx)(t.p,{children:"Testing knowledge decays fast if it isn't written down. This page is meant to be the thing I re-read in six months instead of re-learning from scratch."})}),"\n",(0,i.jsx)(t.hr,{}),"\n",(0,i.jsx)(t.h2,{id:"1-why-testing-matters",children:"1. Why Testing Matters"}),"\n",(0,i.jsxs)(t.p,{children:["Testing is best thought of as ",(0,i.jsx)(t.strong,{children:"insurance for your co
1de"})," \u2014 you pay a small, predictable cost upfront (writing tests) to avoid a large, unpredictable cost later (production failures, lost revenue, reputational damage, or worse)."]}),"\n",(0,i.jsx)(t.p,{children:"Two case studies drive this home:"}),"\n",(0,i.jsx)(t.h3,{id:"knight-capital-2012",children:"Knight Capital (2012)"}),"\n",(0,i.jsxs)(t.p,{children:["A deployment error left old, dormant code active on one of eight production servers. That leftover code was accidentally triggered, causing the system to execute unintended trades at a massive scale. The result: roughly ",(0,i.jsx)(t.strong,{children:"$440 million lost in 45 minutes"}),', nearly bankrupting the firm. The root cause wasn\'t a single "bug" in the traditional sense \u2014 it was a ',(0,i.jsx)(t.strong,{children:"deployment/testing process failure"}),": no reliable way to verify that all servers were running the correct, current code before going live."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Lessons:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"Deployment configuration is part of your system under test \u2014 verify it."}),"\n",(0,i.jsx)(t.li,{children:"Dead/legacy code paths are latent risk; remove or explicitly test them."}),"\n",(0,i.jsxs)(t.li,{children:["Fast systems need fast ",(0,i.jsx)(t.em,{children:"safety nets"})," (kill switches, monitoring, canary releases), not just fast pipelines."]}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"boeing-737-max-mcas",children:"Boeing 737 MAX (MCAS)"}),"\n",(0,i.jsx)(t.p,{children:"The Maneuvering Characteristics Augmentation System (MCAS) was designed to automatically push the aircraft's nose down under certain conditions, based on input from a single angle-of-attack sensor. Faulty sensor readings triggered MCAS incorrectly, and the system lacked adequate safeguards, redundancy, or pilot documentation. This contributed to two fatal crashes."}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Lessons:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Single points of failure"})," (one sensor, no redundancy/cross-check) are a testing and design smell \u2014 test for sensor/input failure, not just the happy path."]}),"\n",(0,i.jsxs)(t.li,{children:["Safety-critical systems need ",(0,i.jsx)(t.strong,{children:"failure-mode testing"}),": what happens when an input is ",(0,i.jsx)(t.em,{children:"wrong"}),", not just ",(0,i.jsx)(t.em,{children:"missing"}),"?"]}),"\n",(0,i.jsx)(t.li,{children:'Documentation and training are part of the "system" \u2014 untested assumptions about what operators know are still bugs.'}),"\n"]}),"\n",(0,i.jsx)(t.admonition,{title:"Takeaway",type:"note",children:(0,i.jsxs)(t.p,{children:['Both cases share a pattern: the failure wasn\'t in the "obvious" logic, it was in an ',(0,i.jsx)(t.strong,{children:"edge case, an untested interaction, or an unverified assumption"}),". Good testing strategy specifically hunts for these."]})}),"\n",(0,i.jsx)(t.hr,{}),"\n",(0,i.jsx)(t.h2,{id:"2-the-testing-pyramid",children:"2. The Testing Pyramid"}),"\n",(0,i.jsxs)(t.p,{children:["A mental model for how to ",(0,i.jsx)(t.em,{children:"allocate effort"})," across test types, balancing speed, confidence, and cost."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{children:"        /\\\n       /  \\        E2E Tests (few)\n      /----\\       \u2014 slow, expensive, high confidence\n     /      \\\n    / Integ. \\     Integration Tests (some)\n   /----------\\    \u2014 medium speed, verifies components work together\n  /            \\\n /  Unit Tests  \\  Unit Tests (many)\n/----------------\\ \u2014 fast, cheap, isolated\n"})}),"\n",(0,i.jsxs)(t.table,{children:[(0,i.jsx)(t.thead,{children:(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.th,{children:"Layer"}),(0,i.jsx)(t.th,{children:"Scope"}),(0,i.jsx)(t.th,{children:"Speed"}),(0,i.jsx)(t.th,{children:"Cost"}),(0,i.jsx)(t.th,{children:"Purpose"})]})}),(0,i.jsxs)(t.tbody,{children:[(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:(0,i.jsx)(t.strong,{children:"Unit tests"})}),(0,i.jsx)(t.td,{children:"A single function/class/module, in isolation (mocks/stubs for dependencies)"}),(0,i.jsx)(t.td,{children:"Very fast (ms)"}),(0,i.jsx)(t.td,{children:"Low"}),(0,i.jsx)(t.td,{children:"Catch logic errors close to the source; fast feedback loop"})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:(0,i.jsx)(t.strong,{children:"Integration tests"})}),(0,i.jsx)(t.td,{children:"Multiple components/modules working together (e.g., service + database, frontend + API)"}),(0,i.jsx)(t.td,{children:"Medium"}),(0,i.jsx)(t.td,{children:"Medium"}),(0,i.jsxs)(t.td,{children:["Catch issues in the ",(0,i.jsx)(t.em,{children:"seams"})," \u2014 where units are individually correct but don't work together"]})]}),(0,i.jsxs)(t.tr,{children:[(0,i.jsx)(t.td,{children:(0,i.jsx)(t.strong,{children:"E2E tests"})}),(0,i.jsx)(t.td,{children:"Full system, simulating real user behavior through the actual UI/API"}),(0,i.jsx)(t.td,{children:"Slow (seconds\u2013minutes)"}),(0,i.jsx)(t.td,{children:"High"}),(0,i.jsx)(t.td,{children:"Catch issues only visible when the whole system runs together; highest confidence, most brittle"})]})]})]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.strong,{children:"Practical rule of thumb:"})," write ",(0,i.jsx)(t.em,{children:"many"})," unit tests, a ",(0,i.jsx)(t.em,{children:"reasonable number"})," of integration tests, and a ",(0,i.jsx)(t.em,{children:"small, high-value set"})," of E2E tests focused on critical user journeys (login, checkout, search) rather than trying to E2E-test everything."]}),"\n",(0,i.jsx)(t.admonition,{title:'Anti-pattern: the "Ice Cream Cone"',type:"caution",children:(0,i.jsxs)(t.p,{children:["A common failure mode is the pyramid flipped upside down \u2014 teams rely heavily on slow, flaky E2E tests and skip unit tests. This leads to slow CI pipelines, flaky builds, and low confidence about ",(0,i.jsx)(t.em,{children:"why"})," something failed."]})}),"\n",(0,i.jsx)(t.hr,{}),"\n",(0,i.jsx)(t.h2,{id:"3-hands-on-automation-with-playwright",children:"3. Hands-on Automation with Playwright"}),"\n",(0,i.jsxs)(t.p,{children:["Practiced against a sample app called ",(0,i.jsx)(t.strong,{children:"TechMart"})," (e-commerce style: search, cart, login, checkout, APIs)."]}),"\n",(0,i.jsx)(t.h3,{id:"31-setup",children:"3.1 Setup"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"npm init playwright@latest\n"})}),"\n",(0,i.jsx)(t.p,{children:"This scaffolds:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"playwright.config.ts"})," \u2014 browser projects (Chromium, Firefox, WebKit), base URL, timeouts, retries"]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"tests/"})," \u2014 example test files"]}),"\n",(0,i.jsx)(t.li,{children:"Config for running headless/headed, in parallel, and across multiple browsers/viewports"}),"\n"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"// playwright.config.ts (key options worth remembering)\nexport default defineConfig({\n  testDir: './tests',\n  fullyParallel: true,\n  retries: process.env.CI ? 2 : 0,\n  use: {\n    baseURL: 'https://techmart.example.com',\n    trace: 'on-first-retry',\n    screenshot: 'only-on-failure',\n  },\n  projects: [\n    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },\n    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },\n    { name: 'webkit', use: { ...devices['Desktop Safari'] } },\n  ],\n});\n"})}),"\n",(0,i.jsx)(t.h3,{id:"32-core-test-writing",children:"3.2 C
1ore Test Writing"}),"\n",(0,i.jsx)(t.p,{children:"Core scenarios practiced on TechMart:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Search"}),' \u2014 typing a query, verifying result count/content, handling "no results" state.']}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Shopping cart"})," \u2014 add/remove items, quantity updates, price recalculation, persistence across navigation."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Login forms"})," \u2014 valid/invalid credentials, validation messages, redirect behavior."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"API endpoints"})," \u2014 testing backend responses directly via Playwright's ",(0,i.jsx)(t.code,{children:"request"})," fixture, independent of the UI."]}),"\n"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"import { test, expect } from '@playwright/test';\n\ntest('user can search for a product', async ({ page }) => {\n  await page.goto('/');\n  await page.getByPlaceholder('Search products').fill('headphones');\n  await page.keyboard.press('Enter');\n\n  await expect(page.getByTestId('search-results')).toContainText('headphones');\n});\n\ntest('adding an item updates the cart badge', async ({ page }) => {\n  await page.goto('/products/wireless-headphones');\n  await page.getByRole('button', { name: 'Add to cart' }).click();\n\n  await expect(page.getByTestId('cart-count')).toHaveText('1');\n});\n\ntest('API: fetching product list returns 200', async ({ request }) => {\n  const response = await request.get('/api/products');\n  expect(response.status()).toBe(200);\n  const body = await response.json();\n  expect(Array.isArray(body.products)).toBeTruthy();\n});\n"})}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"Key Playwright concepts to remember:"})}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Locators are lazy"})," \u2014 ",(0,i.jsx)(t.code,{children:"page.getByRole(...)"})," doesn't query the DOM until an action/assertion is performed, and it auto-waits."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Auto-waiting"})," \u2014 Playwright retries assertions like ",(0,i.jsx)(t.code,{children:"expect(locator).toHaveText(...)"})," until they pass or time out, which reduces flaky tests compared to manual ",(0,i.jsx)(t.code,{children:"sleep()"}),"/",(0,i.jsx)(t.code,{children:"wait()"})," calls."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Fixtures"})," (",(0,i.jsx)(t.code,{children:"page"}),", ",(0,i.jsx)(t.code,{children:"request"}),", ",(0,i.jsx)(t.code,{children:"context"}),") are dependency-injected per test \u2014 no manual browser lifecycle management needed."]}),"\n",(0,i.jsxs)(t.li,{children:["Prefer ",(0,i.jsx)(t.strong,{children:"role/text/testid-based locators"})," over CSS selectors tied to implementation details (classes, DOM structure) \u2014 they're more resilient to UI refactors."]}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"33-advanced-techniques",children:"3.3 Advanced Techniques"}),"\n",(0,i.jsx)(t.h4,{id:"edge-case--security-testing-xss",children:"Edge case & security testing (XSS)"}),"\n",(0,i.jsxs)(t.p,{children:['Testing isn\'t just "does the happy path work" \u2014 it\'s "does the system behave safely when it ',(0,i.jsx)(t.em,{children:"shouldn't"}),' work."']}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"test('search input is sanitized against XSS', async ({ page }) => {\n  await page.goto('/');\n  await page.getByPlaceholder('Search products').fill('<script>alert(1)<\/script>');\n  await page.keyboard.press('Enter');\n\n  // The payload should render as inert text, not execute\n  await expect(page.locator('body')).not.toContainText('alert(1)');\n  const dialogFired = await page\n    .waitForEvent('dialog', { timeout: 1000 })\n    .then(() => true)\n    .catch(() => false);\n  expect(dialogFired).toBe(false);\n});\n"})}),"\n",(0,i.jsx)(t.p,{children:'Other edge cases worth covering: empty inputs, extremely long strings, unicode/emoji, negative quantities, race conditions from double-clicking "Add to cart", and boundary values (0, max int, etc.).'}),"\n",(0,i.jsx)(t.h4,{id:"api-mocking-simulating-network-failures",children:"API mocking (simulating network failures)"}),"\n",(0,i.jsx)(t.p,{children:"Playwright can intercept network calls to simulate slow networks, downtime, or malformed responses \u2014 without touching the real backend."}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"test('shows an error message when the API fails', async ({ page }) =>
1 {\n  await page.route('**/api/products', route =>\n    route.fulfill({ status: 500, body: 'Internal Server Error' })\n  );\n\n  await page.goto('/products');\n  await expect(page.getByText(/something went wrong/i)).toBeVisible();\n});\n\ntest('handles a slow network gracefully', async ({ page }) => {\n  await page.route('**/api/products', async route => {\n    await new Promise(resolve => setTimeout(resolve, 3000));\n    route.continue();\n  });\n\n  await page.goto('/products');\n  await expect(page.getByTestId('loading-spinner')).toBeVisible();\n});\n"})}),"\n",(0,i.jsxs)(t.p,{children:["This is essential for testing ",(0,i.jsx)(t.strong,{children:"resilience"})," \u2014 most bugs users hit in production come from the network being imperfect, not perfect."]}),"\n",(0,i.jsx)(t.h4,{id:"accessibility-testing-with-axe-core",children:"Accessibility testing with Axe Core"}),"\n",(0,i.jsxs)(t.p,{children:["Using ",(0,i.jsx)(t.code,{children:"@axe-core/playwright"})," to automatically scan pages for WCAG violations."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-bash",children:"npm install -D @axe-core/playwright\n"})}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"import { test, expect } from '@playwright/test';\nimport AxeBuilder from '@axe-core/playwright';\n\ntest('homepage has no detectable accessibility violations', async ({ page }) => {\n  await page.goto('/');\n  const results = await new AxeBuilder({ page }).analyze();\n  expect(results.violations).toEqual([]);\n});\n"})}),"\n",(0,i.jsx)(t.p,{children:"Axe catches things like missing alt text, insufficient color contrast, missing form labels, and improper ARIA usage \u2014 issues that are easy to miss manually but block real users (e.g., screen reader users) from using the product."}),"\n",(0,i.jsx)(t.admonition,{title:"Good practice",type:"info",children:(0,i.jsx)(t.p,{children:"Automated accessibility scans (Axe) catch ~30-50% of accessibility issues. They're a great baseline, but manual testing (keyboard-only navigation, screen readers) is still needed for full coverage."})}),"\n",(0,i.jsx)(t.hr,{}),"\n",(0,i.jsx)(t.h2,{id:"4-ai-powered-testing",children:"4. AI-Powered Testing"}),"\n",(0,i.jsx)(t.h3,{id:"41-kaneai",children:"4.1 KaneAI"}),"\n",(0,i.jsx)(t.p,{children:"KaneAI represents a newer generation of AI-driven testing tools. Key capabilities explored:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Natural language test generation"}),' \u2014 describe a test scenario in plain English (e.g., "search for headphones and verify results appear"), and the tool generates the corresponding automated test steps.']}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Auto-healing"})," \u2014 when the underlying UI changes (a button's selector or layout shifts), traditional automated tests break because locators no longer match. Auto-healing tools attempt to detect the change and automatically update the test's locator/logic, reducing maintenance overhead."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"API testing support"})," \u2014 using natural language or AI assistance to construct and validate API requests, similar in spirit to tools like Postman but with AI-assisted test generation."]}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"42-exporting-to-professional-frameworks",children:"4.2 Exporting to Professional Frameworks"}),"\n",(0,i.jsxs)(t.p,{children:["A key workflow: use AI tools like KaneAI to ",(0,i.jsx)(t.em,{children:"rapidly prototype"})," test scenarios, then ",(0,i.jsx)(t.strong,{children:"export the generated tests into Playwright"})," (or similar frameworks) so they can run inside standard ",(0,i.jsx)(t.strong,{children:"CI/CD pipelines"})," \u2014 version controlled, code-reviewed, and integrated with the rest of the engineering workflow, rather than living only inside a proprietary AI tool."]}),"\n",(0,i.jsx)(t.mermaid,{value:"flowchart LR\n    A[Describe scenario in natural language] --\x3e B[AI generates test steps]\n    B --\x3e C[Review & refine generated test]\n    C --\x3e D[Export to Playwright/Selenium code]\n    D --\x3e E[Commit to repo]\n    E --\x3e F[Run in CI/CD pipeline]"}),"\n",(0,i.jsx)(t.h3,{id:"43-ai-as-a-multiplier-not-a-replacement",children:"4.3 AI as a Multiplier, Not a Replacement"}),"\n",(0,i.jsxs)(t.p,{children:["The consistent framing across the course: AI tools are a ",(0,i.jsx)(t.strong,{children:"productivity multiplier"}),", not a substitute for testing judgment."]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:"AI is good at: generating boilerplate quickly, suggesting edge cases you might not think of, healing brittle selectors, and lowering the barrier for non-engineers (manual QA, PMs) to write automated checks."}),"\n",(0,i.jsxs)(t.li,{children:["Humans are still needed for: deciding ",(0,i.jsx)(t.em,{children:"what's actually business-critical"}),' to test, designing test strategy (what belongs in unit vs. integration vs. E2E), catching subtle logic/UX issues AI won\'t flag, and validating that AI-generated tests actually assert the right thing (not just "the page loaded").']}),"\n"]}),"\n",(0,i.jsx)(t.hr,{}),"\n",(0,i.jsx)(t.h2,{id:"5-final-takeaways",children:"5. Final Takeaways"}),"\n",(0,i.jsxs)(t.ol,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Start testing early"})," \u2014 retrofitting tests onto an untested codebase is far more expensive than writing them alongside the code."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Focus on business-critical paths first"})," \u2014 login, checkout, payment, search \u2014 not 100% coverage for its own sake."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Respect the pyramid"})," \u2014 lots of fast unit tests, some integration tests, few but meaningful E2E tests."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Test failure modes, not just success"})," \u2014 XSS, network failures, bad input, single points of failure. This is where Knight Capital and the 737 MAX both failed."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Accessibility is a testable, automatable requirement"}),", not an afterthought \u2014 bake it into the pipeline with tools like Axe C
1ore."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.strong,{children:"Treat AI testing tools as an accelerant"})," for coverage and maintenance (auto-healing, natural language generation) \u2014 while still owning the strategy and judgment calls yourself."]}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,r.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.