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

如何将Selenium中基于this.driver.findElement()的函数抽象到独立文件?

Selenium + Cucumber.js 复用元素检查逻辑的问题解决

问题描述

在Node.js环境中基于Selenium Webdriver和Cucumber.js搭建测试框架时,原本在homePageSteps.js中的横幅检查代码可正常运行:

Then('there should be a banner', async function() {
    var banner = await this.driver.findElement(By.className('banner')).getRect();
    assert.ok(banner.height!==null);
});

为了让该检查逻辑能在任意步骤文件中复用,将代码抽离到banners.js:

function checkBanner(driver) {
    var banner = this.driver.findElement(By.className('banner')).getRect();
    return banner.height;
};

module.exports = { checkBanner };

随后在步骤文件中引入并调用:

const banners = require("../../support/components/banners");

// Other things...

Then('there should be a banner', async function() {
  assert.ok(banners.checkBanner()!==null);
});

运行时出现错误:Cannot read properties of undefined (reading 'findElement'),本质是抽离的函数无法获取当前有效的Selenium driver实例。

错误原因

  1. 抽离的checkBanner函数错误使用this.driver——此处的this并非Cucumber步骤上下文对象,且定义了driver参数却未实际使用。
  2. 调用checkBanner()时未传入this.driver实例,导致函数内部无法获取可操作的driver对象。
  3. Selenium API均为异步操作,抽离的函数未添加async/await处理异步流程,会直接返回Promise而非实际结果。

解决方案

方案一:修正参数传递与异步处理

修改banners.js,正确使用传入的driver参数并处理异步:

const { By } = require('selenium-webdriver');

async function checkBanner(driver) {
    const banner = await driver.findElement(By.className('banner')).getRect();
    return banner.height;
};

module.exports = { checkBanner };

在步骤文件中调用时传入this.driver:

const banners = require("../../support/components/banners");
const assert = require('assert');

Then('there should be a banner', async function() {
  const bannerHeight = await banners.checkBanner(this.driver);
  assert.ok(bannerHeight !== null);
});

方案二:采用页面对象模式(推荐)

对于复杂测试场景,推荐使用页面对象模式封装元素操作,这是UI自动化测试的最佳实践,便于维护和复用:
创建BannerPage.js:

const { By } = require('selenium-webdriver');

class BannerPage {
    constructor(driver) {
        this.driver = driver;
        this.bannerLocator = By.className('banner');
    }

    // 获取横幅高度
    async getBannerHeight() {
        const banner = await this.driver.findElement(this.bannerLocator).getRect();
        return banner.height;
    }

    // 检查横幅是否显示
    async isBannerDisplayed() {
        try {
            const banner = await this.driver.findElement(this.bannerLocator);
            return await banner.isDisplayed();
        } catch (err) {
            // 元素找不到时返回false
            return false;
        }
    }
}

module.exports = BannerPage;

在步骤文件中实例化并使用:

const BannerPage = require("../../support/pages/BannerPage");
const assert = require('assert');

Then('there should be a banner', async function() {
  const bannerPage = new BannerPage(this.driver);
  const isBannerVisible = await bannerPage.isBannerDisplayed();
  assert.ok(isBannerVisible);
});

方案说明

  • 方案一快速解决当前问题,通过正确传递driver实例和异步处理,确保函数能正常操作页面元素。
  • 方案二的页面对象模式将元素定位与测试逻辑分离,后续若横幅的定位规则变化,只需修改BannerPage中的定位器即可,大幅提升代码可维护性,适合长期迭代的测试框架。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 01:33:29