Cypress-wait-until - 等待元素属性更改

问题描述 投票:0回答:3

我正在测试一个应用程序,该应用程序有一个按钮,该按钮会导致屏幕上另一个元素中的值发生更改,而无需重新加载页面。然而,该值的变化几乎是即时的,或者需要几秒钟。显然,我不想使用一些任意的等待,并且我不想使用(硬)断言 - 这可能会导致测试因失败而停止,而不是失败......所以我'一直在研究 cypress-wait-until (https://www.npmjs.com/package/cypress-wait-until)。我已经写了各种变体,大致如下:

    waitForElemToChange(elem) {
        elem.invoke('attr', val').then((initialVal) => {
        cy.waitUntil(() => elem.invoke('attr', 'value').then((val) => val != initialVal))
    }

但到目前为止没有任何效果 - 大多数尝试都导致“重试超时:cy.invoke() 出错,因为您的主题是:null。您无法在 null 值上调用任何函数,例如 attr。”

但它是同一个主题,只是在上一行中返回了一个值??

javascript wait cypress
3个回答
23
投票

这看起来太复杂了。我会通过等待

initialValue
,然后等待不同的值来实现它。

cy.get('input').should('have.value', 'myInitialValue');     // wait for initial value
cy.get('input').should('not.have.value', 'myInitialValue'); // wait for it to change

.should()
将重试断言最多 4 秒。

如果“几秒”指的是超过 4 秒,则可以添加超时选项,这比任意等待更好,因为一旦断言通过,它就会继续。

我假设您的元素是输入,因为您正在访问

val
而不是
text


8
投票

我浏览了你的函数,我认为使用上存在几个问题。这可能是与 cypress 相关的问题或等待插件。

首先,在您的代码中,我认为使用 elem 您尝试传递类似

cy.get("path")
的内容。问题是,当您第一次调用 elem 并尝试重新使用 elem 时,它会变为 null。因此,如果您期望
cy.get('path')
运行两次,那么它不会发生。

其次,由于某种原因,在你的等待中,

cy.waitUntil(() => elem.invoke('attr', 'value').then((val) => val != initialVal))

//This part becomes true all the time.
elem.invoke('attr', 'value').then((val) => val != initialVal))

第三,

invoke('attr', 'value')

不会捕获对象的变化属性。请注意,这些观察结果是通过尝试您尝试做的事情收集的。我需要做额外的研究来找出函数的确切行为。

考虑到上述事实,我对代码做了一些更改。

  • 更改的主要更新是传递 CSS 路径而不是 cypress 对象 (elem)
  • 使用js查询选择器操作来获取变化的值(要取初始值我们可以使用invoke)

示例 1:在 waitUntil 中获取新值并检查变量更改

const CheckElementChange = (path) => {
    //get the initial value of your object
    cy.get(path).invoke('attr', 'value').then($initialVal => {
        //It's better if you can do your click operation here

        //Wait untill the element changes
        cy.waitUntil(() =>
        cy.get(path).then($newVal => 
            $newVal[0].value !== $initialVal),
            //optional timeouts and error messages
            {
                errorMsg: "was expecting some other Value but got : " + $initialVal,
                timeout: 10000, 
                interval: 500 
              }
        ).then(() => {
            cy.log("Found a difference in values")
        })
})
}

示例 2:在新值提取之后移动 waitUntil 并等待 newVal !== initialVal 为 true

const CheckElementChangew = (path) => {
    //get the initial value of your object
    cy.get(path).invoke('attr', 'value').then($initialVal => {
        //It's better if you can do your click operation here

        //Wait untill the element changes
        cy.get(path).then($newVal => {
            cy.waitUntil(() => $newVal[0].value !== $initialVal, {
                //optional timeouts and error messages
                errorMsg: "was expeting some other Value but got : " + $initialVal,
                timeout: 10000, 
                interval: 500 
              }).then(() => {
                cy.log("Found a difference in values")
            })
        })
    })
}

用途:

it('test',() => {
    CheckElementChange2("#fname");
})

注意:如果您期望点击时值会发生变化,除非值变化有几秒的时间间隔,否则最好在提取初始值后再点击(如上面代码中的注释)。


1
投票

您不需要为此使用插件,您只需要:

cy.wrap({}).then(() => Promise((resolve) => { ... });

在承诺之内,想做什么就做什么;属性更改、文档加载等等。

执行此操作的各种插件所做的就是将其包装在如下实用函数中:

const waitForProperty = (checkForProperty) => cy.wrap({}).then(() => new Cypress.Promise((resolve) => {
  // run this every 500ms until our condition is met or 60 seconds has passed. 
  let elapsed = 0;
  const checkIfResolvedYet = () => {
    elapsed += 500;
    if (checkForProperty()) {
      resolve();
      return;
    }

    // If it didn't resolve, check again in 500ms
    if (elapsed < 60000) {
      setTimeout(checkIfResolvedYet, 500);
    }
  };

  // Run initial check
  checkIfResolvedYet();
}));

所以你可以这样使用它:

it("wait for property", () => {
  cy.visit("/");
  cy.get("#app").then(($app) => {

    // Some deferred thing here triggers a property change to wait for
    setTimeout(() => {
      $app.attr("data-test", "test-123");
    }, 1000);

    // Wait for the property to be set
    waitForProperty(() => {
      const value = $app.attr("data-test");
      cy.log("during query: " + value);
      if (value === "test-123") {
        return true;
      }
    });

    cy.log("the property is now set");
  });
});

查询期间记录:未定义

查询期间记录:未定义

查询期间记录:test-123

记录属性现已设置

是的,这些插件可以节省您编写大约 10 行代码。

...但是如果 you 编写代码,则可以添加

cy.log
语句来准确调试条件未触发的原因。

需要使用插件就使用插件;但使用

waitUntil
可能会导致神秘的“永远无法工作”的情况,无法调试任何重要的情况。

一般来说,如果一个插件可以被复制 < 10 lines of code, you may get more value from copying the equivalent code into your tests folder than from using the plugin.

© www.soinside.com 2019 - 2024. All rights reserved.