見出し画像

振る舞い駆動っぽい書き方ができるCodeceptJSは使いやすい?!生成AIとの相性もチェックしてみた!


はじめに

SHIFTで自動化アーキテクトをやっている片山 嘉誉です。

今回は「CodeceptJS」について話をして行きたいと思うのですが、その前に皆さん「Behavior Driven Development (BDD) : 振る舞い駆動開発」をご存じですか?

以前Playwrightとpytest-bddを使った振る舞い駆動のテスト環境を構築しましたが、これはGherkin(ガーキン)で書かれたテストシナリオにPlaywrightのスクリプトを紐づけ、日本語でテストシナリオを書いて 非エンジニアでも分かりやすくしよう! という取り組みでした。

非エンジニアにはとても分かりやすい反面、テストシナリオに紐づく実行処理を別途書かないと行けないため、SeleniumもしくはPlaywrightの知識が必要となります。

世の中にはテスト用のツールがごまんとありますが、色々探しているとSeleniumやPlaywrightの知識が無くても使えるツールとして、Gherkinに近い形でテストコードが書けるCodeceptJSというツールに行きつきました。

ラッパーという言葉でどれだけ伝わるか分かりませんが、このツールはCodeceptJS向けに書いたテストコードを内部でWebDriver(Selemium)やPlaywright向けに変換して実行してくれるというもので、そのテストコードの書き方がGherkinベースで非エンジニアでも馴染みやすい書き方になっているのが特徴です。

そこでどのような使い勝手なのか触ってみたのですが、結論から言ってしまうとテスト対象によっては簡単に実装できて便利なものの、複雑なサイトの場合は結局ロケーターの指定を多用するのでどのフォームに入力してどのボタンを押しているのかが分かりにくくなり、非エンジニアでも分かりやすいコードを書くという事が実現できませんでした。

但し、かなり作りこまれたツールであるため本当のGherkinでシナリオを書く機能に対応していたり、PageObjectによる実装もできるようになっており、テスト自動化のプラットフォームとしては有用に感じたので、ここではどちらかというと非エンジニア向けではなくある程度実装ができる人向けにCodeceptJSの機能を紹介できればと思っています。

なお、導入資料として以下のサイトがとても参考になったので、まずは紹介させて頂きます。

■参考記事

テストデータ作成にCodeceptJSを使ってみた

【E2E】CodeceptJS入門編

■参考動画

【STAC2020】"全部乗せ" フレームワーク CodeceptJS でE2Eテストを楽にしよう

テスト環境構築について

今回はPlaywrightを使ったテスト環境を作って行きますが、セットアップ手順は公式サイトにコマンドが載っているので参照してください。

initの際に言語設定を「ja-JP」にしておくと少し面白いのでオススメします!(後から変更できますし、他はひとまずデフォルトのままで)

■CodeceptJSのインストールコマンド

PS C:\work\codeceptjs> npm install codeceptjs playwright --save
PS C:\work\codeceptjs> npx codeceptjs init

