You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取Python Selenium功能测试对NodeJS浏览器扩展的代码覆盖率?

Getting Code Coverage for Node.js Browser Extensions via Selenium Functional Tests

Great question—measuring code coverage from end-to-end Selenium tests for browser extensions can be tricky because the extension runs in the browser's context, not a Node.js runtime. Here's a practical, step-by-step approach to make this work with Istanbul (nyc):

1. Instrument Your Extension Code Properly

First, ensure your extension's runtime code (background scripts, content scripts, popup JS) is instrumented with Istanbul to track execution.

Configure nyc

Add a nyc section to your package.json to specify which files to instrument and how:

{
  "nyc": {
    "include": [
      "src/background/**/*.js",
      "src/content-scripts/**/*.js",
      "src/popup/**/*.js"
    ],
    "instrument": true,
    "sourceMap": true,
    "report-dir": "./coverage"
  }
}

Build with Instrumentation

If you're using a bundler like Webpack, use the istanbul-instrumenter-loader to instrument code during the build. Alternatively, run nyc directly on your built files:

npx nyc instrument ./dist ./dist-instrumented

Use the dist-instrumented folder to package your test extension.

Critical Note: For Manifest V3 extensions, temporarily adjust your Content Security Policy to allow unsafe-eval (required for Istanbul's instrumentation):

"content_security_policy": {
  "extension_pages": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}

Don’t forget to revert this for production!

2. Capture Coverage Data from the Browser

After running your Selenium tests, extract the __coverage__ object (added by Istanbul) from all parts of your extension. Add these helper functions to your Python Selenium code:

Get Background Script Coverage (Manifest V2)

def get_background_coverage(driver):
    try:
        background_page = driver.execute_script("return chrome.runtime.getBackgroundPage();")
        if background_page:
            return background_page.execute_script("return window.__coverage__;")
    except Exception as e:
        print(f"Failed to get background coverage: {e}")
    return None

Get Content Script Coverage from Tabs

def get_tab_coverage(driver):
    coverage_list = []
    for handle in driver.window_handles:
        driver.switch_to.window(handle)
        try:
            coverage = driver.execute_script("return window.__coverage__;")
            if coverage:
                coverage_list.append(coverage)
        except Exception as e:
            print(f"Failed to get coverage for tab {handle}: {e}")
    return coverage_list

Get Popup Coverage

def get_popup_coverage(driver):
    try:
        # Retrieve the popup view if it's open
        popup_view = driver.execute_script("return chrome.runtime.getViews({type: 'popup'})[0];")
        if popup_view:
            return popup_view.execute_script("return window.__coverage__;")
    except Exception as e:
        print(f"Failed to get popup coverage: {e}")
    return None

For Manifest V3 Service Workers

Manifest V3 uses service workers instead of background pages. Use the Chrome DevTools Protocol to attach to the service worker and fetch coverage:

def get_service_worker_coverage(driver):
    # Enable Debugger domain
    driver.execute_cdp_cmd("Debugger.enable", {})
    # Get all service worker targets
    targets = driver.execute_cdp_cmd("Target.getTargets", {})
    sw_targets = [t for t in targets["targetInfos"] if t["type"] == "service_worker"]
    
    coverage = None
    for target in sw_targets:
        # Attach to the service worker
        driver.execute_cdp_cmd("Target.attachToTarget", {"targetId": target["targetId"], "flatten": True})
        # Fetch coverage data
        result = driver.execute_cdp_cmd("Runtime.evaluate", {"expression": "window.__coverage__"})
        if result.get("result", {}).get("value"):
            coverage = result["result"]["value"]
        # Detach from target
        driver.execute_cdp_cmd("Target.detachFromTarget", {"targetId": target["targetId"]})
    
    driver.execute_cdp_cmd("Debugger.disable", {})
    return coverage

3. Merge Coverage Data and Generate Reports

Once you’ve collected all coverage parts, merge them into a single file and generate human-readable reports:

import json
import os
import subprocess

def save_and_merge_coverage(background_cov, tab_covs, popup_cov):
    # Create directory for partial coverage files
    partial_dir = "./coverage-partials"
    os.makedirs(partial_dir, exist_ok=True)

    # Save background/service worker coverage
    if background_cov:
        with open(os.path.join(partial_dir, "background.json"), "w") as f:
            json.dump(background_cov, f)

    # Save tab coverages
    for i, cov in enumerate(tab_covs):
        with open(os.path.join(partial_dir, f"tab-{i}.json"), "w") as f:
            json.dump(cov, f)

    # Save popup coverage
    if popup_cov:
        with open(os.path.join(partial_dir, "popup.json"), "w") as f:
            json.dump(popup_cov, f)

    # Merge all partials into a single coverage file
    subprocess.run(["npx", "nyc", "merge", partial_dir, "./coverage/coverage-final.json"], check=True)
    
    # Generate HTML report
    subprocess.run(["npx", "nyc", "report", "--reporter=html", "--report-dir=./coverage/html"], check=True)

# Usage after running your tests:
background_cov = get_background_coverage(driver)  # Use get_service_worker_coverage for MV3
tab_covs = get_tab_coverage(driver)
popup_cov = get_popup_coverage(driver)
save_and_merge_coverage(background_cov, tab_covs, popup_cov)

Key Tips

  • Source Maps: Ensure your build process generates source maps so the coverage report links back to your original source files, not the instrumented ones.
  • Cleanup: Delete the coverage-partials directory after each run to avoid leftover data from previous tests.
  • Manifest V3: The service worker approach relies on Chrome DevTools Protocol, which is fully supported in Selenium for Chrome.

This workflow will give you accurate code coverage metrics from your Selenium functional tests, showing exactly which parts of your extension code are exercised during end-to-end testing.

内容的提问来源于stack exchange,提问作者Divyanshu Juneja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:44:01