{
  "schemaVersion": "1.0",
  "item": {
    "slug": "manikantasai-playwright-automation",
    "name": "Manikantasai Playwright Automation",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/Manikantasai1987/manikantasai-playwright-automation",
    "canonicalUrl": "https://clawhub.ai/Manikantasai1987/manikantasai-playwright-automation",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/manikantasai-playwright-automation",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=manikantasai-playwright-automation",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md",
      "_meta.json",
      "examples.py"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "slug": "manikantasai-playwright-automation",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-05T07:43:09.486Z",
      "expiresAt": "2026-05-12T07:43:09.486Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=manikantasai-playwright-automation",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=manikantasai-playwright-automation",
        "contentDisposition": "attachment; filename=\"manikantasai-playwright-automation-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "manikantasai-playwright-automation"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/manikantasai-playwright-automation"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "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/manikantasai-playwright-automation",
    "agentPageUrl": "https://openagent3.xyz/skills/manikantasai-playwright-automation/agent",
    "manifestUrl": "https://openagent3.xyz/skills/manikantasai-playwright-automation/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/manikantasai-playwright-automation/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Playwright Browser Automation",
        "body": "Direct Playwright API for reliable browser automation without MCP complexity."
      },
      {
        "title": "Installation",
        "body": "# Install Playwright\nnpm install -g playwright\n\n# Install browsers (one-time, ~100MB each)\nnpx playwright install chromium\n# Optional:\nnpx playwright install firefox\nnpx playwright install webkit\n\n# For system dependencies on Ubuntu/Debian:\nsudo npx playwright install-deps chromium"
      },
      {
        "title": "Quick Start",
        "body": "const { chromium } = require('playwright');\n\n(async () => {\n  const browser = await chromium.launch({ headless: true });\n  const page = await browser.newPage();\n  \n  await page.goto('https://example.com');\n  await page.screenshot({ path: 'screenshot.png' });\n  \n  await browser.close();\n})();"
      },
      {
        "title": "1. Use Locators (Auto-waiting)",
        "body": "// ✅ GOOD: Uses auto-waiting and retries\nawait page.getByRole('button', { name: 'Submit' }).click();\nawait page.getByLabel('Username').fill('user');\nawait page.getByPlaceholder('Search').fill('query');\n\n// ❌ BAD: May fail if element not ready\nawait page.click('#submit');"
      },
      {
        "title": "2. Prefer User-Facing Attributes",
        "body": "// ✅ GOOD: Resilient to DOM changes\nawait page.getByRole('heading', { name: 'Welcome' });\nawait page.getByText('Sign in');\nawait page.getByTestId('login-button');\n\n// ❌ BAD: Brittle CSS selectors\nawait page.click('.btn-primary > div:nth-child(2)');"
      },
      {
        "title": "3. Handle Dynamic Content",
        "body": "// Wait for network idle\nawait page.goto('https://spa-app.com', { waitUntil: 'networkidle' });\n\n// Wait for specific element\nawait page.waitForSelector('.results-loaded');\nawait page.waitForFunction(() => document.querySelectorAll('.item').length > 0);"
      },
      {
        "title": "4. Use Contexts for Isolation",
        "body": "// Each context = isolated session (cookies, storage)\nconst context = await browser.newContext();\nconst page = await context.newPage();\n\n// Multiple pages in one context\nconst page2 = await context.newPage();"
      },
      {
        "title": "5. Network Interception",
        "body": "// Mock API responses\nawait page.route('**/api/users', route => {\n  route.fulfill({\n    status: 200,\n    body: JSON.stringify({ users: [] })\n  });\n});\n\n// Block resources\nawait page.route('**/*.{png,jpg,css}', route => route.abort());"
      },
      {
        "title": "Form Automation",
        "body": "// Fill form\nawait page.goto('https://example.com/login');\nawait page.getByLabel('Username').fill('myuser');\nawait page.getByLabel('Password').fill('mypass');\nawait page.getByRole('button', { name: 'Sign in' }).click();\n\n// Wait for navigation/result\nawait page.waitForURL('/dashboard');\nawait expect(page.getByText('Welcome')).toBeVisible();"
      },
      {
        "title": "Data Extraction",
        "body": "// Extract table data\nconst rows = await page.$$eval('table tr', rows =>\n  rows.map(row => ({\n    name: row.querySelector('td:nth-child(1)')?.textContent,\n    price: row.querySelector('td:nth-child(2)')?.textContent\n  }))\n);\n\n// Extract with JavaScript evaluation\nconst data = await page.evaluate(() => {\n  return Array.from(document.querySelectorAll('.product')).map(p => ({\n    title: p.querySelector('.title')?.textContent,\n    price: p.querySelector('.price')?.textContent\n  }));\n});"
      },
      {
        "title": "Screenshots & PDFs",
        "body": "// Full page screenshot\nawait page.screenshot({ path: 'full.png', fullPage: true });\n\n// Element screenshot\nawait page.locator('.chart').screenshot({ path: 'chart.png' });\n\n// PDF (Chromium only)\nawait page.pdf({ \n  path: 'page.pdf', \n  format: 'A4',\n  printBackground: true \n});"
      },
      {
        "title": "Video Recording",
        "body": "const context = await browser.newContext({\n  recordVideo: {\n    dir: './videos/',\n    size: { width: 1920, height: 1080 }\n  }\n});\nconst page = await context.newPage();\n\n// ... do stuff ...\n\nawait context.close(); // Video saved automatically"
      },
      {
        "title": "Mobile Emulation",
        "body": "const context = await browser.newContext({\n  viewport: { width: 375, height: 667 },\n  userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0)',\n  isMobile: true,\n  hasTouch: true\n});"
      },
      {
        "title": "Authentication",
        "body": "// Method 1: HTTP Basic Auth\nconst context = await browser.newContext({\n  httpCredentials: { username: 'user', password: 'pass' }\n});\n\n// Method 2: Cookies\nawait context.addCookies([\n  { name: 'session', value: 'abc123', domain: '.example.com', path: '/' }\n]);\n\n// Method 3: Local Storage\nawait page.evaluate(() => {\n  localStorage.setItem('token', 'xyz');\n});\n\n// Method 4: Reuse auth state\nawait context.storageState({ path: 'auth.json' });\n// Later: await browser.newContext({ storageState: 'auth.json' });"
      },
      {
        "title": "File Upload/Download",
        "body": "// Upload\nawait page.setInputFiles('input[type=\"file\"]', '/path/to/file.pdf');\n\n// Download\nconst [download] = await Promise.all([\n  page.waitForEvent('download'),\n  page.click('a[download]')\n]);\nawait download.saveAs('/path/to/save/' + download.suggestedFilename());"
      },
      {
        "title": "Dialogs Handling",
        "body": "page.on('dialog', dialog => {\n  if (dialog.type() === 'alert') dialog.accept();\n  if (dialog.type() === 'confirm') dialog.accept();\n  if (dialog.type() === 'prompt') dialog.accept('My answer');\n});"
      },
      {
        "title": "Frames & Shadow DOM",
        "body": "// Frame by name\nconst frame = page.frame('frame-name');\nawait frame.click('button');\n\n// Frame by locator\nconst frame = page.frameLocator('iframe').first();\nawait frame.getByRole('button').click();\n\n// Shadow DOM\nawait page.locator('my-component').locator('button').click();"
      },
      {
        "title": "Tracing (Debug)",
        "body": "await context.tracing.start({ screenshots: true, snapshots: true });\n\n// ... run tests ...\n\nawait context.tracing.stop({ path: 'trace.zip' });\n// View at https://trace.playwright.dev"
      },
      {
        "title": "Configuration Options",
        "body": "const browser = await chromium.launch({\n  headless: true,        // Run without UI\n  slowMo: 50,           // Slow down by 50ms (for debugging)\n  devtools: false,      // Open DevTools\n  args: ['--no-sandbox', '--disable-setuid-sandbox'] // Docker/Ubuntu\n});\n\nconst context = await browser.newContext({\n  viewport: { width: 1920, height: 1080 },\n  locale: 'ru-RU',\n  timezoneId: 'Europe/Moscow',\n  geolocation: { latitude: 55.7558, longitude: 37.6173 },\n  permissions: ['geolocation'],\n  userAgent: 'Custom Agent',\n  bypassCSP: true,      // Bypass Content Security Policy\n});"
      },
      {
        "title": "Error Handling",
        "body": "// Retry with timeout\ntry {\n  await page.getByRole('button', { name: 'Load' }).click({ timeout: 10000 });\n} catch (e) {\n  console.log('Button not found or not clickable');\n}\n\n// Check if element exists\nconst hasButton = await page.getByRole('button').count() > 0;\n\n// Wait with custom condition\nawait page.waitForFunction(() => \n  document.querySelectorAll('.loaded').length >= 10\n);"
      },
      {
        "title": "Sudoers Setup",
        "body": "For Playwright browser installation:\n\n# /etc/sudoers.d/playwright\nusername ALL=(root) NOPASSWD: /usr/bin/npx playwright install-deps *\nusername ALL=(root) NOPASSWD: /usr/bin/npx playwright install *"
      },
      {
        "title": "References",
        "body": "Playwright Docs\nAPI Reference\nBest Practices\nLocators Guide"
      }
    ],
    "body": "Playwright Browser Automation\n\nDirect Playwright API for reliable browser automation without MCP complexity.\n\nInstallation\n# Install Playwright\nnpm install -g playwright\n\n# Install browsers (one-time, ~100MB each)\nnpx playwright install chromium\n# Optional:\nnpx playwright install firefox\nnpx playwright install webkit\n\n# For system dependencies on Ubuntu/Debian:\nsudo npx playwright install-deps chromium\n\nQuick Start\nconst { chromium } = require('playwright');\n\n(async () => {\n  const browser = await chromium.launch({ headless: true });\n  const page = await browser.newPage();\n  \n  await page.goto('https://example.com');\n  await page.screenshot({ path: 'screenshot.png' });\n  \n  await browser.close();\n})();\n\nBest Practices\n1. Use Locators (Auto-waiting)\n// ✅ GOOD: Uses auto-waiting and retries\nawait page.getByRole('button', { name: 'Submit' }).click();\nawait page.getByLabel('Username').fill('user');\nawait page.getByPlaceholder('Search').fill('query');\n\n// ❌ BAD: May fail if element not ready\nawait page.click('#submit');\n\n2. Prefer User-Facing Attributes\n// ✅ GOOD: Resilient to DOM changes\nawait page.getByRole('heading', { name: 'Welcome' });\nawait page.getByText('Sign in');\nawait page.getByTestId('login-button');\n\n// ❌ BAD: Brittle CSS selectors\nawait page.click('.btn-primary > div:nth-child(2)');\n\n3. Handle Dynamic Content\n// Wait for network idle\nawait page.goto('https://spa-app.com', { waitUntil: 'networkidle' });\n\n// Wait for specific element\nawait page.waitForSelector('.results-loaded');\nawait page.waitForFunction(() => document.querySelectorAll('.item').length > 0);\n\n4. Use Contexts for Isolation\n// Each context = isolated session (cookies, storage)\nconst context = await browser.newContext();\nconst page = await context.newPage();\n\n// Multiple pages in one context\nconst page2 = await context.newPage();\n\n5. Network Interception\n// Mock API responses\nawait page.route('**/api/users', route => {\n  route.fulfill({\n    status: 200,\n    body: JSON.stringify({ users: [] })\n  });\n});\n\n// Block resources\nawait page.route('**/*.{png,jpg,css}', route => route.abort());\n\nCommon Patterns\nForm Automation\n// Fill form\nawait page.goto('https://example.com/login');\nawait page.getByLabel('Username').fill('myuser');\nawait page.getByLabel('Password').fill('mypass');\nawait page.getByRole('button', { name: 'Sign in' }).click();\n\n// Wait for navigation/result\nawait page.waitForURL('/dashboard');\nawait expect(page.getByText('Welcome')).toBeVisible();\n\nData Extraction\n// Extract table data\nconst rows = await page.$$eval('table tr', rows =>\n  rows.map(row => ({\n    name: row.querySelector('td:nth-child(1)')?.textContent,\n    price: row.querySelector('td:nth-child(2)')?.textContent\n  }))\n);\n\n// Extract with JavaScript evaluation\nconst data = await page.evaluate(() => {\n  return Array.from(document.querySelectorAll('.product')).map(p => ({\n    title: p.querySelector('.title')?.textContent,\n    price: p.querySelector('.price')?.textContent\n  }));\n});\n\nScreenshots & PDFs\n// Full page screenshot\nawait page.screenshot({ path: 'full.png', fullPage: true });\n\n// Element screenshot\nawait page.locator('.chart').screenshot({ path: 'chart.png' });\n\n// PDF (Chromium only)\nawait page.pdf({ \n  path: 'page.pdf', \n  format: 'A4',\n  printBackground: true \n});\n\nVideo Recording\nconst context = await browser.newContext({\n  recordVideo: {\n    dir: './videos/',\n    size: { width: 1920, height: 1080 }\n  }\n});\nconst page = await context.newPage();\n\n// ... do stuff ...\n\nawait context.close(); // Video saved automatically\n\nMobile Emulation\nconst context = await browser.newContext({\n  viewport: { width: 375, height: 667 },\n  userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0)',\n  isMobile: true,\n  hasTouch: true\n});\n\nAuthentication\n// Method 1: HTTP Basic Auth\nconst context = await browser.newContext({\n  httpCredentials: { username: 'user', password: 'pass' }\n});\n\n// Method 2: Cookies\nawait context.addCookies([\n  { name: 'session', value: 'abc123', domain: '.example.com', path: '/' }\n]);\n\n// Method 3: Local Storage\nawait page.evaluate(() => {\n  localStorage.setItem('token', 'xyz');\n});\n\n// Method 4: Reuse auth state\nawait context.storageState({ path: 'auth.json' });\n// Later: await browser.newContext({ storageState: 'auth.json' });\n\nAdvanced Features\nFile Upload/Download\n// Upload\nawait page.setInputFiles('input[type=\"file\"]', '/path/to/file.pdf');\n\n// Download\nconst [download] = await Promise.all([\n  page.waitForEvent('download'),\n  page.click('a[download]')\n]);\nawait download.saveAs('/path/to/save/' + download.suggestedFilename());\n\nDialogs Handling\npage.on('dialog', dialog => {\n  if (dialog.type() === 'alert') dialog.accept();\n  if (dialog.type() === 'confirm') dialog.accept();\n  if (dialog.type() === 'prompt') dialog.accept('My answer');\n});\n\nFrames & Shadow DOM\n// Frame by name\nconst frame = page.frame('frame-name');\nawait frame.click('button');\n\n// Frame by locator\nconst frame = page.frameLocator('iframe').first();\nawait frame.getByRole('button').click();\n\n// Shadow DOM\nawait page.locator('my-component').locator('button').click();\n\nTracing (Debug)\nawait context.tracing.start({ screenshots: true, snapshots: true });\n\n// ... run tests ...\n\nawait context.tracing.stop({ path: 'trace.zip' });\n// View at https://trace.playwright.dev\n\nConfiguration Options\nconst browser = await chromium.launch({\n  headless: true,        // Run without UI\n  slowMo: 50,           // Slow down by 50ms (for debugging)\n  devtools: false,      // Open DevTools\n  args: ['--no-sandbox', '--disable-setuid-sandbox'] // Docker/Ubuntu\n});\n\nconst context = await browser.newContext({\n  viewport: { width: 1920, height: 1080 },\n  locale: 'ru-RU',\n  timezoneId: 'Europe/Moscow',\n  geolocation: { latitude: 55.7558, longitude: 37.6173 },\n  permissions: ['geolocation'],\n  userAgent: 'Custom Agent',\n  bypassCSP: true,      // Bypass Content Security Policy\n});\n\nError Handling\n// Retry with timeout\ntry {\n  await page.getByRole('button', { name: 'Load' }).click({ timeout: 10000 });\n} catch (e) {\n  console.log('Button not found or not clickable');\n}\n\n// Check if element exists\nconst hasButton = await page.getByRole('button').count() > 0;\n\n// Wait with custom condition\nawait page.waitForFunction(() => \n  document.querySelectorAll('.loaded').length >= 10\n);\n\nSudoers Setup\n\nFor Playwright browser installation:\n\n# /etc/sudoers.d/playwright\nusername ALL=(root) NOPASSWD: /usr/bin/npx playwright install-deps *\nusername ALL=(root) NOPASSWD: /usr/bin/npx playwright install *\n\nReferences\nPlaywright Docs\nAPI Reference\nBest Practices\nLocators Guide"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/Manikantasai1987/manikantasai-playwright-automation",
    "publisherUrl": "https://clawhub.ai/Manikantasai1987/manikantasai-playwright-automation",
    "owner": "Manikantasai1987",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/manikantasai-playwright-automation",
    "downloadUrl": "https://openagent3.xyz/downloads/manikantasai-playwright-automation",
    "agentUrl": "https://openagent3.xyz/skills/manikantasai-playwright-automation/agent",
    "manifestUrl": "https://openagent3.xyz/skills/manikantasai-playwright-automation/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/manikantasai-playwright-automation/agent.md"
  }
}