typescript .then中的返回函数

9nvpjoqh  于 2023-05-30  发布在  TypeScript
关注(0)|答案(4)|浏览(520)

我遇到了以下Cypress异步行为的问题。我需要创建一个函数方法,它将从一个URL中获取一个参数并返回它,因为稍后它将在不同的地方使用
所以这个方法看起来像这样:

getParameterFromUrl(): string {
  cy.url().then(url => {
    cy.log(url);
    const parameterFromUrl = url.match(/\d+$/)[0];
    cy.log(paramterFromUrl);
    // return parameterFromUrl   I know this doesnt work because is within a then
  }
}

然后在测试的很多部分,我需要使用这个参数:

const parameter = onMyPageObject.getParameterFromUrl();

cy.log(parameter)

我知道这是undefined。我已经检查了很多可能的解决方案,但任何说服我,因为我必须解释的代码无处不在,然后在外面和匹配的正则表达式无处不在(我不喜欢在所有)。等待只是为请求工作,所以我甚至可以使用它。
在这种情况下,我可以做些什么来改变异步行为,做一些像这样简单的事情?

ha5z0ras

ha5z0ras1#

最简单的方法是从方法中返回链。
.then(... return parameterFromUrl)只是修改你返回的内容,但是你必须返回整个链,并像Chainable<string>一样对待它。

getParameterFromUrl(): Chainer<string> {   // use this return type

  return cy.url().then(url => {
    const parameterFromUrl = url.match(/\d+$/)[0];

    return parameterFromUrl  // this works, modifies the return value of the chain
  }
}

使用该方法:

getParameterFromUrl()
  .then(parameter => {
    cy.log(parameter)
  })
rqenqsqc

rqenqsqc2#

您不必在方法内部设置别名,可以使用Zoe提供的模式在测试外部设置别名。
然后,方法的调用者能够指定使用什么别名。

getParameterFromUrl().as('myFunnyAliasName')

...  // somewhere else

cy.get('@myFunnyAliasName').then(value => {
  cy.log(value)
})

它的工作原理与Cypress给出的示例相同,您只是将一些代码推到了方法中。

t2a7ltrp

t2a7ltrp3#

这永远不会像现在这样工作,仅仅因为你调用了一个异步函数。url()调用不会返回一个值,而是会触发一个请求,该请求将在 * 将来某个时候 * 完成,但不会立即完成。因此,getParameterFromUrl根本不可能返回正确的响应,因为当它返回它所依赖的url调用时,它还没有完成。
这个问题有两种可能的解决方案。
第一种选择:
getParameterFromUrl传递一个回调函数,这样只要url完成并有完整的响应,它就会回调调用者。这是Javascript中最常见的模式,你的代码正在使用它。一种可能的实现方式如下:

getParameterFromUrl(callback: ((url: string) => void)): string {
    cy.url().then(url => {
        cy.log(url);
        const parameterFromUrl = url.match(/\d+$/)[0];
        cy.log(paramterFromUrl);
        if (callback) callback(parameterFromUrl);     //If we've got a callback call it with the final return parameter.
    }
}

在这里,getParameterFromUrl接受一个函数作为参数,如果在获得最终值时调用该函数,则调用者可以使用它来知道值何时准备就绪。所以现在你把你的调用站点改成这样:

onMyPageObject.getParameterFromUrl(url => {
    cy.log(url);
});

请注意,您只使用回调中的最终值,而不是原始调用的返回值。如果在此调用之后有代码,则这一点很重要。
第二种选择:
让getParameterFromUrl返回一个promise,以符合更现代的Javascript开发。这一次我们返回一个对象,该对象将在调用完成时通知调用者并获取可用值。使用语言功能,我们可以使其更容易使用:

getParameterFromUrl(): Promise<string> {
    return new Promise<string>(resolve => {
        cy.url().then(url => {
            cy.log(url);
            const parameterFromUrl = url.match(/\d+$/)[0];
            cy.log(paramterFromUrl);
            resolve(parameterFromUrl);     //Resolve our promise with the proper value to return.
        }
    );
}

表面上的简单性来自async行为,它给人一种线性执行的错觉,而实际上它不是,并且将以与以前几乎相同的顺序运行。调用者也需要修改以使用此:

const parameter = await onMyPageObject.getParameterFromUrl();
cy.log(parameter);

这要求包含函数也是async,这将强制使其一直到达调用树的顶部,但希望它能产生更自然的代码,更容易理解。当然,如果你想避免大量的重写,你也可以编写一个.then调用,达到同样的效果。

hfsqlsce

hfsqlsce4#

好吧,我找到了一个解决方案,但我不太喜欢它,因为未来的开发人员将不得不进入方法内部检查别名,因为我们在不同的类中

getParameterFromUrl(alias:string){
  cy.url().then(url => {
    cy.log(url);
    const parameterFromUrl = url.match(/\d+$/)[0];
    cy.log(paramterFromUrl);
    cy.wrap(paramterFromUrl).as(alias)
  }
}

然后在另一个班级

getParameterFromUrl(parameter)

//in a complete different point in the tests

cy.get<string>('@parameter').then(parameter => {
  cy.log(parameter)
}

正如我告诉你的,这在官方文档@jonrsharpe中解释过,但有几个问题。我不能直接在第二个类中使用这个.parameter,因为这会失败,第二件事是,未来的开发人员可能会在上面的很多行中使用这个@parameter,并且必须寻找实际定义别名的方法并检查别名名称。一种选择是将别名作为参数添加,但同样必须在代码中查找,因为它是在方法中键入的字符串,而不是真实的变量。另外,所有使用此参数的代码都将包含在一个新的then()命令中,这将使代码非常难以阅读。
所以是的,这个解决方案有效,但我认为它应该是一个更好的

相关问题