Installing to C:\work\codeceptjs
? Do you plan to write tests in TypeScript? No
? Where are your tests located? ./*_test.js        
? What helpers do you want to use? Playwright
? Where should logs, screenshots, and reports to be stored? ./output
? Do you want to enable localization for tests? http://bit.ly/3GNUBbh ja-JP
Configure helpers...
? [Playwright] Browser in which testing will be performed. Possible options: chromium, firefox, webkit or electron chromium
? [Playwright] Base url of site to be tested http://localhost
? [Playwright] Show browser window Yes

何故か最後の項目(サンプルコードを自動生成してくれる部分)がエラーになってしまいますが、サンプルコードが無くても問題は無いので、これは特に気にしなくて良いです。

? Feature which is being tested (ex: account, login, etc) etc
? Filename of a test etc_test.js
C:\work\codeceptjs\node_modules\codeceptjs\lib\command\generate.js:66
      if (vocabulary.contexts.Feature) testContent = testContent.replace('Feature', vocabulary.contexts.Feature);
                              ^

TypeError: Cannot read properties of undefined (reading 'Feature')
    at C:\work\codeceptjs\node_modules\codeceptjs\lib\command\generate.js:66:31
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

なお、デフォルト設定のままだとテスト用のスクリプトを配置する場所がルートディレクトリ直下となるのですが、私は他のファイルとは分けて管理したいので「tests」フォルダを作成して「codecept.conf.js」で参照するディレクトリの設定を変更しておきました。

■testsフォルダの作成

PS C:\work\codeceptjs> mkdir tests

環境の設定は以上で完了です。

では、ここからテストコードを作成して実行してみたいと思うのですが、「tests」フォルダ配下に「google_test.js」というファイルを作成し、以下を貼り付けてください。

■Google検索を行うテストコード

// google_test.js

Feature('Google検索');

Scenario('Google検索で株式会社SHIFTを検索する。', ({ I }) => {
    I.amOnPage('https://www.google.co.jp/')
    I.fillField('検索', '株式会社SHIFT')
    I.click('Google 検索')
    I.seeInTitle('株式会社SHIFT - Google 検索')
});

テストの実行は「npx codeceptjs run」で行えるのですが、処理の実行状況を確認するオプション「--steps」を付けて実行すると、言語設定を「ja-JP」にしている場合は実行結果が日本語で表示されることが確認できます。

■実行結果

PS C:\work\codeceptjs> npx codeceptjs run --steps
CodeceptJS v3.5.4 #StandWithUkraine
Using test root "C:\work\codeceptjs"

Google検索 --
  Google検索で株式会社SHIFTを検索する。
    私は ページを移動する "https://www.google.co.jp/"
    私は フィールドに入力する "検索", "株式会社SHIFT"
    私は クリックする "Google 検索"
    私は タイトルに文字が含まれていることを確認する "株式会社SHIFT - Google 検索"
  √ OK in 2635ms


  OK  | 1 passed   // 5s
PS C:\work\codeceptjs> 

テストコードを日本語で書く

CodeceptJSは多言語対応されており、日本語でコードを書くことができます。

ただ、この書き方をするためには若干設定が必要となり、「codecept.conf.js」の以下の部分に「私は」を追加する必要があります。

■設定ファイルを変更

/** @type {CodeceptJS.MainConfig} */
exports.config = {
  …
  include: {
    I: './steps_file.js',   ← カンマを追加
    '私は': './steps_file.js' ← この行を追加
  },
  …
}

この設定を行う事で「I」の部分を「私は」でも記載できるようになり、日本語で書いたコードで同じ処理を行うことができます。

■日本語で記載したテストコード

// google_test.js

Feature('Google検索');

Scenario('Google検索で株式会社SHIFTを検索する。', ({ 私は }) => {
    私は.ページを移動する('https://www.google.co.jp/')
    私は.フィールドに入力する('検索', '株式会社SHIFT')
    私は.クリックする('Google 検索')
    私は.タイトルに文字が含まれていることを確認する('株式会社SHIFT - Google 検索')
});

ただ、CodeceptJSの多くの参考文献が英語ですし、生成AIでコードを作ろうと思うとデフォルトの英語の方が都合が良いので、日本語を使って書く事のメリットはあまり無いように感じました。

なので、ログとして日本語で出力される、というところだけ活用するのが良いと思います。

生成AIとの相性について

CodeceptJSにはGUI操作によりテストコードを作成するレコーディング機能は存在していませんが、代わりにOpenAIのAPIを使ってコードを生成するという機能が提供されているようです。

テストコードの自動修復機能も提供されているようなので少し興味はありますが、ここでは以前紹介したをPlaywrightのレコーディング機能使ってスクリプトを自動生成できるかやってみたいと思います。

補足ですが、SHIFTでは社内で誰でもGPT-4が使える環境が提供されており、今回はその環境を使ってコードの生成を行っています。

もしこの記事を読んでやってみたけど全然ダメじゃん!っと思った方はGPT-4を使ってみてください。

Playwrightからの変換(失敗)

まずはPlaywrightのレコーディング機能テストサイトを使って適当な操作を行ってみます。

