web-dev-qa-db-ja.com

サイプレスのE2EテストでAuth0にログインする方法は?

反応するWebアプリのテストを開始しましたが、ログインに問題があるため、遠くまで行きませんでした。 cypress e2eテストツールを使用しています。

ログインボタンが表示されたウェルカムページが表示され、 _auth0_ サービスにリダイレクトされます。ユーザーはメールとパスワードを使用してログインし、トークンを使用してwebappにリダイレクトされます。

私はそれらのそれぞれが異なる問題をもたらす多くの異なるアプローチを試みました。

注:Auth0をテストするのではなく、webappに入力するだけです。

試行1.ログインボタンをクリックする

試行済み:サイプレスはユーザーの操作と同じ操作を行う必要があるため、テストではログインボタンをクリックしてAuth0に移動し、資格情報を入力します。問題:サイプレスでは、テスト中に別のドメインに移動することはできません。

サイプレスは独自のホストURLをアプリケーションのホストURLと一致するように変更するため、1回のテスト全体にわたってアプリケーションが同じスーパードメインにとどまる必要があります。

_"chromeWebSecurity": false_で_cypress.json_の設定を無効にすることができるはずですが、 cy.visit()で単一のドメインにしかアクセスできないため

試行2.テストからプログラムでログインする

試した: _auth0-js_ ライブラリを使用してサイプレステストからログインするため、ログインボタンをクリックする必要がないため、ドメインの変更は発生しません。

_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()フェッチ要求を待たない 、回避策は cy.stub(win, 'fetch') を使用することです。待ちません。

enter image description here

試み3. webappからプログラムでログインする

試した:私はサイプレスがアプリ自体からではなく、アプリ自体からのスパイリクエストのみであると考え始めました(上記の点で試したように)。

ようこそページにfake-loginボタンを追加し、ハードコードされた資格情報で_auth0-js_(ドメイン変更なし)を呼び出し、テストからそれをクリックします

_cy.get('#fake-login').click()
_

問題:その戦略は機能しましたが、もちろん、ウェルカムページに資格情報付きのボタンを追加したくありません。そこで、テスト中にwebappにbutton要素を追加してみました:

_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でのログイン方法の誤解です。ログインが必要ないようにモックデータを操作する必要がありますか。

15
Mikel

これは現在、サイプレスではサポートされていません。しかし、役立つかもしれない回避策を構築しました。

サイプレスと並行して実行される単純なサーバーをセットアップしました。エンドポイントは、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秒かかりますが、これは非常に面倒ですが、認証がまったくないよりはましです:/

2
Brandon

これに従うことができます 記事 私にとってはうまくいきませんでしたが。 この記事 :の助けを借りてそれを管理しました:

yarn add 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: '[email protected]',
        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

0
Ruhul Amin