ここまで4回の投稿でCypressテストの設定・テストコードなどをご紹介してきました。5回目の今回は、laracasts/cypressというLaravelでCypressを使用するために作成されたパッケージをご紹介します。Laravel10.xのプロジェクトにインストールして使ってみました。
Cypressのセットアップや基本的なテストなど、以前の記事は以下からご覧いただけます。
Cypressセットアップ・実行方法
Cypress画面表示のテスト
Cypressログイン・ログアウトのテスト
Cypressパスワードリセットのテスト
laracasts/cypressインストール
今までご紹介したCypressのテストでは、テスト対象プロジェクトとCypressが全く別のディレクトリでも問題なかったのですが、今回ご紹介するlaracasts/cypressはLaravelのartisanコマンドやfactoryなどを使用するため、テスト対象のLaravelプロジェクト内にインストールする必要があります。
ではまずはCypressをインストールします。Laravelのプロジェクトルートで、以下のコマンドを実行します。
% npm install cypress --save-dev
執筆時点で、cypress13.14.2がインストールされました。次にlaracasts/cypressのインストールです。以下のコマンドを実行します。
% composer require laracasts/cypress --dev
このコマンドで、laracasts/cypress3.0.2と関連パッケージがインストールされました。
最後に、以下のコマンドで初期ファイルを作成します。コマンドを実行するとcypressのディレクトリをどこに作成するか?を質問されるので、任意のディレクトリを指定してください。ここではコマンドラインで提案された通りのtests/配下を指定しました。
% php artisan cypress:boilerplate Where should we put the cypress directory? [tests/cypress]: > Updated tests/cypress/support/index.js Updated tests/cypress/plugins/index.js Created tests/cypress/plugins/swap-env.js Created tests/cypress/integration/example.cy.js Created tests/cypress/support/laravel-commands.js Created tests/cypress/support/laravel-routes.js Created tests/cypress/support/assertions.js Created tests/cypress/support/index.d.ts Created cypress.config.js Created .env.cypress
ファイルが作成されました、さっそくCypressを立ち上げてみます。以下のコマンドを実行してください。
% npx cypress open
ここで、require is not defined in ES module scopeというエラーが発生しました。
require is not defined の修正
Laravel10ではデフォルトでpackage.jsonに"type": "module"が設定されているのですが、これとlaracasts/cypressで使用されているCommonJS形式の記述がマッチしないことが原因でエラーとなっているようです。
このエラーの修正方法には何パターンかありますが、ここではLaravelのデフォルトを変更せず、またできるだけ簡単にエラーを解消できるよう以下の修正を行います。
1:ファイルの拡張子を.cjsに変更
まず、Cypress実行の際にrequireされる以下の2ファイルの拡張子を.jsから.cjsへ変更します。
/cypress.config.cjs // .jsから.cjsへ /tests/cypress/plugins/swap-env.cjs // .jsから.cjsへ
2:configファイルを修正
次に、cypress.config.cjsファイルのe2e内、setupNodeEvents()に以下のtaskを追加します。
const { defineConfig } = require('cypress')
module.exports = defineConfig({
.....
    e2e: {
        setupNodeEvents(on, config) {
          // ここにtaskを追加(plugins/index.jsの内容を移動)
          on('task', require('./tests/cypress/plugins/swap-env.cjs'));  //ここを追加
          return config                              //ここを追加
        },
.....
    },
})
3:index.jsを削除
2の変更により/tests/cypress/plugins/index.jsは不要になるので削除します。
ここまででエラー修正は完了です。
4:baseUrlの指定
configファイルを開いているので、テストの実行に必要なbaseUrlも設定しておきましょう。
同じくconfigファイルのe2e内にLaravelプロジェクトのURLをセットします。
const { defineConfig } = require('cypress')
module.exports = defineConfig({
.....
    e2e: {
        setupNodeEvents(on, config) {
          // return require('./tests/cypress/plugins/index.js')(on, config)
          // ここに元のplugins/index.jsの内容を移動
          on('task', require('./tests/cypress/plugins/swap-env.cjs'));
          return config
        },
        baseUrl: 'http://127.0.0.1:8000', //プロジェクトURLの指定
.....
    },
})
ここまで進めたら、再度以下のコマンドでCypressを立ち上げます。
% npx cypress open
問題なく起動したらダッシュボードを開いて、laracasts/cypressインストール時に自動生成されたexample.cy.jsを選択し、実行してみます。
こちらもエラーなく成功したら準備は完了です。
laracasts/cypressのコマンド
laracasts/cypressでは、Laravelプロジェクトのテストに便利なコマンドが用意されています。その中からいくつかテストでよく使うものをご紹介します。
まずはcreate()から。factoyと連動して、テスト用データを作成できます。以下の例ではUserデータを作成しています。
    cy.create('App\\Models\\User', { 
        name: 'ユーザー名',
        email: 'login-test@example.com',
    });
