🌰

kintoneで、E2Eテストをやってみた

2024/05/30に公開

kintoneでE2Eテストをしてみる

弊社では、kintoneのアプリが30個以上を超えてきてまた
カスタムJSもかなり複雑になってきていて何かを変更した時に
うまくレコードが作成されないなど品質的な部分での悩みが増えてきました。
まだ、テストが一切なく手動で確認しているので、E2Eテストをちょっと触ってみました。

何ができるのか

kintoneの自動ログイン、kitoneのアプリ画面でフィールド入力、レコード保存、編集、画面確認など
ユーザが操作することは基本的にできます!!

「E2Eテスト」とは?

E2Eテストとは、1つのアプリケーションに対し「複数のユーザーワークフローでシミュレーションを実施し、そのパフォーマンスを測るもの」です。E2Eテストが、単体テストや結合テストといったほかのテストと異なるのは、ユーザーのワークフロー全体にフォーカスしている点です。E2EとはEnd-to-End(端から端まで)の略

何を使うか

jinzo-ningen

GitHub - goqoo-on-kintone/jinzo-ningen

jinzo-ningen は、puppeteer による kintone 操作を補助する Node.js 用ライブラリです。

パペティアとは

Puppeteerは、Node.jsライブラリで、Headless ChromeやChromiumブラウザを制御するために使用されます。

Headlessブラウザは、グラフィカルユーザーインターフェイス(GUI)を持たないブラウザで、通常は自動化されたタスクやテストの実行に使用されます。Puppeteerは、これらのブラウザをプログラムで制御し、Webページの操作、スクリーンショットの取得、フォームの入力、ページのナビゲーション、Webスクレイピングなどを行うことができます。

設定

基本的には以下のREADMEとチュートリアル通りに設定を行なっていきます。

jinzo-ningen・jest・jest-puppeteerをインストール

npm add --save-dev jinzo-ningen jest jest-puppeteer
# or
yarn add --dev jinzo-ningen jest jest-puppeteer

jest.config.jsの作成

module.exports = {
  preset: 'jest-puppeteer',
}

プロジェクトのルートに下記の内容で jest-puppeteer.config.js を保存します。

ここでは headless に false を設定し、テスト時に headless ではない Chromium を表示して挙動を確認します。

module.exports = {
  launch: {
    // headless ではない Chromium を使用する。デフォルトは true
    headless: false,
  },
}

package.json に下記のエントリを追加します。

  "scripts": {
    "test": "jest"
  },

任意のディレクトリを作成する。


mkdir jinzo-ningen-test
cd jinzo-ningen-test
mkdir __tests__

実装

jinzo-ningen-test/__tests__配下に以下testファイルを作成
では実際のテストを記載していきます!

注意 README通りにログインを変更前で記載するとログインできなかったので
変更後で記載するとログインできました。

  // テストのセットアップ。ここで kintone へのログインを行う
  変更前
  beforeAll(async () => {
    // global.page オブジェクトは jest-puppeteer が自動的にロードしている
    await page.setViewport({ width: 1920, height: 980 });
    // kintone にログイン(domain, username, password が必要)
    await jz.login({ domain, username, password });
  });
  
  変更後
  beforeAll(async () => {
    await page.setViewport({ width: 1920, height: 980 });
    await page.goto(`https://${domain}/login`);
    await page.type('input[name="username"]', username);
    await page.type('input[name="password"]', password);
    await page.click('input.login-button');
    await page.waitForNavigation();
  });

kintoneにログインのためのコード

index.test.jsを作成

const jz = require('jinzo-ningen');

// テスト全体のタイムアウト時間を設定(単位:ミリ秒)。
jest.setTimeout(60 * 1000);

// テストの記述
describe('レコード作成テスト', () => {
  // ログイン情報はテストする kintone 環境、アプリに置き換える
  const domain = '設定のドメイン';
  const username = 'ログインユーザー名';
  const password = 'パスワード';
  const appId = アプリID;
  
  // テストのセットアップ。ここで kintone へのログインを行う
  beforeAll(async () => {
    await page.setViewport({ width: 1920, height: 980 });
    await page.goto(`https://${domain}/login`);
    await page.type('input[name="username"]', username);
    await page.type('input[name="password"]', password);
    await page.click('input.login-button');
    await page.waitForNavigation();
  });

  // ログインが成功したことを確認するテスト
  it('ログインが成功すること', async () => {
    // kintone アプリのホーム画面が表示されていることを確認
    await expect(page).toMatch('kintone');
  });
});

下記のコマンドでテストを実行します。

npm test

コマンドを実行すると、自動でログイン画面が表示され

ログインが成功したはずです!!

流れとしては、レコード作成画面で対象のフィールドに値を入れ保存し

レコード作成後、詳細画面に遷移が成功したことをテストしています。

今回操作するフィールド

  • 文字列(一行)
  • ルックアップ
  • 文字列(複数行)
  • 数値
  • ドロップダウン
  • 日付
const jz = require('jinzo-ningen');

// テスト全体のタイムアウト時間を設定(単位:ミリ秒)。
jest.setTimeout(60 * 1000);

// テストの記述
describe('レコード作成テスト', () => {
  // ログイン情報はテストする kintone 環境、アプリに置き換える
  const domain = '設定のドメイン';
  const username = 'ログインユーザー名';
  const password = 'パスワード';
  const appId = アプリID;
  
  // テストのセットアップ。ここで kintone へのログインを行う
  beforeAll(async () => {
    await page.setViewport({ width: 1920, height: 980 });
    await page.goto(`https://${domain}/login`);
    await page.type('input[name="username"]', username);
    await page.type('input[name="password"]', password);
    await page.click('input.login-button');
    await page.waitForNavigation();
  });

  // ログインが成功したことを確認するテスト
  it('ログインが成功すること', async () => {
    // kintone アプリのホーム画面が表示されていることを確認
    const content = await page.content();
    await expect(content).toMatch('kintone');
  });

  // レコード作成画面への遷移をテストするdescribeブロック
  describe('レコード作成画面', () => {
    beforeAll(async () => {
      await jz.gotoCreatePage(domain, appId);
    });

    // レコード作成画面が表示されていることを確認するテスト
    it('レコード作成画面が表示されること', async () => {
      // テキスト
      await jz.setSingleLineText('支払先名_取引先マスタ', "test株式会社");
      // ルックアップ
      await jz.setLookup('支払先名_取引先マスタ', 'test株式会社');
      // 複数文字   
      await jz.setMultiLineText('金額明細', "test");
      // 数値
      await jz.setNumber('税抜金額', 1000);
      // ドロップダウン
      await jz.selectDropdown('支払サイト', '25日_月末締め翌月25日');

      // レコードを保存して詳細画面が表示されることを確認
      await jz.pressSaveAndWaitForDetailScreen();
      const detailContent = await page.content();
      await expect(detailContent).toMatch('レコードの詳細'); // 適切な確認テキストを指定してください
    });
  });
});

これでテストが成功しました!

Test Suites: 2 passed, 2 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        11.151 s, estimated 13 s
Ran all test suites.
Waiting for the debugger to disconnect...
Waiting for the debugger to disconnect...

まとめ

今回kintoneのjinzo-ningen のライブラリを利用して、E2Eテストを実施してみました。

全てのテストケースを網羅するのは、難しいので標準的な正常系だけでも

テストするのは品質を担保するには良いかなと思いました!

Discussion