首页 文章

如何使用赛普拉斯在E2E测试中登录Auth0?

提问于
浏览
10

我已经开始测试一个反应webapp但我没有走远,因为我遇到了登录问题 . 我正在使用cypress e2e测试工具 .

将显示一个欢迎页面,其中包含一个要登录的按钮,该页面将重定向到auth0服务 . 用户使用电子邮件和密码登录,然后使用令牌重定向回webapp .

我尝试了许多不同的方法,导致了不同的问题 .

注意:我不想测试Auth0,我只想输入我的webapp .

Attempt 1. Clicking on login button

尝试:赛普拉斯应该像用户一样做,因此测试将点击登录按钮并转到Auth0并填写凭据 . 问题:赛普拉斯不允许您在测试期间导航到其他域 .

因为赛普拉斯更改了自己的主机URL以匹配您的应用程序的URL,所以它要求您的应用程序保留在同一个超级域中以进行单个测试 .

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

Attempt 2. Login programmatically from the test

尝试:使用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

Attempt 3. Login programmatically from the webapp

尝试:我开始认为柏树只是从应用程序发出的 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
})

由于某些原因,这不起作用,元素被添加但是不会等到请求发出 .

所以我不知道还有什么可以尝试的 . 也许所有事情都是对如何在E2E中进行登录的误解,我是否应该使用模拟数据以便不需要登录?

2 回答

  • 0

    赛普拉斯目前不支持此功能 . 不过,我构建了一个可能有用的解决方法 .

    我 Build 了一个与cypress并行运行的简单服务器 . endpoints 打开Puppeteer的无头实例并完成登录流程,使用所有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);
    

    然后我只是扩展赛普拉斯以添加 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秒,这很糟糕,但比没有任何身份验证更好:/

  • 0

    你可以按照这个article虽然对我来说它没有用 . 我在this article的帮助下完成了它的工作:

    yarn添加auth0-js --dev

    让我们创建一个名为 loginAsAdmin 的自定义命令:

    Cypress.Commands.add('loginAsAdmin', (overrides = {}) => {
    Cypress.log({
        name: 'loginAsAdminBySingleSignOn'
    });
    
    const webAuth = new auth0.WebAuth({
        domain: 'my-super-duper-domain.eu.auth0.com', // Get this from https://manage.auth0.com/#/applications and your application
        clientID: 'myclientid', // Get this from https://manage.auth0.com/#/applications and your application
        responseType: 'token id_token'
    });
    
    webAuth.client.login(
        {
            realm: 'Username-Password-Authentication',
            username: 'mytestemail@something.co.uk',
            password: 'SoVeryVeryVery$ecure',
            audience: 'myaudience', // Get this from https://manage.auth0.com/#/apis and your api, use the identifier property
            scope: 'openid email profile'
        },
        function(err, authResult) {
            // Auth tokens in the result or an error
            if (authResult && authResult.accessToken && authResult.idToken) {
                const token = {
                    accessToken: authResult.accessToken,
                    idToken: authResult.idToken,
                    // Set the time that the access token will expire at
                    expiresAt: authResult.expiresIn * 1000 + new Date().getTime()
                };
    
                window.sessionStorage.setItem('my-super-duper-app:storage_token', JSON.stringify(token));
            } else {
                console.error('Problem logging into Auth0', err);
    throw err;
            }
        }
    );
      });
    

    要使用它:

    describe('access secret admin functionality', () => {
        it('should be able to navigate to', () => {
            cy.visitHome()
                .loginAsAdmin()
                .get('[href="/secret-adminny-stuff"]') // This link should only be visible to admins
                .click()
                .url()
                .should('contain', 'secret-adminny-stuff/'); // non-admins should be redirected away from this url
        });
    });
    

    所有功劳都归于Johnny Reilly

相关问题