■レコーディング機能の起動

npx playwright codegen demo.playwright.dev/todomvc

上記はToDoリストに「hoge」「fuga」「piyo」を登録して、「hoge」と「piyo」を完了にし、「fuga」だけアクティブとして残すという操作です。

これを生成AIに入れてCodeceptJS向けのコードを書いて貰います。

■プロンプト

```
import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
  await page.goto('https://demo.playwright.dev/todomvc/#/');
  await page.getByPlaceholder('What needs to be done?').click();
  await page.getByPlaceholder('What needs to be done?').fill('hoge');
  await page.getByPlaceholder('What needs to be done?').press('Enter');
  await page.getByPlaceholder('What needs to be done?').fill('fuga');
  await page.getByPlaceholder('What needs to be done?').press('Enter');
  await page.getByPlaceholder('What needs to be done?').fill('piyo');
  await page.getByPlaceholder('What needs to be done?').press('Enter');
  await page.locator('li').filter({ hasText: 'hoge' }).getByLabel('Toggle Todo').check();
  await page.locator('li').filter({ hasText: 'piyo' }).getByLabel('Toggle Todo').check();
  await page.getByRole('link', { name: 'Active' }).click();
});
```
上記はJavaScriptで書かれたPlaywrightのコードである。
CodeceptJSのコードに変換して欲しい。

残念ながら、生成されたこのコードを実行すると「{"placeholder":"What needs to be done?"}」のところで止まってしまいました。

■実行結果

PS C:\work\codeceptjs> npx codeceptjs run --steps
CodeceptJS v3.5.4 #StandWithUkraine
Using test root "C:\work\codeceptjs"

Test --
  test
    私は ページを移動する "https://demo.playwright.dev/todomvc/#/"
    私は クリックする {"placeholder":"What needs to be done?"}
  × FAILED in 5186ms


-- FAILURES:

  1) Test
       test:
     locator.all: Unknown engine "placeholder" while parsing selector placeholder=What needs to be done?
      at Playwright.findElements (node_modules\codeceptjs\lib\helper\Playwright.js:3252:55)
      at Playwright.findClickable (node_modules\codeceptjs\lib\helper\Playwright.js:3313:47)
      at Playwright.proceedClick (node_modules\codeceptjs\lib\helper\Playwright.js:3282:35)

  Scenario Steps:
  - 私は.クリックする({"placeholder":"What needs to be done?"}) at Test. (.\tests\google_test.js:7:5)
  - 私は.ページを移動する("https://demo.playwright.dev/todomvc/#/") at Test. (.\tests\google_test.js:6:5)

  Artifacts:
  - screenshot: C:\work\codeceptjs\output\test.failed.png


  FAIL  | 0 passed, 1 failed   // 7s
Run with --verbose flag to see complete NodeJS stacktrace
PS C:\work\codeceptjs> 

上記エラー内容を見ると「Unknown engine "placeholder"」とあり、Playwrightの「getByPlaceholder」から変換した結果では役に立たないということが分かりました。(因みにプレースホルダーとはテキストボックスの入力サンプルとしてグレー表示されているもの)

これだとPlaywrightのレコーディング機能を使うのは難しいため、続いてSelenium IDEでどうなるか検証してみます。

Selenium IDEからの変換(成功)

Selenium IDEに関する細かい操作説明は割愛しますが、Chromeブラウザの拡張機能を使ってPlaywrightで行った操作と同じ操作を記録して行きます。

XPathの情報も含んだsideファイルのままでもテストコードは生成できるのですが、プロンプトが長くなってしまうため一旦「JavaScript Mocha」形式でエクスポートしたものからコードを生成してみます。

■プロンプト

