{
  "schemaVersion": "1.0",
  "item": {
    "slug": "qa-testing-bots",
    "name": "Automated QA Testing Bots",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/g4dr/qa-testing-bots",
    "canonicalUrl": "https://clawhub.ai/g4dr/qa-testing-bots",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "manual_only",
    "downloadUrl": "/downloads/qa-testing-bots",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=qa-testing-bots",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Open the source page and confirm the package flow manually.",
      "Review SKILL.md if you can obtain the files.",
      "Treat this source as manual setup until the download is verified."
    ],
    "agentAssist": {
      "summary": "Use the source page and any available docs to guide the install because the item currently does not return a direct package file.",
      "steps": [
        "Open the source page via Open source listing.",
        "If you can obtain the package, extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the source page and extracted files."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I tried to install a skill package from Yavira, but the item currently does not return a direct package file. Inspect the source page and any extracted docs, then tell me what you can confirm and any manual steps still required."
        },
        {
          "label": "Upgrade existing",
          "body": "I tried to upgrade a skill package from Yavira, but the item currently does not return a direct package file. Compare the source page and any extracted docs with my current installation, then summarize what changed and what manual follow-up I still need."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "qa-testing-bots",
      "status": "source_issue",
      "reason": "not_found",
      "recommendedAction": "review_source",
      "checkedAt": "2026-04-30T07:54:38.592Z",
      "expiresAt": "2026-05-01T07:54:38.592Z",
      "httpStatus": 404,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=qa-testing-bots",
      "contentType": "text/plain",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=qa-testing-bots",
        "contentDisposition": null,
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "qa-testing-bots"
      },
      "scope": "item",
      "summary": "Known item issue.",
      "detail": "This item's current download entry is known to bounce back to a listing or homepage instead of returning a package file.",
      "primaryActionLabel": "Open source listing",
      "primaryActionHref": "https://clawhub.ai/g4dr/qa-testing-bots"
    },
    "validation": {
      "installChecklist": [
        "Open the source listing and confirm there is a real package or setup artifact available.",
        "Review SKILL.md before asking your agent to continue.",
        "Treat this source as manual setup until the upstream download flow is fixed."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/qa-testing-bots",
    "agentPageUrl": "https://openagent3.xyz/skills/qa-testing-bots/agent",
    "manifestUrl": "https://openagent3.xyz/skills/qa-testing-bots/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/qa-testing-bots/agent.md"
  },
  "agentAssist": {
    "summary": "Use the source page and any available docs to guide the install because the item currently does not return a direct package file.",
    "steps": [
      "Open the source page via Open source listing.",
      "If you can obtain the package, extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the source page and extracted files."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I tried to install a skill package from Yavira, but the item currently does not return a direct package file. Inspect the source page and any extracted docs, then tell me what you can confirm and any manual steps still required."
      },
      {
        "label": "Upgrade existing",
        "body": "I tried to upgrade a skill package from Yavira, but the item currently does not return a direct package file. Compare the source page and any extracted docs with my current installation, then summarize what changed and what manual follow-up I still need."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Overview",
        "body": "This skill enables Claude to build and run automated QA testing bots that simulate\nreal user journeys across websites and web applications — catching bugs, broken flows,\nand regressions before your users do.\n\nPowered by Apify with Puppeteer and Playwright under the hood.\n\n🔗 Sign up for Apify here: https://www.apify.com/?fpr=dx06p"
      },
      {
        "title": "What This Skill Does",
        "body": "Simulate complete user journeys (signup, login, checkout, form submission)\nDetect broken links, 404 errors, and failed redirects across an entire site\nValidate UI elements — buttons, inputs, modals, dropdowns — are present and functional\nRun regression tests after deployments to catch newly introduced bugs\nTake screenshots and video recordings at each step for visual debugging\nTest across multiple viewports (desktop, tablet, mobile)\nAssert response times and flag pages that are too slow"
      },
      {
        "title": "Step 1 — Get Your Apify API Token",
        "body": "Go to https://www.apify.com/?fpr=dx06p and create a free account\nNavigate to Settings → Integrations\n\nDirect link: https://console.apify.com/account/integrations\n\n\nCopy your Personal API Token: apify_api_xxxxxxxxxxxxxxxx\nSet it as an environment variable:\nexport APIFY_TOKEN=apify_api_xxxxxxxxxxxxxxxx"
      },
      {
        "title": "Step 2 — Install Dependencies",
        "body": "npm install apify-client"
      },
      {
        "title": "Actors for QA Testing",
        "body": "Actor IDBest Forapify/puppeteer-scraperFull browser automation, form testing, click flowsapify/playwright-scraperCross-browser testing (Chrome, Firefox, WebKit)apify/broken-links-checkerDetect all 404s and broken links site-wideapify/website-content-crawlerCrawl all pages and validate structure"
      },
      {
        "title": "Test a Full User Registration Flow",
        "body": "import ApifyClient from 'apify-client';\n\nconst client = new ApifyClient({ token: process.env.APIFY_TOKEN });\n\nconst run = await client.actor(\"apify/puppeteer-scraper\").call({\n  startUrls: [{ url: \"https://your-app.com/signup\" }],\n  pageFunction: async function pageFunction(context) {\n    const { page } = context;\n    const results = { steps: [], passed: true, errors: [] };\n\n    try {\n      // Step 1 — Page loads\n      await page.waitForSelector('#signup-form', { timeout: 5000 });\n      results.steps.push({ step: \"Page loaded\", status: \"PASS\" });\n\n      // Step 2 — Fill registration form\n      await page.type('#firstName', 'Test');\n      await page.type('#lastName', 'User');\n      await page.type('#email', `testuser+${Date.now()}@example.com`);\n      await page.type('#password', 'SecurePass123!');\n      results.steps.push({ step: \"Form filled\", status: \"PASS\" });\n\n      // Step 3 — Submit\n      await Promise.all([\n        page.waitForNavigation({ timeout: 8000 }),\n        page.click('button[type=\"submit\"]')\n      ]);\n      results.steps.push({ step: \"Form submitted\", status: \"PASS\" });\n\n      // Step 4 — Assert success redirect\n      const currentUrl = page.url();\n      if (!currentUrl.includes('/dashboard')) {\n        throw new Error(`Expected /dashboard, got: ${currentUrl}`);\n      }\n      results.steps.push({ step: \"Redirected to dashboard\", status: \"PASS\" });\n\n      // Step 5 — Screenshot proof\n      await page.screenshot({ path: 'signup-success.png', fullPage: true });\n\n    } catch (err) {\n      results.passed = false;\n      results.errors.push(err.message);\n      await page.screenshot({ path: 'signup-error.png', fullPage: true });\n    }\n\n    return results;\n  }\n});\n\nconst { items } = await run.dataset().getData();\nconst report = items[0];\n\nconsole.log(report.passed ? \"✅ All steps passed\" : \"❌ Test failed\");\nreport.steps.forEach(s => console.log(`  [${s.status}] ${s.step}`));\nif (report.errors.length) console.log(\"Errors:\", report.errors);"
      },
      {
        "title": "Test a Complete E-Commerce Checkout Flow",
        "body": "const run = await client.actor(\"apify/puppeteer-scraper\").call({\n  startUrls: [{ url: \"https://your-shop.com/products/test-item\" }],\n  pageFunction: async function pageFunction(context) {\n    const { page } = context;\n    const journey = [];\n\n    // 1 — Product page\n    await page.waitForSelector('.add-to-cart');\n    journey.push({ step: \"Product page loaded\", status: \"PASS\" });\n\n    // 2 — Add to cart\n    await page.click('.add-to-cart');\n    await page.waitForSelector('.cart-count', { timeout: 3000 });\n    const cartCount = await page.$eval('.cart-count', el => el.innerText);\n    journey.push({\n      step: \"Item added to cart\",\n      status: cartCount > 0 ? \"PASS\" : \"FAIL\",\n      value: cartCount\n    });\n\n    // 3 — Go to cart\n    await page.click('.cart-icon');\n    await page.waitForSelector('.cart-summary');\n    journey.push({ step: \"Cart page loaded\", status: \"PASS\" });\n\n    // 4 — Proceed to checkout\n    await page.click('.proceed-to-checkout');\n    await page.waitForSelector('#checkout-form');\n    journey.push({ step: \"Checkout page loaded\", status: \"PASS\" });\n\n    // 5 — Fill shipping info\n    await page.type('#shipping-name', 'QA Test User');\n    await page.type('#shipping-address', '123 Test Street');\n    await page.type('#shipping-city', 'San Francisco');\n    await page.type('#shipping-zip', '94105');\n    journey.push({ step: \"Shipping info filled\", status: \"PASS\" });\n\n    return { journey, allPassed: journey.every(s => s.status === \"PASS\") };\n  }\n});"
      },
      {
        "title": "Detect All Broken Links Site-Wide",
        "body": "const run = await client.actor(\"apify/broken-links-checker\").call({\n  startUrls: [{ url: \"https://your-website.com\" }],\n  maxCrawlingDepth: 3,\n  maxRequestsPerCrawl: 200\n});\n\nconst { items } = await run.dataset().getData();\n\nconst broken = items.filter(link => link.statusCode >= 400);\nconsole.log(`Found ${broken.length} broken links out of ${items.length} checked`);\n\nbroken.forEach(link => {\n  console.log(`  [${link.statusCode}] ${link.url} — found on: ${link.referrer}`);\n});"
      },
      {
        "title": "Responsive Design Test — Multi-Viewport",
        "body": "const viewports = [\n  { name: \"Desktop\", width: 1440, height: 900 },\n  { name: \"Tablet\",  width: 768,  height: 1024 },\n  { name: \"Mobile\",  width: 375,  height: 812 }\n];\n\nconst run = await client.actor(\"apify/puppeteer-scraper\").call({\n  startUrls: [{ url: \"https://your-app.com\" }],\n  pageFunction: async function pageFunction(context) {\n    const { page } = context;\n    const results = [];\n\n    const viewports = [\n      { name: \"Desktop\", width: 1440, height: 900 },\n      { name: \"Tablet\",  width: 768,  height: 1024 },\n      { name: \"Mobile\",  width: 375,  height: 812 }\n    ];\n\n    for (const vp of viewports) {\n      await page.setViewport({ width: vp.width, height: vp.height });\n      await page.reload();\n\n      const navVisible = await page.$('.navbar') !== null;\n      const ctaVisible = await page.$('.cta-button') !== null;\n\n      results.push({\n        viewport: vp.name,\n        resolution: `${vp.width}x${vp.height}`,\n        navbarPresent: navVisible,\n        ctaButtonPresent: ctaVisible,\n        status: navVisible && ctaVisible ? \"PASS\" : \"FAIL\"\n      });\n    }\n\n    return results;\n  }\n});"
      },
      {
        "title": "Performance & Load Time Assertions",
        "body": "const run = await client.actor(\"apify/puppeteer-scraper\").call({\n  startUrls: [{ url: \"https://your-app.com\" }],\n  pageFunction: async function pageFunction(context) {\n    const { page } = context;\n\n    const startTime = Date.now();\n    await page.waitForSelector('main');\n    const loadTime = Date.now() - startTime;\n\n    const metrics = await page.metrics();\n    const perfEntries = await page.evaluate(() =>\n      JSON.stringify(window.performance.timing)\n    );\n    const timing = JSON.parse(perfEntries);\n    const ttfb = timing.responseStart - timing.navigationStart;\n    const domReady = timing.domContentLoadedEventEnd - timing.navigationStart;\n\n    return {\n      url: page.url(),\n      loadTimeMs: loadTime,\n      ttfbMs: ttfb,\n      domReadyMs: domReady,\n      jsHeapUsedMB: (metrics.JSHeapUsedSize / 1024 / 1024).toFixed(2),\n      passed: loadTime < 3000 && ttfb < 600,\n      warnings: [\n        loadTime > 3000 ? `Slow load: ${loadTime}ms (threshold: 3000ms)` : null,\n        ttfb > 600 ? `High TTFB: ${ttfb}ms (threshold: 600ms)` : null\n      ].filter(Boolean)\n    };\n  }\n});"
      },
      {
        "title": "QA Workflow — How Claude Uses This Skill",
        "body": "When asked to test a site or app, Claude will:\n\nMap the user journeys to test (registration, login, checkout, search...)\nBuild a Puppeteer/Playwright test script for each journey\nRun all tests in parallel via Apify actors\nCollect pass/fail results, screenshots, and error messages\nGenerate a structured test report with step-by-step results\nFlag failures with context — which step failed and why\nOptionally schedule recurring runs after each deployment"
      },
      {
        "title": "Normalized Test Report Schema",
        "body": "{\n  \"testName\": \"User Registration Flow\",\n  \"url\": \"https://your-app.com/signup\",\n  \"passed\": true,\n  \"duration\": 4823,\n  \"steps\": [\n    { \"step\": \"Page loaded\",            \"status\": \"PASS\", \"durationMs\": 820 },\n    { \"step\": \"Form filled\",            \"status\": \"PASS\", \"durationMs\": 310 },\n    { \"step\": \"Form submitted\",         \"status\": \"PASS\", \"durationMs\": 2100 },\n    { \"step\": \"Redirected to dashboard\",\"status\": \"PASS\", \"durationMs\": 593 }\n  ],\n  \"errors\": [],\n  \"screenshotUrl\": \"https://api.apify.com/v2/key-value-stores/.../records/signup-success.png\",\n  \"runAt\": \"2025-02-25T10:00:00Z\"\n}"
      },
      {
        "title": "CI/CD Integration (GitHub Actions)",
        "body": "# .github/workflows/qa.yml\nname: Automated QA Tests\n\non:\n  push:\n    branches: [main, staging]\n  pull_request:\n    branches: [main]\n\njobs:\n  qa:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Run QA Tests via Apify\n        run: |\n          curl -X POST \\\n            -H \"Content-Type: application/json\" \\\n            -H \"Authorization: Bearer ${{ secrets.APIFY_TOKEN }}\" \\\n            -d '{\"startUrls\":[{\"url\":\"${{ vars.STAGING_URL }}\"}]}' \\\n            \"https://api.apify.com/v2/acts/apify~puppeteer-scraper/runs\""
      },
      {
        "title": "Best Practices",
        "body": "Use unique test emails with +timestamp suffixes to avoid conflicts between runs\nAlways take a screenshot on failure for instant visual debugging\nSet timeout on every waitForSelector — never let a test hang indefinitely\nUse waitForNavigation after any click that triggers a page load\nTest both the happy path and edge cases (empty fields, wrong passwords, network slow)\nStore all test artifacts (screenshots, reports) in Apify Key-Value Store for later review\nIntegrate with Slack or email webhooks to get instant failure notifications"
      },
      {
        "title": "Error Handling",
        "body": "try {\n  const run = await client.actor(\"apify/puppeteer-scraper\").call(input);\n  const dataset = await run.dataset().getData();\n  return dataset.items;\n} catch (error) {\n  if (error.statusCode === 401) throw new Error(\"Invalid Apify token — check credentials\");\n  if (error.statusCode === 429) throw new Error(\"Rate limit hit — reduce parallel test runs\");\n  if (error.message.includes(\"timeout\")) throw new Error(\"Test timed out — check if the app is reachable\");\n  throw error;\n}"
      },
      {
        "title": "Requirements",
        "body": "An Apify account → https://www.apify.com/?fpr=dx06p\nA valid Personal API Token from Settings → Integrations\nNode.js 18+ for apify-client\nA staging or production URL to test against\nOptional: CI/CD pipeline (GitHub Actions, GitLab CI) for post-deployment triggering"
      }
    ],
    "body": "Automated QA Testing Bots Skill\nOverview\n\nThis skill enables Claude to build and run automated QA testing bots that simulate real user journeys across websites and web applications — catching bugs, broken flows, and regressions before your users do.\n\nPowered by Apify with Puppeteer and Playwright under the hood.\n\n🔗 Sign up for Apify here: https://www.apify.com/?fpr=dx06p\n\nWhat This Skill Does\nSimulate complete user journeys (signup, login, checkout, form submission)\nDetect broken links, 404 errors, and failed redirects across an entire site\nValidate UI elements — buttons, inputs, modals, dropdowns — are present and functional\nRun regression tests after deployments to catch newly introduced bugs\nTake screenshots and video recordings at each step for visual debugging\nTest across multiple viewports (desktop, tablet, mobile)\nAssert response times and flag pages that are too slow\nStep 1 — Get Your Apify API Token\nGo to https://www.apify.com/?fpr=dx06p and create a free account\nNavigate to Settings → Integrations\nDirect link: https://console.apify.com/account/integrations\nCopy your Personal API Token: apify_api_xxxxxxxxxxxxxxxx\nSet it as an environment variable:\nexport APIFY_TOKEN=apify_api_xxxxxxxxxxxxxxxx\n\nStep 2 — Install Dependencies\nnpm install apify-client\n\nActors for QA Testing\nActor ID\tBest For\napify/puppeteer-scraper\tFull browser automation, form testing, click flows\napify/playwright-scraper\tCross-browser testing (Chrome, Firefox, WebKit)\napify/broken-links-checker\tDetect all 404s and broken links site-wide\napify/website-content-crawler\tCrawl all pages and validate structure\nExamples\nTest a Full User Registration Flow\nimport ApifyClient from 'apify-client';\n\nconst client = new ApifyClient({ token: process.env.APIFY_TOKEN });\n\nconst run = await client.actor(\"apify/puppeteer-scraper\").call({\n  startUrls: [{ url: \"https://your-app.com/signup\" }],\n  pageFunction: async function pageFunction(context) {\n    const { page } = context;\n    const results = { steps: [], passed: true, errors: [] };\n\n    try {\n      // Step 1 — Page loads\n      await page.waitForSelector('#signup-form', { timeout: 5000 });\n      results.steps.push({ step: \"Page loaded\", status: \"PASS\" });\n\n      // Step 2 — Fill registration form\n      await page.type('#firstName', 'Test');\n      await page.type('#lastName', 'User');\n      await page.type('#email', `testuser+${Date.now()}@example.com`);\n      await page.type('#password', 'SecurePass123!');\n      results.steps.push({ step: \"Form filled\", status: \"PASS\" });\n\n      // Step 3 — Submit\n      await Promise.all([\n        page.waitForNavigation({ timeout: 8000 }),\n        page.click('button[type=\"submit\"]')\n      ]);\n      results.steps.push({ step: \"Form submitted\", status: \"PASS\" });\n\n      // Step 4 — Assert success redirect\n      const currentUrl = page.url();\n      if (!currentUrl.includes('/dashboard')) {\n        throw new Error(`Expected /dashboard, got: ${currentUrl}`);\n      }\n      results.steps.push({ step: \"Redirected to dashboard\", status: \"PASS\" });\n\n      // Step 5 — Screenshot proof\n      await page.screenshot({ path: 'signup-success.png', fullPage: true });\n\n    } catch (err) {\n      results.passed = false;\n      results.errors.push(err.message);\n      await page.screenshot({ path: 'signup-error.png', fullPage: true });\n    }\n\n    return results;\n  }\n});\n\nconst { items } = await run.dataset().getData();\nconst report = items[0];\n\nconsole.log(report.passed ? \"✅ All steps passed\" : \"❌ Test failed\");\nreport.steps.forEach(s => console.log(`  [${s.status}] ${s.step}`));\nif (report.errors.length) console.log(\"Errors:\", report.errors);\n\nTest a Complete E-Commerce Checkout Flow\nconst run = await client.actor(\"apify/puppeteer-scraper\").call({\n  startUrls: [{ url: \"https://your-shop.com/products/test-item\" }],\n  pageFunction: async function pageFunction(context) {\n    const { page } = context;\n    const journey = [];\n\n    // 1 — Product page\n    await page.waitForSelector('.add-to-cart');\n    journey.push({ step: \"Product page loaded\", status: \"PASS\" });\n\n    // 2 — Add to cart\n    await page.click('.add-to-cart');\n    await page.waitForSelector('.cart-count', { timeout: 3000 });\n    const cartCount = await page.$eval('.cart-count', el => el.innerText);\n    journey.push({\n      step: \"Item added to cart\",\n      status: cartCount > 0 ? \"PASS\" : \"FAIL\",\n      value: cartCount\n    });\n\n    // 3 — Go to cart\n    await page.click('.cart-icon');\n    await page.waitForSelector('.cart-summary');\n    journey.push({ step: \"Cart page loaded\", status: \"PASS\" });\n\n    // 4 — Proceed to checkout\n    await page.click('.proceed-to-checkout');\n    await page.waitForSelector('#checkout-form');\n    journey.push({ step: \"Checkout page loaded\", status: \"PASS\" });\n\n    // 5 — Fill shipping info\n    await page.type('#shipping-name', 'QA Test User');\n    await page.type('#shipping-address', '123 Test Street');\n    await page.type('#shipping-city', 'San Francisco');\n    await page.type('#shipping-zip', '94105');\n    journey.push({ step: \"Shipping info filled\", status: \"PASS\" });\n\n    return { journey, allPassed: journey.every(s => s.status === \"PASS\") };\n  }\n});\n\nDetect All Broken Links Site-Wide\nconst run = await client.actor(\"apify/broken-links-checker\").call({\n  startUrls: [{ url: \"https://your-website.com\" }],\n  maxCrawlingDepth: 3,\n  maxRequestsPerCrawl: 200\n});\n\nconst { items } = await run.dataset().getData();\n\nconst broken = items.filter(link => link.statusCode >= 400);\nconsole.log(`Found ${broken.length} broken links out of ${items.length} checked`);\n\nbroken.forEach(link => {\n  console.log(`  [${link.statusCode}] ${link.url} — found on: ${link.referrer}`);\n});\n\nResponsive Design Test — Multi-Viewport\nconst viewports = [\n  { name: \"Desktop\", width: 1440, height: 900 },\n  { name: \"Tablet\",  width: 768,  height: 1024 },\n  { name: \"Mobile\",  width: 375,  height: 812 }\n];\n\nconst run = await client.actor(\"apify/puppeteer-scraper\").call({\n  startUrls: [{ url: \"https://your-app.com\" }],\n  pageFunction: async function pageFunction(context) {\n    const { page } = context;\n    const results = [];\n\n    const viewports = [\n      { name: \"Desktop\", width: 1440, height: 900 },\n      { name: \"Tablet\",  width: 768,  height: 1024 },\n      { name: \"Mobile\",  width: 375,  height: 812 }\n    ];\n\n    for (const vp of viewports) {\n      await page.setViewport({ width: vp.width, height: vp.height });\n      await page.reload();\n\n      const navVisible = await page.$('.navbar') !== null;\n      const ctaVisible = await page.$('.cta-button') !== null;\n\n      results.push({\n        viewport: vp.name,\n        resolution: `${vp.width}x${vp.height}`,\n        navbarPresent: navVisible,\n        ctaButtonPresent: ctaVisible,\n        status: navVisible && ctaVisible ? \"PASS\" : \"FAIL\"\n      });\n    }\n\n    return results;\n  }\n});\n\nPerformance & Load Time Assertions\nconst run = await client.actor(\"apify/puppeteer-scraper\").call({\n  startUrls: [{ url: \"https://your-app.com\" }],\n  pageFunction: async function pageFunction(context) {\n    const { page } = context;\n\n    const startTime = Date.now();\n    await page.waitForSelector('main');\n    const loadTime = Date.now() - startTime;\n\n    const metrics = await page.metrics();\n    const perfEntries = await page.evaluate(() =>\n      JSON.stringify(window.performance.timing)\n    );\n    const timing = JSON.parse(perfEntries);\n    const ttfb = timing.responseStart - timing.navigationStart;\n    const domReady = timing.domContentLoadedEventEnd - timing.navigationStart;\n\n    return {\n      url: page.url(),\n      loadTimeMs: loadTime,\n      ttfbMs: ttfb,\n      domReadyMs: domReady,\n      jsHeapUsedMB: (metrics.JSHeapUsedSize / 1024 / 1024).toFixed(2),\n      passed: loadTime < 3000 && ttfb < 600,\n      warnings: [\n        loadTime > 3000 ? `Slow load: ${loadTime}ms (threshold: 3000ms)` : null,\n        ttfb > 600 ? `High TTFB: ${ttfb}ms (threshold: 600ms)` : null\n      ].filter(Boolean)\n    };\n  }\n});\n\nQA Workflow — How Claude Uses This Skill\n\nWhen asked to test a site or app, Claude will:\n\nMap the user journeys to test (registration, login, checkout, search...)\nBuild a Puppeteer/Playwright test script for each journey\nRun all tests in parallel via Apify actors\nCollect pass/fail results, screenshots, and error messages\nGenerate a structured test report with step-by-step results\nFlag failures with context — which step failed and why\nOptionally schedule recurring runs after each deployment\nNormalized Test Report Schema\n{\n  \"testName\": \"User Registration Flow\",\n  \"url\": \"https://your-app.com/signup\",\n  \"passed\": true,\n  \"duration\": 4823,\n  \"steps\": [\n    { \"step\": \"Page loaded\",            \"status\": \"PASS\", \"durationMs\": 820 },\n    { \"step\": \"Form filled\",            \"status\": \"PASS\", \"durationMs\": 310 },\n    { \"step\": \"Form submitted\",         \"status\": \"PASS\", \"durationMs\": 2100 },\n    { \"step\": \"Redirected to dashboard\",\"status\": \"PASS\", \"durationMs\": 593 }\n  ],\n  \"errors\": [],\n  \"screenshotUrl\": \"https://api.apify.com/v2/key-value-stores/.../records/signup-success.png\",\n  \"runAt\": \"2025-02-25T10:00:00Z\"\n}\n\nCI/CD Integration (GitHub Actions)\n# .github/workflows/qa.yml\nname: Automated QA Tests\n\non:\n  push:\n    branches: [main, staging]\n  pull_request:\n    branches: [main]\n\njobs:\n  qa:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Run QA Tests via Apify\n        run: |\n          curl -X POST \\\n            -H \"Content-Type: application/json\" \\\n            -H \"Authorization: Bearer ${{ secrets.APIFY_TOKEN }}\" \\\n            -d '{\"startUrls\":[{\"url\":\"${{ vars.STAGING_URL }}\"}]}' \\\n            \"https://api.apify.com/v2/acts/apify~puppeteer-scraper/runs\"\n\nBest Practices\nUse unique test emails with +timestamp suffixes to avoid conflicts between runs\nAlways take a screenshot on failure for instant visual debugging\nSet timeout on every waitForSelector — never let a test hang indefinitely\nUse waitForNavigation after any click that triggers a page load\nTest both the happy path and edge cases (empty fields, wrong passwords, network slow)\nStore all test artifacts (screenshots, reports) in Apify Key-Value Store for later review\nIntegrate with Slack or email webhooks to get instant failure notifications\nError Handling\ntry {\n  const run = await client.actor(\"apify/puppeteer-scraper\").call(input);\n  const dataset = await run.dataset().getData();\n  return dataset.items;\n} catch (error) {\n  if (error.statusCode === 401) throw new Error(\"Invalid Apify token — check credentials\");\n  if (error.statusCode === 429) throw new Error(\"Rate limit hit — reduce parallel test runs\");\n  if (error.message.includes(\"timeout\")) throw new Error(\"Test timed out — check if the app is reachable\");\n  throw error;\n}\n\nRequirements\nAn Apify account → https://www.apify.com/?fpr=dx06p\nA valid Personal API Token from Settings → Integrations\nNode.js 18+ for apify-client\nA staging or production URL to test against\nOptional: CI/CD pipeline (GitHub Actions, GitLab CI) for post-deployment triggering"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/g4dr/qa-testing-bots",
    "publisherUrl": "https://clawhub.ai/g4dr/qa-testing-bots",
    "owner": "g4dr",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/qa-testing-bots",
    "downloadUrl": "https://openagent3.xyz/downloads/qa-testing-bots",
    "agentUrl": "https://openagent3.xyz/skills/qa-testing-bots/agent",
    "manifestUrl": "https://openagent3.xyz/skills/qa-testing-bots/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/qa-testing-bots/agent.md"
  }
}