testing - 如何在使用 Cypress 的 E2E 测试中登录 Auth0?

标签 testing mocking auth0 e2e-testing cypress

我已经开始测试一个 React Web 应用程序,但我并没有走得太远,因为我在登录时遇到了问题。我正在使用 cypress e2e测试工具。

欢迎页面显示一个登录按钮,它将把您重定向到 auth0服务。用户使用电子邮件和密码登录,然后使用 token 重定向回 webapp。

我尝试了很多不同的方法,每种方法都导致了不同的问题。

注意:我不想测试 Auth0,我只想进入我的 webapp。

尝试 1. 点击登录按钮

尝试过: Cypress 应该做与用户相同的事情,因此测试将单击登录按钮并转到 Auth0 并填写凭据。 问题: Cypress 不允许您在测试期间导航到另一个域。

Because Cypress changes its own host URL to match that of your applications, it requires that your application remain on the same superdomain for the entirety of a single test.

您应该能够在 cypress.json 中禁用该设置设置 "chromeWebSecurity": false 但它不会工作,因为 you can only visit a single domain with cy.visit()

尝试 2. 从测试中以编程方式登录

已尝试:使用 auth0-js 从 Cypress 测试登录库,因此不需要单击登录按钮,因此不会发生域更改。

describe('Waiting to fetch', () => {
  beforeEach(() => {
    this.fetchAuthDeferred = getDeferred()
    cy.visit('http://localhost:3000', {
      onBeforeLoad(win) {
        cy.stub(win, 'fetch')
          .withArgs($url)
          .as('fetchAuth')
          .returns(this.fetchAuthDeferred.promise)
      }
    })
  })

  it('login', () => {
    cy.visit('http://localhost:3000')

    const auth = new auth0.WebAuth(authOptions)
    auth.login(loginOptions)

    cy.get('@fetchAuth', { timeout: 10000 }).should('haveOwnProperty', 'token')

    cy.visit('http://localhost:3000')
    cy.get('[class*="hamburger"]').click()
  })
})

问题:cy.route() doesn't wait for fetch request , 解决方法是使用 cy.stub(win, 'fetch') .它不会等待:

enter image description here

尝试 3. 从 webapp 以编程方式登录

尝试过:我开始认为 cypress 只是从应用程序而不是测试本身发出的 spy 请求(正如我在上面的尝试中所尝试的那样)。

我在欢迎页面中添加了一个假登录按钮,它将使用硬编码凭据调用auth0-js(因此不会更改域)并从测试中单击它

cy.get('#fake-login').click()

问题:该策略有效,但我当然不想在欢迎页面中添加带有凭据的按钮。所以我尝试在测试期间将按钮元素添加到 webapp 中:

it('Login adding element', () => {
  cy.visit('http://localhost:3000')
  const = document.createElement('div')
  fakeLogin.innerHTML = 'Fake login'
  fakeLogin.onclick = function() {
    const auth = new auth0.WebAuth(authOptions)
    auth.login(loginOptions)
  }
  fakeLogin.style.position = 'absolute'
  fakeLogin.style.zIndex = 1000
  fakeLogin.id = 'fake-login'

  cy.get('#root').invoke('prepend', fakeLogin)
  cy.get('#fake-login').click()
  cy.get('[class*="hamburger"]').click() // Visible when logged in
})

由于某种原因,这不起作用,添加了元素,但 yt 不会等到发出请求。

所以我不知道还能尝试什么。 也许一切都是对 E2E 应该如何登录的误解,我应该使用模拟数据而不需要登录吗?

最佳答案

Cypress 目前不支持此功能。不过,我构建了一个可能有帮助的解决方法。

我设置了一个与 cypress 并行运行的简单服务器。端点打开 Puppeteer 的 headless 实例并完成登录流程,使用所有 cookie 响应调用:

const micro = require("micro");
const puppeteer = require("puppeteer");
const url = require("url");

const login = async (email, password) => {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto("https://my-login-page.com");
  // do whatever you have to do to get to your auth0 lock screen, then:
  await page.waitFor(".auth0-lock-input-email");
  await page.waitFor("span.auth0-label-submit");
  await page.type(".auth0-lock-input-email input", email);
  await page.type(".auth0-lock-input-password input", password);
  await page.click("span.auth0-label-submit");
  await page.waitFor("some-selector-on-your-post-auth-page");
  return page.cookies();
 };

const server = micro(async (req, res) => {
  // expect request Url of form `http://localhost:3005?email=blahblah&password=blahblah
  const data = url.parse(req.url, true);
  const { email, password} = data.query;
  console.log(`Logging ${email} in.`);
  return login(email, password);
});

server.listen(3005);

然后我只是扩展 Cypress 以添加 login 命令:

Cypress.Commands.add("login", (email, password) => {
  const reqUrl = `http://localhost:3005?email=${encodeURIComponent(
    email
  )}&password=${encodeURIComponent(password)}`;
  console.log("Beginning login.", reqUrl);
  cy.request(reqUrl).then(res => {
    const cookies = res.body;
    cookies.forEach((c) => {
      cy.setCookie(c.name, c.value, c);
    });
  });
});

每次调用大约需要 5-10 秒,这很糟糕,但总比没有任何授权要好:/

关于testing - 如何在使用 Cypress 的 E2E 测试中登录 Auth0?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51208998/

相关文章:

unit-testing - NSubstitute 是否支持 Partial Mocks 的想法?

php - 在实例化自己对象的函数内部使用 PHP 中的模拟对象

node.js - 验证 Auth0 JWT 抛出无效算法

unit-testing - SystemVerilog 程序 block 与传统测试平台

ruby-on-rails-3 - 如何编写 Rails3 rake 任务来运行单个单元或功能测试

android - 如何在robotium中使用getChild?

node.js - Auth0 getProfile 不返回 user_id

ios - 在 iOS 上测试不同的日历

c# - 所有的类(class)都应该是可测试的吗?

Azure 应用服务在访问需要身份验证的 Web api 终结点时收到 401。但在本地工作