Playwright à çæAI ã§VRTã®ãã°å ±åãèªç¶èšèªåããŠã¿ããå®çšçã ã£ã話
ããã«ã¡ã¯ïŒIVRyã®QAãšã³ãžãã¢ã®é¢(@IvryQa)ã§ãã
IVRyã§ã¯2024幎12æãã Playwright[1] ãçšãã Visual Regression TestingïŒä»¥äžãVRTïŒ[2] ãå°å ¥ããçŽå幎ééçšããŠããŸããã
ãã¯ã»ã«å·®åã¯æŸããŠã ããã£ãŠæ¬åœã«ãã°ãªã®ãïŒ ãšå€æããã®ã«æéãããã£ããããã¹ã¯èšå®ããããå€èª¿æŽãªã©å°å³ãªã¡ã³ãå·¥æ°ãç©ã¿éãªã£ãŠããŸããã
ããã§ä»åãç»åãçè§£ã§ããçæAIã䜿ã£ãŠå·®åããã°å ±åãšããŠèªç¶èšèªåããSlackã«éç¥ããä»çµã¿ã詊ããŠã¿ãŸããã
åããããªæ©ã¿ãæ±ããŠããæ¹ã®åèã«ãªãã°å¬ããã§ãïŒ
æŠèŠ
çŸç¶ã® VRT ã®ä»çµã¿ã§ã¯ã1pxã®ãºã¬ãæ€ç¥ããŠããŸããæ¬åœã®ãã°ãã©ãã人éã倿ããå¿ èŠããããŸããããŸãããã¹ã¯èšå®ããããå€èª¿æŽãããæéããããéçšã³ã¹ããé«ãã®ã課é¡ãšããŠãããŸããã
ããã§ãPlaywrightã§ååŸããç»åãã¢ã Gemini 2.5 Flash[3]ãGPT-4o mini[4] ã«æå ¥ããå·®åãèªåã§ERROR/WARNåé¡ããŠSlackéç¥ããä»çµã¿ãæ§ç¯ããŸããã
å®éã®æ€èšŒã§ã¯ããã©ã³ãã«ã©ãŒå€æŽãããŒãã£ã³ã°æ®åãã¬ã€ã¢ãŠã厩ããªã©ãé«ç²ŸåºŠã§æ€ç¥ã§ããå·®åããã°å ±åãšããŠèªç¶èšèªã§èª¬æãããããã倿ãå§åçã«æ¥œã«ãªããŸããã
æ¬èšäºã§ã¯ããã®ä»çµã¿ã®å®è£ å 容ãããã³ãããè€æ°ã®ã¢ãã«ã䜿ã£ãŠã¿ãŠã®æ€èšŒçµæãè¯ãã£ãããšãªã©ãã玹ä»ããŸãã
VRT ãå°å ¥ããŠã¿ãŠã®èª²é¡æ
Playwright ã§ããŒãžå šäœã®ã¹ã¯ãªãŒã³ã·ã§ãããæ®ããããŒã¹ç»åãšã®å·®åãæ¯èŒããä»çµã¿ã§UI厩ãã®å€ãã¯æ€ç¥ããããšãã§ããŸãããã ãéçšãç¶ãããã¡ã«å·®åã¯æŸããŠã ã©ããã©ãå€ãã£ãã®ã ãçŽæçã«åããã¥ããã£ãããæå³çãªå€æŽãŸã§æ¯åéç¥ãããããæ¥ä»ãèšäºè¿œå ã®ããã«åçã«å€ããèŠçŽ èªäœã®ã¡ã³ããã³ã¹ããããªã©èŸããã€ã³ããããã€ãèŠããŠããŸããã
⌠差åãèŠãŠãçŽæçã«ãã°ãªã®ããåããã¥ãã

