【ECCUBE】【playwrite】店舗設定:個別設定のE2Eテストコード全体構成

2024-10-03
筆者が苦戦したE2Eテストコードを記録として残す。
特に、fixtureを使ったDBへのレコード作成!!ファイル同士の関連性が分からな過ぎた (´;ω;`)

前提条件

  • ECCUBE がローカルに保存されている事

コード全体

(1) 【spec】E2Eテストコード

《場所》
e2e-tests/spec/admin/tenant/individual_settings.spec.ts

《test関数説明》
個別設定:個別設定ページで値を入力し保存・反映がされるか確認
定休日カレンダー設定_新規作成:定休日が新規作成できるかどうか確認
定休日カレンダー設定_複数行_ページ遷移確認:定休日レコードが複数ある場合のページネーション確認

import {test} from "../../../fixtures/admin_login.fixture";
import {AdminShopIndividualSettingsPage} from "../../../pages/admin/tenant/individual_settings.page";

test('個別設定',
    {tag: ["@tenant_owner_a"]},
    async ({loginPage,page}) => { 
        const ShopIndividualSettingsPage = new AdminShopIndividualSettingsPage(page);

        // ログイン確認
        await loginPage.seeAfterLoginSuccess();

        // 店舗設定を開く
        await ShopIndividualSettingsPage.gotoIndividualSetting();

        // タブタイトルの存在確認
        await ShopIndividualSettingsPage.seeTabTitle();

        // 値入力
        await ShopIndividualSettingsPage.fillIndividualSetting(
            {
                businessHours: 'サンプル営業時間',
                postage: '123456789',
                taxSet: '999999999'
            }
        );
        // 保存
        await ShopIndividualSettingsPage.clickRegisterButton();

        // 反映確認
        await ShopIndividualSettingsPage.seeInputIndividualSetting();

        // 値入力
        await ShopIndividualSettingsPage.fillIndividualSetting(
            {
                businessHours: '',
                postage: '',
                taxSet: ''
            }
        );
        // 保存
        await ShopIndividualSettingsPage.clickRegisterButton();

        // 反映確認
        await ShopIndividualSettingsPage.seeDeleteIndividualSetting();
        await ShopIndividualSettingsPage.seeSavedMessage();
    }
);

test('定休日カレンダー設定_新規作成',
    {tag: ["@tenant_owner_a"]},
    async ({loginPage,page}) => {
        const ShopIndividualSettingsPage = new AdminShopIndividualSettingsPage(page);

        // ログイン確認
        await loginPage.seeAfterLoginSuccess();

        // 店舗設定を開く
        await ShopIndividualSettingsPage.gotoIndividualSetting();

        // 値入力
        await ShopIndividualSettingsPage.fillCalendarHoliday(
            {
                calendarTitle: '定休日はありません_新規作成',
                calendarHoliday: '2024-10-07'
            }
        );
        // 保存
        await ShopIndividualSettingsPage.clickCreateButton();
        await ShopIndividualSettingsPage.clickRegisterButton();

        // 反映確認
        await ShopIndividualSettingsPage.seeInputHolidayCalendar();
    }
);

test('定休日カレンダー設定_複数行_ページ遷移確認',
    {tag: ["@tenant_owner_a"]},
    async ({loginPage,page}) => {
        const ShopIndividualSettingsPage = new AdminShopIndividualSettingsPage(page);

        // ログイン確認
        await loginPage.seeAfterLoginSuccess();

        // 店舗設定を開く
        await ShopIndividualSettingsPage.gotoIndividualSetting();

        // 11行のカレンダー作成
        await ShopIndividualSettingsPage.createCalendar(10);

        // 次へボタン押下
        await ShopIndividualSettingsPage.clickNextPageButton();

        // 画面遷移されているか確認
        await ShopIndividualSettingsPage.seePrevPageButton();
    }
);

(2) 【page】(1)で使うクラス・関数まとめ

《場所》
e2e-tests/pages/admin/tenant/individual_settings.page.ts

import {expect, Locator, Page} from "@playwright/test";
import {ECCUBE_ADMIN_ROUTE} from "../../../config/default.config";
import {createCalendar} from "../../../fixtures/admin/tenant/individual_settings.fixture";

export class AdminShopIndividualSettingsPage {
    readonly page: Page;
    readonly url: string;
    readonly businessHours: Locator;        // 店舗情報
    readonly postage: Locator;              // 送料
    readonly taxSet: Locator;               // 税設定
    readonly registerButton: Locator;       // 登録
    readonly createButton: Locator;         // 新規作成
    readonly calendarTitle: Locator;        // 入力:カレンダータイトル
    readonly calendarHoliday: Locator;      // 入力:定休日
    readonly confCalenderTitle: Locator;    // 確認:カレンダータイトル
    readonly calenderRow01: Locator;        // 登録カレンダー1行目
    readonly nextPage: Locator;             // 次へ
    readonly prevPage: Locator;             // 前へ

    constructor(page: Page) {
        this.page = page;
        this.url = `${ECCUBE_ADMIN_ROUTE}/tenant/tradelaw`;
        this.businessHours = page.locator('#shop_master_business_hour');
        this.postage = page.locator('#shop_master_delivery_free_amount');
        this.taxSet = page.locator('#shop_master_invoice_registration_number');
        this.calendarTitle = page.locator('#calendar_item_new #calendar_title');
        this.calendarHoliday = page.locator('#calendar_item_new #calendar_holiday');
        this.nextPage = page.locator('.pagination .page-item:has-text("次へ")');
        this.prevPage = page.locator('.pagination .page-item:has-text("前へ")');
        this.registerButton = page.getByRole('button', {name: '登録'});
        this.createButton = page.getByRole('button', {name: '新規作成'});
        this.calenderRow01 = page.locator('.card-body .table tbody tr').nth(1);
    }

    // 対象URLへ遷移
    async goto() {
        await this.page.goto(this.url);
    }

    // メニュー操作
    async gotoIndividualSetting() {
        await this.page.getByRole('link', {name: '店舗設定'}).click();
        await this.page.getByRole('link', {name: '個別設定'}).click();
    }

    // タブタイトルの存在確認
    async seeTabTitle() {
        await expect(this.page).toHaveTitle('店舗設定 個別設定 - EC-CUBE SHOP_tenant_1');
    }

    // 値入力:
    // 定休日以外の設定
    async fillIndividualSetting(individualSetting: {
            businessHours: string,
            postage: string,
            taxSet: string,
    }){
        await this.businessHours.fill(individualSetting.businessHours);
        await this.postage.fill(individualSetting.postage);
        await this.taxSet.fill(individualSetting.taxSet);
    }
    // 定休日設定
    async fillCalendarHoliday(calendarHolidaySetting: {
        calendarTitle: string,
        calendarHoliday: string,
    }){
        await this.calendarTitle.fill(calendarHolidaySetting.calendarTitle);
        await this.calendarHoliday.fill(calendarHolidaySetting.calendarHoliday);
    }

    // 反映確認:
    // 入力判定
    async seeInputIndividualSetting() {
        await expect(this.businessHours).toHaveValue('サンプル営業時間');
        await expect(this.postage).toHaveValue('123,456,789');
        await expect(this.taxSet).toHaveValue('999999999');
    }
    async seeInputHolidayCalendar() {
        await expect(this.calenderRow01).toContainText('定休日はありません_新規作成');
        await expect(this.calenderRow01).toContainText('2024/10/07');
    }

    // 削除判定
    async seeDeleteIndividualSetting() {
        await expect(this.businessHours).toHaveValue('');
        await expect(this.postage).toHaveValue('');
        await expect(this.taxSet).toHaveValue('');
    }
    // async seeDeleteHolidayCalendar() {
    //     await expect(this.businessHours).toHaveValue('');
    //     await expect(this.postage).toHaveValue('');
    // }

    // 登録ボタン押下
    async clickRegisterButton() {
        await this.registerButton.click();
    }

    // 新規作成ボタン押下
    async clickCreateButton() {
        await this.createButton.click();
    }

    // 登録ボタンの表示確認
    async seeRegisterButton() {
        await expect(this.registerButton).toBeVisible();
    }

    // 次へボタン押下
    async clickNextPageButton() {
        await this.nextPage.click();
    }

    // 前へボタン押下
    async seePrevPageButton() {
        await expect(this.prevPage).toBeVisible();
    }

    // 登録完了メッセージ
    async seeSavedMessage() {
        await expect(this.page.locator('.alert-success')).toContainText('保存しました');
    }

    // 定休日レコード作成
    async createCalendar(
        record: number,
    ) {
        for (let i = 0; i < record; i++) {
            await createCalendar();
        }
    }
}

(3) 【type】ECCUBEから返ってきてほしいリスポンスの期待型

《場所》
e2e-tests/types/calendar.type.ts

export type Calendar = {
    "id": number,
    "title": string,
    "holiday": string,
    "create_date": string,
    "update_date": string,
    "baseInfo": {
        "id": number
    }
}

(4)【fixtures】APIを使用

《場所》
e2e-tests/fixtures/admin/tenant/individual_settings.fixture.ts

import {request} from "@playwright/test";
import {Calendar} from "../../../types/calendar.type";

/**
 * 定休日カレンダーのレコード作成
 */
// Promise<typeファイル->type名>
export const createCalendar = async (): Promise<Calendar> => {
    
    // 新規HTTPリクエストする
    const context = await request.newContext();

    // GETでURLにアクセスー>リスポンスを返却
    // APIクッキーの作成
    await context.get(`/fixture/get_mall_role`);

    // ECCUBE側(FixtureController.php)の指定ルートにPOST依頼をかけている
    // 処理結果を変数に格納
    const CalendarResponse = await context.post('/fixture/calendar/generate_calendar');
    
    // 結果をJSONに変換
    return await CalendarResponse.json();
}

(5) 【generator】DBの操作

《場所》
tests/Eccube/Tests/Fixture/Generator.php


    /**
     * Calendar オプジェクトを生成して返す.
     * @return Calendar
     */
    public function createCalendar()
    {
        // 新規カレンダーオブジェクトを作成
        $Calendar = new Calendar();

        // カレンダーを登録したい店舗を変数に格納
        $tenant_a = 2;
        $tenant = $this->entityManager->getRepository(BaseInfo::class)->find($tenant_a);

        // レコードに値を設定し保存
        $title = '年中無休で営業しております';
        $Calendar
            ->setBaseInfo($tenant)
            ->setTitle($title)
            ->setHoliday(new \DateTime())
            ->setCreateDate(new \DateTime())
            ->setUpdateDate(new \DateTime());
        $this->entityManager->persist($Calendar);
        $this->entityManager->flush();

        // 登録結果を返す
        return $Calendar;
    }

(6) 【fixture】ECCUBE側でHTTPリクエストの受け取り + レコード作成

    /**
     * 定休日カレンダーの作成
     */
    // ルート名は任意
    #[Route(
        '/calendar/generate_calendar',
        name: 'generate_calendar',
        methods: ['POST'],
    )]
    public function generateCalendarWithClass(Request $request, bool $baseOrderOnly = true): Response
    {   
        // カレンダーレコードを作成。
        $Calendar = $this->generator->createCalendar();

        // createCalendar()の実行結果をjsonファイルとして返す。
        return new Response(
            $Calendar->toJSON(),
            Response::HTTP_CREATED,
            ['Content-Type' => 'application/json']
        );
    }

関連サイト

【ECCUBE】【Playwrite】fixtrueを使ってDBにレコードを追加する方法

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール