【问题标题】:How to rewrite code using then block using javascript, react and cypress?如何使用然后使用javascript,react和cypress重写代码?
【发布时间】:2021-09-07 08:47:01
【问题描述】:

我有如下代码,它使用了很多嵌套的 then 子句。此代码用于测试我用 javascript 编写的代码并使用 cypress 做出反应。

{
export const waitForItems = (retries, nrItems) => {
    cy.apiGetItems().then(items => {
        if(items.length!== nrItems && retries > 0) {
            cy.wait(1000);
            return waitForItems(retries -1, nrItems);
        }
        expect(items.length).to.be.equal(nrItems);
    });
};

const item = {
    name: 'name1',
};
const itemFamily = 'ItemFamily1';
const subfamily = {
    name: 'subfamily1',
}

describe('some test', () => {
    before(() => {
        cy.clickButtonByLabel('Click');
        switchUser(USERNAME);
        waitForItems(NUMBEROFRETRIES, NUMBEROFITEMS);

        cy.apiGetItems({ name: item.name })
            .then(createdItem => {
                item.id = createdItem[0].id;
        })
        .then(() => {
            cy.apiGetItemFamily({
                name: itemFamilyName,
            }).then(family => {
                cy.apiGetSubFamily({
                    name: subfamily1.name,
                    item__family__id__in: family[0].id,
                }).then(subfamily => {
                    subfamily1.id = subfamily[0].id; //error here says cannot read 
                    // id of undefined
                    cy.apiPostSomething({
                        ...something,
                        items: [item.id],
                        subfamily: [subfamily1.id],
                    }).then(createdSomething => {
                        something.id = createdSomething.id;
                        cy.apiGetItemVariable({
                            key: ItemVariableName,
                            subfamily__id__in: subfamily1.id,
                        }).then(variable => {
                            cy.apiPostVariableValue({
                                variable: variable[0].id,
                                value: controlValue,
                            }).then(() => {
                                cy.apiGetsubFamily({
                                    name: subfamily1.name,
                            }).then(newControl => {
                                const versions =
                                    newControl[0].versions;
                                const latestVersionControl = versions.find(
                                    v => v.version === '3.9.0'
                                );
                                const id = latestVersionControl.id;
                                cy.apiPatchSomething({
                                    id: Something.id,
                                    controls: [id], 
                                });
                            });
                        });
                    });
                });
            });
        });
    });
});

上面的代码工作正常。但有时我在 then(subfamily) 子句中收到错误“无法读取未定义的 id”。

我不确定为什么 subfamily[0] 在尝试这样分配时仍然不可用

 .then(subfamily => {
     subfamily1.id = subfamily[0].id;
 }

谁能帮我解决这个问题。谢谢。

【问题讨论】:

  • cy.apiGetSubFamily 的内部结构导致了问题,因为你得到了它的结果。请提供此代码。
  • 另外,您能说明subfamily1 的来源吗?它是在测试之外初始化的对象吗?

标签: javascript reactjs cypress


【解决方案1】:

首先,你应该尝试使用 async/await 语法,因为你使用了 Promise。它将帮助您编写更易于阅读的代码:

describe('some test', () => {
    before(async () => { //add async there
        cy.clickButtonByLabel('Click');
        switchUser(USERNAME);
        waitForItems(NUMBEROFRETRIES, NUMBEROFITEMS);

        const createdItem = await cy.apiGetItems({ name : item.name });
        item.id = createdItem[0].id;
        const family = await cy.apiGetItemFamily({ name: itemFamilyName });
        //and so one
    });
});

这样,您将以一种看起来同步的方式编写代码。

关于亚科的问题,

可能是cy.apiGetSubFamily的返回值没有返回数组,或者返回的是一个空数组。

编辑赛普拉斯:

Cypress 不能很好地与 Promise 配合使用,这与 async/await 语法问题无关。由于 Cypress 返回 thenable,async/await 应该可用。

但是由于 Cypress paradigm 以它的方式处理异步,当我们等待时,await/async 语法会导致不确定的结果。更多信息可以在这里找到:https://github.com/cypress-io/cypress/issues/1417

【讨论】:

  • await cy.apiGetItems() 无效,因为它不返回 Promise。
  • @Vispo 我的错。给定代码cy.apiGetItems({ name: item.name }).then(createdItem => {item.id = createdItem[0].id; }),我错误地认为它使用了常规承诺。当时对 API 调用和赛普拉斯一无所知。谢谢。
  • @Vispo 我刚刚了解到,您不仅可以在 Promise 上使用 async/await 语法,还可以在 thenable 对象上使用。 thenable 是一个实现 then 方法的对象。所以,我关于 async/await 的陈述是正确的。只需测试一下:const test = { then : callback => setTimeout(callback, 2000) }; (async () => { console.log('start'); await test; console.log('done !'); })();
  • MDN 说 thenable 是可等待的,但请测试它。任何产生 Chainable 的命令都会在await 上为您提供null 结果。
  • @user16695029 因此,由于我对这些解释不满意,所以我挖掘了更多内容。它比“不能使用 async/await 因为不是 promise”要复杂一些,因为 async/await 可以使用不是 promise 的 thenable。事实上,阅读github.com/cypress-io/cypress/issues/1417,promise 会不一致地解析(值、null 或未定义)。这是不确定的,但这与 async/await 或 Promise 无关。造成这种情况的是柏树范式。为什么和如何是重要的。我永远不会反对一个解释清楚的断言。
猜你喜欢
  • 1970-01-01
  • 2021-06-09
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
  • 2011-03-18
  • 1970-01-01
  • 1970-01-01
  • 2021-08-05
相关资源
最近更新 更多