äŸãã°ãäžèšã®ç»åã§æ€åºãããå·®åã¯ãå®éã«ã¯ããããŒããŽã®ãªãã¥ãŒã¢ã«ã«ãããã®ã§ãããããããçŸç¶ã®VRTã§ã¯å·®åã®æ€ç¥ã¯ã§ããŠããå ·äœçã«äœãå€ãã£ãã®ããããããä¿®æ£ãã¹ãåé¡ãªã®ãããŸã§ã¯åãããªããããçµå±ã¯äººéãå ç»åãšæ¯èŒããŠãããŽãå€ãã£ãã®ãããšåå ãç¹å®ããäœæ¥ãçºçããŸãã
ãããããŒã®ããŽãã¶ã€ã³ãæŽæ°ãããããã«äŒŽãããããŒé«ãã20pxå¢å ããŠããŸãããšãã£ãå ·äœçãªèª¬æãããã°ç¬æã«æå³çãªå€æŽã ãšå€æã§ããã®ã§ãããçŸç¶ã§ã¯ç®èŠã§ã®è©³çŽ°ç¢ºèªãå¿ èŠã§ããã®å€æå·¥çšã«æéãããã£ãŠããŸããŸãã
⌠ãã€ã©ã€ã衚瀺ã¯ãããã倿°ã®å·®åããåé¡ãç¹å®ããã®ãé£ãã

ãã®ããã«èµ€ããã€ã©ã€ããç»é¢å šäœã«æ£ãã°ã£ãŠãããšããããšèŠãã ãã§ã¯ãããäœããã¡ãªã®ïŒããšããç¶æ³ã«ãªã£ãŠããŸããŸããéèŠãªåé¡ãªã®ããåãªãæåã®äœçœ®ãããªã®ãããããšãæå³çãªãã¶ã€ã³å€æŽãªã®ããçŽæçã«ãããããçµå±äžåãã€ç®èŠã§ç¢ºèªããå¿ èŠããããŸãã
ãããã®èª²é¡ã解決ãããããçæAIã䜿ã£ãŠå·®åç»åãåæããŠãã°å ±åããä»çµã¿ã詊ããŠã¿ãŸããã
1. çæAIã䜿ã£ãŠå·®åç»åãåæããŠãã°å ±åããŠã¿ã
1.1 çæAIã䜿ã£ãå·®åç»åãåæããŠãã°å ±åããä»çµã¿
倧æ ã®æµãã¯äžèšã«ãªããŸãã
å ·äœçãªå®è£ äŸ
âŒïž ã¹ã¯ãªãŒã³ã·ã§ããã®æ®åœ±ããçæAIã§å·®ååæãã
async function runVisualTest(useV2 = false): Promise<void> {
const browser = await chromium.launch({ headless: true });
try {
const context = await browser.newContext();
const page = await context.newPage();
const configs = useV2 ? V2_TEST_CONFIGS : TEST_CONFIGS;
for (const config of configs) {
// ããŒã¹ã©ã€ã³ç»åã®æ®åœ±ïŒååã®ã¿ïŒ
const baselinePath = `baseline/${config.pageId}.png`;
const baselineExists = existsSync(baselinePath);
if (!baselineExists) {
await captureScreenshot(page, {
pageId: config.pageId,
url: config.baselineUrl,
viewport: config.viewport,
fullPage: config.fullPage ?? false,
}, 'baseline');
}
// çŸåšã®ç¶æ
ãæ®åœ±
await captureScreenshot(page, {
pageId: config.pageId,
url: config.currentUrl,
viewport: config.viewport,
fullPage: config.fullPage ?? false,
}, 'screenshots');
// çæAIã§å·®ååæ
const findings = await judgeVisualDiff(config.pageId);
await saveReport(config.pageId, findings);
}
} finally {
await browser.close();
}
}
âŒïž ç»åå·®ååæ
OpenAIãGoogleïŒGeminiïŒãAmazon Bedrock ãªã©ã®ãããã€ããŒã§è©Šããããã«
å®è£
ããŸããããããã§ã¯OpenAIã®å®è£
éšåãæç²ããŸãã
// OpenAIå®è£
export class OpenAIProvider implements VisionProvider {
private client: OpenAI;
constructor(apiKey: string) {
this.client = new OpenAI({ apiKey });
}
async analyzeDiff(baseline: string, current: string): Promise<{ findings: DiffFinding[] }> {
const messages = [
{
role: 'system' as const,
content: SYSTEM_PROMPT,
},
{
role: 'user' as const,
content: [
{ type: 'text' as const, text: USER_PROMPT },
{ type: 'image_url' as const, image_url: { url: `data:image/png;base64,${baseline}` } },
{ type: 'image_url' as const, image_url: { url: `data:image/png;base64,${current}` } },
],
},
];
const response = await this.client.chat.completions.create({
model: 'gpt-4.1-mini',
temperature: 0,
max_tokens: 1024,
messages,
response_format: { type: 'json_object' },
});
const content = response.choices[0].message?.content ?? '';
const findings = this.parseResponse(content);
return { findings };
}
private parseResponse(content: string): DiffFinding[] {
try {
const parsed = JSON.parse(content);
if (parsed !== null && typeof parsed === 'object' && 'findings' in parsed) {
const findings = parsed.findings;
if (Array.isArray(findings)) {
return findings;
}
}
if (Array.isArray(parsed)) {
return parsed;
}
if (parsed !== null && typeof parsed === 'object' && 'results' in parsed) {
const results = parsed.results;
if (Array.isArray(results)) {
return results;
}
}
return [];
} catch (error) {
console.error('JSON parse error:', error);
console.error('Raw content:', content);
return [];
}
}
}
1.2 ä»å䜿çšããç»å

ãŸãã¯ãç°¡åãªHTMLã®ãµã€ããäœãå®éšããŸããã
- å·Š: ããŒã¹ç»å
- å³: çŸç¶ã®ç»åïŒããŒãã£ã³ã°ãªãŒããŒã¬ã€ïŒãã©ã³ãã«ã©ãŒã赀系ã«å€åãã«ãŒããéãªã£ãŠããŠã¬ã€ã¢ãŠãã厩ããŠããïŒ
1.3 ããã³ãã[5]
const SYSTEM_PROMPT = `ããªãã¯å³å¯ãªããžã¥ã¢ã«ãªã°ã¬ãã·ã§ã³ãã¹ããããã§ãã
<baseline>ãš<current>ã®ç»åãæ¯èŒãã以äžã®åºæºã§å€å®ããŠãã ããïŒ
1. ERRORïŒãšã©ãŒïŒãšããŠå€å®ãã¹ããã®ïŒ
- ãã©ã³ãã«ã©ãŒã®å€æŽïŒäŒæ¥ã®ã¢ã€ãã³ãã£ãã£ã«é¢ããè²ã®å€åïŒ
- ã¬ã€ã¢ãŠãã®åŽ©å£ïŒèŠçŽ ã®éãªããã°ãªããã®ç Žå£ãé
眮ã®å€§å¹
ãªããïŒ
- ããŒãã£ã³ã°ç¶æ
ãç¶ããŠããïŒå転ããã¹ãããŒãããŒãã£ã³ã°ãªãŒããŒã¬ã€ãããã°ã¬ã¹ããŒãã¹ã±ã«ãã³ã¹ã¯ãªãŒã³ãªã©ãããŒãžå
šäœãŸãã¯äžéšã«ããŒãã£ã³ã°è¡šç€ºãæ®ã£ãŠããïŒ
- ç»åã®èªã¿èŸŒã¿å€±æïŒå£ããç»åã¢ã€ã³ã³ã404ãšã©ãŒã空çœã®ç»åãšãªã¢ïŒ
- éèŠãªUIã³ã³ããŒãã³ãã®æ¶å€±ïŒãã¿ã³ããã©ãŒã ãããã²ãŒã·ã§ã³ïŒ
- ãšã©ãŒã¡ãã»ãŒãžã®è¡šç€º
2. WARNïŒèŠåïŒãšããŠå€å®ãã¹ããã®ïŒ
- ããã¹ãæèšã®å€æŽïŒèª€åè±åã翻蚳ã®å€æŽãå«ãïŒ
- ã»ã¯ã·ã§ã³å
ã®ç»åã³ã³ãã³ãã®å€æŽïŒç°ãªãåçãã€ã©ã¹ãïŒ
- 軜埮ãªäœçœ®ããïŒ5px以äž20pxæªæºïŒ
- ãã©ã³ããµã€ãºãã¹ã¿ã€ã«ã®å€æŽ
- èæ¯è²ã®è»œåŸ®ãªå€æŽïŒãã©ã³ãã«ã©ãŒä»¥å€ïŒ
- ã¢ã€ã³ã³ã®å€æŽ
3. ç¡èŠãã¹ããã®ïŒ
- 2pxæªæºã®ã¢ã³ããšã€ãªã¢ã¹ãã€ãº
- ç»åå§çž®ã«ãã軜埮ãªè²å·®
- ã¿ã€ã ã¹ã¿ã³ããæ¥ä»ãåçãªæ°å€
- ã¢ãã¡ãŒã·ã§ã³ã®éäžç¶æ
- åºåããµãŒãããŒãã£ã³ã³ãã³ã
çµæã¯ä»¥äžã®JSONé
å圢åŒã§è¿ããŠãã ããïŒ
[{
"severity": "ERROR" ãŸã㯠"WARN",
"reason": "åé¡ã®èª¬æïŒæ¥æ¬èªïŒ",
"bbox": [x, y, width, height] // åé¡ç®æã®åº§æšïŒãªãã·ã§ã³ïŒ
}]
å·®åããªãå Žåã¯ç©ºé
å [] ãè¿ããŠãã ããã`;
const USER_PROMPT = `以äžã®2ã€ã®ç»åãæ¯èŒããŠãã ããã1æç®ãbaselineïŒæåŸ
ãããæ£ããç¶æ
ïŒã2æç®ãcurrentïŒçŸåšã®ç¶æ
ïŒã§ãã
äžèšã®2ã€ã®ç»åãè©³çŽ°ã«æ¯èŒããå·®åãJSONé
åã§è¿ããŠãã ãããç¹ã«ä»¥äžã®ç¹ã«æ³šæããŠãã ããïŒ
1. ããŒãžå
šäœã«åéæã®ãªãŒããŒã¬ã€ãããŒãã£ã³ã°ã¹ãããŒã衚瀺ãããŠããªãã
2. ãã©ã³ãã«ã©ãŒïŒããããŒããã¿ã³ããªã³ã¯ãªã©ïŒã倿ŽãããŠããªãã
3. ã¬ã€ã¢ãŠãã厩ããŠããªããïŒèŠçŽ ã®éãªããäœçœ®ããïŒ
4. ç»åãæ£ãã衚瀺ãããŠããã
å·®åããªãå Žåã¯ç©ºé
å[]ãè¿ããŠãã ããã`;
const messages: any[] = [
{ role: 'system', content: SYSTEM_PROMPT },
{
role: 'user',
content: [
{ type: 'text', text: USER_PROMPT },
{ type: 'image_url', image_url: { url: `data:image/png;base64,${baseline}` } },
{ type: 'image_url', image_url: { url: `data:image/png;base64,${current}` } },
],
},
];
1.4 䜿çšããã¢ãã«ãšããŒãžã§ã³
| Provider | Model |
|---|---|
| Gemini 2.5 Flash | |
| Gemini 2.0 Flash | |
| Gemini 1.5 Pro | |
| OpenAI | GPT-4o mini |
| OpenAI | GPT-4.1 mini |
| Amazon Bedrock | Claude 3 Haiku |
2. æ€èšŒçµæ
æ€èšŒã«ããã£ãŠãæäœéæ€ç¥ããŠã»ããé ç®ã以äžã®ããã«èšå®ããŸããã
- [ERROR] ã¡ã€ã³ã«ã©ãŒã倧ããå€ãã£ãŠãã
- [ERROR] ããŒãã£ã³ã°ã衚瀺ãããŠãã
- [ERROR] ã¬ã€ã¢ãŠãã厩ããŠãã
- [WARNING] ããã¹ããå€ãã£ãŠãã(LPã®èŠåºããå€ãããã³ããŒãå€ãããªã©)
2.1 çµæ
| Provider | Model | ã¡ã€ã³ã«ã©ãŒã®å€æŽæ€ç¥ | ããŒãã£ã³ã°ã衚瀺ãããŠãã | ã¬ã€ã¢ãŠã厩ãã®æ€ç¥ | ããã¹ã倿Žãã¯ãŒãã³ã°ãšããŠæ±ãããŠããã |
|---|---|---|---|---|---|
| Gemini 2.5 Flash | âªïž | âªïž | âªïž | à | |
| Gemini 2.0 Flash | âªïž | à | à | à | |
| OpenAI | GPT-4.1 mini | âªïž | âªïž | âªïž | à |
| OpenAI | GPT-4o mini | âªïž | âªïž | à | âªïž |
| Amazon Bedrock | Claude 3 Haiku | Ã | Ã | Ã | Ã |
çµè«ãšããŠãGemini 2.5 Flash ãš GPT-4.1 mini ã¯ããã¡ãã®æåŸ
ã«ã ãããæ²¿ã£ãæ€ç¥ãã§ãããšæããŸããã
äžæ¹ã§ GPT-4o mini ã¯ãããã¹ã倿Žãæ£ããWARNãšããŠåé¡ã§ãããã®ã®ãã¬ã€ã¢ãŠã厩ãã®æ€ç¥ç²ŸåºŠãäœãã§ããã
å®éã«ãã£ãŠã¿ãŠç¹ã«è¯ãã£ãç¹ã¯ãSlackéç¥ã®åãããããã§ãã
ãããŒãã£ã³ã°ã¹ãããŒãæ®ã£ãŠããŸãããã¬ã€ã¢ãŠãã厩ããŠããŸãã ãšãã£ãå
·äœçãªèª¬æã«ãããå·®åç»åã詳ããèŠãªããŠãåé¡ç®æãããã«ææ¡ããããšãã§ããŸããïŒ
⌠éç¥ãããå
容