```
// Generated by Selenium IDE
const { Builder, By, Key, until } = require('selenium-webdriver')
const assert = require('assert')

describe('Untitled', function() {
  this.timeout(30000)
  let driver
  let vars
  beforeEach(async function() {
    driver = await new Builder().forBrowser('chrome').build()
    vars = {}
  })
  afterEach(async function() {
    await driver.quit();
  })
  it('Untitled', async function() {
    await driver.get("https://demo.playwright.dev/todomvc/#/")
    await driver.manage().window().setRect({ width: 1265, height: 999 })
    await driver.findElement(By.css(".new-todo")).click()
    await driver.findElement(By.css(".new-todo")).sendKeys("hoge")
    await driver.findElement(By.css(".new-todo")).sendKeys(Key.ENTER)
    await driver.findElement(By.css(".new-todo")).sendKeys("fuga")
    await driver.findElement(By.css(".new-todo")).sendKeys(Key.ENTER)
    await driver.findElement(By.css(".new-todo")).sendKeys("piyo")
    await driver.findElement(By.css(".new-todo")).sendKeys(Key.ENTER)
    await driver.findElement(By.css("li:nth-child(1) .toggle")).click()
    await driver.findElement(By.css("li:nth-child(3) .toggle")).click()
    await driver.findElement(By.linkText("Active")).click()
  })
})
```
上記はJavaScriptで書かれたSeleniumのコードである。
CodeceptJSのコードに変換して欲しい。

このコードは問題無く実行され、パスする事が確認できました。

■実行結果

PS C:\work\codeceptjs> npx codeceptjs run --steps
CodeceptJS v3.5.4 #StandWithUkraine
Using test root "C:\work\codeceptjs"

Untitled --
  test something
    私は ページを移動する "https://demo.playwright.dev/todomvc/#/"
    私は ウィンドウをリサイズする 1265, 999
    私は クリックする ".new-todo"
    私は フィールドに入力する ".new-todo", "hoge"
    私は キー入力する "Enter"
    私は フィールドに入力する ".new-todo", "fuga"
    私は キー入力する "Enter"
    私は フィールドに入力する ".new-todo", "piyo"
    私は キー入力する "Enter"
    私は クリックする "li:nth-child(1) .toggle"
    私は クリックする "li:nth-child(3) .toggle"
    私は click link "Active"
clickLink deprecated: Playwright automatically waits for navigation to happen.
Replace I.clickLink with I.click
  √ OK in 2537ms


  OK  | 1 passed   // 5s
PS C:\work\codeceptjs>

上記より、Selenium IDEを使えばある程度の精度でテストコードが自動で作れることが分かりましたが、これぐらいの事であれば生成AIを使うまでも無い話なので、ここからはCodeceptJSでサポートしているGherkinによるテストシナリオの記述とPageObjectによる実装について触れて行きたいと思います。

因みにこれは余談ですがGPT-4であれば長いプロンプトでも行ける為、Seleniumのsideファイルの内容そのままで生成できるか試してみたのですが、こちらも問題無く生成できたので参考に載せておきます。

GherkinとPageObjectついて

さて、ここからはCodeceptJSにおけるGherkinとPageObjectついてに話して行きたい思います。

なぜGherkinとPageObjectをまとめて扱っているかというと、以前生成AIを使ってpytest-bddのコードを自動生成した際にシナリオとなるGherkinと共通処理となるconftest.pyのコードを同時に生成することができており、この辺りのコード生成を一括で行うというのは生成AIにとって得意であると思ったからです。

Gherkinの書き方についてはpytest-bddとCodeceptJSで大きな差は無いのですが、pytest-bddではExamplesで指定したパラメータの使いまわしができない(同じパラメータを複数回使えない)という制限がある一方、CodeceptJSでは好きに使いまわしができたので、その点CodeceptJSの方が良くできている印象を受けました。

※CodeceptJSの方がより自然に使える印象です。

PageObjectに関してCodeceptJS特有の感想というのは特にないのですが、ページ内の共通処理を外だしして、コードの可読性をあげるという意味ではとても有用であると思うので、公式にサポートされているのは好印象です。

さて、実際にこれらを使う方法ですが、Gherkinを使うためには「npx codeceptjs gherkin:init」コマンドを実行する必要があります。

■Gherkinを使用するための初期設定

PS C:\work\codeceptjs> npx codeceptjs gherkin:init
Initializing Gherkin (Cucumber BDD) for CodeceptJS

Created C:\work\codeceptjs\features, place your *.feature files in it
Created sample feature file: features/basic.feature
Created C:\work\codeceptjs\step_definitions, place step definitions into it
Created sample steps file: step_definitions/steps.js
Updating configuration file...
Gherkin setup is done.
Start writing feature files and implement corresponding steps.
PS C:\work\codeceptjs> 

するとプロジェクトの構成が変更され、「features」フォルダ配下に「basic.feature」ファイルが、「step_definitions」フォルダ配下に「steps.js」ファイルが作成されます。

PageObjectの方は特にコマンドなど不要ですが、「npx codeceptjs gpo」を実行するとPageObjectのひな形が生成されるので、覚えておくと便利かと思います。

■PageObjectのサンプルコード生成

PS C:\work\codeceptjs> npx codeceptjs gpo
Creating a new page object

? Name of a page object Login
? Where should it be stored ./pages/Login.js
? What is your preferred object type module
Page object for Login was created in C:\work\codeceptjs\pages\Login.js
Your config file (include section) has included the new created PO:

    include: {
    ...
      loginPage: './pages/Login.js',
    },
Use loginPage as parameter in test scenarios to access this object:

Scenario('my new test', ({ I, loginPage })) { /** ... */ }

TypeScript Definitions provide autocompletion in Visual Studio Code and other IDEs
Definitions were generated in steps.d.ts
PS C:\work\codeceptjs>

この際「pages」フォルダ配下に指定したファイル名(Login.js)のファイルが作成されるのと併せて「codecept.conf.js」の「include:」に自動でコードが追加されるのですが、「,」の問題でそのままだとエラーになってしまいますので、以下の様になおしてください。

■設定ファイルの変更

/** @type {CodeceptJS.MainConfig} */
exports.config = {
  …
  include: {
    I: './steps_file.js',
    '私は': './steps_file.js', ← ここにカンマを入れてあげる

    loginPage: "./pages/Login.js",
  },
  …
}

因みにincludeの設定は特に行わなくてもPageObjectを使用する「steps.js」側で「const loginPage = require('../pages/Login');」と定義して使うこともできるため、ここに書かなくても問題はありません。

以下に環境の設定が終わった後のプロジェクト構成を記載します。

■プロジェクト構成

project
├─ codecept.conf.js … 設定ファイル
├─ features
│  └─ basic.feature … Gherkinで記載するテストシナリオのベースファイル
├─ node_modules
├─ output
├─ pages
│  └─ Login.js … PageObjectのファイル
├─step_definitions
│  └─ steps.js … Gherkinから呼び出される処理はこちらに記載する
└─tests

これらを踏まえて先ほど使用したSelenium IDEのコードから生成AIを使って各ファイルを生成して行きたいと思います。

生成AIでGherkinとPageObjectを作成する

pytest-bddで使用したプロンプトをベースにCodeceptJSの構成に合わせてプロンプトを改良してみました。

■プロンプト

