【问题标题】:How to wait for a function to be called when testing using Selenium WebDriver/Jest?使用 Selenium WebDriver/Jest 进行测试时如何等待调用函数?
【发布时间】:2019-05-07 03:36:30
【问题描述】:

我有一个使用 Ext JS 创建的应用程序,我正在使用 Selenium WebDriver(Node package - 版本 4.0.0-alpha.1)和 Jest 为它编写测试。在我的一个测试脚本中,我想等待一个函数被调用,然后再继续剩余的测试逻辑,但我不确定如何实现它。为了帮助演示我想要完成的工作,我使用 Sencha Fiddle 创建了一个示例应用程序。该应用程序的所有代码以及该应用程序的运行版本都可以在此处找到:https://fiddle.sencha.com/#view/editor&fiddle/2o6m。如果您查看 fiddle 的 app 文件夹,您会看到有一个带有简单控制器的 Test 组件。控制器中有一个 onAdd 函数,这是我在继续之前要等待的函数,因为在我的实际应用程序中,该函数中有代码,其余的测试都依赖于该函数。我可以通过运行以下代码行在开发工具中访问该函数: Ext.ComponentQuery.query('test')[0].getController().onAdd (请注意,需要将 activeElement 设置为预览 iFrame(文档.getElementsByName('fiddle-run-iframe')[0]) 在小提琴中使其工作)。这意味着我可以以同样的方式访问 driver.executeScript 中的函数,但是一旦我有了这个函数,我就不确定如何等待它被调用后再继续。我试图在 Jest 中使用模拟/间谍功能,但这不起作用,因为 jest 没有在 driver.executeScript 中定义,所以我不能调用 jest.fn 或 jest.spyOn。我创建了一个与示例应用程序一起使用的示例测试脚本来演示我正在尝试做什么,但现在它失败并出现错误,因为正如我所说,jest 没有在 driver.executeScript 中定义。以下是示例测试脚本的代码:

const {Builder, By, Key, until} = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');

const driver = global.driver = new Builder()
            .forBrowser('chrome')
            .setChromeOptions(new chrome.Options())
            .build();

jest.setTimeout(10000);

beforeAll(async () => {
    await driver.manage().window().maximize();
    await driver.get('https://fiddle.sencha.com/#view/editor&fiddle/2o6m');
});

afterAll(async () => {
    await driver.quit();
});


describe('check title', () => {
    it('should be SAMPLE STORE LOAD', async () => {
        expect(await driver.wait(until.elementLocated(By.css('.fiddle-title'))).getText()).toBe('SAMPLE STORE LOAD');
    });
});

describe('check store add', () => {
    it('should call add function', async () => {
        let spy;

        await driver.switchTo().frame(await driver.findElement(By.name('fiddle-run-iframe')));
        await driver.wait(until.elementIsNotVisible(await driver.wait(until.elementLocated(By.xpath('//div[starts-with(@id, "loadmask")]')))));
        await driver.executeScript(() => {
            const test = document.getElementsByName('fiddle-run-iframe')[0].contentWindow.Ext.ComponentQuery.query('test')[0];
            spy = jest.spyOn(test.getController(), 'onAdd'); //This throws an error since jest is not defined inside driver.executeScript
        });

        expect(spy).toHaveBeenCalled(); //wait for onAdd function to be called before continuing
    });

    //additional tests occur here after wait...
}); 

您可以忽略与切换到 iFrame 相关的所有逻辑,因为这只对 fiddle 是必需的,因为它在 iFrame 中运行应用程序的预览。我的实际应用程序不存在于 iFrame 中。尽管如此,我认为这个脚本有效地展示了我想要完成的工作,即等到 onAdd 函数被调用,然后再继续我的测试。我不确定是否需要使用 Selenium 或 Jest、两者的某种组合或完全不同的测试工具来执行此操作。我对编写测试比较陌生,这是我第一次在 Stack Overflow 上发帖,所以如果我说的不清楚,我深表歉意。如果您有任何问题,我很乐意澄清任何事情,并感谢您提供的任何建议!

【问题讨论】:

    标签: javascript testing selenium-webdriver extjs jestjs


    【解决方案1】:

    在我看来,在一个测试中结合 2 个不同的框架(测试方法)可能不是最好的主意。以下是关于我将如何处理类似案件的一些想法。很少的理论:

    Selenium - 非常适合使用浏览器模拟最终用户行为。基本上,它可以模拟动作(点击、文本输入等)并可以从浏览器窗口获取信息(元素、文本、样式等的存在)

    Jest - 是一个 unit 测试框架来开玩笑 javascript 代码。

    executeScript 是 Selenium 的一个方法,它在浏览器中执行任何 javascript 代码。浏览器不知道关于 jest 的任何信息 - 因此预计您遇到了您所描述的错误。您的项目知道 jest,因为它是专门导入到项目中的。

    回到问题“如何在 Selenium 中检查一个 js 函数已被调用?”

    1. 最典型的解决方案是等到浏览器屏幕上的某些内容发生变化。典型案例:

      • 出现一些元素

      • 某些元素消失了

      • 某些元素的样式发生了变化

    wait for condition in js example

    1. (有点小技巧)另一种可能的解决方案是在应用程序的 js 代码中添加一些标志,该标志在调用函数之前为 false,并在调用函数后设置为 true。然后你可以在 executeScript 中访问这个标志的值。

    some possible implementations here

    【讨论】:

    • 感谢您的详细解释。这就是为什么我不能在 Selenium 中使用 Jest 代码的原因。我想我将不得不等待 DOM 发生变化,但监听该函数会更容易,因为我正在开发的应用程序具有动态 ID。但我想我必须为此想出一个解决方法。再次感谢您的帮助并花时间回答我的问题!
    • 不客气!很高兴我能提供帮助。动态 id 的一个潜在解决方法是为元素添加一个特殊属性(当然,如果您的开发团队愿意让您的自动化生活更轻松)。例如,我们同意添加自定义属性“data-seleniumid”并在 cssSelectors 中使用。
    猜你喜欢
    • 1970-01-01
    • 2020-08-16
    • 2013-12-31
    • 2011-09-06
    • 1970-01-01
    • 2018-09-08
    • 2021-03-05
    • 2022-01-24
    • 1970-01-01
    相关资源
    最近更新 更多