<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>テスト &#8211; ねこねこネットワーク</title>
	<atom:link href="https://neko-neko.sai-net.work/category/%e3%83%86%e3%82%b9%e3%83%88/feed/" rel="self" type="application/rss+xml" />
	<link>https://neko-neko.sai-net.work</link>
	<description></description>
	<lastBuildDate>Thu, 03 Oct 2024 12:17:59 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.1</generator>
	<item>
		<title>【ECCUBE】【playwrite】店舗設定：個別設定のE2Eテストコード全体構成</title>
		<link>https://neko-neko.sai-net.work/759/</link>
					<comments>https://neko-neko.sai-net.work/759/#respond</comments>
		
		<dc:creator><![CDATA[nekoneko_admin]]></dc:creator>
		<pubDate>Thu, 03 Oct 2024 12:11:38 +0000</pubDate>
				<category><![CDATA[EC-CUBE]]></category>
		<category><![CDATA[テスト]]></category>
		<guid isPermaLink="false">https://neko-neko.sai-net.work/?p=759</guid>

					<description><![CDATA[2024-10-03筆者が苦戦したE2E [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>2024-10-03<br>筆者が苦戦したE2Eテストコードを記録として残す。<br>特に、fixtureを使ったDBへのレコード作成！！ファイル同士の関連性が分からな過ぎた (´;ω;｀)</p>



<h2 class="wp-block-heading">前提条件</h2>



<ul class="wp-block-list">
<li>ECCUBE がローカルに保存されている事</li>
</ul>



<p></p>



<h2 class="wp-block-heading">コード全体</h2>



<h4 class="wp-block-heading">(1) 【spec】E2Eテストコード</h4>



<p>《場所》<br>e2e-tests/spec/admin/tenant/individual_settings.spec.ts</p>



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



<pre class="wp-block-code"><code>import {test} from "../../../fixtures/admin_login.fixture";
import {AdminShopIndividualSettingsPage} from "../../../pages/admin/tenant/individual_settings.page";

test('個別設定',
    {tag: &#91;"@tenant_owner_a"]},
    async ({loginPage,page}) =&gt; { 
        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: &#91;"@tenant_owner_a"]},
    async ({loginPage,page}) =&gt; {
        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: &#91;"@tenant_owner_a"]},
    async ({loginPage,page}) =&gt; {
        const ShopIndividualSettingsPage = new AdminShopIndividualSettingsPage(page);

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

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

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

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

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



<p></p>



<h4 class="wp-block-heading">(2) 【page】(1)で使うクラス・関数まとめ</h4>



<p>《場所》<br>e2e-tests/pages/admin/tenant/individual_settings.page.ts</p>



<pre class="wp-block-code"><code>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 &lt; record; i++) {
            await createCalendar();
        }
    }
}</code></pre>



<h4 class="wp-block-heading">(3) 【type】ECCUBEから返ってきてほしいリスポンスの期待型</h4>



<p>《場所》<br>e2e-tests/types/calendar.type.ts</p>



<pre class="wp-block-code"><code>export type Calendar = {
    "id": number,
    "title": string,
    "holiday": string,
    "create_date": string,
    "update_date": string,
    "baseInfo": {
        "id": number
    }
}</code></pre>



<h4 class="wp-block-heading">(4)【fixtures】APIを使用</h4>



<p>《場所》<br>e2e-tests/fixtures/admin/tenant/individual_settings.fixture.ts</p>



<pre class="wp-block-code"><code>import {request} from "@playwright/test";
import {Calendar} from "../../../types/calendar.type";

/**
 * 定休日カレンダーのレコード作成
 */
// Promise&lt;typeファイル-&gt;type名&gt;
export const createCalendar = async (): Promise&lt;Calendar&gt; =&gt; {
    
    // 新規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();
}</code></pre>



<h4 class="wp-block-heading">(5) 【generator】DBの操作</h4>



<p>《場所》<br>tests/Eccube/Tests/Fixture/Generator.php</p>



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

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

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

        // 登録結果を返す
        return $Calendar;
    }</code></pre>



<h4 class="wp-block-heading">(6) 【fixture】ECCUBE側でHTTPリクエストの受け取り + レコード作成</h4>



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

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



<h2 class="wp-block-heading">関連サイト</h2>



<figure class="wp-block-embed is-type-wp-embed">
<blockquote class="wp-embedded-content" data-secret="QlyUF2eq1p"><a href="https://neko-neko.sai-net.work/722/">【ECCUBE】【Playwrite】fixtrueを使ってDBにレコードを追加する方法</a></blockquote><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;【ECCUBE】【Playwrite】fixtrueを使ってDBにレコードを追加する方法&#8221; &#8212; ねこねこネットワーク" src="https://neko-neko.sai-net.work/722/embed/#?secret=ymqGrkjf1W#?secret=QlyUF2eq1p" data-secret="QlyUF2eq1p" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</figure>
]]></content:encoded>
					
					<wfw:commentRss>https://neko-neko.sai-net.work/759/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【ECCUBE】【POSTMAN】PostManを使いリクエストを実行</title>
		<link>https://neko-neko.sai-net.work/742/</link>
					<comments>https://neko-neko.sai-net.work/742/#respond</comments>
		
		<dc:creator><![CDATA[nekoneko_admin]]></dc:creator>
		<pubDate>Thu, 03 Oct 2024 11:30:16 +0000</pubDate>
				<category><![CDATA[ツール]]></category>
		<category><![CDATA[テスト]]></category>
		<guid isPermaLink="false">https://neko-neko.sai-net.work/?p=742</guid>

					<description><![CDATA[関連記録 前提条件 ・postmanがロ [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">関連記録</h2>



<figure class="wp-block-embed is-type-wp-embed">
<blockquote class="wp-embedded-content" data-secret="uGkGZRfKQb"><a href="https://neko-neko.sai-net.work/722/">【ECCUBE】【Playwrite】fixtrueを使ってDBにレコードを追加する方法</a></blockquote><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;【ECCUBE】【Playwrite】fixtrueを使ってDBにレコードを追加する方法&#8221; &#8212; ねこねこネットワーク" src="https://neko-neko.sai-net.work/722/embed/#?secret=hptzFp9XT5#?secret=uGkGZRfKQb" data-secret="uGkGZRfKQb" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<figcaption class="wp-element-caption">=> E2Eテスト実行確認のためにpostmanを使用</figcaption></figure>



<h2 class="wp-block-heading">前提条件</h2>



<p>・postmanがローカルに保存されいてる状態</p>



<figure class="wp-block-embed">https://qiita.com/ponsuke0531/items/03483449ea0df505a540</figure>



<p></p>



<h2 class="wp-block-heading">使用手順</h2>



<p>1. 新規リクエストの作成</p>



<p>サイドメニュー-&gt;コレクション-&gt;「+」マーク押下</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="574" height="481" src="https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202101.jpg" alt="" class="wp-image-743" srcset="https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202101.jpg 574w, https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202101-300x251.jpg 300w" sizes="(max-width: 574px) 100vw, 574px" /></figure>



<p>2. リクエストを実行</p>



<p>GETの隣にある「▽」を押下 -&gt; アクセスしたいURL入力 -&gt; 送信押下</p>



<figure class="wp-block-image size-full"><img decoding="async" width="876" height="655" src="https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202139a.jpg" alt="" class="wp-image-745" srcset="https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202139a.jpg 876w, https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202139a-300x224.jpg 300w, https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202139a-768x574.jpg 768w" sizes="(max-width: 876px) 100vw, 876px" /></figure>



<p>3. 結果の確認</p>



<figure class="wp-block-image size-full"><img decoding="async" width="625" height="235" src="https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202156.jpg" alt="" class="wp-image-747" srcset="https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202156.jpg 625w, https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-202156-300x113.jpg 300w" sizes="(max-width: 625px) 100vw, 625px" /></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://neko-neko.sai-net.work/742/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【ECCUBE】【Playwrite】fixtrueを使ってDBにレコードを追加する方法</title>
		<link>https://neko-neko.sai-net.work/722/</link>
					<comments>https://neko-neko.sai-net.work/722/#respond</comments>
		
		<dc:creator><![CDATA[nekoneko_admin]]></dc:creator>
		<pubDate>Thu, 03 Oct 2024 10:14:22 +0000</pubDate>
				<category><![CDATA[EC-CUBE]]></category>
		<category><![CDATA[テスト]]></category>
		<guid isPermaLink="false">https://neko-neko.sai-net.work/?p=722</guid>

					<description><![CDATA[今回は本編で苦戦した fixtrue を [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>今回は本編で苦戦した fixtrue を使ってのレコード追加方法を記していく。</p>



<p></p>



<h2 class="wp-block-heading">したい事</h2>



<p>E2E側からの操作でECCUBEのDBにレコードを追加したい。<br>今回は、dtb_calendarにレコードを追加をする。</p>



<figure class="wp-block-embed is-type-wp-embed">
<blockquote class="wp-embedded-content" data-secret="5aRKKWKyWq"><a href="https://neko-neko.sai-net.work/759/">【ECCUBE】【playwrite】店舗設定：個別設定のE2Eテストコード全体構成</a></blockquote><iframe loading="lazy" class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;【ECCUBE】【playwrite】店舗設定：個別設定のE2Eテストコード全体構成&#8221; &#8212; ねこねこネットワーク" src="https://neko-neko.sai-net.work/759/embed/#?secret=YF1lESlBrh#?secret=5aRKKWKyWq" data-secret="5aRKKWKyWq" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</figure>



<h2 class="wp-block-heading">実行手順</h2>



<ol class="wp-block-list">
<li>EntityManagerを使い、dtb_calendarにレコードを追加</li>



<li>ルート名の設定 + レコード作成結果を返す</li>



<li>E2E側でECCUBE側に対してのHTTPリクエスト処理を作成</li>



<li>テストコードを作成</li>
</ol>



<p></p>



<h4 class="wp-block-heading">1. EntityManagerを使い、dtb_calendarにレコードを追加</h4>



<p>《場所》<br>tests/Eccube/Tests/Fixture/Api/Controller/FixtureController.php</p>



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

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

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

        // 登録結果を返す
        return $Calendar;
    }</code></pre>



<p>《疑問》</p>



<p>疑問：店舗情報を取得しているのはなぜか？<br>結論：レコード追加先の店舗を設定するため。</p>



<p>疑問：setBaseInfo()をEntity/Calendar.phpで探してもなかった。ではどこか？<br>結論：TenantTrait.phpに関数が存在する。</p>



<p>src/Eccube/Entity/Calendar.php</p>



<pre class="wp-block-code"><code>    class Calendar extends AbstractEntity
    {
        use Traits\TenantTrait;
　　　　 .....
    }</code></pre>



<p>src/Eccube/Entity/Traits/TenantTrait.php</p>



<pre class="wp-block-code"><code>    /**
     * テナント情報を設定する
     *
     * @param BaseInfo $baseInfo
     * @return $this
     */
    public function setBaseInfo(BaseInfo $baseInfo)
    {
        $this-&gt;baseInfo = $baseInfo;
        return $this;
    }</code></pre>



<p></p>



<h4 class="wp-block-heading">2. ルート名の設定 + レコード作成結果を返す</h4>



<p>《場所》<br>tests/Eccube/Tests/Fixture/Generator.php</p>



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

        // createCalendar()の実行結果をJSON形式で返す
        return new Response(
            $Calendar-&gt;toJSON(),
            Response::HTTP_CREATED,
            &#91;'Content-Type' =&gt; 'application/json']
        );
    }</code></pre>



<p>#[Route]：アクセス名・期待したいるメゾット (GET? POST?)</p>



<p></p>



<h4 class="wp-block-heading">3. postmanでカレンダーレコード作成関数の実行確認</h4>



<p>（1）<a href="http://localhost:8080/fixture/get_mall_role">http://localhost:8080/fixture/get_mall_role</a> にアクセスしAPIクッキーを作成<br>（2）<a href="http://localhost:8080/fixture/calendar/generate_calendar">http://localhost:8080/fixture/calendar/generate_calendar</a> にアクセスしテストを実行</p>



<figure class="wp-block-embed is-type-wp-embed">
<blockquote class="wp-embedded-content" data-secret="0WyjT97g32"><a href="https://neko-neko.sai-net.work/742/">【ECCUBE】【POSTMAN】PostManを使いリクエストを実行</a></blockquote><iframe loading="lazy" class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;【ECCUBE】【POSTMAN】PostManを使いリクエストを実行&#8221; &#8212; ねこねこネットワーク" src="https://neko-neko.sai-net.work/742/embed/#?secret=T4wJFVEiFJ#?secret=0WyjT97g32" data-secret="0WyjT97g32" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</figure>



<p></p>



<h4 class="wp-block-heading">4. E2E側でECCUBE側に対してHTTPリクエストする処理を作成</h4>



<p>《場所》<br>e2e-tests/fixtures/admin/tenant/individual_settings.fixture.ts</p>



<pre class="wp-block-code"><code>/**
 * 定休日カレンダーのレコード作成
 */
// Promise&lt;typeファイル-&gt;type名&gt;
export const createCalendar = async (): Promise&lt;Calendar&gt; =&gt; {
    
    // 新規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();
}</code></pre>



<p></p>



<h4 class="wp-block-heading">5. テストコードを作成</h4>



<p>《場所》<br>e2e-tests/spec/admin/tenant/individual_settings.spec.ts</p>



<pre class="wp-block-code"><code>test('定休日カレンダー設定_複数行_ページ遷移確認',
    {tag: &#91;"@tenant_owner_a"]},
    async ({loginPage,page}) =&gt; {
　　　　 // レコード
        const ShopIndividualSettingsPage = new AdminShopIndividualSettingsPage(page);

　　　　　......
　　　　　
        // 10行のカレンダー作成
        await ShopIndividualSettingsPage.createCalendar(10);
    }
);</code></pre>



<p>《場所》<br>e2e-tests/pages/admin/tenant/individual_settings.page.ts</p>



<pre class="wp-block-code"><code>export class AdminShopIndividualSettingsPage {

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



<p></p>



<h2 class="wp-block-heading">E2Eテストの実行</h2>



<p>リスポンス情報と共に&#8221;1 passed (5.0s)&#8221;が返却されたため成功！！(^▽^)/</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="177" src="https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-200734-1024x177.jpg" alt="" class="wp-image-733" srcset="https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-200734-1024x177.jpg 1024w, https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-200734-300x52.jpg 300w, https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-200734-768x132.jpg 768w, https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-200734-1536x265.jpg 1536w, https://neko-neko.sai-net.work/cms/wp-content/uploads/2024/10/スクリーンショット-2024-10-03-200734-2048x353.jpg 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-embed is-type-wp-embed">
<blockquote class="wp-embedded-content" data-secret="rpzVgvxz4x"><a href="https://neko-neko.sai-net.work/587/">【EC-CUBE】【Playlight】E2Eテストを実行</a></blockquote><iframe loading="lazy" class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;【EC-CUBE】【Playlight】E2Eテストを実行&#8221; &#8212; ねこねこネットワーク" src="https://neko-neko.sai-net.work/587/embed/#?secret=m8hydnRM4y#?secret=rpzVgvxz4x" data-secret="rpzVgvxz4x" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</figure>
]]></content:encoded>
					
					<wfw:commentRss>https://neko-neko.sai-net.work/722/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【ECCUBE】【Playwrite】テストコードを作成する</title>
		<link>https://neko-neko.sai-net.work/682/</link>
					<comments>https://neko-neko.sai-net.work/682/#respond</comments>
		
		<dc:creator><![CDATA[nekoneko_admin]]></dc:creator>
		<pubDate>Wed, 25 Sep 2024 10:11:52 +0000</pubDate>
				<category><![CDATA[EC-CUBE]]></category>
		<category><![CDATA[テスト]]></category>
		<guid isPermaLink="false">https://neko-neko.sai-net.work/?p=682</guid>

					<description><![CDATA[したい事 実際のコード 1. 会員情報の [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">したい事</h2>



<ol class="wp-block-list">
<li>会員情報の登録確認</li>



<li>画面遷移とテキスト表示確認</li>



<li>管理側 -&gt; コンテンツ管理 -&gt; ファイル管理 -&gt; htmlファイルのダウンロード実行確認</li>
</ol>



<p></p>



<h2 class="wp-block-heading">実際のコード</h2>



<h4 class="wp-block-heading">1. 会員情報の登録確認</h4>



<p>フロント側 -&gt; 新規会員登録 -&gt; 趣味項目を追加し、DBへの登録確認</p>



<p>(1) 下記に従い、新規会員登録画面に新規入力項目を追加</p>



<figure class="wp-block-embed is-type-wp-embed">
<blockquote class="wp-embedded-content" data-secret="Km0eo0tEER"><a href="https://neko-neko.sai-net.work/92/">【EC-CUBE】【Front】新規会員登録画面に新規入力項目を追加</a></blockquote><iframe loading="lazy" class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;【EC-CUBE】【Front】新規会員登録画面に新規入力項目を追加&#8221; &#8212; ねこねこネットワーク" src="https://neko-neko.sai-net.work/92/embed/#?secret=xxwgwDjcc9#?secret=Km0eo0tEER" data-secret="Km0eo0tEER" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</figure>



<p>(2) テストコードを記述</p>



<p>EntryPageクラス<br>場所：e2e-tests/pages/front/entry.page.ts</p>



<pre class="wp-block-code"><code>// 外部ライブラリからlocatorとpageクラスをimport
import {Locator, Page} from "@playwright/test";

export class EntryPage {
　　// 読み込み専用の変数設定 
    readonly page: Page;
    readonly url: string;
    readonly termsLink: Locator;

　　// 変数に値を格納
    constructor(page: Page) {
        // 上記で設定した変数に↓が格納
　　　　 // playrightのpageオブジェクト
        this.page = page;
　　　　　// テスト対象のurl
        this.url = `/entry`;
        this.termsLink = page.locator('.ec-checkbox .ec-link');
    }
　　
　　// 遷移関数
    async goto() {
        await this.page.goto(this.url);
    }

　　// 指定リンクを押下
    async clickServiceTermsLink() {
        await this.termsLink.click();
    }
}</code></pre>



<p>テスト実行関数<br>場所：e2e-tests/spec/front/entry.spec.ts</p>



<pre class="wp-block-code"><code>// クラスの使用宣言
import {expect, test} from "@playwright/test";
import {EntryPage} from "../../pages/front/entry.page";

test('ECCUBE 新規会員登録チェック', async ({ page }) =&gt; {
    // 変数設定
    const entryPage = new EntryPage(page);
    const name01 = 'テスト';
    const name02 = '太郎';
    const kana01 = 'テスト';
    const kana02 = 'タロウ';
    const hobby = '趣味';
    const pref = '27';
    const add_num = '5400010';
    const add01 = '大阪府中央区';
    const add02 = 'ドエル南本町';
    const phone_num = '11122223333';
    const email01 = 'testtaro@gmail.com';
    const email02 = 'testtaro@gmail.com';
    const pass01 = 'sainetJp5018+++---';
    const pass02 = 'sainetJp5018+++---';

    // 新規会員登録画面に遷移
    await entryPage.goto();
　　
    // 対象(idで指定)の入力項目に値を入力
    await page.locator('#entry_name_name01').fill(name01);
    await page.locator('#entry_name_name02').fill(name02);
    await page.locator('#entry_kana_kana01').fill(kana01);
    await page.locator('#entry_kana_kana02').fill(kana02);
    await page.locator('#entry_postal_code').fill(add_num);
    await page.locator('#entry_address_pref').selectOption(pref);
    await page.locator('#entry_hobby').fill(hobby);
    await page.locator('#entry_address_addr01').fill(add01);
    await page.locator('#entry_address_addr02').fill(add02);
    await page.locator('#entry_phone_number').fill(phone_num);
    await page.locator('#entry_email_first').fill(email01);
    await page.locator('#entry_email_second').fill(email02);
    await page.locator('#entry_plain_password_first').fill(pass01);
    await page.locator('#entry_plain_password_second').fill(pass02);
    await page.locator('#entry_user_policy_check').click();
　　
　　// name："指定テキストが入る" という名前のボタン要素を押下
    await page.getByRole('button', { name: '同意する' }).click();
    await page.getByRole('button', { name: '会員登録をする' }).click();
   
　　// 完了画面の表示確認
　　await expect(page).toHaveURL('/entry/complete');
});</code></pre>



<p></p>



<h4 class="wp-block-heading">2. 画面遷移とテキスト表示確認</h4>



<p>フロント側 -&gt; Mypage -&gt; 趣味項目を追加し、指定のページまで画面遷移とテキスト表示確認</p>



<p>(1) 下記に従い、MyPageに趣味項目を追加</p>



<p>(2) テストコードを記述</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://neko-neko.sai-net.work/682/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【ECCUBE】【Playwrite】ファイル構成とコードの流れ</title>
		<link>https://neko-neko.sai-net.work/670/</link>
					<comments>https://neko-neko.sai-net.work/670/#respond</comments>
		
		<dc:creator><![CDATA[nekoneko_admin]]></dc:creator>
		<pubDate>Wed, 25 Sep 2024 09:11:56 +0000</pubDate>
				<category><![CDATA[EC-CUBE]]></category>
		<category><![CDATA[テスト]]></category>
		<guid isPermaLink="false">https://neko-neko.sai-net.work/?p=670</guid>

					<description><![CDATA[ファイル構成 config：eccube [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">ファイル構成</h2>



<p>config：eccubeへの接続情報が記載 (URLやログイン情報)<br>fixtures：テスト実行事前準備ファイル格納 <br>(ECCUBEにログインしたり、受注情報を登録したりする)<br>(fixturesがないと、ECCUBEにアクセスできない)<br>pages：specで使う関数・クラスまとめ<br>spec：テストコード格納<br>type：</p>



<h2 class="wp-block-heading">コード理解</h2>



<p>場所：e2e-tests/spec/admin/order/order/list.spec.ts<br>関数：EA0401-UC03-T01 配送CSVダウンロード</p>



<p>ここでは、from 以降のパスでexportされているクラスや、定数を取得(import)している。</p>



<pre class="wp-block-code"><code>import {expect, test} from "../../../../fixtures/admin_login.fixture";
import {Order_count} from "../../../../types/order_count.type";
import {createOrder, hasExistingOrders} from "../../../../fixtures/admin/order/order.fixture";
import {AdminOrderListPage} from "../../../../pages/admin/order/order/list.page";
import {Download} from "@playwright/test";
import {Iconv} from "iconv";</code></pre>



<p></p>



<p>EA0401-UC03-T01 配送CSVダウンロード</p>



<pre class="wp-block-code"><code>test('EA0401-UC03-T01 配送CSVダウンロード', async ({ loginPage, page }) =&gt; {
    // ログイン実行がされたか確認
    await loginPage.seeAfterLoginSuccess();
    // 受注数を数えている？？
    const existingOrdersCnt: Order_count = await hasExistingOrders();
    // 対象のid要素を取得
    const OrderList = new AdminOrderListPage(page);
    // documentをダウンロードし終えるまで待機
    await page.waitForLoadState('domcontentloaded');
    // 一覧押下
    await OrderList.gotoViaMenu();
    // 件数確認
    await OrderList.confirmTotalResultCount(existingOrdersCnt.product_count);
    // ダウンロードが開始されるまで待機
    const downloadPromise = page.waitForEvent('download', { timeout: 2000});
    // csvボタン -&gt; 出荷・受注CSVが表示されるか確認
    await OrderList.downloadOrderDeliveryCsv();
    // イベント実行されたか確認
    const download: Download = await downloadPromise;
    // assert filename
    // ダウンロードしたファイルとが、指定のファイル名と一致するか確認
    expect(download.suggestedFilename()).toMatch(new RegExp('^shipping_\\d{14}\\.csv$'));
    // get and assert stats
    const fs = require('fs').promises;
    //　疑問：何している？
    expect((await fs.stat(await download.path() as string)).size).toBeGreaterThan(200);
    
    const path: string = await download.path();
    const content: string = await fs.readFile(path);
    const iconv = new Iconv('SHIFT_JIS', 'UTF-8');
    const utf8Content = iconv.convert(content).toString();
    const rows = utf8Content.trim().split('\n');
    const rowCount = rows.length;
    expect(rowCount).toBeGreaterThan(existingOrdersCnt.product_count + 1);
});</code></pre>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://neko-neko.sai-net.work/670/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
