<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:media="http://search.yahoo.com/mrss/"
	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>Kenmingの鮮思維</title>
	<atom:link href="https://kenming.idv.tw/feed/" rel="self" type="application/rss+xml" />
	<link>https://kenming.idv.tw</link>
	<description>不用牽掛過去，不必擔心未來，踏實於現在，就與過去和未來同在！</description>
	<lastBuildDate>Tue, 11 Aug 2026 01:44:32 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.3</generator>

<image>
	<url>https://kenming.idv.tw/wp-content/medias/cropped-favicon-32x32.png</url>
	<title>Kenmingの鮮思維</title>
	<link>https://kenming.idv.tw</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>為 Bricks Builder 打造一個開發輔助 Skill</title>
		<link>https://kenming.idv.tw/bricks-builder-development-skill/</link>
					<comments>https://kenming.idv.tw/bricks-builder-development-skill/#respond</comments>
		
		<dc:creator><![CDATA[Wang Kenming]]></dc:creator>
		<pubDate>Tue, 11 Aug 2026 00:35:59 +0000</pubDate>
				<category><![CDATA[應用軟體使用分享]]></category>
		<category><![CDATA[AI應用與開發]]></category>
		<category><![CDATA[軟體實作與編程技術]]></category>
		<category><![CDATA[Agent Skill]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[AI Agent]]></category>
		<category><![CDATA[Bricks Builder]]></category>
		<guid isPermaLink="false">https://kenming.idv.tw/?p=24099</guid>

					<description><![CDATA[<p>去年重新整理自己的 WordPress Blog 時，我最後選擇使用 Bricks Builder 作為網站主 [&#8230;]</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/bricks-builder-development-skill/">為 Bricks Builder 打造一個開發輔助 Skill</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/bricks-builder/bricks-builder-skill-cover.webp" alt="封面圖：發布 Bricks Builder 開發輔助 Skill" style="width:620px"/></figure>



<p class="wp-block-paragraph">去年重新整理自己的 WordPress Blog 時，我最後選擇使用 Bricks Builder 作為網站主要的 Theme 與頁面建置工具。</p>



<p class="wp-block-paragraph">當時選擇 Bricks Builder，一個很重要的原因是它不只是一套視覺化 Page Builder，本身也保留了相當大的開發彈性。對熟悉 CSS、PHP 與 WordPress 開發的人來說，可以在視覺化建置與客製程式之間取得不錯的平衡。</p>



<p class="wp-block-paragraph">關於當時為什麼選擇 Bricks Builder，我曾另外整理過一篇文章：</p>



<p class="wp-block-paragraph"><a href="https://kenming.idv.tw/2025_site_rebuild_using_bricksbuilder/">2025 年網站重新建置：使用 Bricks Builder</a></p>



<h3 class="wp-block-heading">最初只是想讓 AI 比較容易查 Bricks 文件</h3>



<p class="wp-block-paragraph">隨著使用 Bricks Builder 的程度越來越深入，我開始頻繁查閱 Bricks Academy（官方文檔）。</p>



<p class="wp-block-paragraph">Bricks 官方其實提供了不少文件，包括 Builder 功能、Dynamic Data、Query Loop、Components、Hooks、Filters、Custom Elements 與各種 Developer API。不過實際使用下來，我一直覺得官方文件的分類與查詢並不是那麼方便，尤其當要找的是某個比較細節的開發資訊時，常常得花一些時間才能找到真正相關的文件。</p>



<p class="wp-block-paragraph">如果改成讓 AI Agent 自己到 Bricks Academy 搜尋，同樣會遇到類似問題：搜尋、開啟不同頁面、判斷哪些文件真正相關，不但效率不高，也會消耗不少 Context Token。</p>



<p class="wp-block-paragraph">所以我一開始做這個 Skill 的目的其實很單純：</p>



<p class="wp-block-paragraph"><strong>把 Bricks Academy 官方文件預先下載並轉換成 Markdown，建立一套可以讓 AI Agent 在本機直接搜尋的文件庫。</strong></p>



<p class="wp-block-paragraph">目前這套文件庫已同步超過 700 篇 Bricks Academy 文件以及相關圖片，Agent 可以先從本機 corpus 搜尋真正需要的內容，而不需要每次都重新到官方網站尋找。</p>



<p class="wp-block-paragraph">同時我也做了文件同步機制，可以檢查 Bricks Academy 是否有新的或異動的文件，需要時再重新下載、轉換與建立索引。因此它並不是建立一次之後就不再更新的靜態知識庫，而是可以持續與官方文件保持同步。</p>



<h3 class="wp-block-heading">從文件查詢逐漸擴展成開發輔助 Skill</h3>



<p class="wp-block-paragraph">實際使用一段時間後，我發現單純「找得到文件」仍然不完全足以協助 Bricks Builder 開發。</p>



<p class="wp-block-paragraph">例如處理 Bricks element tree、page JSON、responsive settings、global classes、Dynamic Data、Query Loop 或 Custom Elements 時，除了官方文件之外，Agent 還需要知道一些基本的資料模型、修改原則與驗證流程。</p>



<p class="wp-block-paragraph">因此後來又逐步加入了一些精簡的 development references，讓 Skill 除了負責文件查詢之外，也可以提供 Bricks Builder 開發時需要的工作流程與約束。</p>



<p class="wp-block-paragraph">目前這個 Skill 大致涵蓋：</p>



<ul class="wp-block-list">
<li>本機搜尋 Bricks Academy 官方文件。</li>



<li>Bricks element tree 與資料結構的基本模型。</li>



<li>Page / Element JSON 的建立與修改流程。</li>



<li>Custom Elements 開發。</li>



<li>Responsive settings、Theme Styles、Global Classes、Variables 與 Components。</li>



<li>Dynamic Data、Hooks、Query Loop 與 Forms。</li>



<li>修改後在 Builder 與 Frontend 的驗證流程。</li>
</ul>



<p class="wp-block-paragraph">另外有些 Bricks 的實作細節會隨版本改變，例如 control keys、hook signatures、JSON shapes 或內部資料結構。因此這個 Skill 也不會單純依賴既有文件或模型記憶，在有實際 Bricks 開發環境可以查驗時，會以目前安裝版本作為最後的驗證依據。</p>



<p class="wp-block-paragraph">換句話說，我希望它扮演的角色不是一套「什麼都知道的 Bricks 知識庫」，而是一個知道<strong>去哪裡找資料、如何進行開發，以及什麼資訊需要進一步查證</strong>的輕量開發輔助 Skill。</p>



<h3 class="wp-block-heading">Bricks Builder Skill</h3>



<p class="wp-block-paragraph">目前我已將這個 Skill 整理後放到 GitHub 公開：</p>



<p class="wp-block-paragraph"><strong>GitHub：</strong><br><a href="https://github.com/kenming/bricks-builder-skill" target="_blank" rel="noreferrer noopener">https://github.com/kenming/bricks-builder-skill</a></p>



<p class="wp-block-paragraph">如果平常也使用 AI Agent 協助 Bricks Builder 網站開發，可以自行下載使用。</p>



<p class="wp-block-paragraph">Repository 的 README 已整理目前支援的能力、安裝方式、Skill 觸發方式、文件同步工具，以及版本查驗與授權邊界等相關說明。</p>



<p class="wp-block-paragraph">這個專案目前主要還是配合我自己的 Bricks Builder 網站開發持續使用與調整；後續只要 Bricks Academy 文件或實際開發需求有所變化，也會持續更新。</p>



<h3 class="wp-block-heading">Screenshots</h3>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/bricks-builder/evidence-workflow.webp" alt="Workflow：How the Bricks Builder Skill Builds an Answer" style="width:620px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">​​圖：local-first Agent Skill，用來查詢、開發、修改與審核 Bricks Builder 網站</p>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/bricks-builder/chat-container-query.webp" alt="提出明確的 Bricks 問題，即可隱式觸發 Skill" style="width:620px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">​​圖：提出明確的 Bricks 問題，即可隱式觸發 Skill</p>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/bricks-builder/chat-hook-query.webp" alt="需要查詢精確 hook、schema 或實作細節時，可用 $bricks-builder 明確觸發" style="width:620px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">​​圖：需要查詢精確 hook、schema 或實作細節時，可用&nbsp;<code>$bricks-builder</code>&nbsp;明確觸發</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/bricks-builder-development-skill/">為 Bricks Builder 打造一個開發輔助 Skill</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://kenming.idv.tw/bricks-builder-development-skill/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<media:content url="https://images.kenming.idv.tw/software/bricks-builder/bricks-builder-skill-cover.webp" medium="image"></media:content>
	</item>
		<item>
		<title>從使用者操作到可驗證腳本：Playwright Test 核心能力</title>
		<link>https://kenming.idv.tw/playwright-test-core-capabilities/</link>
					<comments>https://kenming.idv.tw/playwright-test-core-capabilities/#respond</comments>
		
		<dc:creator><![CDATA[Wang Kenming]]></dc:creator>
		<pubDate>Fri, 31 Jul 2026 08:14:51 +0000</pubDate>
				<category><![CDATA[AI應用與開發]]></category>
		<category><![CDATA[軟體實作與編程技術]]></category>
		<category><![CDATA[Playwright]]></category>
		<category><![CDATA[UI 自動化測試]]></category>
		<category><![CDATA[AI Agent]]></category>
		<category><![CDATA[測試案例]]></category>
		<category><![CDATA[軟體測試]]></category>
		<guid isPermaLink="false">https://kenming.idv.tw/?p=23988</guid>

					<description><![CDATA[<p>UI 自動化測試 - 使用 Playwright x AI Agent 系列 #03 UI 自動化測試的重點， [&#8230;]</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/playwright-test-core-capabilities/">從使用者操作到可驗證腳本：Playwright Test 核心能力</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/pw-test-core-script-ability.webp" alt="封面圖：Playwright Test 核心能力" style="width:620px"/></figure>



<div style="height:24px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-text-color has-link-color wp-elements-65b14f6a42fd0420a566b994d89525f0 wp-block-paragraph" style="color:#4f6b8a;font-size:16px"><strong><strong>UI 自動化測試 - 使用 Playwright x AI Agent</strong></strong> <strong>系列 #03</strong></p>



<div style="height:16px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">UI 自動化測試的重點，不是讓程式模擬滑鼠點擊，而是把一段使用者操作流程，轉換為可重複執行、可判定通過或失敗，並能持續維護的測試腳本。</p>



<p class="wp-block-paragraph">Playwright Test 提供的核心能力可整理為一條固定路徑：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">開啟頁面
→ 定位元素
→ 執行操作
→ 驗證結果
→ 處理等待
→ 整理測試結構</code></pre>



<p class="wp-block-paragraph">本文使用一個寵物購物系統作為案例，示範登入、商品搜尋、商品詳情、購物車與折扣金額驗證。QA 開發人員可將系統視為黑箱（Black-box），不需理解內部程式實作，而是從使用者操作界面、可觀察行為與預期結果出發，分析並撰寫 Playwright 測試腳本。</p>



<p class="wp-block-paragraph">重點不在於特定購物系統本身，而是理解如何將使用者操作流程轉換為具備明確驗證條件的 Playwright Test。</p>



<h2 class="wp-block-heading">從人工操作轉換為測試腳本</h2>



<p class="wp-block-paragraph">以登入流程為例，人工操作通常會描述為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">開啟登入頁
→ 輸入帳號
→ 輸入密碼
→ 點擊登入
→ 確認進入商品列表頁</code></pre>



<p class="wp-block-paragraph">這段操作轉為 Playwright Test 後，可以寫成：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">import { test, expect } from &#039;@playwright/test&#039;;
​
test(&#039;有效帳號可以登入並進入商品列表&#039;, async ({ page }) =&gt; {
  await page.goto(&#039;/login&#039;);
​
  await page.getByTestId(&#039;username-input&#039;).fill(&#039;user1&#039;);
  await page.getByTestId(&#039;password-input&#039;).fill(&#039;user1&#039;);
  await page.getByTestId(&#039;login-submit&#039;).click();
​
  await expect(
    page.getByRole(&#039;heading&#039;, { name: &#039;寵物用品&#039; })
  ).toBeVisible();
​
  await expect(
    page.getByTestId(&#039;current-user&#039;)
  ).toHaveText(&#039;user1&#039;);
});</code></pre>



<p class="wp-block-paragraph">這段測試包含四個基本區段：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>區段</th><th>Playwright 語法</th><th>用途</th></tr></thead><tbody><tr><td>定義測試</td><td><code>test(...)</code></td><td>定義一個可執行的測試案例</td></tr><tr><td>開啟頁面</td><td><code>page.goto()</code></td><td>進入測試起點</td></tr><tr><td>操作畫面</td><td><code>fill()</code>、<code>click()</code></td><td>模擬使用者操作</td></tr><tr><td>驗證結果</td><td><code>expect(...)</code></td><td>判定測試是否通過</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">​</p>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/pw-script-operation-mapping.webp" alt="流程對照圖：人工操作流程對應到腳本步驟" style="width:620px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">​​圖：人工流程對應到腳本步驟</p>



<p class="wp-block-paragraph">這裡最重要的差異是：人工操作通常只描述「做了什麼」，測試腳本還必須定義「什麼結果才算正確」。</p>



<h2 class="wp-block-heading">使用 3A Pattern 組織測試結構與驗證意圖</h2>



<p class="wp-block-paragraph">Playwright 測試可使用 3A Pattern 整理：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">Arrange：準備測試狀態
Act：執行使用者操作
Assert：驗證使用者可見結果</code></pre>



<p class="wp-block-paragraph">例如商品搜尋測試：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">test(&#039;使用者可以搜尋犬糧商品&#039;, async ({ page }) =&gt; {
  // Arrange：登入並進入商品列表
  await page.goto(&#039;/login&#039;);
  await page.getByTestId(&#039;username-input&#039;).fill(&#039;user1&#039;);
  await page.getByTestId(&#039;password-input&#039;).fill(&#039;user1&#039;);
  await page.getByTestId(&#039;login-submit&#039;).click();
​
  // Act：執行搜尋
  await page.getByLabel(&#039;搜尋商品&#039;).fill(&#039;犬糧&#039;);
  await page.getByRole(&#039;button&#039;, { name: &#039;搜尋&#039; }).click();
​
  // Assert：驗證搜尋結果
  await expect(
    page.getByText(&#039;活力雞肉犬糧&#039;)
  ).toBeVisible();
});</code></pre>



<p class="wp-block-paragraph">​</p>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/pw-script-aaa-structure.webp" alt="圖：使用 3A（Arrange/Act/Assert）Pattern 撰寫測試案例" style="width:620px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">​圖：使用 3A Pattern 撰寫測試案例</p>



<p class="wp-block-paragraph">AAA 並不是 Playwright 強制語法，而是一種讓測試意圖更清楚的組織方式。當測試失敗時，也較容易判斷問題發生在前置狀態、操作步驟或驗證結果。</p>



<h2 class="wp-block-heading">TypeScript 在 Playwright 測試中的角色</h2>



<p class="wp-block-paragraph">Playwright Test 可使用 JavaScript 或 TypeScript。TypeScript 在 UI 測試中的主要價值，是提供型別檢查、編輯器提示與較佳的維護性，而不是用來建立前端應用程式。</p>



<p class="wp-block-paragraph">常見結構如下：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">import { test, expect, type Page } from &#039;@playwright/test&#039;;
test 用於定義測試案例，expect 用於結果驗證，Page 則可用於 helper function 的型別標註。
async function login(page: Page) {
  // 共用登入流程
}</code></pre>



<p class="wp-block-paragraph">Playwright Test 會在測試執行時提供 <code>page</code> fixture，代表目前測試使用的瀏覽器頁面，因此不需要在每支測試中自行建立 browser、context 與 page。</p>



<h2 class="wp-block-heading">Navigation：確認測試是否進入正確頁面</h2>



<p class="wp-block-paragraph">Navigation 不只是呼叫 <code>page.goto()</code>，還包含確認頁面是否到達可操作狀態。</p>



<p class="wp-block-paragraph">若 <code>playwright.config.ts</code> 已設定 <code>baseURL</code>：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">use: {
  baseURL: &#039;http://127.0.0.1:8765&#039;,
}</code></pre>



<p class="wp-block-paragraph">測試中即可使用相對路徑：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await page.goto(&#039;/login&#039;);</code></pre>



<p class="wp-block-paragraph">頁面開啟後，應驗證一個可觀察的狀態：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await expect(
  page.getByRole(&#039;button&#039;, { name: &#039;登入&#039; })
).toBeVisible();</code></pre>



<p class="wp-block-paragraph">登入成功後，也可驗證 URL：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await expect(page).toHaveURL(/.*products/);</code></pre>



<p class="wp-block-paragraph">但 URL 不一定是最重要的判準。若系統使用相同 URL 呈現不同狀態，應優先驗證使用者可見內容，例如頁面標題、目前登入者、商品名稱或完成訊息。</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await expect(
  page.getByRole(&#039;heading&#039;, { name: &#039;寵物用品&#039; })
).toBeVisible();</code></pre>



<h2 class="wp-block-heading">Locator：找到元素不代表定位方式合理</h2>



<p class="wp-block-paragraph">Locator 決定測試如何找到欄位、按鈕、連結、商品卡片與提示訊息。</p>



<p class="wp-block-paragraph">Playwright 測試不應只追求「目前找得到元素」，而應選擇在 UI 小幅調整後仍能維持穩定的定位方式。</p>



<p class="wp-block-paragraph">常見 Locator 包括：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">page.getByRole(&#039;button&#039;, { name: &#039;登入&#039; });
page.getByLabel(&#039;搜尋商品&#039;);
page.getByPlaceholder(&#039;請輸入商品名稱&#039;);
page.getByText(&#039;活力雞肉犬糧&#039;);
page.getByTestId(&#039;username-input&#039;);
page.locator(&#039;input[name=&quot;username&quot;]&#039;);</code></pre>



<p class="wp-block-paragraph">建議優先順序如下：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>優先順序</th><th>Locator</th><th>適用情境</th></tr></thead><tbody><tr><td>1</td><td><code>getByRole()</code></td><td>按鈕、連結、標題、輸入框等具語意元素</td></tr><tr><td>2</td><td><code>getByLabel()</code></td><td>表單欄位</td></tr><tr><td>3</td><td><code>getByPlaceholder()</code></td><td>缺少 label 的輸入欄位</td></tr><tr><td>4</td><td><code>getByText()</code></td><td>商品名稱、訊息與可見文字</td></tr><tr><td>5</td><td><code>getByTestId()</code></td><td>需要穩定且明確的測試識別</td></tr><tr><td>6</td><td><code>locator()</code></td><td>使用穩定的 <code>name</code>、<code>type</code> 等屬性</td></tr><tr><td>7</td><td>結構型 CSS 或 XPath</td><td>無其他可靠線索時的最後手段</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">先縮小範圍，再操作目標元素</h3>



<p class="wp-block-paragraph">商品列表中可能存在多個「查看」連結。下列寫法可能點擊第一個匹配項目，而不是指定商品：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await page.getByRole(&#039;link&#039;, { name: &#039;查看&#039; }).click();</code></pre>



<p class="wp-block-paragraph">較合理的作法，是先定位商品卡片，再操作卡片內的連結：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">const productCard = page
  .getByTestId(&#039;product-card&#039;)
  .filter({ hasText: &#039;活力雞肉犬糧&#039; });
​
await productCard
  .getByRole(&#039;link&#039;, { name: &#039;查看&#039; })
  .click();</code></pre>



<p class="wp-block-paragraph">這種寫法保留了明確的操作意圖：不是點擊任意「查看」，而是開啟指定商品的詳情頁。</p>



<h3 class="wp-block-heading">避免容易失效的 Selector</h3>



<p class="wp-block-paragraph">下列 Selector 過度依賴 DOM 位置、CSS class 或完整結構：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">page.locator(&#039;div:nth-child(3) &gt; button&#039;);
page.locator(&#039;.btn.btn-primary.mt-2&#039;);
page.locator(&#039;#app &gt; main &gt; section &gt; div &gt; div:nth-child(2)&#039;);</code></pre>



<p class="wp-block-paragraph">只要畫面重新排版、CSS class 調整或外層增加容器，測試就可能失效。</p>



<p class="wp-block-paragraph">較好的寫法應描述使用者操作意圖：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await page
  .getByRole(&#039;button&#039;, { name: &#039;加入購物車&#039; })
  .click();</code></pre>



<p class="wp-block-paragraph">Locator 品質會直接影響測試穩定性。測試腳本應保護使用者行為，而不是綁定當下的 HTML 排版方式。</p>



<h2 class="wp-block-heading">User Actions：模擬使用者實際操作</h2>



<p class="wp-block-paragraph">常見 User Actions 包括：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await page.getByRole(&#039;button&#039;, { name: &#039;登入&#039; }).click();
await page.getByLabel(&#039;搜尋商品&#039;).fill(&#039;犬糧&#039;);
await page.getByLabel(&#039;商品分類&#039;).selectOption(&#039;dog&#039;);
await page.getByRole(&#039;checkbox&#039;, { name: &#039;只顯示有庫存商品&#039; }).check();</code></pre>



<p class="wp-block-paragraph">搜尋框若支援 Enter，也可以使用：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">const searchBox = page.getByLabel(&#039;搜尋商品&#039;);
​
await searchBox.fill(&#039;犬糧&#039;);
await searchBox.press(&#039;Enter&#039;);</code></pre>



<p class="wp-block-paragraph">測試操作應盡量符合真實使用方式。若使用者會點擊搜尋按鈕，就測試 <code>click()</code>；若正式流程支援 Enter，就測試 <code>press('Enter')</code>。</p>



<p class="wp-block-paragraph">測試不應為了方便而改走使用者不會使用的捷徑，否則即使測試通過，也未必能證明實際 UI 流程可用。</p>



<h2 class="wp-block-heading">Assertions 設計原則</h2>



<p class="wp-block-paragraph">Action 只代表操作已執行，不代表功能正確。</p>



<p class="wp-block-paragraph">例如：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await page
  .getByRole(&#039;button&#039;, { name: &#039;加入購物車&#039; })
  .click();</code></pre>



<p class="wp-block-paragraph">這行只能證明 Playwright 成功點擊按鈕，不能證明商品真的加入購物車，更不能證明數量、折扣與總金額正確。</p>



<p class="wp-block-paragraph">購物車流程應進一步驗證：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await expect(
  page.getByText(&#039;活力雞肉犬糧&#039;)
).toBeVisible();
​
await expect(
  page.getByTestId(&#039;cart-subtotal&#039;)
).toHaveText(&#039;NT$ 1360&#039;);
​
await expect(
  page.getByTestId(&#039;cart-discount&#039;)
).toHaveText(&#039;NT$ 136&#039;);
​
await expect(
  page.getByTestId(&#039;cart-total&#039;)
).toHaveText(&#039;NT$ 1224&#039;);</code></pre>



<p class="wp-block-paragraph">不同操作可對應不同的業務結果：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>不足的驗證</th><th>較完整的驗證</th></tr></thead><tbody><tr><td>登入按鈕可點擊</td><td>登入後顯示商品列表與目前使用者</td></tr><tr><td>搜尋欄可以輸入文字</td><td>搜尋結果出現指定商品</td></tr><tr><td>加入購物車按鈕可點擊</td><td>購物車顯示商品、數量與金額</td></tr><tr><td>前往結帳按鈕可點擊</td><td>結帳頁顯示訂單摘要與正確總額</td></tr><tr><td>送出訂單按鈕可點擊</td><td>顯示訂單成立訊息與訂單金額</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Assertion 的目的，是證明使用者真正關心的結果仍然成立。</p>



<h2 class="wp-block-heading">Auto-waiting：等待機制與 timeout 使用原則</h2>



<p class="wp-block-paragraph">Playwright 在執行操作前，會自動檢查元素是否可見、穩定、可接收事件，並確認沒有被其他元素遮住。這些機制稱為 auto-waiting 與 actionability checks。</p>



<p class="wp-block-paragraph">因此，多數測試不需要自行加入固定等待：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await page.waitForTimeout(3000);</code></pre>



<p class="wp-block-paragraph">固定等待有兩個問題：</p>



<ul class="wp-block-list">
<li>頁面若 1 秒完成，測試仍會浪費 3 秒。</li>



<li>頁面若超過 3 秒才完成，測試仍會失敗。</li>
</ul>



<p class="wp-block-paragraph">較好的方式是等待明確狀態：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await expect(
  page.getByText(&#039;活力雞肉犬糧&#039;)
).toBeVisible();</code></pre>



<p class="wp-block-paragraph">或等待頁面切換與標題出現：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">await expect(page).toHaveURL(/.*cart/);
​
await expect(
  page.getByRole(&#039;heading&#039;, { name: &#039;購物車&#039; })
).toBeVisible();</code></pre>



<p class="wp-block-paragraph">Timeout 也不應用來掩蓋不穩定測試。測試經常 timeout 時，應先檢查：</p>



<ul class="wp-block-list">
<li>服務是否已啟動。</li>



<li>URL 或 port 是否正確。</li>



<li>Locator 是否符合目前 UI。</li>



<li>前一步操作是否成功。</li>



<li>Assertion 是否符合實際畫面。</li>



<li>測試資料是否受到前一次執行影響。</li>
</ul>



<p class="wp-block-paragraph">只有在明確知道某個操作確實需要較長時間時，才調整 timeout。</p>



<h2 class="wp-block-heading">測試案例的命名原則</h2>



<p class="wp-block-paragraph">測試案例不應只是描述操作：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">test(&#039;click checkout button&#039;, async ({ page }) =&gt; {
  // ...
});</code></pre>



<p class="wp-block-paragraph">較好的名稱應直接表達驗證目標：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">test(&#039;購物車達滿額門檻時可以看到 9 折後總額&#039;, async ({ page }) =&gt; {
  // ...
});</code></pre>



<p class="wp-block-paragraph">測試名稱應回答：</p>



<pre class="wp-block-preformatted">這個測試要證明什麼行為仍然成立？</pre>



<p class="wp-block-paragraph">當測試報告顯示失敗時，具體名稱也能讓開發者直接理解受影響的功能，而不必先閱讀整支腳本。</p>



<h2 class="wp-block-heading">集中管理測試資料</h2>



<p class="wp-block-paragraph">測試資料若散落在操作與 Assertion 中，後續很難判斷各數值的來源。</p>



<p class="wp-block-paragraph">可先集中整理：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">const testUser = {
  username: &#039;user1&#039;,
  password: &#039;user1&#039;,
};
​
const targetProduct = {
  keyword: &#039;犬糧&#039;,
  name: &#039;活力雞肉犬糧&#039;,
  unitPriceText: &#039;NT$ 680&#039;,
  quantityForDiscount: &#039;2&#039;,
  subtotalWithDiscountText: &#039;NT$ 1360&#039;,
  discountText: &#039;NT$ 136&#039;,
  totalWithDiscountText: &#039;NT$ 1224&#039;,
};</code></pre>



<p class="wp-block-paragraph">當商品價格、測試帳號或折扣規則調整時，就能清楚知道哪些預期值需要同步修改。</p>



<p class="wp-block-paragraph">測試資料的整理方式可依規模選擇：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>資料規模</th><th>建議方式</th><th>適用情境</th></tr></thead><tbody><tr><td>少量固定資料</td><td>測試檔或 helper 檔案</td><td>單一 Smoke Test、少量帳號與商品</td></tr><tr><td>中量測試資料</td><td>JSON 或 CSV</td><td>多組登入、搜尋與預期結果</td></tr><tr><td>大量或需重設狀態</td><td>DB seed data</td><td>商品、使用者、訂單與初始狀態</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">DB seed data 可用來建立固定前置條件，但不能取代 UI 驗證。Playwright 測試仍應從使用者可見畫面判斷商品、金額、錯誤訊息與流程結果是否正確。</p>



<h2 class="wp-block-heading">使用 Helper Function 整理重複操作</h2>



<p class="wp-block-paragraph">當多支測試都需要登入、搜尋商品或進入商品詳情頁，可將重複操作抽成 helper function。</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">async function login(page: Page) {
  await page.goto(&#039;/login&#039;);
​
  await page
    .getByTestId(&#039;username-input&#039;)
    .fill(testUser.username);
​
  await page
    .getByTestId(&#039;password-input&#039;)
    .fill(testUser.password);
​
  await page
    .getByTestId(&#039;login-submit&#039;)
    .click();
​
  await expect(
    page.getByRole(&#039;heading&#039;, { name: &#039;寵物用品&#039; })
  ).toBeVisible();
}</code></pre>



<p class="wp-block-paragraph">搜尋商品也可整理為：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">async function searchProduct(
  page: Page,
  keyword: string,
  productName: string,
) {
  await page
    .getByLabel(&#039;搜尋商品&#039;)
    .fill(keyword);
​
  await page
    .getByRole(&#039;button&#039;, { name: &#039;搜尋&#039; })
    .click();
​
  await expect(
    page.getByRole(&#039;heading&#039;, { name: productName })
  ).toBeVisible();
}</code></pre>



<p class="wp-block-paragraph">Helper function 應保持短小，並封裝具備明確語意的重複操作。若過度包裝，測試案例本身反而會失去可讀性。</p>



<p class="wp-block-paragraph">另外，不應讓測試案例彼此呼叫。多個案例若共用前置流程，應抽成 helper function 或放入 <code>beforeEach()</code>，讓每個 <code>test(...)</code> 仍可獨立執行。</p>



<h2 class="wp-block-heading">建立最小購物流程測試</h2>



<p class="wp-block-paragraph">將登入、清空購物車、搜尋商品、開啟商品詳情與金額驗證整合後，可形成下列測試：</p>


<pre class="language-typescript no-line-numbers"><code class="language-typescript no-line-numbers">import { test, expect, type Page } from &#039;@playwright/test&#039;;
​
const testUser = {
  username: &#039;user2&#039;,
  password: &#039;user2&#039;,
};
​
const product = {
  keyword: &#039;犬糧&#039;,
  name: &#039;活力雞肉犬糧&#039;,
  quantity: &#039;2&#039;,
  subtotalText: &#039;NT$ 1360&#039;,
  discountText: &#039;NT$ 136&#039;,
  totalText: &#039;NT$ 1224&#039;,
};
​
async function login(page: Page) {
  await page.goto(&#039;/login&#039;);
​
  await page
    .getByTestId(&#039;username-input&#039;)
    .fill(testUser.username);
​
  await page
    .getByTestId(&#039;password-input&#039;)
    .fill(testUser.password);
​
  await page
    .getByTestId(&#039;login-submit&#039;)
    .click();
​
  await expect(
    page.getByRole(&#039;heading&#039;, { name: &#039;寵物用品&#039; })
  ).toBeVisible();
}
​
async function clearCart(page: Page) {
  await page.goto(&#039;/cart&#039;);
​
  while (
    await page.getByRole(&#039;button&#039;, { name: /移除/ }).count()
  ) {
    await page
      .getByRole(&#039;button&#039;, { name: /移除/ })
      .first()
      .click();
  }
}
​
test(
  &#039;使用者可以搜尋商品並在加入購物車後看到滿額折扣&#039;,
  async ({ page }) =&gt; {
    await login(page);
    await clearCart(page);
    await page.goto(&#039;/products&#039;);
​
    await page
      .getByLabel(&#039;搜尋商品&#039;)
      .fill(product.keyword);
​
    await page
      .getByRole(&#039;button&#039;, { name: &#039;搜尋&#039; })
      .click();
​
    const productCard = page
      .getByTestId(&#039;product-card&#039;)
      .filter({ hasText: product.name });
​
    await productCard
      .getByRole(&#039;link&#039;, { name: &#039;查看&#039; })
      .click();
​
    await page
      .getByLabel(&#039;數量&#039;)
      .fill(product.quantity);
​
    await page
      .getByRole(&#039;button&#039;, { name: &#039;加入購物車&#039; })
      .click();
​
    await expect(
      page.getByRole(&#039;heading&#039;, { name: &#039;購物車&#039; })
    ).toBeVisible();
​
    await expect(
      page.getByTestId(&#039;cart-subtotal&#039;)
    ).toHaveText(product.subtotalText);
​
    await expect(
      page.getByTestId(&#039;cart-discount&#039;)
    ).toHaveText(product.discountText);
​
    await expect(
      page.getByTestId(&#039;cart-total&#039;)
    ).toHaveText(product.totalText);
  },
);</code></pre>



<p class="wp-block-paragraph">這支測試同時示範：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">Navigation
→ Locator
→ User Actions
→ Assertions
→ Auto-waiting
→ Test Data
→ Helper Function</code></pre>



<p class="wp-block-paragraph">測試執行前先清空購物車，是為了避免前一次執行殘留資料影響金額。這也說明 UI 測試的穩定性不只取決於腳本語法，還取決於可控制的測試前置狀態。</p>



<h2 class="wp-block-heading">觀察測試實際操作瀏覽器</h2>



<p class="wp-block-paragraph">Playwright Test 預設使用 headless 模式。若需要觀察實際操作，可加入 <code>--headed</code>：</p>


<pre class="language-powershell no-line-numbers"><code class="language-powershell no-line-numbers">npx playwright test tests/core-scripts/petshop_product_flow.spec.ts --project=chromium --headed</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Playwright Test 預設使用 headless（無頭）模式，也就是測試執行時不顯示瀏覽器視窗，適合快速執行與自動化驗證。Headed（有頭）模式則會開啟可見的瀏覽器視窗，方便觀察實際操作流程、檢查 Locator 與分析測試失敗原因。</p>
</blockquote>



<p class="wp-block-paragraph">若要逐步檢查 Locator 與操作流程，可使用 debug 模式：</p>


<pre class="language-powershell no-line-numbers"><code class="language-powershell no-line-numbers">npx playwright test tests/core-scripts/petshop_product_flow.spec.ts --project=chromium --debug</code></pre>



<p class="wp-block-paragraph">Debug 模式會開啟 Playwright Inspector，可逐步查看操作、Locator 與測試狀態。</p>



<p class="wp-block-paragraph">使用 VS Code 的 Playwright Test 擴充套件時，也可在 Testing 面板啟用 <strong>Show Browser</strong>，直接觀察測試執行過程。</p>



<p class="wp-block-paragraph">​</p>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/pw-vscode-show-browser-run.webp" alt="圖：Playwright 測試總管啟用 Show Browser 後執行測試" style="width:320px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">​圖：Playwright 測試總管啟用 Show Browser 後執行測試</p>



<h2 class="wp-block-heading">不要急著把所有流程塞進一支測試</h2>



<p class="wp-block-paragraph">完整購物主流程可能包含：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">登入
→ 商品列表
→ 分類與分頁
→ 搜尋商品
→ 商品詳情
→ 加入購物車
→ 折扣驗證
→ 修改數量
→ 結帳
→ 送出訂單
→ 訂單成立</code></pre>



<p class="wp-block-paragraph">若一開始就把所有步驟塞進單一測試，腳本會過長，失敗時也難以定位問題。</p>



<p class="wp-block-paragraph">較合理的作法是先拆成：</p>



<ol class="wp-block-list">
<li>登入後可以進入商品列表。</li>



<li>可以搜尋指定商品並進入商品詳情。</li>



<li>加入商品後可以看到正確小計與折扣。</li>



<li>修改數量後，折扣金額會依規則變化。</li>



<li>達到折扣門檻後可以完成結帳。</li>
</ol>



<p class="wp-block-paragraph">待各段流程穩定後，再依測試目的決定是否組合為一條核心 UI Smoke Test。</p>



<p class="wp-block-paragraph">Smoke Test 的價值不在於步驟最多，而在於能以合理成本快速回答：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">系統修改後，最重要的使用者流程是否仍然可以完成？</p>
</blockquote>



<h2 class="wp-block-heading">結語</h2>



<p class="wp-block-paragraph">Playwright 核心腳本能力可以整理為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">Navigation
→ Locator
→ User Actions
→ Assertions
→ Waiting / Auto-waiting
→ Test Structure</code></pre>



<p class="wp-block-paragraph">撰寫 UI 測試時，應先理解使用者操作流程，再決定如何定位、操作與驗證。</p>



<p class="wp-block-paragraph">Locator 應盡量使用接近使用者視角的語意；Action 應對應真實操作；Assertion 應驗證使用者可見的業務結果，而不是只確認按鈕可以點擊。</p>



<p class="wp-block-paragraph">當測試資料、前置狀態與重複流程也被適當整理後，Playwright 腳本才會從一次性的瀏覽器操作，轉變為可重複執行、可診斷、可維護的驗收規格。</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/playwright-test-core-capabilities/">從使用者操作到可驗證腳本：Playwright Test 核心能力</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://kenming.idv.tw/playwright-test-core-capabilities/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<media:content url="https://images.kenming.idv.tw/software/ui-automation-test/pw-test-core-script-ability.webp" medium="image"></media:content>
	</item>
		<item>
		<title>從 GitHub Issue 至 PR：遠端協同開發的寬鬆耦合的合作模式</title>
		<link>https://kenming.idv.tw/github-issue-to-pr-loosely-coupled-collaboration/</link>
					<comments>https://kenming.idv.tw/github-issue-to-pr-loosely-coupled-collaboration/#respond</comments>
		
		<dc:creator><![CDATA[Wang Kenming]]></dc:creator>
		<pubDate>Tue, 28 Jul 2026 07:56:28 +0000</pubDate>
				<category><![CDATA[軟體開發方法論]]></category>
		<category><![CDATA[AI應用與開發]]></category>
		<category><![CDATA[軟體設計]]></category>
		<category><![CDATA[GitHub協作]]></category>
		<category><![CDATA[遠端協同開發]]></category>
		<category><![CDATA[LooseCoupling]]></category>
		<guid isPermaLink="false">https://kenming.idv.tw/?p=23981</guid>

					<description><![CDATA[<p>前兩個星期，我完成了 ZenGTPX。它可以將 Zen7（天頂圍棋）包裝成標準 GTP 引擎，除了可供人機對局 [&#8230;]</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/github-issue-to-pr-loosely-coupled-collaboration/">從 GitHub Issue 至 PR：遠端協同開發的寬鬆耦合的合作模式</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/github-issue-to-pr-loosely-coupled-collaboration.webp" alt="封面圖：從 GitHub Issue 至 PR：遠端協同開發的寬鬆耦合的合作模式" style="width:620px"/></figure>



<p class="wp-block-paragraph">前兩個星期，我完成了 ZenGTPX。它可以將 Zen7（天頂圍棋）包裝成標準 GTP 引擎，除了可供人機對局使用，也能與其他圍棋 AI 引擎進行自動對局。</p>



<p class="wp-block-paragraph">🔗 <a href="https://github.com/kenming/ZenGTPX" target="_blank" rel="noopener">https://github.com/kenming/ZenGTPX</a></p>



<p class="wp-block-paragraph">我把 ZenGTPX 加入 LizzieYzy Next，作為其中一個 GTP 引擎。如此不僅可以在該介面內進行人機對局，也能安排 Zen7 與 KataGo 等不同引擎進行自動對局。</p>



<p class="wp-block-paragraph">🔗 <a href="https://github.com/wimi321/lizzieyzy-next" target="_blank" rel="noopener">https://github.com/wimi321/lizzieyzy-next</a></p>



<p class="wp-block-paragraph">不過，LizzieYzy Next 原本的引擎設定介面主要提供通用的啟動與對局參數，無法直接呈現 ZenGTPX 專屬的棋力設定。</p>



<p class="wp-block-paragraph">ZenGTPX 提供三種棋力設定模式：<code>rank</code>、<code>fixed-time</code> 與 <code>advanced</code>。</p>



<p class="wp-block-paragraph"><code>rank</code> 模式最為方便，只要直接設定棋力，範圍從 6 級到 9 段即可；<code>fixed-time</code> 模式則固定每手棋的思考時間，實際能完成多少搜尋計算，仍會受到 CPU 運算效能影響；<code>advanced</code> 模式提供更細部的參數設定，可透過 Config 設定檔調整多組 Zen7 搜尋參數，包括部分原 Zen7 GUI 未直接提供的底層設定，用以進一步微調棋力與搜尋行為。</p>



<p class="wp-block-paragraph">因此，我在 LizzieYzy Next 的 GitHub 提出了一篇 Issue，希望它可以支援 ZenGTPX 的棋力參數設定。</p>



<p class="wp-block-paragraph">作者好有心，很快就回覆，並且提出一個更具擴展性的方向：由 GTP 引擎透過穩定的擴充協定，自行提供設定 Schema、目前生效值、參數驗證與 Profile；LizzieYzy Next 則負責偵測引擎是否具備這項能力，並依據 Schema 自動產生設定介面。</p>



<p class="wp-block-paragraph">如此一來，這套機制不會只適用於 ZenGTPX，未來其他支援標準 GTP 協定的 AI 引擎，也可以使用相同方式擴充自己的專屬設定。</p>



<p class="wp-block-paragraph">從設計角度來看，這是以擴充協定、能力偵測與設定 Schema 為核心的 Plugin 設計。LizzieYzy Next 不需要預先知道各種引擎有哪些參數，而是由引擎自行描述能力與設定內容。</p>



<p class="wp-block-paragraph">🔗 <a href="https://github.com/wimi321/lizzieyzy-next/issues/101" target="_blank" rel="noopener">https://github.com/wimi321/lizzieyzy-next/issues/101</a></p>



<p class="wp-block-paragraph">我依照這個方向，在 ZenGTPX 端完成了 Configuration Protocol v1；LizzieYzy Next 作者則在 Next 端完成通用協定的偵測、設定介面、Profile 保存、執行中套用、多引擎設定隔離與錯誤處理。</p>



<p class="wp-block-paragraph">作者先使用模擬的 fake ZenGTPX Process 跑過完整流程，驗證能力偵測、設定、保存與重新啟動後的 Profile 還原。自動化測試全部通過後，他提交了 PR #126，將這套通用的 GTP 引擎棋力設定機制整合進 LizzieYzy Next。</p>



<p class="wp-block-paragraph">🔗 <a href="https://github.com/wimi321/lizzieyzy-next/pull/126" target="_blank" rel="noopener">https://github.com/wimi321/lizzieyzy-next/pull/126</a></p>



<p class="wp-block-paragraph">PR 合併後，作者希望我協助進行 Windows 與真實 Zen7／Zen.dll 的整合驗證。</p>



<p class="wp-block-paragraph">我先使用 VS Code 開啟原來的 ZenGTPX 專案，再將 PR 連結交給 Codex 分析。Codex 隨即取得相關分支內容，並整理出兩組可供 LizzieYzy Next 使用的 ZenGTPX 設定檔；接著我再請 Codex 啟動 LizzieYzy Next，讓我直接進行實機驗證。</p>



<p class="wp-block-paragraph">實際測試結果完全正常。<code>rank</code>、<code>fixed-time</code> 與 <code>advanced</code> 三種模式皆可正常顯示與套用，設定保存、執行中更新、重新啟動後還原，以及相同執行檔的多引擎 Profile 隔離也都沒有問題。</p>



<p class="wp-block-paragraph">完成測試後，我將結果交給 Codex 整理成 PR 回覆。作者之後又在最新的主分支上重新執行相同測試，確認全部通過，最後正式關閉原來的 Issue。</p>



<p class="wp-block-paragraph">整個遠端協同開發的過程，不到一個星期便完成了兩個應用程式的擴展整合。真正讓我感到有意思的，並不只是功能最終得以實現，而是整個合作過程幾乎完全建立在 GitHub 的標準協作機制上：先透過 Issue 整理需求與交換設計想法，再由開發者建立獨立分支完成實作，透過 PR（Pull Request）公開變更內容，交由另一方測試、驗證與回報，最後才合併至正式版本。</p>



<p class="wp-block-paragraph">雙方不需要共享相同的開發環境，也不需要頻繁召開會議或同步各自的工作進度，只要將需求、協定、程式變更與驗證結果清楚地留在 Issue 與 PR 中，便能各自在相對獨立的情況下完成工作。這正是一種 Loose Coupling 的協同開發模式：彼此保持低度依賴，卻能透過明確的介面、流程與可追蹤的紀錄，快速完成跨專案的合作與整合。</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/github-issue-to-pr-loosely-coupled-collaboration/">從 GitHub Issue 至 PR：遠端協同開發的寬鬆耦合的合作模式</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://kenming.idv.tw/github-issue-to-pr-loosely-coupled-collaboration/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<media:content url="https://images.kenming.idv.tw/software/github-issue-to-pr-loosely-coupled-collaboration.webp" medium="image"></media:content>
	</item>
		<item>
		<title>從業務流程到測試案例：Playwright 基礎操作與實務應用</title>
		<link>https://kenming.idv.tw/business-process-to-playwright-ui-automation-testing/</link>
					<comments>https://kenming.idv.tw/business-process-to-playwright-ui-automation-testing/#respond</comments>
		
		<dc:creator><![CDATA[Wang Kenming]]></dc:creator>
		<pubDate>Thu, 23 Jul 2026 12:47:48 +0000</pubDate>
				<category><![CDATA[AI應用與開發]]></category>
		<category><![CDATA[軟體實作與編程技術]]></category>
		<category><![CDATA[測試案例]]></category>
		<category><![CDATA[u]]></category>
		<category><![CDATA[Business Process]]></category>
		<category><![CDATA[Playwright]]></category>
		<category><![CDATA[UI 自動化測試]]></category>
		<category><![CDATA[AI Agent]]></category>
		<guid isPermaLink="false">https://kenming.idv.tw/?p=23965</guid>

					<description><![CDATA[<p>UI 自動化測試 - 使用 Playwright x AI Agent 系列 #02 開始使用 Playwri [&#8230;]</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/business-process-to-playwright-ui-automation-testing/">從業務流程到測試案例：Playwright 基礎操作與實務應用</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/business-to-playwright-automation-test.webp" alt="封面圖：AI Agent 協作開發中的 UI 自動化驗證流程" style="width:620px"/></figure>



<div style="height:24px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-text-color has-link-color wp-elements-132d68c1d37b685e9774bd76dd554e5b wp-block-paragraph" style="color:#4f6b8a;font-size:16px"><strong><strong>UI 自動化測試 - 使用 Playwright x AI Agent</strong></strong> <strong>系列 #02</strong></p>



<div style="height:16px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">開始使用 Playwright 撰寫 UI 自動化測試時，往往會先將注意力放在 click()、fill()、Locator 與 Assertion 等基礎腳本語法。然而，真正影響測試能否穩定執行、重複驗證與持續維護的關鍵，通常不在語法本身，而在於是否已先明確界定測試範圍。</p>



<p class="wp-block-paragraph">現實中的業務流程（Business Process）通常橫跨多個角色、作業活動與系統狀態，涵蓋範圍往往過大；Playwright 測試腳本則需要明確界定前置條件、操作步驟、測試資料與預期結果。若未先將業務流程轉換為具體的測試情境與測試案例，開發者或 AI Agent 便只能自行推測測試應從何處開始、驗證範圍到哪裡為止，以及符合哪些條件才算通過。</p>



<p class="wp-block-paragraph">因此，進入 Playwright 腳本實作前，需要先處理兩個問題：</p>



<ol class="wp-block-list">
<li>如何從業務流程界定 Test Scenario、Test Suite 與 Test Case。</li>



<li>Playwright 測測試體系的三個核心組成（CLI、Skill 與 Test），以及他們在瀏覽器操作、Agent 協作與自動化測試中的分工。</li>
</ol>



<p class="wp-block-paragraph">這兩個問題釐清後，瀏覽器操作才可能從一次性的 UI 探索，轉換為可重複執行的自動化測試。</p>



<h2 class="wp-block-heading">業務流程不等於測試案例</h2>



<p class="wp-block-paragraph">業務流程（Business Process）通常描述跨角色、跨活動與跨系統狀態的完整作業脈絡。例如：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">建立申請
→ 主管審核
→ 退回補件
→ 再次送審
→ 核准
→ 查詢處理結果</code></pre>



<p class="wp-block-paragraph">這份流程適合用來理解系統如何運作，但不適合直接轉成一支 Playwright Test。流程中可能包含不同角色登入、人工判斷、等待事件、外部通知，以及無法在同一次瀏覽器操作中穩定完成的狀態轉換。</p>



<p class="wp-block-paragraph">若直接把完整流程塞進一支測試，常見結果包括：</p>



<ul class="wp-block-list">
<li>測試執行時間過長。</li>



<li>前置狀態與測試資料難以重建。</li>



<li>任一中間步驟失敗，後續驗證全部中斷。</li>



<li>失敗結果只能指出流程未完成，卻難以定位問題。</li>
</ul>



<p class="wp-block-paragraph">UI 自動化需要先從完整業務流程中找出可由單一角色連續操作、而且可以從畫面判定結果的範圍。</p>



<h2 class="wp-block-heading">企業流程、活動與操作程序的區分</h2>



<p class="wp-block-paragraph">將業務描述轉換為 UI 測試之前，需先區分業務流程（Business Process）、業務活動（Activity）與操作程序（Operation Procedure）三個層級。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>名稱</th><th>定位</th><th>範例</th></tr></thead><tbody><tr><td>業務流程</td><td>跨角色與活動的完整作業脈絡</td><td>購買商品、付款、出貨與配送</td></tr><tr><td>業務活動</td><td>某個角色在特定節點完成的工作</td><td>顧客購買商品</td></tr><tr><td>操作程序</td><td>操作者在一次操作階段內完成的一連串 UI 步驟</td><td>登入、搜尋商品、加入購物車與完成結帳</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">以電子商務購物流程為例，可以拆分為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">Business Process：商品購物與訂單處理流程
　
Activity：訂購（購買）商品
Operation Procedure：
登入網站 → 搜尋商品 → 查看商品詳情 → 加入購物車
→ 填寫收件與付款資料 → 送出訂單
　
Activity：處理商品出貨
Operation Procedure：
登入後台 → 查詢待出貨訂單 → 檢視訂單內容
→ 建立出貨資料 → 更新訂單狀態</code></pre>



<p class="wp-block-paragraph">使用 Playwright 撰寫測試案例時，通常不會直接驗證完整的業務流程，而是選定其中某項業務活動所包含的操作程序，進一步界定為可執行、可驗證的測試範圍。</p>



<p class="wp-block-paragraph">例如：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">客戶登入電子商務網站
→ 搜尋並查看商品詳情
→ 將商品加入購物車
→ 填寫訂購資料並完成結帳
→ 確認畫面顯示訂單成立結果</code></pre>



<p class="wp-block-paragraph">這段操作程序具有明確的起點與終點，測試資料及前置狀態也可加以控制，最終結果則能透過畫面內容判定，因此較適合進一步轉換為自動化測試案例。</p>



<h2 class="wp-block-heading">從業務情境轉換為測試情境、測試套件與測試案例</h2>



<p class="wp-block-paragraph">業務流程與使用者操作程序仍不屬於正式的測試規格。若要進一步轉換為可執行的使用者介面（UI）測試，需先區分測試情境（Test Scenario）、測試套件（Test Suite）與測試案例（Test Case）。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>名稱</th><th>回答的問題</th><th>主要用途</th></tr></thead><tbody><tr><td>測試情境</td><td>要驗證什麼情境？</td><td>描述使用者目標或主要業務情境</td></tr><tr><td>測試套件</td><td>如何組織相關案例？</td><td>依功能、流程或驗證目的管理一組測試案例</td></tr><tr><td>測試案例</td><td>如何進行具體驗證？</td><td>定義前置條件、測試資料、操作步驟與預期結果</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">三者的關係可簡化為：</p>



<ul class="wp-block-list">
<li>測試情境：界定測試意圖</li>



<li>測試套件：組織相關測試案例</li>



<li>測試案例：界定可執行條件與預期結果</li>
</ul>



<p class="wp-block-paragraph">以一般電子商務網站為例：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">測試情境：
已登入的客戶可以搜尋商品、加入購物車並完成結帳。
　
測試套件：
購物主流程 UI 驗證
　
測試案例：
1. 使用有效帳號登入後，可以進入商品列表。
2. 輸入指定關鍵字後，可以看到目標商品。
3. 將商品加入購物車後，商品數量與小計顯示正確。
4. 進入結帳頁面後，訂單總額與購物車金額一致。
5. 送出訂單後，畫面顯示訂單成立結果。</code></pre>



<p class="wp-block-paragraph">測試情境用於描述需要驗證的使用者目標，不必包含所有操作細節；測試案例則必須提供足夠資訊，使人工執行者、Playwright 測試腳本與 AI Agent 對驗證範圍及成功條件產生一致理解。</p>



<p class="wp-block-paragraph">一個可執行的測試案例，至少需要回答下列問題：</p>



<ul class="wp-block-list">
<li>要驗證哪一項使用者目標？</li>



<li>測試從什麼系統狀態開始？</li>



<li>使用哪些帳號與測試資料？</li>



<li>需要執行哪些 UI 操作？</li>



<li>操作程序在哪個階段結束？</li>



<li>應依據哪些畫面、文字、網址或資料判定測試通過？</li>



<li>測試失敗時，是否能定位至特定操作階段？</li>
</ul>



<p class="wp-block-paragraph">若缺少這些條件，內容仍只是業務流程或操作程序的描述，尚不能直接視為可供 Playwright 執行的測試規格。</p>



<h2 class="wp-block-heading">測試資料與前置條件是測試案例的必要組成</h2>



<p class="wp-block-paragraph">測試需求若只描述為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">加入商品並確認折扣。</code></pre>



<p class="wp-block-paragraph">這段描述沒有明確指定商品單價、購買數量、折扣門檻與預期金額。執行者只能自行補充缺少的條件，最後可能只確認畫面出現「折扣」文字，卻未實際驗證折扣金額與訂單總額是否計算正確。</p>



<p class="wp-block-paragraph">較完整的測試資料（Test Data）可以定義為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">商品單價：NT$ 500
購買數量：2
折扣規則：消費滿 NT$ 1,000 享 9 折
　
預期小計：NT$ 1,000
預期折扣金額：NT$ 100
預期訂單總額：NT$ 900</code></pre>



<p class="wp-block-paragraph">除了測試資料，測試案例也必須明確定義前置條件（Precondition）。以前述折扣案例為例，執行測試前應確認：</p>



<ul class="wp-block-list">
<li>測試帳號可以正常使用。</li>



<li>使用者已完成登入，或測試案例包含登入步驟。</li>



<li>購物車處於空白狀態。</li>



<li>指定商品存在、庫存充足且可正常購買。</li>



<li>對應的折扣規則已啟用。</li>



<li>前一次測試未留下訂單、購物車或暫存資料。</li>
</ul>



<p class="wp-block-paragraph">測試資料決定「使用哪些數值進行驗證」，前置條件則決定「測試從什麼系統狀態開始」。兩者若未明確界定，即使 Playwright 腳本語法正確，測試結果仍可能因資料或環境狀態不同而不穩定。</p>



<p class="wp-block-paragraph">這類問題不應只透過固定等待、重試（Retry）或延長逾時時間（Timeout）加以掩蓋，而應先確認測試資料是否隔離，以及每次執行前後的系統狀態是否已正確建立與清理。</p>



<h2 class="wp-block-heading">從業務流程中裁適 UI Smoke Test 範圍</h2>



<p class="wp-block-paragraph">冒煙測試（Smoke Test）不是業務流程的同義詞，而是從既有測試情境與測試案例中，選出少量具代表性且可快速執行的基準測試，用於確認系統最重要的功能與使用者操作路徑仍可正常運作。</p>



<p class="wp-block-paragraph">以電子商務網站為例，購物主流程可整理為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">登入
→ 搜尋商品
→ 查看商品詳情
→ 加入購物車
→ 進入結帳頁面
→ 送出訂單
→ 確認訂單成立</code></pre>



<p class="wp-block-paragraph">規劃第一組 UI Smoke Test 時，不需要同時涵蓋：</p>



<ul class="wp-block-list">
<li>登入密碼錯誤。</li>



<li>商品搜尋無結果。</li>



<li>輸入無效購買數量。</li>



<li>多種折扣規則組合。</li>



<li>商品庫存不足。</li>



<li>付款處理失敗。</li>



<li>訂單取消或退款。</li>
</ul>



<p class="wp-block-paragraph">這些情境可能同樣重要，但應依不同驗證目的，分別整理為其他測試案例。若將所有正常流程、例外條件與業務規則都納入同一支測試案例，測試範圍會逐漸擴張成龐大的端到端回歸流程，不僅執行時間增加，失敗原因也更難定位，因而失去 Smoke Test 快速檢查核心功能的作用。</p>



<p class="wp-block-paragraph">從業務流程中裁適 UI Smoke Test 範圍時，可依下列條件評估：</p>



<ol class="wp-block-list">
<li><strong>代表性</strong>：是否涵蓋系統最重要的使用者目標與核心操作路徑。</li>



<li><strong>可重複性</strong>：測試資料與前置狀態是否能在每次執行前穩定建立。</li>



<li><strong>可判定性</strong>：是否具備明確且可由程式自動驗證的預期結果。</li>



<li><strong>可定位性</strong>：測試失敗時，是否能快速判斷問題發生在哪一個操作階段。</li>



<li><strong>執行效率</strong>：是否能在合理時間內完成，並適合頻繁執行。</li>
</ol>



<p class="wp-block-paragraph">因此，UI Smoke Test 應視為測試套件（Test Suite）中一組高優先級的基準測試案例，而不是將完整業務流程直接縮寫成單一測試案例。</p>



<h2 class="wp-block-heading">明確界定測試意圖，避免 AI Agent 自行推測</h2>



<p class="wp-block-paragraph">AI Agent 可以協助操作瀏覽器、產生測試腳本與分析失敗原因，但不應自行決定測試範圍與業務規則。</p>



<p class="wp-block-paragraph">模糊要求：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">請測試購物流程是否正常。</code></pre>



<p class="wp-block-paragraph">Agent 可能自行選擇商品、忽略購物車前置狀態，或只確認頁面可以切換，卻沒有驗證金額與訂單結果。</p>



<p class="wp-block-paragraph">較合理的輸入應明確界定：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">驗證目標：已登入使用者可以完成一次商品結帳。
　
前置條件：
- 使用固定測試帳號。
- 測試開始前購物車必須為空。
　
操作範圍：
- 搜尋指定關鍵字。
- 開啟第一筆符合條件的商品。
- 加入 2 件商品。
- 進入結帳頁並送出訂單。
　
驗證項目：
- 購物車數量為 2。
- 小計與預期計算一致。
- 結帳頁總額與購物車一致。
- 送出後顯示訂單成立訊息或訂單編號。
　
限制：
- 不修改產品功能。
- 不降低 Assertion 條件。
- 若實際畫面與描述不一致，先回報差異。</code></pre>



<p class="wp-block-paragraph">這種輸入讓 Agent 的責任集中在依據實際 UI 完成驗證，而不是替需求補寫規則。</p>



<h2 class="wp-block-heading">Playwright CLI、Skill 與 Playwright Test 的基本分工</h2>



<p class="wp-block-paragraph">Playwright CLI、Playwright Skill 與 Playwright Test 位於不同層次。三者不是互相取代，而是形成一個由觀察、規範到正式測試的流程。</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">Playwright CLI
→ 讓 AI Agent 操作瀏覽器與觀察 UI 狀態
　
Playwright Skill
→ 規範 AI Agent 如何正確使用 Playwright CLI
　
Playwright Test
→ 將使用者操作流程整理為可重複執行的測試案例</code></pre>



<p class="wp-block-paragraph">Playwright CLI 適合用來開啟頁面、取得 snapshot、執行操作與保留 screenshot。基本操作流程可以表示為：</p>


<pre class="language-powershell no-line-numbers"><code class="language-powershell no-line-numbers">playwright-cli open &lt;target-url&gt;
playwright-cli snapshot
playwright-cli screenshot
playwright-cli close</code></pre>



<p class="wp-block-paragraph">CLI 可協助確認：</p>



<ul class="wp-block-list">
<li>實際頁面有哪些可互動元素。</li>



<li>預期按鈕或欄位是否存在。</li>



<li>操作後畫面如何變化。</li>



<li>Locator 應根據哪些實際資訊建立。</li>
</ul>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/playwright-cli-open-url.webp" alt="" style="width:620px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">圖：Playwright CLI 操作並取得頁面狀態</p>



<p class="wp-block-paragraph">需注意一次 CLI 操作不等於正式測試。它通常沒有完整 Test Case 定義，也不會自然形成可版本控管、可重複執行的回歸驗證。</p>



<h3 class="wp-block-heading">Playwright Skill：約束 Agent 的操作與回報</h3>



<p class="wp-block-paragraph">Playwright Skill 不會增加新的瀏覽器 API，也不會取代 Playwright Test。它主要用來規範 Agent：</p>



<ul class="wp-block-list">
<li>必須實際開啟頁面。</li>



<li>先取得頁面狀態，再決定操作方式。</li>



<li>回報實際執行步驟與觀察結果。</li>



<li>必要時保留 snapshot 或 screenshot。</li>



<li>畫面與需求不一致時，停止猜測並回報差異。</li>
</ul>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/agent-playwright-skill-verification.webp" alt="" style="width:620px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">圖：AI Agent 依 Playwright Skill 執行頁面驗證並回報結果</p>



<p class="wp-block-paragraph">Skill 的價值，是降低 Agent 未實際操作瀏覽器就直接推測 UI 狀態的風險。</p>



<h3 class="wp-block-heading">Playwright Test：UI 自動化測試框架</h3>



<p class="wp-block-paragraph">Playwright Test 是 Playwright 提供的測試框架與測試執行器（Test Runner），用於撰寫、執行及管理可重複的 UI 自動化測試案例。</p>



<p class="wp-block-paragraph">它主要負責：</p>



<ul class="wp-block-list">
<li>組織與執行測試案例。</li>



<li>管理瀏覽器生命週期與測試隔離。</li>



<li>執行操作步驟與斷言。</li>



<li>產出測試結果、HTML Report、Trace 與 Screenshot。</li>
</ul>



<p class="wp-block-paragraph">相較於 Playwright CLI 主要用於操作與觀察瀏覽器，Playwright Test 則負責承載正式的測試腳本，並提供一致、可重複的測試執行與結果判定機制。</p>



<h2 class="wp-block-heading">頁面快照、畫面截圖、HTML 測試報告與追蹤記錄</h2>



<p class="wp-block-paragraph">UI 測試不只需要執行操作，也需要留下可供核對的測試證據（Evidence）。不同類型的測試證據，適合用於判斷不同問題：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>測試證據</th><th>主要用途</th></tr></thead><tbody><tr><td>頁面快照（Snapshot）</td><td>確認頁面文字、結構與可互動元素</td></tr><tr><td>畫面截圖（Screenshot）</td><td>確認實際視覺狀態、版面配置與錯誤訊息</td></tr><tr><td>HTML 測試報告（HTML Report）</td><td>彙整測試通過、失敗、錯誤訊息與相關附件</td></tr><tr><td>追蹤記錄（Trace）</td><td>還原失敗前後的操作、文件物件模型（DOM）、網路請求與頁面狀態</td></tr></tbody></table></figure>



<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/playwright-html-report.webp" alt="" style="width:620px"/></figure>



<p class="has-text-align-center has-small-font-size wp-block-paragraph">圖：Playwright HTML 測試報告集中呈現測試結果</p>



<p class="wp-block-paragraph">例如：</p>



<ul class="wp-block-list">
<li>確認按鈕是否存在，可先檢查頁面快照。</li>



<li>判斷按鈕是否被其他元素遮蔽，需要查看畫面截圖。</li>



<li>確認哪一支測試案例執行失敗，可以從 HTML 測試報告中檢查。</li>



<li>分析點擊後未跳轉的原因，通常需要透過追蹤記錄還原操作過程。</li>
</ul>



<p class="wp-block-paragraph">測試證據的目的不是增加附件數量，而是讓測試結果能夠被判讀、重現與分類。</p>



<h2 class="wp-block-heading">從一次性 UI 操作轉為可重複執行的測試</h2>



<p class="wp-block-paragraph">將業務流程轉換為 Playwright 測試，可以依下列順序進行：</p>



<ol class="wp-block-list">
<li>確認 Business Process 與主要業務活動。</li>



<li>選定單一角色的 Operation Procedure。</li>



<li>定義 Test Scenario、Test Suite 與 Test Case。</li>



<li>固定測試資料、帳號與前置狀態。</li>



<li>使用 Playwright CLI 或 Agent 操作實際頁面。</li>



<li>根據 snapshot 與 screenshot 核對 UI 狀態。</li>



<li>修正錯誤的流程假設與 Locator 判斷。</li>



<li>將穩定操作整理為 Playwright Test。</li>



<li>執行測試並檢查 HTML Report 或 Trace。</li>



<li>保留為可重複執行的基準驗證。</li>
</ol>



<p class="wp-block-paragraph">這個順序比直接要求 Agent 生成完整測試更可靠。Agent 先接觸實際頁面，再根據已界定的測試意圖撰寫腳本，可以降低錯誤 Locator、模糊 Assertion 與錯誤流程假設。</p>



<h2 class="wp-block-heading">常見問題</h2>



<h3 class="wp-block-heading">將完整業務流程寫成單一測試案例</h3>



<p class="wp-block-paragraph">跨角色、跨系統或跨狀態的業務流程應分段驗證。若將完整流程寫成單一測試案例，任何中間步驟失敗，都可能使後續驗證失去意義，也會增加問題定位的難度。</p>



<h3 class="wp-block-heading">將測試情境視為測試案例</h3>



<p class="wp-block-paragraph">「使用者可以完成結帳」只描述測試情境（Test Scenario），尚未明確定義前置條件、測試資料、操作步驟與預期結果，因此不能直接作為可執行的測試案例（Test Case）。</p>



<h3 class="wp-block-heading">為了讓測試通過而降低斷言要求</h3>



<p class="wp-block-paragraph">例如，原本應驗證精確的折扣金額與訂單總額，最後卻只確認頁面出現「結帳成功」。測試雖然通過，卻未實際保護重要的業務規則。</p>



<p class="wp-block-paragraph">調整斷言（Assertion）時，應確認驗證條件是否仍符合原始測試意圖，而不是單純降低通過門檻。</p>



<h3 class="wp-block-heading">依靠固定等待掩蓋狀態問題</h3>



<p class="wp-block-paragraph">大量使用固定秒數等待，通常表示測試沒有依據實際 UI 狀態進行同步，或測試資料與前置狀態不穩定。</p>



<p class="wp-block-paragraph">應優先依據實際 UI 狀態進行非同步等待，例如等待具體元素、文字、網址或網路狀態符合預期，而不是使用固定秒數等待。</p>



<h3 class="wp-block-heading">將一次性的 AI Agent 操作視為回歸測試</h3>



<p class="wp-block-paragraph">AI Agent 成功完成一次操作，只能證明該流程在當時的環境與資料狀態下可能可用，不能直接視為可重複執行的回歸測試（Regression Testing）。</p>



<p class="wp-block-paragraph">若要形成正式驗證，仍需將操作流程整理為明確的測試案例，並使用 Playwright Test 撰寫成具備固定資料、操作步驟、斷言與執行結果的自動化測試腳本。</p>



<h3 class="wp-block-heading">在初期一次納入過多測試情境</h3>



<p class="wp-block-paragraph">初期應先建立一組穩定且具代表性的主要流程測試，再逐步增加錯誤情境、邊界值與替代操作路徑。</p>



<p class="wp-block-paragraph">相較於一次建構所有分支，這種漸進式作法更容易驗證測試設計、控制執行範圍及維持後續可維護性。</p>



<h2 class="wp-block-heading">結語</h2>



<p class="wp-block-paragraph">Playwright UI 自動化測試的起點，不是直接使用瀏覽器操作介面，而是先將業務流程轉換為明確、可執行且可驗證的測試案例。</p>



<p class="wp-block-paragraph">業務流程（Business Process）用於理解完整的作業脈絡；業務活動（Activity）與操作程序（Operation Procedure）則用於找出可由單一角色執行的操作範圍。測試情境（Test Scenario）描述需要驗證的使用者目標，測試套件（Test Suite）負責組織相關測試案例，測試案例（Test Case）則明確定義前置條件、測試資料、操作步驟與預期結果。UI 冒煙測試（UI Smoke Test）是從這些測試案例中選出的高優先級基準測試，而不是完整業務流程的替代名稱。</p>



<p class="wp-block-paragraph">進入實際操作後，Playwright CLI 可用於操作瀏覽器並觀察頁面狀態；Playwright Skill 用於規範人工智慧代理（AI Agent）的操作方式與結果回報；Playwright Test 則是 Playwright 提供的測試框架與測試執行器，用於撰寫、執行及管理可重複的 UI 自動化測試。頁面快照（Snapshot）、畫面截圖（Screenshot）、HTML 測試報告（HTML Report）與追蹤記錄（Trace），則提供結果判定與失敗診斷所需的測試證據（Evidence）。</p>



<p class="wp-block-paragraph">只有先界定流程層級、測試範圍與各項工具的責任，定位器（Locator）、使用者操作（User Actions）與斷言（Assertions），才能共同形成可執行、可觀察且可維護的 UI 自動化測試。</p>



<h2 class="wp-block-heading">延伸閱讀</h2>



<ul class="wp-block-list">
<li>Playwright CLI + Skills：<a href="https://github.com/microsoft/playwright-cli" target="_blank" rel="noopener">https://github.com/microsoft/playwright-cli</a></li>



<li>Playwright Test CLI：<a href="https://playwright.dev/docs/test-cli" target="_blank" rel="noopener">https://playwright.dev/docs/test-cli</a></li>



<li>Playwright for VS Code：<a href="https://playwright.dev/docs/getting-started-vscode" target="_blank" rel="noopener">https://playwright.dev/docs/getting-started-vscode</a></li>
</ul>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/business-process-to-playwright-ui-automation-testing/">從業務流程到測試案例：Playwright 基礎操作與實務應用</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://kenming.idv.tw/business-process-to-playwright-ui-automation-testing/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<media:content url="https://images.kenming.idv.tw/software/ui-automation-test/business-to-playwright-automation-test.webp" medium="image"></media:content>
	</item>
		<item>
		<title>有了 AI Agent 輔助開發後，我開始喜歡寫文件</title>
		<link>https://kenming.idv.tw/why-i-started-enjoying-writing-docs-with-ai-agent/</link>
					<comments>https://kenming.idv.tw/why-i-started-enjoying-writing-docs-with-ai-agent/#respond</comments>
		
		<dc:creator><![CDATA[Wang Kenming]]></dc:creator>
		<pubDate>Wed, 22 Jul 2026 07:59:28 +0000</pubDate>
				<category><![CDATA[AI應用與開發]]></category>
		<category><![CDATA[軟體開發方法論]]></category>
		<category><![CDATA[軟體五四三與經驗談]]></category>
		<category><![CDATA[agile]]></category>
		<category><![CDATA[軟體架構]]></category>
		<category><![CDATA[AI Agent]]></category>
		<category><![CDATA[開發方法論]]></category>
		<category><![CDATA[UML]]></category>
		<guid isPermaLink="false">https://kenming.idv.tw/?p=23959</guid>

					<description><![CDATA[<p>過去輔導企業團隊進行軟體開發時，我其實不太鼓勵團隊花費大量時間撰寫詳細文件。 以往常見的做法是：專案經理認為必 [&#8230;]</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/why-i-started-enjoying-writing-docs-with-ai-agent/">有了 AI Agent 輔助開發後，我開始喜歡寫文件</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ai-agent-document-code-iteration-linkedin-cover.webp" alt="AI-Agent-文件與程式碼迭代協作" style="width:620px"/></figure>



<p class="wp-block-paragraph">過去輔導企業團隊進行軟體開發時，我其實不太鼓勵團隊花費大量時間撰寫詳細文件。</p>



<p class="wp-block-paragraph">以往常見的做法是：專案經理認為必須先完成完整的需求文件，開發人員才能開始寫碼。但需求文件與實際開發之間，往往相隔數週甚至數月。等到真正進入實作時，需求、限制條件與技術判斷可能早已改變，文件內容也逐漸失真。</p>



<p class="wp-block-paragraph">問題不在於文件本身，而在於把文件視為一次完成、後續只需要照表實作的規格。</p>



<p class="wp-block-paragraph">當需求分析、系統設計與程式開發被切割成前後相接的階段，就容易落入<strong>典型的 Waterfall 思維</strong>。相較之下，Agile 強調 <strong>Iteration &amp; Increment（迭代與漸增）</strong>，讓需求分析、設計、Coding 與驗證快速形成循環，盡早取得回饋，再逐步補足功能與設計細節。</p>



<p class="wp-block-paragraph">在沒有 AI Agent 的年代，我比較常使用 UML 或架構圖作為設計草稿：</p>



<ul class="wp-block-list">
<li>使用案例圖：表達使用者的操作目的。</li>



<li>類別圖：表達軟體結構與責任分配。</li>



<li>循序圖：表達物件之間的互動流程。</li>



<li>架構圖：表達分層、微服務、部署與系統邊界。</li>
</ul>



<p class="wp-block-paragraph">這些設計圖主要是溝通與思考工具，不是追求精確與完整的規格文件。很多時候，簡單草圖甚至手繪就已經足夠。</p>



<p class="wp-block-paragraph">當時的開發核心仍然是程式碼。</p>



<p class="wp-block-paragraph">界定一項系統功能後，應該在幾天內完成一次可執行的 Iteration，而不是持續等待文件變得「完整」。</p>



<p class="wp-block-paragraph">但 AI Agent 的出現，改變了文件在開發流程中的角色。</p>



<p class="wp-block-paragraph">現在我所謂的「撰寫文件」，並不是由開發人員投入大量時間逐字編寫，而是將自己的想法、討論結果與技術調研交給 AI Agent，協助整理成結構化文檔。</p>



<p class="wp-block-paragraph">這些文件主要是給誰閱讀？</p>



<p class="wp-block-paragraph">首先是 AI Agent。</p>



<p class="wp-block-paragraph">開發人員、使用者與利益關係人（Stackholder）當然也會閱讀，但主要用於審閱、參考與掌握重點。因此，採用 AI 與人員都容易閱讀及編輯的 Markdown，會是相當實用的文件交換格式。</p>



<p class="wp-block-paragraph">開發人員也不再需要完全依照文件自行寫碼。AI Agent 可以讀取需求、架構與技術規格，據此生成：</p>



<ul class="wp-block-list">
<li>應用程式碼</li>



<li>測試程式碼</li>



<li>部署腳本</li>



<li>組態設定</li>



<li>專案文件</li>
</ul>



<p class="wp-block-paragraph">我目前會依專案需求，逐步建立幾類文件：</p>



<ul class="wp-block-list">
<li>Research：技術調研與參考資料。</li>



<li>Requirements：需求範圍、功能點、業務邏輯與驗收條件。</li>



<li>Architecture：系統結構、模組邊界與設計決策。</li>



<li>Specification：技術框架、分層規範與實作限制。</li>



<li>Backlog：每次開發迭代預定完成的工作項目。</li>



<li>DevLog：實際完成內容、問題處理與版本變更紀錄。</li>
</ul>



<p class="wp-block-paragraph">每次準備進入開發迭代前，我會先要求 Agent 整理 Backlog。完成工作後，再由 Agent 將實際結果整理為 DevLog，最後 Commit 並 Push 至 GitHub，形成可追蹤的版本與專案紀錄。</p>



<p class="wp-block-paragraph">這件事其實有些諷刺。</p>



<p class="wp-block-paragraph">以前我最反對開發人員花時間填寫各種 Worksheet；現在卻建立了比以前更多的文件。</p>



<p class="wp-block-paragraph">差別在於：以前的文件經常是一項需要人工維護、卻很快失真的交付物；現在的文件則可以直接成為 AI Agent 執行工作的上下文、限制條件與判斷依據。</p>



<p class="wp-block-paragraph">那麼，是否應該先建立完整的文件目錄與所有規格，再開始生成程式碼？</p>



<p class="wp-block-paragraph">當然不是。</p>



<p class="wp-block-paragraph">若堅持先完成所有文件，再開始實作，本質上仍然是 Waterfall 思維。</p>



<p class="wp-block-paragraph">文件與程式碼之間沒有絕對的先後順序。真正重要的是，兩者必須隨著開發持續同步演進。</p>



<p class="wp-block-paragraph">這在過去很難實現，因為文件與程式碼通常由不同人員、在不同時間分別維護。但 AI Agent 具備同時讀取規格、修改實作並回寫工作紀錄的能力，反而有機會降低兩者長期分離的問題。</p>



<p class="wp-block-paragraph">我目前採用的開發循環大致如下：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">最小規格／文件
⇄ AI Agent 實作
⇄ 驗證實作結果
⇄ 修訂並補充規格文件</code></pre>



<p class="wp-block-paragraph">AI Agent 帶來的改變，不只是更快地生成程式碼。</p>



<p class="wp-block-paragraph">更重要的是，它讓文件從靜態交付物，逐漸轉變為可以參與開發、約束實作，並隨程式碼共同演進的工程資產。</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/why-i-started-enjoying-writing-docs-with-ai-agent/">有了 AI Agent 輔助開發後，我開始喜歡寫文件</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://kenming.idv.tw/why-i-started-enjoying-writing-docs-with-ai-agent/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<media:content url="https://images.kenming.idv.tw/software/ai-agent-document-code-iteration-linkedin-cover.webp" medium="image"></media:content>
	</item>
		<item>
		<title>AI Agent 協作開發中的 UI 自動化驗證流程</title>
		<link>https://kenming.idv.tw/ai-agent-ui-automation-validation-workflow/</link>
					<comments>https://kenming.idv.tw/ai-agent-ui-automation-validation-workflow/#respond</comments>
		
		<dc:creator><![CDATA[Wang Kenming]]></dc:creator>
		<pubDate>Tue, 21 Jul 2026 07:22:54 +0000</pubDate>
				<category><![CDATA[AI應用與開發]]></category>
		<category><![CDATA[軟體實作與編程技術]]></category>
		<category><![CDATA[Playwright]]></category>
		<category><![CDATA[E2E Testing]]></category>
		<category><![CDATA[UI 自動化測試]]></category>
		<category><![CDATA[AI Agent]]></category>
		<guid isPermaLink="false">https://kenming.idv.tw/?p=23942</guid>

					<description><![CDATA[<p>UI 自動化測試 - 使用 Playwright x AI Agent 系列 #01 Codex、GitHub [&#8230;]</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/ai-agent-ui-automation-validation-workflow/">AI Agent 協作開發中的 UI 自動化驗證流程</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image aligncenter size-large is-resized img-border"><img decoding="async" src="https://images.kenming.idv.tw/software/ui-automation-test/ai-agent-ui-automation-validation-workflow.webp" alt="封面圖：AI Agent 協作開發中的 UI 自動化驗證流程" style="width:620px"/></figure>



<div style="height:24px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-text-color has-link-color wp-elements-b0380cb659b02a60328c6616ebae682e wp-block-paragraph" style="color:#4f6b8a;font-size:16px"><strong><strong>UI 自動化測試 - 使用 Playwright x AI Agent</strong></strong> <strong>系列 #01</strong></p>



<div style="height:16px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">Codex、GitHub Copilot、Claude Code 等 AI Agent 已能快速修改功能、調整畫面與重構程式碼。開發流程面對的新問題，已不只是「AI 能不能寫出程式碼」，而是：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">AI Agent 修改系統功能後，如何證明使用者原本可以完成的操作流程仍然正確？</p>
</blockquote>



<p class="wp-block-paragraph">在以 Web 為操作界面的應用系統中，最容易受到變更影響的往往不是單一函式，而是跨越畫面元件、API、資料狀態與操作順序的完整流程。例如登入、搜尋、表單送出、購物車金額計算與錯誤訊息顯示，都可能在局部程式修改後出現連鎖影響。</p>



<p class="wp-block-paragraph">單元測試可以確認某個函式、服務或資料處理邏輯是否正確，但無法完整代表使用者在瀏覽器中的實際操作結果。</p>



<p class="wp-block-paragraph">因此，當系統開始頻繁透過 AI Agent 修改功能、調整畫面或重構流程時，就需要一套可重複執行、可留下證據、可回饋修正的 UI 驗證機制。</p>



<h2 class="wp-block-heading">為什麼 Agent 協作需要可重複執行的 UI 驗證</h2>



<p class="wp-block-paragraph">傳統開發中，開發者完成小幅修改後，常直接開啟瀏覽器操作幾次，確認畫面看起來正常。當變更頻率低、修改範圍小，而且開發者熟悉系統脈絡時，這種方式勉強可以運作。</p>



<p class="wp-block-paragraph">但在 AI Agent 協作情境中，這種方式會快速失效，原因包括：</p>



<ul class="wp-block-list">
<li>Agent 可以快速修改多個檔案，但不一定理解完整使用者流程。</li>



<li>Agent 可能修好局部程式碼，卻破壞另一個畫面操作。</li>



<li>Agent 可能依據錯誤假設修改 selector、欄位名稱或狀態處理。</li>



<li>人工檢查不容易持續重複，也不容易提供精準失敗證據。</li>



<li>若沒有可執行驗收條件，Agent 任務完成與否會變成主觀判斷。</li>
</ul>



<p class="wp-block-paragraph">因此，AI Agent 協作開發需要一個可重複執行的驗證機制，用來回答最基本的問題：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Agent 修改後，使用者原本應該能完成的主要操作流程，是否仍然可以完成？</p>
</blockquote>



<h2 class="wp-block-heading">UI Automation、E2E Testing 與 Smoke Test</h2>



<p class="wp-block-paragraph">UI 自動化測試常與 E2E Testing、Smoke Test 混用，但三者的定位並不相同。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>名稱</th><th>核心定位</th><th>實務用途</th></tr></thead><tbody><tr><td>UI Automation</td><td>以程式撰寫腳本自動操作瀏覽器畫面</td><td>將登入、輸入、點擊與導頁等操作轉為可重複執行的腳本</td></tr><tr><td>E2E Testing</td><td>驗證跨越前端、API、後端與資料狀態的完整流程</td><td>確認使用者從操作起點到結果呈現的流程仍然成立</td></tr><tr><td>Smoke Test</td><td>以最小測試集合快速確認主要功能可用</td><td>作為功能修改後的基本驗收與回歸檢查</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">UI Automation：讓界面操作流程可以被重複執行</h3>



<p class="wp-block-paragraph">UI Automation 的核心，是將原本需要人工操作的畫面流程，轉換為可由程式重複執行的操作步驟。例如，一段人工登入流程可以描述為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">開啟登入頁
→ 輸入帳號與密碼
→ 點擊登入
→ 確認進入主畫面</code></pre>



<p class="wp-block-paragraph">轉為 UI Automation 後，這段流程可以固定使用相同的步驟與測試資料執行，並納入版本控管。其價值不只是節省點擊時間，而是讓操作方式與驗證結果具備一致性。</p>



<h3 class="wp-block-heading">E2E Testing：確認跨層流程仍然成立</h3>



<p class="wp-block-paragraph">以購物系統的「加入購物車」為例，實際流程可能跨越：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">商品列表
→ 商品資料載入
→ 加入購物車
→ 購物車狀態更新
→ 數量與金額重新計算</code></pre>



<p class="wp-block-paragraph">即使 API 測試已通過，畫面仍可能因欄位名稱、事件處理、狀態同步或 UI 重構而無法完成操作。E2E Testing 關注的正是這種從使用者畫面出發、跨越多個系統層次的完整結果。</p>



<h3 class="wp-block-heading">Smoke Test：先驗證最小但關鍵的流程</h3>



<p class="wp-block-paragraph">Smoke Test 不是完整測試策略，也不追求一次覆蓋所有分支與邊界條件。它以最低成本確認系統是否仍具備基本可用性。</p>



<p class="wp-block-paragraph">Smoke Test 的設計原則如下：</p>



<ul class="wp-block-list">
<li>測試數量不追求多，先覆蓋核心流程。</li>



<li>測試案例需能快速執行。</li>



<li>測試結果需能清楚指出失敗位置。</li>



<li>測試證據需能回饋給 Agent 作為修正依據。</li>



<li>測試腳本需能隨課程案例逐步調整，而不是一次設計到完整測試平台。</li>
</ul>



<p class="wp-block-paragraph">對 AI Agent 協作開發而言，Smoke Test 特別重要。原因是 Agent 修改通常速度很快，但每次修改後都需要有一個低成本、可重複的方式確認主要流程是否被破壞。</p>



<h2 class="wp-block-heading">Playwright 在驗證閉環中的三種角色</h2>



<p class="wp-block-paragraph">Playwright 不只是瀏覽器操作工具。在 AI Agent 協作流程中，它可以同時扮演驗證層、測試證據（Evidence） 來源與完成條件三種角色。</p>



<h3 class="wp-block-heading">1. 驗證層：確認主要流程仍可操作</h3>



<p class="wp-block-paragraph">Playwright 測試腳本可以模擬實際使用者操作瀏覽器，例如：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">登入
→ 搜尋資料
→ 開啟明細
→ 修改狀態
→ 送出流程
→ 驗證完成結果</code></pre>



<p class="wp-block-paragraph">這類驗證可以補足單元測試與 API 測試無法直接覆蓋的部分，特別是 UI 元件互動、畫面狀態變更與使用者可見結果。</p>



<h3 class="wp-block-heading">2. Evidence 來源：提供失敗診斷依據</h3>



<p class="wp-block-paragraph">測試失敗時，只知道 <code>failed</code> 並不足以修正問題。開發者與 Agent 還需要知道失敗步驟、當時畫面、實際 DOM 狀態，以及前後操作是否符合預期。</p>



<p class="wp-block-paragraph">Playwright 可提供下列 Evidence（測試證據）：</p>



<ul class="wp-block-list">
<li><strong>Screenshot</strong>：保留失敗當下的畫面狀態。</li>



<li><strong>Trace</strong>：記錄操作步驟、Locator、DOM Snapshot、Console 與 Network 資訊。</li>



<li><strong>Video</strong>：觀察整段測試的畫面變化與卡住位置。</li>



<li><strong>HTML Report</strong>：彙整測試結果、錯誤訊息、執行時間與附件。</li>
</ul>



<p class="wp-block-paragraph">這些輸出可以作為 AI Agent 修正時的依據，而不是只提供一段模糊的自然語言描述。</p>



<h3 class="wp-block-heading">3. Done Definition：讓 Agent 任務具備可驗收標準</h3>



<p class="wp-block-paragraph">Agent 回報「已完成修改」不應被視為任務已完成。更合理的方式，是將測試通過作為完成定義的一部分，例如：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">完成條件：
- 已依需求修改登入錯誤提示。
- 已更新相關 UI Smoke Test。
- `npx playwright test` 執行通過。
- 若測試失敗，需提供 Trace、錯誤摘要與修正說明。</code></pre>



<p class="wp-block-paragraph">如此可將 Agent 的工作成果從「產出程式碼」提升為「產出可驗證的變更」。</p>



<h2 class="wp-block-heading">為何採用 Playwright？</h2>



<p class="wp-block-paragraph">Selenium 長期被廣泛應用於企業瀏覽器自動化驗證，適合已有多語言測試框架、跨平台基礎建設與大量既有案例的團隊。採用 Playwright 並不表示 Selenium 已失去價值。</p>



<p class="wp-block-paragraph">在 AI Agent 協作開發情境中，Playwright 的主要優勢，是較容易建立快速驗證閉環：內建 Auto-waiting 與 Actionability Checks，並整合 Trace、Screenshot、Video 與 HTML Report 等診斷能力。對需要小步修改、立即驗證、快速回饋的現代 Web 專案而言，導入阻力通常較低。</p>



<p class="wp-block-paragraph">真正的判斷標準不是哪一套工具較新，而是哪一套工具較符合現有團隊、系統與驗證流程。</p>



<h2 class="wp-block-heading">測試腳本就是可執行的驗收規格</h2>



<p class="wp-block-paragraph">傳統驗收條件常以文字描述：</p>



<ul class="wp-block-list">
<li>使用者登入後應能看到商品列表。</li>



<li>使用者可以搜尋商品。</li>



<li>使用者可以將商品加入購物車。</li>
</ul>



<p class="wp-block-paragraph">這些敘述適合需求討論，但無法自動判斷修改後的系統是否仍符合要求。當它們被轉換為 Playwright 測試腳本後，便成為可執行的驗收規格。</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>驗收描述</th><th>可執行驗證方式</th></tr></thead><tbody><tr><td>使用者可以登入</td><td>操作登入表單，驗證導頁與登入後畫面</td></tr><tr><td>使用者可以搜尋</td><td>輸入關鍵字，驗證列表內容變化</td></tr><tr><td>使用者可以加入購物車</td><td>點擊加入按鈕，驗證商品與數量</td></tr><tr><td>使用者可以修改數量</td><td>操作數量欄位，驗證小計與總額</td></tr><tr><td>使用者可以完成結帳</td><td>執行結帳流程，驗證完成訊息與訂單結果</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">重點不是將所有需求全部轉為 E2E 測試，而是優先保護最能代表系統可用性的主流程。當關鍵流程具有固定測試資料、操作步驟與預期結果後，Agent 的修改便有明確的安全邊界。</p>



<h2 class="wp-block-heading">建立最小可行的驗證閉環</h2>



<p class="wp-block-paragraph">可將 AI Agent 與 Playwright 的協作流程整理為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">需求或修改任務
→ Agent 修改系統
→ Playwright 執行 UI Smoke Test
→ 產出測試結果與 Evidence
→ 判斷失敗原因
→ 回饋 Agent 修正
→ 再次執行測試</code></pre>



<p class="wp-block-paragraph">落地時可依下列順序進行：</p>



<ul class="wp-block-list">
<li>Step 1：定義最重要的使用者流程</li>



<li>Step 2：建立一條最小 UI Smoke Test</li>



<li>Step 3：使用固定測試資料執行驗證</li>



<li>Step 4：保存錯誤訊息與 Evidence</li>



<li>Step 5：分類產品、測試、資料或環境問題</li>



<li>Step 6：將明確診斷結果回饋 Agent</li>



<li>Step 7：重新執行測試確認修正結果</li>
</ul>



<p class="wp-block-paragraph">測試腳本在這個流程中成為開發者、Agent 與團隊之間的共同語言：</p>



<ul class="wp-block-list">
<li>對開發者而言，測試腳本定義了變更後必須保留的行為。</li>



<li>對 Agent 而言，測試結果提供了明確且可核對的修正目標。</li>



<li>對團隊而言，測試 Evidence 提供了變更是否可接受的判斷依據。</li>
</ul>



<h2 class="wp-block-heading">從「生成程式碼」轉向「交付可驗證變更」</h2>



<p class="wp-block-paragraph">AI Agent 提高了程式碼產生與修改速度，但速度本身不等於交付能力。沒有可重複執行的驗證流程，修改越快，累積不確定性的速度也可能越快。</p>



<p class="wp-block-paragraph">UI 自動化測試的價值，不只是取代人工點擊，而是將主要使用者流程轉換為可版本控管、可重複執行、可產出證據的驗收機制。E2E Testing 用來確認跨層流程仍然成立；Smoke Test 則以最小成本保護系統的基本可用性。</p>



<p class="wp-block-paragraph">將 Playwright 納入 AI Agent 工作流程後，開發閉環便可從：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">Agent 修改程式碼 → Agent 回報已完成</p>
</blockquote>



<p class="wp-block-paragraph">轉變為：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers">Agent 修改程式碼
→ 執行可重複 UI 驗證
→ 依 Evidence 診斷與修正
→ 以測試結果確認完成</code></pre>



<pre class="wp-block-preformatted">真正值得建立的，不是一組零散的自動化腳本，而是一套「修改、驗證、診斷、修正、再驗證」的可持續工作方式。</pre>



<p class="wp-block-paragraph">後續可再從工具鏈與專案環境著手，將 Playwright CLI、Playwright Test、Agent Skill 與專案規範整合為可實際執行的驗證基礎。</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/ai-agent-ui-automation-validation-workflow/">AI Agent 協作開發中的 UI 自動化驗證流程</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://kenming.idv.tw/ai-agent-ui-automation-validation-workflow/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<media:content url="https://images.kenming.idv.tw/software/ui-automation-test/ai-agent-ui-automation-validation-workflow.webp" medium="image"></media:content>
	</item>
		<item>
		<title>ZenGTPX 發佈 &#8211; 讓天頂圍棋 Zen7 接入 KataGo 與 LizzieYzy Next</title>
		<link>https://kenming.idv.tw/zengtpx-release-zen7-katago-lizzieyzy-next/</link>
					<comments>https://kenming.idv.tw/zengtpx-release-zen7-katago-lizzieyzy-next/#respond</comments>
		
		<dc:creator><![CDATA[Wang Kenming]]></dc:creator>
		<pubDate>Mon, 13 Jul 2026 11:34:34 +0000</pubDate>
				<category><![CDATA[AI應用與開發]]></category>
		<category><![CDATA[應用軟體使用分享]]></category>
		<category><![CDATA[LizzieYzyNext]]></category>
		<category><![CDATA[ZenGTPX]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[KataGo]]></category>
		<category><![CDATA[圍棋AI]]></category>
		<guid isPermaLink="false">https://kenming.idv.tw/?p=23926</guid>

					<description><![CDATA[<p>如果想進行人機對奕，可以透過 LizzieYzy / LizzieYzy Next 、 KaTrain 等免費 [&#8230;]</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/zengtpx-release-zen7-katago-lizzieyzy-next/">ZenGTPX 發佈 &#8211; 讓天頂圍棋 Zen7 接入 KataGo 與 LizzieYzy Next</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">如果想進行人機對奕，可以透過 <a href="https://github.com/yzyray/lizzieyzy" data-type="link" data-id="https://github.com/yzyray/lizzieyzy" target="_blank" rel="noreferrer noopener">LizzieYzy</a> / <a href="https://github.com/wimi321/lizzieyzy-next" data-type="link" data-id="https://github.com/wimi321/lizzieyzy-next" target="_blank" rel="noreferrer noopener">LizzieYzy Next</a> 、 <a href="https://github.com/sanderland/katrain" target="_blank" rel="noreferrer noopener">KaTrain</a> 等免費對奕圍棋界面軟體，只要設置好 <a href="https://github.com/lightvector/katago" target="_blank" rel="noreferrer noopener">KataGo</a> AI 引擎設定，即可實現對局者與 AI 引擎的對局。</p>



<p class="wp-block-paragraph">但 KataGo 的棋力實在太強。我使用的是 <a href="https://katagotraining.org/networks/" data-type="link" data-id="https://katagotraining.org/networks/" target="_blank" rel="noreferrer noopener">28b 權重</a>模型，即使將對局條件限制為每手 1 秒、800 visits，仍大致具備職業強初段以上的水準。更重要的是，它的著手往往不容易理解，少了人類下棋時的思考脈絡與「人味」，實際與之對局時，往往只會帶來強烈的挫敗感。</p>



<p class="wp-block-paragraph">因此，我利用幾天的空餘時間，將多年前由日本開發的「天頂圍棋 Zen7」核心元件 <code>Zen.dll</code>，透過 C#/.NET 包裝成一個 GTP Wrapper，並將這個專案命名為 <strong><strong><a href="https://github.com/kenming/ZenGTPX" target="_blank" rel="noreferrer noopener">ZenGTPX</a></strong></strong>。</p>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6a7aabc7b7412&quot;}" data-wp-interactive="core/image" data-wp-key="6a7aabc7b7412" class="wp-block-image aligncenter size-large is-resized img-border wp-lightbox-container"><img decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://images.kenming.idv.tw/2026/zengtpx/zengtpx-game-screen.webp" alt="LizzieYzy Next KataGo 與 ZenGTPX 自動對局" style="width:620px"/><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p class="wp-block-paragraph">先簡單介紹下 ，Zen7（天頂圍棋 7）是由日本開發的商用圍棋軟體，其最高棋力可設定為 9 段，整體實力仍接近職業初段水準。相較於現今棋力極強的 KataGo，Zen7 的整體實力雖已不及新一代圍棋 AI，但 Zen7 的棋風較為穩重厚實，著手也更接近人類棋手的思考方式，因此特別適合業餘棋友用來進行人機對弈，並從中學習布局方向、厚薄判斷與基本棋理。</p>



<p class="wp-block-paragraph">我所開發的 ZenGTPX，主要就是可以讓 Zen7 能以 <a href="https://senseis.xmp.net/?GoTextProtocol" target="_blank" rel="noreferrer noopener">GTP（Go Text Protocol）</a>引擎的形式，被現代圍棋 GUI 載入使用。除了可實現 Zen7 與 KataGo 的自動對弈，也能設定於 LizzieYzy 與 LizzieYzy Next 中，作為人機對局或引擎對局使用的 AI 引擎。</p>



<p class="wp-block-paragraph">目前，ZenGTPX 已連同原始程式碼、可執行檔及相關組態設定檔，一併發布於 <a href="https://github.com/kenming/ZenGTPX" data-type="link" data-id="https://github.com/kenming/ZenGTPX" target="_blank" rel="noreferrer noopener">GitHub</a>。具體如何安裝與設置，可以參考：<a href="https://github.com/kenming/ZenGTPX/blob/main/README.md" target="_blank" data-type="link" data-id="https://github.com/kenming/ZenGTPX/blob/main/README.md" rel="noreferrer noopener">README.md</a>（我已盡量寫得相當詳細了）。</p>



<p class="wp-block-paragraph">需要注意的是，ZenGTPX 不包含 Zen7，也不包含 <code>Zen.dll</code>。使用者需要自行準備合法取得的 Zen7 內附的 <code>Zen.dll</code> 檔案，並複製放在 <code>ZenGTPX.exe</code> 同一個資料夾。</p>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6a7aabc7b7796&quot;}" data-wp-interactive="core/image" data-wp-key="6a7aabc7b7796" class="wp-block-image aligncenter size-large is-resized img-border wp-lightbox-container"><img decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://images.kenming.idv.tw/2026/zengtpx/zengtpx-folder-layout.webp" alt="ZenGTPX 設置資料夾" style="width:540px"/><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p class="wp-block-paragraph">目前 ZenGTPX 已實現的功能可以參考：<a href="https://github.com/kenming/ZenGTPX/blob/main/FEATURES.md" data-type="link" data-id="https://github.com/kenming/ZenGTPX/blob/main/FEATURES.md" target="_blank" rel="noreferrer noopener">FEATURES.md</a>，以下列出主要的功能供參考：</p>



<ul class="wp-block-list">
<li>以 Windows x86 self-contained executable 發行（不用再另行安裝 .NET SDK）。</li>
</ul>



<ul class="wp-block-list">
<li>支援在 LizzieYzy Next 中作為一般 GTP v2 Engine 使用。</li>



<li>透過 GTP analysis commands 顯示候選點與勝率。</li>



<li>支援人機對局（GenMove 與 Analysis 模式）。</li>



<li>支援 ZenGTPX 與其他 GTP Engine 自動對局。</li>



<li>支援透過 LizzieYzy Next 的 ReadBoard / Fox 同步機制進行網路（<a href="https://www.foxwq.com/" target="_blank" data-type="link" data-id="https://www.foxwq.com/" rel="noreferrer noopener">野狐圍棋</a>）同步對局。</li>



<li>支援&nbsp;<code>rank</code>、<code>fixed-time</code>&nbsp;與&nbsp;<code>advanced</code>&nbsp;棋力設定模式。</li>



<li>提供英文與繁體中文設定檔範本。</li>



<li>提供搜尋、policy、territory 與 final-score 檢查用的診斷 GTP commands。</li>



<li>提供 LizzieYzy Next 所需的相容命令，包含&nbsp;<code>kata-analyze</code>、<code>lz-analyze</code>、<code>kata-genmove_analyze</code>、<code>loadsgf</code>，以及部分 KataGo-style parameter/rules commands。</li>
</ul>



<h4 class="wp-block-heading">ZenGTPX 人機對局設置</h4>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6a7aabc7b7b17&quot;}" data-wp-interactive="core/image" data-wp-key="6a7aabc7b7b17" class="wp-block-image aligncenter size-large is-resized img-border wp-lightbox-container"><img decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://images.kenming.idv.tw/2026/zengtpx/lizzieyzy-next-human-vs-zengtpx.webp" alt="LizzieYzy Next 設置 ZenGTPX 人機對局" style="width:620px"/><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<h4 class="wp-block-heading">引擎對局設置（KataGo vs ZenGTPX）</h4>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6a7aabc7b7d0a&quot;}" data-wp-interactive="core/image" data-wp-key="6a7aabc7b7d0a" class="wp-block-image aligncenter size-large is-resized img-border wp-lightbox-container"><img decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://images.kenming.idv.tw/2026/zengtpx/lizzieyzy-next-engine-to-engine.webp" alt="LizzieYzy Next 設置 ZenGTPX 與 KataGo 引擎之間的對局" style="width:620px"/><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<h4 class="wp-block-heading">網路棋盤同步</h4>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6a7aabc7b7eeb&quot;}" data-wp-interactive="core/image" data-wp-key="6a7aabc7b7eeb" class="wp-block-image aligncenter size-large is-resized img-border wp-lightbox-container"><img decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://images.kenming.idv.tw/2026/zengtpx/lizzieyzy-next-sync-tool.webp" alt="LizzieYzy Next 設置 ZenGTPX 同步工具" style="width:560px"/><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6a7aabc7b807d&quot;}" data-wp-interactive="core/image" data-wp-key="6a7aabc7b807d" class="wp-block-image aligncenter size-large is-resized img-border wp-lightbox-container"><img decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://images.kenming.idv.tw/2026/zengtpx/lizzieyzy-next-zengtpx-sync-fox-play.webp" alt="LizzieYzy Next 設置 ZenGTPX 網路同步對局" style="width:620px"/><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p class="wp-block-paragraph">我另行寫了一個腳本在終端機模式下，讓 KataGo 與 Zen7 自動對局。我將 KataGo 固定設為每手 1 秒、800 visits，並只使用支援 CPU 的 OpenCL 引擎；Zen7 則設定為被讓 3 子，並分別使用固定時間模式（每手 30 秒）與固定棋力模式（9D）各下了幾局作為測試。</p>



<p class="wp-block-paragraph">結果，KataGo 仍能相當輕鬆地取勝。不過在多數對局中，Zen7 其實一度維持領先，甚至取得壓倒性的勝率優勢，最後往往是因為局部細算與攻殺能力明顯不足，才遭到逆轉落敗。</p>



<p class="wp-block-paragraph">這是否代表 Zen7 的棋力已顯得脆弱？倒也不能這麼說。它在 9D 設定下，仍具備業餘高段至接近職業初段的實力，一般業餘棋手想要擊敗它，依然相當困難；只是當它被拿來與現代 KataGo 比較時，兩者之間的差距便會被明顯放大。我也曾進行多盤網路同步對局測試，僅將 Zen7 設定為 6D、每手 12 秒，面對野狐 5D 的快棋對局時，仍能相當輕鬆地取勝。</p>



<p class="wp-block-paragraph">我開發 ZenGTPX 的主要用意，並不是要讓 Zen7 重新挑戰現代最強圍棋 AI，而是希望提供一個更適合人機對局的選項。Zen7 的棋風比較符合傳統人類思維，棋型也相對端正；雖然細算力不足，但這主要是相對於 KataGo 而言。</p>



<p class="wp-block-paragraph">對我來說，比較理想的使用方式是：先與 Zen7 對局，取得一盤比較接近人類實戰感的棋局；局後再用 KataGo 高權重分析引擎進行覆盤。這樣一來，雙方在關鍵處的勝率波動會更明顯，也更容易看出哪些著手真正造成局勢變化。對學習棋理、理解錯著，以及保留互有勝負的對局樂趣，應該會更有幫助。</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/zengtpx-release-zen7-katago-lizzieyzy-next/">ZenGTPX 發佈 &#8211; 讓天頂圍棋 Zen7 接入 KataGo 與 LizzieYzy Next</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://kenming.idv.tw/zengtpx-release-zen7-katago-lizzieyzy-next/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<media:content url="https://images.kenming.idv.tw/2026/zengtpx/zengtpx-game-screen.webp" medium="image"></media:content>
	</item>
		<item>
		<title>關於 LizzieYzy Next 的形勢判斷引擎設置</title>
		<link>https://kenming.idv.tw/lizzieyzy-next-territory-estimation-engine-setup/</link>
					<comments>https://kenming.idv.tw/lizzieyzy-next-territory-estimation-engine-setup/#respond</comments>
		
		<dc:creator><![CDATA[Wang Kenming]]></dc:creator>
		<pubDate>Mon, 15 Jun 2026 11:35:28 +0000</pubDate>
				<category><![CDATA[應用軟體使用分享]]></category>
		<category><![CDATA[生活點滴]]></category>
		<category><![CDATA[KataGo]]></category>
		<category><![CDATA[圍棋AI]]></category>
		<category><![CDATA[LizzieYzyNext]]></category>
		<guid isPermaLink="false">https://kenming.idv.tw/?p=23916</guid>

					<description><![CDATA[<p>在舊版 LizzieYzy 中，載入棋譜後即可透過「分析」選單執行「形勢判斷」（快捷鍵為 /）。只要事先完成形 [&#8230;]</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/lizzieyzy-next-territory-estimation-engine-setup/">關於 LizzieYzy Next 的形勢判斷引擎設置</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">在舊版 <a href="https://github.com/yzyray/lizzieyzy" data-type="link" data-id="https://github.com/yzyray/lizzieyzy" target="_blank" rel="noreferrer noopener">LizzieYzy</a> 中，載入棋譜後即可透過「分析」選單執行「形勢判斷」（快捷鍵為 <code>/</code>）。只要事先完成形勢判斷引擎的啟動命令設定，執行後就會開啟一個小窗格。點擊窗格中的【形勢判斷】按鈕後，棋盤上會顯示黑白雙方的地勢判斷結果，同時窗格也會列出黑方或白方目前大約領先多少目。</p>



<figure data-wp-context="{&quot;imageId&quot;:&quot;6a7aabc7bb195&quot;}" data-wp-interactive="core/image" data-wp-key="6a7aabc7bb195" class="wp-block-image aligncenter size-large is-resized img-border wp-lightbox-container"><img decoding="async" data-wp-class--hide="state.isContentHidden" data-wp-class--show="state.isContentVisible" data-wp-init="callbacks.setButtonStyles" data-wp-on--click="actions.showLightbox" data-wp-on--load="callbacks.setButtonStyles" data-wp-on--pointerdown="actions.preloadImage" data-wp-on--pointerenter="actions.preloadImageWithDelay" data-wp-on--pointerleave="actions.cancelPreload" data-wp-on-window--resize="callbacks.setButtonStyles" src="https://images.kenming.idv.tw/2026/go-lizzieyzy-next/lizzyzy-next-territory.webp" alt="LizzieYzy Next 形勢判斷設置" style="width:620px"/><button
			class="lightbox-trigger"
			type="button"
			aria-haspopup="dialog"
			data-wp-bind--aria-label="state.thisImage.triggerButtonAriaLabel"
			data-wp-init="callbacks.initTriggerButton"
			data-wp-on--click="actions.showLightbox"
			data-wp-style--right="state.thisImage.buttonRight"
			data-wp-style--top="state.thisImage.buttonTop"
		>
			<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
				<path fill="#fff" d="M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z" />
			</svg>
		</button></figure>



<p class="wp-block-paragraph">同樣在 LizzieYzy Next 也有支持該功能。不過需了解，形勢判斷引擎並不需要是主分析引擎本身，而是另外啟動一個用於盤面歸屬、領地估算與粗略點目的輔助引擎的設置。它可以使用 KataGo，也可以使用 ZenGTP。由於這個功能的設置方式與一般 KataGo 分析引擎不完全相同，因此實際設置時需要注意的幾個重點。</p>



<p class="wp-block-paragraph">第一次尚未設置形勢判斷命令時，所出現的窗格就會讓使用者填入加載的指令。它支持使用另外一個引擎 Zen7 執行形勢判斷，但需要擁有 Zen7 的可執行 DLL（Zen.dll），以及可以執行 ZenGTP 運行的指令（好像是舊版 LizzieYzy 專案內有？我也忘了！）。</p>



<p class="wp-block-paragraph">另外就是透過 Katago 引擎執行加載命令，但建議使用權重低些，例如 20B 版本，並且不要設置分析秒數、計算量等參數，盡量讓其系統資源耗用較低，能快速執行並顯示形勢判斷結果即可，並不需要過度精確要求。</p>



<p class="wp-block-paragraph">我個人是仍然沿用同一個 KataGo 分析引擎（b28c512nbt），但需要把原來的 config 設定檔複製一份，並更名為如：gtp_estimate_b28.cfg，然後最主要需調整以下參數（完整參數內容可以參考我的 <a href="https://gist.github.com/kenming/8a473b2c35b9fca4bd7e7ad35fe0312d" target="_blank" data-type="link" data-id="https://gist.github.com/kenming/8a473b2c35b9fca4bd7e7ad35fe0312d" rel="noreferrer noopener">KataGo Gist 範本</a>）：</p>


<pre class="language-text no-line-numbers"><code class="language-text no-line-numbers"># ---------------------------------------------------------------------------
# 一、日誌設定
# 形勢判斷會頻繁呼叫，不建議開啟完整 GTP 與搜尋日誌。
# ---------------------------------------------------------------------------
logAllGTPCommunication = false
logSearchInfo = false
logSearchInfoForChosenMove = false
logToStderr = false
# ---------------------------------------------------------------------------
# 二、分析輸出設定
# 形勢判斷主要使用 kata-raw-nn 0，不需要長 PV 或額外探索噪聲。
# ---------------------------------------------------------------------------
analysisPVLen = 8
reportAnalysisWinratesAs = SIDETOMOVE
analysisWideRootNoise = 0.0
analysisIgnorePreRootHistory = true
# ---------------------------------------------------------------------------
# 三、規則與貼目設定
# 以韓國規則、黑貼 6.5 目為基準。
# 注意：LizzieYzy Next 形勢判斷流程可能會送出
# kata-set-rules chinese 或 kata-set-rules japanese 覆蓋 rules。
# ---------------------------------------------------------------------------
rules = korean
komi = 6.5
# 若只分析固定貼目的棋譜，才考慮啟用。
# 一般不建議，避免與 SGF / GUI 的貼目設定衝突。
# ignoreGTPAndForceKomi = 6.5
# ---------------------------------------------------------------------------
# 四、投降設定
# 形勢判斷引擎不需要投降，但相關欄位仍建議保留，避免啟動缺 key。
# ---------------------------------------------------------------------------
allowResignation = false
resignThreshold = -0.90
resignConsecTurns = 3
# ---------------------------------------------------------------------------
# 五、搜尋與思考設定
# 形勢判斷不需要高強度搜尋，避免搶主分析引擎資源。
# ---------------------------------------------------------------------------
numSearchThreads = 2
ponderingEnabled = false
# 形勢判斷不建議固定搜尋限制。
# maxVisits = 500
# maxPlayouts = 500
# maxTime = 10.0</code></pre>



<p class="wp-block-paragraph">然後加載命令行與啟動 KataGo 引擎命令是一樣的，只是 config 檔改為上述已修改的配置檔。例如填入以下：</p>


<pre class="language-powershell no-line-numbers"><code class="language-powershell no-line-numbers">H:\Game\Go\GoAI\Katago\engines\v1.16.5-cuda12.8-trt10.9\katago.exe gtp -model H:\Game\Go\GoAI\Katago\models\kata1-zhizi-b28c512nbt-muonfd2.bin.gz -config H:\Game\Go\GoAI\Katago\configs\gtp_estimate_b28.cfg</code></pre>



<p class="wp-block-paragraph">LizzieYzy Next 的形勢判斷引擎，主要用途是快速提供盤面局勢的約略判斷，而不是取代 KataGo 主分析引擎的精確計算。它比較接近野狐圍棋對弈時可以點選的「局勢判斷」功能：可以快速看出黑白雙方大致的地盤分布、盤面歸屬與領先方向，但不應把它視為嚴格點目或最終勝負判定。</p>



<p class="wp-block-paragraph">因此，形勢判斷引擎的設置重點不是追求長時間搜尋或高 visits，而是讓它能穩定、快速地回傳盤面估算結果。真正需要深入檢討一手棋的得失、勝率變化、目差變化與後續變化圖，仍應回到 KataGo 主分析引擎來判斷。</p>



<p class="wp-block-paragraph">簡單來說：形勢判斷適合用來快速掌握盤勢輪廓；精確復盤與關鍵手分析，仍應以主分析引擎為準。</p>
<p>〈<a rel="nofollow" href="https://kenming.idv.tw/lizzieyzy-next-territory-estimation-engine-setup/">關於 LizzieYzy Next 的形勢判斷引擎設置</a>〉這篇文章最早發佈於《<a rel="nofollow" href="https://kenming.idv.tw">Kenmingの鮮思維</a>》。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://kenming.idv.tw/lizzieyzy-next-territory-estimation-engine-setup/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<media:content url="https://images.kenming.idv.tw/2026/go-lizzieyzy-next/lizzyzy-next-territory.webp" medium="image"></media:content>
	</item>
	</channel>
</rss>
