在Cypress中,在测试之前将令牌设置在localStorage中。

75
我想登录并在客户端上设置一个localStorage令牌(特别是jwt)。
如何使用Cypress文档中建议的cy.request来实现这一目标?
6个回答

110

以下是添加一个命令cy.login()的示例,你可以在任何Cypress测试中使用它,或将其放置在beforeEach钩子中。

Cypress.Commands.add('login', () => { 
  cy.request({
    method: 'POST',
    url: 'http://localhost:3000/api/users/login',
    body: {
      user: {
        email: 'jake@jake.jake',
        password: 'jakejake',
      }
    }
  })
  .then((resp) => {
    window.localStorage.setItem('jwt', resp.body.user.token)
  })

})

接着在你的测试中:

beforeEach(() => {
  cy.login()
})

1
这个可以工作,但是当我访问应用程序的URL时,该值会被覆盖。我的应用似乎无法读取创建的本地存储。 - otong
2
您需要在设置localStorage之前导航到您的页面。 - kuceb
5
我建议使用cy.window()(请参见Cypress文档)来获取当前页面的窗口对象:cy.window().then(win => win.localStorage.setItem('jwt', resp.body.user.token)) - guillaumepn
cy.window().then(win => win.localStorage.setItem('jwt', resp.body.user.token)) 运行正常,谢谢 @guillaumepn - Pablo Papalardo
完美的答案。 - Abadis
显示剩余2条评论

29
作为额外的内容,你还可以使用cypress-localstorage-commands包在测试之间保留localStorage,这样登录请求只会被执行一次:
在support/commands.js中:
import "cypress-localstorage-commands";

Cypress.Commands.add('login', () => { 
  cy.request({
    method: 'POST',
    url: 'http://localhost:3000/api/users/login',
    body: {
      user: {
        email: 'jake@jake.jake',
        password: 'jakejake',
      }
    }
  })
  .its('body')
  .then(body => {
    cy.setLocalStorage("jwt", body.user.token);
  })
});

接下来,在你的测试中:

before(() => {
  cy.login();
  cy.saveLocalStorage();
});

beforeEach(() => {
  cy.restoreLocalStorage();
});

只有使用你指定的软件包才对我有效。谢谢。 - Mauricio Moraes
1
根据npm文档,您应该在before()中清除存储,然后在beforeEach中进行恢复和访问,最后在afterEach中保存localstorage。请注意,在所有测试之间保留localStorage的使用beforeEachafterEach。此外,在before语句中使用clearLocalStorageSnapshot以避免与其他测试文件保留localStorage可能发生的冲突。 - dragon788
从哪里获取这个信息? cy.setLocalStorage("jwt", body.user.token); 我正在尝试设置它,但在body.user.token部分失败了。 - ZombiePie
嗨 @ZombiePie,示例中显示的代码仅用于描述如何使用cy.setLocalStorage命令。它只能在你启动了一个 API,并且该 API 在 http://localhost:3000/api/users/login 上返回一个带有 JSON 主体和 user.token 属性的响应时才能正常工作。你需要根据自己的情况来调整登录请求和响应。 - Javier Brea
我正在尝试使用:https://blog.digital-craftsman.de/keep-local-storage-in-cypress/ 我有一个问题,如果我应用这个,系统是否仍然会每次登录? - ZombiePie
我不是很明白你的意思,@ZombiePie。这个答案涉及到 cypress-localstorage-commands Cypress 插件的使用,而你提到的博客文章与此无关。 - Javier Brea

18

我已经使用过类似bkuceras回答的东西一段时间了。最近,在测试多个角色/登录时遇到了一个问题。基本上是我以管理员身份登录并进行了一次测试,然后我以非管理员身份登录并进行第二次测试。第一个测试正常运行并结束(cypress清除本地存储),但是当第二个测试开始时,第一个测试仍在运行某些xhr请求。这些xhr请求不再看到令牌,从而触发我的应用程序看到401未经授权的错误并清除本地存储(包括我设置的非管理员令牌)。现在第二个测试失败了,因为该非管理员令牌在本地存储中不可用。

最终我的解决方案是在测试之前预取令牌,然后在visit的onBeforeLoad函数中设置令牌。这确保了在访问命令之前没有任何竞争条件会清除令牌。

cy.visit('/app', {
    onBeforeLoad: function (window) {
        window.localStorage.setItem('token', myToken);
    }
})

实际上这是一个相当独特的边缘情况,但希望这可以帮助某人,因为我花了很多时间找到这个解决方案。


2
可能是比大多数解决方案更干净的解决方案。您甚至可以将其制作成自定义命令,始终设置该项。 - Ricardo Pedroni
1
尽管与所问的问题无关,但这对我有所帮助,因为我正在使用cy.visit。谢谢! - Ryan Haney

2
如果您愿意尝试实验模式,我强烈建议使用cy.session来存储令牌:
Cypress.Commands.add('login', (username, password) => {
  cy.session([username, password], () => {
    cy.request({
      method: 'POST',
      url: '/login',
      body: { username, password },
    }).then(({ body }) => {
      window.localStorage.setItem('authToken', body.token)
    })
  })
})

更多信息请查看官方Cypress文档: https://docs.cypress.io/api/commands/session


0

我认为这个主题的标题应该更新一下。JWT令牌是这次讨论的重点!

主要问题是关于JWT令牌的,但总的来说,所有现代应用程序都在使用OIDC Microsoft article - v2-protocols-oidc / ADAL,并且在仅通过API调用生成令牌来获取访问权限时,这里有一个非常棘手的情况。 我在这里找到了 enter image description here 并将其与我的应用程序进行检查。但请确保您精通JS,并且从您的DevTeam获得良好的协助;)


-6

我已经花费了很多时间在这上面,最终可以得出结论:它永远不会适用于OAuth请求。

它可能适用于本地服务器,但在获取身份验证令牌时不起作用。


您可以向OAuth提供程序发出请求,以检索所需的数据。 - Johnnes Souza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接