次に、login()・logout()です。コマンド名の通りログイン・ログアウトの処理を実行するコマンドで、PHPUnitでauth()->login($user)、auth()->logout()と記述した時と同じ動作をしてくれます。以下のように、引数にユーザーの情報を渡して使用します。
    cy.login({ name: 'ユーザー名' });
    cy.logout({ email: 'test@example.com'' });
そして次はcurrentUser()です。これはLaravelのauth()->user()と同じく、現在認証されているユーザーを取得してくれます。取得したユーザー情報は、Cypressコマンドのits()と組み合わせることで任意のプロパティが取り出せます。以下の例では取得したユーザーのemailデータを取り出し、期待通りか確認しています。
    cy.currentUser().its('email').should('eq', 'test@example.com');
最後に、refreshDatabase()です。Laravelのmigrate:refreshをコールします。このコマンドは任意の場所で使用できますが、CypressのbeforeEach()コマンドと組み合わせて使用すると、各テストケースの前にDBをリフレッシュしてくれるので便利です。
    beforeEach(() => {
        cy.refreshDatabase();
    });
テストコード
今回は新規会員登録・ログイン・ログアウトのテストを、ここまでご紹介したlaracasts/cypressのコマンドを使用して作成しました。
describe('laracasts/cypress Test', () => {
    beforeEach(() => {
        cy.refreshDatabase();
    });
    it('新規会員登録テスト', () => {
        cy.visit('/register');
        // フォームに情報を入力・送信
        cy.get('input[name=name]').type('新規登録ユーザー');
        cy.get('input[name=email]').type('test@example.com');
        cy.get('input[name=password]').type('password');
        cy.get('input[name=password_confirmation]').type('password');
        cy.get('button[type="submit"]').click()
        // ダッシュボードにリダイレクトされたことを確認
        cy.url().should('eq', Cypress.config().baseUrl + '/dashboard');
        // 認証中のユーザーを確認
        cy.currentUser().its('name').should('eq', '新規登録ユーザー');
    });
    it('ログインテスト', () => {
        // ユーザーを作成
        cy.create('App\\Models\\User', {
            name: 'ログインテスト',
            email: 'login-test@example.com',
        });
        cy.visit('/login');
        cy.get('input[name=email]').type('login-test@example.com');
        cy.get('input[name=password]').type('password');
        cy.get('button[type="submit"]').click()
        // ダッシュボードに遷移したことを確認
        cy.url().should('eq', Cypress.config().baseUrl + '/dashboard');
        // 認証中のユーザーを確認
        cy.currentUser().its('email').should('eq', 'login-test@example.com');
    });
    it('ログアウトテスト', () => {
        // ユーザーを作成
        cy.create('App\\Models\\User', {
            name: 'ログアウトテスト',
            email: 'logout-test@example.com',
        });
        //ログインを実行
        cy.login({ name: 'ログアウトテスト' });
        cy.visit('/dashboard')
        //ドロップダウンメニューを開くためのボタンクリック・ログアウトボタンをクリック
        cy.get('.relative').click()
        cy.contains('a', 'ログアウト').click()
        cy.visit('/dashboard').assertRedirect('/login');
        // 認証中のユーザーがいないことを確認
        cy.currentUser().should('not.exist');
    });
});
では、テストを実行してみましょう。Cypressのブラウザでテストファイルをクリックします。まだCypressを立ち上げていない場合はnpx cypress openを実行してCypressを立ち上げてくださいね。
全て成功しました!今回Cypressコマンドの説明は省きましたが、以下の記事で実行方法や代表的なコマンドをご紹介していますのでぜひご覧ください。
Cypressセットアップ・実行方法
Cypress画面表示のテスト
Cypressログイン・ログアウトのテスト
Cypressパスワードリセットのテスト