```
// Generated by Selenium IDE
const { Builder, By, Key, until } = require('selenium-webdriver')
const assert = require('assert')

describe('Untitled', function() {
  this.timeout(30000)
  let driver
  let vars
  beforeEach(async function() {
    driver = await new Builder().forBrowser('chrome').build()
    vars = {}
  })
  afterEach(async function() {
    await driver.quit();
  })
  it('Untitled', async function() {
    await driver.get("https://demo.playwright.dev/todomvc/#/")
    await driver.manage().window().setRect({ width: 1265, height: 999 })
    await driver.findElement(By.css(".new-todo")).click()
    await driver.findElement(By.css(".new-todo")).sendKeys("hoge")
    await driver.findElement(By.css(".new-todo")).sendKeys(Key.ENTER)
    await driver.findElement(By.css(".new-todo")).sendKeys("fuga")
    await driver.findElement(By.css(".new-todo")).sendKeys(Key.ENTER)
    await driver.findElement(By.css(".new-todo")).sendKeys("piyo")
    await driver.findElement(By.css(".new-todo")).sendKeys(Key.ENTER)
    await driver.findElement(By.css("li:nth-child(1) .toggle")).click()
    await driver.findElement(By.css("li:nth-child(3) .toggle")).click()
    await driver.findElement(By.linkText("Active")).click()
  })
})
```
上記はJavaScriptで書かれたSeleniumのコードである。
CodeceptJSのコードに変換して欲しい。
・features/basic.featureでGherkinのフォーマットに従い振る舞いを必ず日本語で定義する。
・features/basic.featureのフォーマットを以下に示す。
```
Feature: 目的

  Scenario Outline: シナリオ
    Given 前提条件"<定義1>"前提条件
    When 操作"<定義2>"操作
    Then 結果"<定義3>"結果

    Examples:
    | 定義1 | 定義2 | 定義3 |
    | A | B | C |
```
・振る舞いの中でテストシナリオとして変更可能な部分のみに鍵カッコを付け、テストシナリオとして変更できない部分に鍵カッコは付けない。
・pagesフォルダ配下にPageObjectを作成する。
・step_definitions/steps.jsでスクリプトを作成する。
・steps.jsでPageObjectを参照する。
・basic.featureでは変更可能な部分は<>で括って変数名を付ける。
・変数名はbasic.featureとsteps.jsで関連付ける。
・steps.jsでは変更可能な部分を{string}や{int}ではなく{word}で実装する。

PageObjectのファイル名に関しては敢えて指定しない事で生成AI側で決めてもらうようにしていますが、上記の場合は「pages」フォルダ配下に「TodoPage.js」というファイルを作成して中身をコピペします。

惜しいことにそのままでは動作しない箇所が2行ほどあったので手直ししましたが、ほぼそのまま動作するコードを生成することができました。

少し処理の流れについて説明しておくと、Gherkinのテストシナリオ(basic.feature)に紐づいている処理(steps.js)が呼び出され、そこからPageObjectの処理(TodoPage.js)が呼び出されています。

【basic.feature】
    When ""という新しいTodoを追加する
    And ""という新しいTodoを追加する
    And ""という新しいTodoを追加する
    
   ↓
【steps.js】
When('"{word}"という新しいTodoを追加する', (task) => {
  TodoPage.enterTask(task);
});

   ↓
【TodoPage.js】
  enterTask(name) {
    I.fillField(this.fields.todo, name);
    I.pressKey('Enter');
  },

上記のようにテストの開始はfeatureファイルとなっており、以下のようにオプションとして「--features」を指定する事で任意のfeatureファイルを起点にテストを開始することができます。

PS C:\work\codeceptjs> npx codeceptjs run --steps --features .\features\basic.feature
CodeceptJS v3.5.4 #StandWithUkraine
Using test root "C:\work\codeceptjs"

ユーザーは新しいTodoを追加し、それを活動状態にする --
  新しいTodoを追加し、それを活動状態にする {"url":"https://demo.playwright.dev/todomvc/#/","task1":"hoge","task2":"fuga","task3":"piyo","activeTask":"fuga"}
   Given "https://demo.playwright.dev/todomvc/#/"にアクセスする ""
   When "hoge"という新しいTodoを追加する ""
   And "fuga"という新しいTodoを追加する ""
   And "piyo"という新しいTodoを追加する ""
   And 最初と最後のTodoを完了にする ""
   And "Active"リンクをクリックする ""
   Then "fuga"という名前のTodoが一つだけ表示される ""
  √ OK in 2333ms


  OK  | 1 passed   // 5s
PS C:\work\codeceptjs>

PageObjectに関しては書き方のバリエーションが広いので再生成する度に全く違う構成に変わってしまうのですが、もう少しプロンプトを工夫して方針を決めてあげれば安定してくるかも知れません。

拡張機能(ヘルパー)の作成について

最後に拡張機能について説明したいと思います。

今回ファイル名に現在時刻を指定して画面キャプチャを撮ろうと思った際、生成AIがCodeceptJSのヘルパー機能の実装について提案してきました。