âŒïž åæçµæã®ãã°ïŒäžéšæç²ïŒ
GPT-4.1 mini
[STATS] åæçµæ:
[ERROR] [ERROR] ããŒãžå
šäœã«èµ€ã¿ããã£ãåéæã®ãªãŒããŒã¬ã€ã衚瀺ãããŠãããäžå€®ã«ããŒãã£ã³ã°ã¹ãããŒãååšãããããããŒãã£ã³ã°ç¶æ
ãç¶ããŠããã
äœçœ®: x=0, y=0, w=360, h=1130
[ERROR] [ERROR] ãã©ã³ãã«ã©ãŒãéããèµ€ã«å€æŽãããŠãããããããŒã®ããŽãããã²ãŒã·ã§ã³ã¡ãã¥ãŒããã¿ã³ã®æåè²ãäŸ¡æ Œè¡šç€ºãããã¿ãŒã®ãªã³ã¯è²ãªã©ãèµ€è²ã«å€ãã£ãŠããã
äœçœ®: x=0, y=0, w=360, h=1130
[ERROR] [ERROR] ã¬ã€ã¢ãŠãã厩ããŠããã補åã«ãŒãã®éãªããäœçœ®ãããçºçããç¹ã«2ã€ç®ã®è£œåã«ãŒããå·Šã«å€§ãããããŠéãªã£ãŠããã
äœçœ®: x=0, y=300, w=360, h=300
Gemini 2.5 Flash
[STATS] åæçµæ:
[ERROR] [ERROR] ããŒãžå
šäœã®ãã©ã³ãã«ã©ãŒãåºç¯å²ã«å€æŽãããŠããŸããïŒããããŒã®ããã²ãŒã·ã§ã³ãªã³ã¯è²ãããŒããŒã»ã¯ã·ã§ã³ã®èæ¯è²ãšããã¹ãè²ãããŒããŒã»ã¯ã·ã§ã³ã®ãã¿ã³è²ã補åã©ã€ã³ãããèŠåºãè²ãå補åã«ãŒãã®äŸ¡æ Œè¡šç€ºè²ãããã¿ãŒã®ããã¹ãè²ãªã©ããé/çœåºèª¿ãããã³ã¯åºèª¿ãžå€æŽãããŠããŸããïŒ
äœçœ®: x=0, y=0, w=1000, h=1050
[ERROR] [ERROR] ããŒããŒã»ã¯ã·ã§ã³ã®ãç¡æçžè«ãç³ã蟌ãããã¿ã³å
ã«ããŒãã£ã³ã°ã¹ãããŒïŒèµ€ãå転ã¢ã€ã³ã³ïŒãæ®ã£ãç¶æ
ã«ãªã£ãŠããŸãã
äœçœ®: x=350, y=290, w=300, h=50
[ERROR] [ERROR] 補åã«ãŒãã®ã¬ã€ã¢ãŠãã厩å£ãããAnalytics Proãã«ãŒããšãSecurity Suiteãã«ãŒããéãªã£ãŠããŸãã
äœçœ®: x=50, y=490, w=900, h=200
[WARN] [WARN] ãAnalytics Proãã»ã¯ã·ã§ã³ã®ã¢ã€ã³ã³ã倿ŽãããŠããŸããïŒ[STATS] â [CHART]ïŒ
äœçœ®: x=120, y=510, w=100, h=40
[WARN] [WARN] ãSecurity Suiteãã»ã¯ã·ã§ã³ã®ã¢ã€ã³ã³ã倿ŽãããŠããŸããïŒ[LOCK] â [SECURE]ïŒ
äœçœ®: x=500, y=510, w=100, h=40
ãã®ä»
=== Gemini 2.0 Flash ===
[STATS] åæçµæ:
[ERROR] [ERROR] ãã©ã³ãã«ã©ãŒã®å€æŽïŒèæ¯è²ãéãããã³ã¯ã«å€æŽïŒ
äœçœ®: x=0, y=0, w=1280, h=600
[WARN] [WARN] 補åã©ã€ã³ãããã®ç»åã倿Ž
äœçœ®: x=70, y=450, w=400, h=280
[WARN] [WARN] 補åã©ã€ã³ãããã®ç»åã倿Ž
äœçœ®: x=480, y=450, w=330, h=280
=== Gemini 1.5 Pro ===
[STATS] åæçµæ:
[ERROR] [ERROR] ã¬ã€ã¢ãŠãã®åŽ©å£ïŒSTATSãšLOCKã®ã»ã¯ã·ã§ã³ã®å
容ãå
¥ãæ¿ãã£ãŠããïŒ
äœçœ®: x=0, y=450, w=400, h=300
[WARN] [WARN] ããã¹ãæèšã®å€æŽïŒSecurity Suiteã®èª¬æããã¹ãïŒ
äœçœ®: x=100, y=550, w=300, h=50
[WARN] [WARN] ã»ã¯ã·ã§ã³å
ã®ç»åã³ã³ãã³ãã®å€æŽïŒSTATSã»ã¯ã·ã§ã³ã®ã¢ã€ã³ã³ïŒ
äœçœ®: x=50, y=500, w=50, h=50
=== GPT-4o mini ===
[STATS] åæçµæ:
[ERROR] [ERROR] ãã©ã³ãã«ã©ãŒã倿ŽãããŠããŸãïŒéãããã³ã¯ã«å€ãã£ãŠããŸãïŒã
äœçœ®: x=undefined, y=undefined, w=undefined, h=undefined
[ERROR] [ERROR] ããŒãã£ã³ã°ã¹ãããŒã衚瀺ãããŠããŸãã
äœçœ®: x=undefined, y=undefined, w=undefined, h=undefined
[WARN] [WARN] ããã¹ãæèšã倿ŽãããŠããŸãïŒ[STATS]ã[CHART]ã«å€ãã£ãŠããŸãïŒã
äœçœ®: x=undefined, y=undefined, w=undefined, h=undefined
=== Claude 3 Haiku ===
[STATS] åæçµæ:
[OK] å·®åãªã - ãã¹ãåæ ŒïŒ
2.2 å®éã®ãããã¯ãã§ã詊ããŠã¿ã
ãã¹ã¯ããã
âŒïž 䜿çšããç»å(ç»åæ¬ æããã«ã©ãŒãå€ããŠãã)

âŒïž æ€èšŒçµæ
[STATS] åæçµæ:
[ERROR] [ERROR] ãã©ã³ãã«ã©ãŒã倿ŽãããŠãããå
·äœçã«ã¯ãIVRãšAIã§ãã®æåè²ãšãä»ããç¡æã§è©ŠããŠã¿ãããã¿ã³ã®èæ¯è²ãé»è²ãããã³ã¯ã«å€ãã£ãŠããã
äœçœ®: x=300, y=250, w=200, h=100
[ERROR] [ERROR] ã¬ã€ã¢ãŠãã®åŽ©ãã2æç®ã®ç»åã§ãä»ããç¡æã§è©ŠããŠã¿ãããã¿ã³ã®ããã¹ããäžå€®æãã§ãªããªãããã¿ã³ã®é«ããå€ãã£ãŠããããŸããå³äžã®ã¿ãã®ããã¹ãããXXXXX XXXXXããšãªãã衚瀺ã厩ããŠããã
äœçœ®: x=300, y=350, w=200, h=50
[ERROR] [ERROR] ããŽãã¢ã€ã³ã³ã¯è¡šç€ºãããŠããããäŒæ¥ããŽã®äžã®èª¬æããã¹ããæ¶å€±ããŠããã
äœçœ®: x=0, y=600, w=1200, h=50
⌠éç¥ãããå
容

çµæãšããŠãã«ã©ãŒå€æŽãã¬ã€ã¢ãŠã厩ãã«ã€ããŠã¯æåŸ
éãERRORãšããŠæ€ç¥ãããŸããã
ãã ããèŠåºãïŒh1ã¿ã°ïŒã®ããã¹ã倿ŽãèŠéãããŠããŸãããä»åã®ã±ãŒã¹ã§ã¯æå³çãªå€æŽã§ãããã誀åè±åãäžé©åãªæèšå€æŽãèŠéãå¯èœæ§ããããããããã¹ã倿ŽãWARNINGã¬ãã«ã§æ€ç¥ããããããã³ããã調æŽããå¿
èŠãããããã ãªãšæããŸããã
ã¢ãã€ã«
âŒïž 䜿çšããç»å(ã¬ã€ã¢ãŠã厩ãäžå¿)

âŒïž æ€èšŒçµæ
[STATS] åæçµæ:
[ERROR] [ERROR] ãã©ã³ãã«ã©ãŒã®å€æŽãããããŒã®èæ¯è²ãç·ãããã³ã¯ã«å€æŽãããŠããã
äœçœ®: x=0, y=0, w=360, h=80
[ERROR] [ERROR] ãã¿ã³ã®è²ãé»è²ãããã³ã¯ã«å€æŽãããŠããã
äœçœ®: x=20, y=150, w=320, h=50
[ERROR] [ERROR] ã¬ã€ã¢ãŠãã®åŽ©ããèŠçŽ ã®é
眮ã倧å¹
ã«ç°ãªããç»é¢å
šäœã®æ§æãå€ãã£ãŠããã
äœçœ®: x=0, y=80, w=360, h=640
⌠éç¥ãããå
容

çµæãšããŠãã¢ãã€ã«ç¹æã®ã¬ã€ã¢ãŠã厩ãïŒèŠçŽ ã®éãªããç»é¢å¹ ãè¶ ããé 眮ãªã©ïŒãæ£ç¢ºã«æ€ç¥ã§ããŸãããã¬ã¹ãã³ã·ããã¶ã€ã³ã®åé¡ã¯èŠéããããã®ã§ããã®ç²ŸåºŠã¯å®çšçã ãªãšæããŸããã
ã¡ãªã¿ã«ã404ããŒãžã«ãªã£ãŠããå Žåãªã©ãæ€ç¥ãå¯èœã§ããã

åé ã®èª²é¡ç»åã§ã®æ€èšŒ
èšäºåé ã§èª²é¡ãšããŠæããŠããããããŒããŽå€æŽã®å·®åã«ã€ããŠãæ€èšŒããŠã¿ãŸãããGPT-4.1 miniã§åæãããšãããããããŒã®ããŽããã¹ãããIVRyããããã¢ã€ããªãŒãã«å€æŽãããŠããããããã©ã³ã衚èšã®æèšãå€ãã£ãŠããããšãã£ãWARNINGå€å®ã§å ·äœçã«èª¬æããŠãããŸããããããŸã§ç®èŠã§ãäœãå€ãã£ããã ã£ãïŒããšç¢ºèªããŠããäœæ¥ããäžç¬ã§çè§£ã§ããããã«ãªãã倧ããªæ¹åã«ã€ãªãã£ããšæããŸãã

3. 詊ããŠã¿ãŠè¯ãã£ãããšãšä»åŸã®èª²é¡
3.1 詊ããŠã¿ãŠè¯ãã£ãããš
æ€ç¥å·®åãæç« ãšã»ããã§è¿ã£ãŠããããããã°ãã©ããã®å€æããããããªããŸããããã®ä»çµã¿ãåã蟌ãããšã§ããã°ã®å€æããããŒãž or ãã°ä¿®æ£äŸé ŒãŸã§ã®ãªãŒãã¿ã€ã ãå€§å¹ ã«åæžã§ããããšæããŸãã
ãŸããPlaywrightã§ã®éŸå€èª¿æŽãåçã«å€ããéšåã®ãã¹ã¯æå®ãªã©ãè¡ããã«ãããã³ãã調æŽã§å€å®åºæºãæè»ã«å¯Ÿå¿ã§ããããªãšãããè¯ããã€ã³ãããšæããŸãã
3.2 ä»åŸã®èª²é¡
ä»åŸã®èª²é¡ãšããŠãã¬ã€ã¢ãŠã厩ãã®çްããªå®çŸ©ããŸã åºãŸã£ãŠããããã©ã®çšåºŠã®ãºã¬ã厩ããšã¿ãªãããèŠçŽ å士ã®éãªããã©ãæ±ãããšãã£ãåºæºäœãã«æéãæããããªãšæã£ãŠããŸããå®éã«ã¯ãäžå®æééçšããªãããã¥ãŒãã³ã°ããŠããå¿ èŠããããšæããŠããŸãã
ãŸãã誀æ€ç¥ãèŠéããçºçããå¯èœæ§ãããããã宿çãªããã³ããã®èŠçŽããããŒã¹ç»åã®æŽæ°ãªã©ãä»çµã¿èªäœã®ã¡ã³ããã³ã¹ãç¶ç¶çã«è¡ãå¿ èŠããããŸãã
ããã¹ã倿Žã«ããæ€ç¥ãäžååã ã£ãç¹ã«é¢ããŠã¯ãããã¹ãå·®åçš ã®éèŠæèšãªã¹ã ãçšæãããã®ãªã¹ããšç §ããåãã㊠æãããªèª€åã»è±åãããã°â¯ERRORãããã§ãªããã°â¯OKâ¯ãšå€å®ããéçšã詊ããŠãããããšèããŠããŸãã
3.3 ä»åŸã®å±æ
ä»åã®æ€èšŒã§äžå®ã®ææãåŸããããšæããã®ã§ããŸãã¯ä»ãã VRT ã®ä»çµã¿ã«ããã®çæAIã䜿ã£ãåæã®ä»çµã¿ãçµã¿èŸŒãã§ããããšæããŸãã
ãŸããçæAIã®ç²ŸåºŠã®åäžã«ãã£ãŠã芳ç¹ã«ãã£ãŠã¯ã人éã§ã¯ãªãçæAIã«ä»»ããããšãã§ãããªãšæããã®ã§ãUI/UX 芳ç¹ã®ãã¹ãã«ãç©æ¥µçã«æŽ»çšããŠãããããšèããŠããŸãã
4. ãŸãšã
ä»åãPlaywright à çæAI ãçµã¿åãããŠãVRTã®å·®åå€å®ãèªç¶èšèªã®ãã°å ±åã«å€æããä»çµã¿ãæ§ç¯ããŸããã
åãªããã¯ã»ã«å·®åã§ã¯ãªããããããŒã®è²ãããããâ³â³ã«å€ãã£ãŠããŸãããããã®ã¬ã€ã¢ãŠãã厩ããŠããŸãããšãã£ãåãããããæ¥æ¬èªã§æããŠãããããããã°å€æãæ Œæ®µã«æ¥œã«ãªããŸããããæ³å以äžã«å®çšçã ãªãšæããŸããã
ãŸããä»åã®çµéšãéããŠããã®ããæ¹ãå¿çšããŠãVRTã ãã§ãªãUI/UXãã¢ã¯ã»ã·ããªãã£ãã§ãã¯ãªã©ãèŠèŠçãªå質ä¿èšŒå
šè¬ã«æŽ»çšã§ããæå¿ããæããŸããã
ä»åŸãçæAIãæŽ»çšããªãããæ¥åã®å¹çåãèŠèœãšããã¡ãªå質ãå¹ççã«åºäžãããåãçµã¿ã«ææŠããŠãããŸãã
ãã²ãä»åã®èšäºãèªãã§èå³ãæã£ãŠããã ããæ¹ã¯ããæ°è»œã«å£°ããããŠãããããšå¬ããã§ãïŒ
æ å ±äº€æãªã© X ãã«ãžã¥ã¢ã«ã«ã話ãã§ããããšæããŸãïŒ
-
Microsoft補ã®E2Eãã¹ãèªååãã¬ãŒã ã¯ãŒã¯ãhttps://playwright.dev/ â©ïž
-
Visual Regression Testingãç»é¢ã®èŠãç®ã®å€æŽãæ€ç¥ãããã¹ãææ³ã â©ïž
-
Googleã®Geminiã·ãªãŒãºã®é«éãã«ãã¢ãŒãã«ã¢ãã«ã â©ïž
-
OpenAI補ã®è»œéçãã«ãã¢ãŒãã«ã¢ãã«ãã³ã¹ãå¹çãé«ãã â©ïž
-
ããã³ããã¯è©Šè¡é¯èª€ã®çµæãä»åŸãç¶ç¶çã«æ¹åäºå® â©ïž
Discussion