プロンプトはかなりシンプルなのですがちゃんと動くコードが生成されたので、ここに残しておきたいと思います。

■プロンプト

CodeceptJSとPlaywrightを使っている環境で現在時刻を使ってスクリーンショットを取得する共通処理を作成したい。
どのファイルに実装するかも含めてプログラムを作成して欲しい。

■ヘルパーの実装(「helpers」フォルダを作成し「ScreenshotHelper.js」ファイルを作って以下をコピペする)

// helpers/ScreenshotHelper.js
class ScreenshotHelper extends Helper {
  async takeScreenshot() {
    const { page } = this.helpers.Playwright;
    const currentTime = new Date().toISOString().replace(/:/g, '-');
    const screenshotPath = `output/${currentTime}.png`;
    await page.screenshot({ path: screenshotPath });
    console.log(`Screenshot saved at ${screenshotPath}`);
  }
}

module.exports = ScreenshotHelper;

■設定の変更(codecept.conf.jsに先ほど作ったScreenshotHelperクラスを追加する)

// codecept.conf.js
exports.config = {
  // ...
  helpers: {
    Playwright: {
      // ...
    },
    ScreenshotHelper: {
      require: './helpers/ScreenshotHelper.js',
    },
  },
  // ...
};

■実装例(steps.jsなど、テストコードに対して処理を実装する)

Scenario('test something', async ({ I }) => {
  I.amOnPage('https://example.com');
  // ...
  await I.takeScreenshot();
  // ...
});

テストを実行すると「output」フォルダ配下にキャプチャファイルが保存されていきます。

実際に取得した画像が以下の様になります。

こんなに簡単にヘルパーを使った実装ができるということは生成AIの学習対象としてCodeceptJSの情報がかなりあるのでは無いかと思ったりしています。

そういった意味で、困った時に生成AIだよりで色々対応できる可能性を持っているのはテスト環境のベースとして良さそうに思いました。

おわりに

当初は非エンジニアにも優しいテストコードが書けることを期待して触ってみたCodeceptJSですが、結局ロケーターだらけのコードになって分かりづらいものになってしまい、思っていた目的は達成できませんでした。(とはいえログを日本語にできるなど、非エンジニアにもある程度理解はしやすい環境だとは思います)

これはテスト対象となるサイトにも依存する話なので一概には言えませんが、CodeceptJSのベストプラクティスによればCSSやXPathなどのロケーターを使わず画面上に表示されている内容に従いコードを書くことが推奨されています。

一応入力した文字列に対して最初にヒットしたオブジェクトを操作する、という仕組みみたいなので、これで記述できるサイトならそれで良いのですが、難しい場合はGherkinを使ってシナリオを分離して、ロケーターを使って実装するというやり方が良さそうです。

CodeceptJSはかなり多機能なので他にも色々できることがあるのですが、GUIを使ってコードを書く機能があるので使ってみたものの、まだβ版のようですし正直使い勝手が良くなかったので今回紹介しませんでした。

他にもAppiumを使ってAndroidやiOSを操作する機能もあるようなので少し触ってみたのですが、どうもAppium側の改変(プレフィックスとして"appium:"を付ける必要がある)にCodeceptJS側がついて行けておらず、実行時にエラーとなってしまうようです…。

少し残念な部分もあるので今後の発展に期待しつつ、今回のCodeceptJSの紹介を終わりたいと思います。

それではまた次の記事でお会いしましょう!「スキ」と「フォロー」もお願いします!


執筆者プロフィール:片山 嘉誉 (Katayama Yoshinori)
SIerとして長年AOSP(Android Open Source Project)をベースとしたAndroidスマートフォンの開発に携わり、併せてスマートフォン向けのアプリ開発を行ってきた。
Wi-FiやBluetoothといった無線通信機能の担当が長かったため通信系のシステムに強く、AWSを使用したシステム開発の経験もある。
生産性向上や自動化というワードが大好きで、SHIFTでは自動化アーキテクトとして参画。
最近のマイブームはChatGPTとStable Diffusionである。

《お問合せはお気軽に》

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら