ã¯ããã« ããã«ã¡ã¯ïŒããã³ããšã³ãéçºèª²ã® koki _matsuraã§ãã ãã®èšäºã§ã¯ãE2Eãã¹ã ãã¬ãŒã ã¯ãŒã¯ ãšããŠçšããããPlaywrightã®ã€ã³ã¹ããŒã«ãšããã€ãåºæ¬çãªãã¹ãã³ãŒããæåŸã« æ¡åŒµæ©èœ ã«ã€ããŠãã玹ä»ãããŠããã ããŸããããããPlaywrightã§ãã¹ããæžããã人ãE2Eãã¹ãã«å°ãã§ãèå³ãæã£ãŠããã ããæ¹ã«èªãã§ããã ãããšå¹žãã§ãã ç®æ¬¡ã¯æ¬¡ã®éãã«ãªã£ãŠããŸãã ã¯ããã« Playwrightãšã¯ ã€ã³ã¹ããŒã« ç°¡åãªãã¹ããæžããŠã¿ãã Playwrightã®èšå®ãç·šéããã å¥ã¿ããéããã¹ããæžãã å¥ã¿ããã³ãŒãããéãã±ãŒã¹ å¥ã¿ãããªã³ã¯ããéãã±ãŒã¹ ãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹ããã¹ãããã ã¢ãã¯ã䜿ã£ãŠãã¹ãããã Playwrightæ¡åŒµæ©èœã䜿ãã ãã¹ãã®å®è¡ å®è¡ãã©ãŠã¶ã®å€æŽ ãããã¬ã¹ã¢ãŒãã®éžæ èŠçŽ ã®ååŸ ãã¹ãã³ãŒãã®çæ ãããã« Playwrightãšã¯ Webãã©ãŠã¶ ã®èªååãã¹ããå®è¡ããããã®ã©ã€ãã©ãªã§ãããNode.jsã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšããããšãã§ããŸãã ã¹ã¯ã¬ã€ãã³ã° ããã¹ãèªååãUIãã¹ããããã©ãŒãã³ã¹ãã¹ãã ã¹ã¯ãªãŒã³ã·ã§ãã ãPDFã®çæãªã©ããŸããŸãªçšéã§äœ¿çšããããšãã§ããŸããç¹åŸŽã¯äžèšã®ããã«ãªã£ãŠããŸãã Chrome ã» Firefox ã» Safari ã»Edgeãªã©è€æ°ã®ãã©ãŠã¶ããµããŒãããŠãã ç°¡æœãª API ãæäŸããŠãããçŽæçã«WebããŒãžãæäœã§ãã éåæã§åäœããããšã«ããããã¹ãã®é«éå®è¡ããã©ãŠã¶ã®ã¯ã©ãã·ã¥ãããªãŒãºã«å¯Ÿãã匷ãèæ§ãæã£ãŠãã Puppeteerãšé¡äŒŒããŠãããšã«ããPuppeteerãŠãŒã¶ãŒã¯åãå
¥ãããã ã€ã³ã¹ããŒã« Playwrightã䜿çšããã«ã¯Playwright Testã®ã€ã³ã¹ããŒã«ãšãã©ãŠã¶ã®ã€ã³ã¹ããŒã«ãå¿
èŠãšãªããŸãã äžèšã®ã³ãã³ãã§Playwright Testãšãã©ãŠã¶ãåæã«ã€ã³ã¹ããŒã«ã§ããŸãã npm init playwright@latest ã€ã³ã¹ããŒã«ããéã«æ¬¡ã®é
ç®ã«ã€ããŠèãããŸãã TypeScriptã JavaScript ã®ã©ã¡ãã䜿çšããŸãã (ããã©ã«ãã¯TypeScript) -> ããã©ã«ããéžæ ãã¹ããã©ã«ããŒã®åå (ããã©ã«ã㯠tests ãŸã㯠e2e) -> ããã©ã«ããéžæ GitHub Actions ã¯ãŒã¯ãããŒã远å ããŠãCI ã§ãã¹ãããã -> falseãéžæ Playwright ãã©ãŠã¶ãŒ ãã€ã³ã¹ããŒã«ããŸã (ããã©ã«ã㯠true) -> ããã©ã«ããéžæ æºåã¯ããã ãã§ããããšã¯ãã¹ãã³ãŒããäœæããã ãã§ç°¡åã«ãã¹ãèªååãå®çŸã§ããŸãã ç°¡åãªãã¹ããæžããŠã¿ãã æ©éã§ãããç°¡åãªãã¹ããæžããŠã¿ãŸãããããã¹ãå
å®¹ã¯æ¬¡ã®ããã«ããŸãã Chrome ãã©ãŠã¶ã§ Google æ€çŽ¢ãšã³ãžã³ ã®ãããããŒãžãéã æ€çŽ¢é
ç®ã«ãæ ªåŒäŒç€Ÿ ã©ã¯ ã¹ããšå
¥åããEnterãã¯ãªãã¯ ãæ ªåŒäŒç€Ÿ ã©ã¯ ã¹ãã®å
¬åŒãµã€ãã®ãªã³ã¯ãã¯ãªã㯠ããŒãžãæ£ãã衚瀺ãããŠããããã¹ã ãã¹ãã®ã³ãŒãã¯ããã©ã«ãã§äœæãããŠãã tests/example.spec.ts ã«æžããŠãããŸãã äŸãšããŠæžãããŠãããã¹ããç䌌ããŠãtestã®å€§æ ãæžããŠã¿ãŸããããå
容ã¯äžæŠãã³ã¡ã³ãã§æžããŠãããŸãã // example.spec.ts test ( 'ã©ã¯ã¹ã®ãµã€ãã衚瀺ãããŠããã' , async ( { page } ) => { // Googleæ€çŽ¢ãšã³ãžã³ãéã // æ€çŽ¢æ¬ã«ãæ ªåŒäŒç€Ÿã©ã¯ã¹ããå
¥å // EnterãæŒã // æ€çŽ¢çµæããå
¬åŒãµã€ããã¯ãªã㯠// ãã¹ãïŒå
¬åŒãµã€ãã衚瀺ãããŠããã } ) test颿°ã¯ç¬¬äžåŒæ°ã«ãã¹ãã®ååãã第äºåŒæ°ã«ãã¹ãã®é¢æ°ãæžããŠãããŸãããã¹ãã®é¢æ°ã«åŒæ°ãšããŠå
¥ã£ãŠããpageãšã¯ãã©ãŠã¶ã§éãããWebããŒãžã衚ããªããžã§ã¯ãã§ãã ãã¹ããèšè¿°ããŠãããŸããã Google æ€çŽ¢ãšã³ãžã³ ãéããã®äžã«æžããŸããããäœãã®ããŒãžãžç§»åãããå Žåã¯goto颿°ã䜿ããŸããåŒæ°ã«ã¯URLãå
¥ããŸãã await page. goto( 'https://www.google.com/' ); ããã§ Google æ€çŽ¢ã®ããŒãžãžé·ç§»ããã¯ãã§ãã æ¬¡ã¯ãæ€çŽ¢æ¬ã«ãæ ªåŒäŒç€Ÿ ã©ã¯ ã¹ããšå
¥åããã³ãŒããæžããŠãããŸãããã®ã³ãŒãã«ã¯æ€çŽ¢æ¬ã®èŠçŽ ãååŸãå¿
èŠã§ããã§ãããèŠçŽ ãååŸããã®ã¯æå€ãšé¢åã§ãã ãã®ãããªå Žåã¯Playwrightã®ã³ãŒããžã§ãã¬ãŒã¿ã䜿ããŸããããäœ¿ãæ¹ã¯ç°¡åã§ããäžèšã®ã³ãã³ããæã¡ãŸãã npx playwright codegen https://www.google.com Playwright Inspectorãš Chromium ã§ Google æ€çŽ¢ãéããããšæããŸãã Google æ€çŽ¢ã®æ€çŽ¢æ¬ã®èŠçŽ ãæ¬²ããã®ã§ãããã«ãããŒããŸãããããšãäžèšã®ç»åã®ããã«èŠçŽ ã衚瀺ãããŸãã ãã®èŠçŽ ãã¯ãªãã¯ããŠãæ€çŽ¢æ¬ã«ãæ ªåŒäŒç€Ÿ ã©ã¯ ã¹ããšå
¥åããenterããŒãæŒããŸãããããšãInspectorã®æ¹ã«æ¬¡ã®ãããªã³ãŒããçæãããŠãããšæããŸãã getByRoleãšã¯ååã®éããèŠçŽ ã圹å²å¥ã«ååŸã§ãããã®ã§ããä»åã¯comboboxãšããRoleãæå®ããŠããŸãããbuttonãinputãªã©ããããŸãã await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .click (); await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .fill ( 'æ ªåŒäŒç€Ÿã©ã¯ã¹' ); await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .press ( 'Enter' ); æåŸã«å
¬åŒãµã€ããæ€çŽ¢çµæããã¯ãªãã¯ããã ãã§ããInspectorããçæãããã³ãŒããæ¬¡ã®ããã«ãªã£ãŠããã°åé¡ãããŸããã await page.getByRole ( 'link' , { name: 'äŒæ¥ã®æé·ãæ¯æŽããã¯ã©ãŠããµãŒãã¹ | æ ªåŒäŒç€Ÿã©ã¯ã¹ ã©ã¯ã¹ https://www.rakus.co.jp' } ) .click (); çæãããã³ãŒãã example.spec.ts ã«ã³ããããŸãã // example.spec.ts test ( 'ã©ã¯ã¹ã®ãµã€ãã衚瀺ãããŠããã' , async ( { page } ) => { // Googleæ€çŽ¢ãšã³ãžã³ãéã await page. goto( 'https://www.google.com/' ); // æ€çŽ¢æ¬ã«ãæ ªåŒäŒç€Ÿã©ã¯ã¹ããå
¥å await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .click (); await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .fill ( 'æ ªåŒäŒç€Ÿã©ã¯ã¹' ); // EnterãæŒã await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .press ( 'Enter' ); // æ€çŽ¢çµæããå
¬åŒãµã€ããã¯ãªã㯠await page.getByRole ( 'link' , { name: 'äŒæ¥ã®æé·ãæ¯æŽããã¯ã©ãŠããµãŒãã¹ | æ ªåŒäŒç€Ÿã©ã¯ã¹ ã©ã¯ã¹ https://www.rakus.co.jp' } ) .click (); // ãã¹ãïŒå
¬åŒãµã€ãã衚瀺ãããŠããã } ) æåŸã«å
¬åŒãµã€ãã衚瀺ãããŠãããããã¹ãããŸããèšãæãããšãçŸåšã®ããŒãžã®URLã ã©ã¯ ã¹ã®å
¬åŒãµã€ãURLãšäžèŽãããã®ãã¹ãã§ãã æ¬¡ã®ã³ãŒããããã¹ãïŒå
¬åŒãµã€ãã衚瀺ãããŠããããã®ã³ã¡ã³ãäžã«è¿œèšããŸãã expect㯠ã¢ãµãŒã·ã§ã³ ã©ã€ãã©ãªã®äžã€ã§æåŸ
ãããçµæãæ€èšŒãããšãã«çšãããã®ã§ããpageã https://www.rakus.co.jp/ ãæã£ãŠãããã®æ€èšŒã瀺ããŠããŸãã await expect ( page ) .toHaveURL ( "https://www.rakus.co.jp/" ); ãã¹ããæžãçµããã®ã§å®è¡ãããŸããå®è¡ã¯äžèšã®ã³ãã³ãã§ãã"9 passed"ãšè¡šç€ºãããŠããã°ãã¹ãééã§ããŠããŸãã npx playwright test ã¬ããŒã㯠npx playwright show-report ãå®è¡ãã該åœã®ããŒãžã衚瀺ãããšèŠãããšãã§ããŸãã ãã¹ããå®è¡ããããšãã§ããŸããã ã¡ãªã¿ã«ããã¹ãã³ãŒããæžãããã«ã¯å¯Ÿè±¡ãšãªãèŠçŽ ãååŸããããšãåºæ¬ãšãªããPlaywrightã§ã¯LocatorãšããWebããŒãžã®èŠçŽ ãæ€çŽ¢ããããã®ãªããžã§ã¯ãã䜿ããŸãã CSS ã»ã¬ã¯ã¿ ãããã¹ããèŠçŽ ã®å±æ§ãªã©ãæ§ã
ãªæ¹æ³ã§èŠçŽ ãæ€çŽ¢ã§ããŸãã ãšãŠã䟿å©ã§ãããLocatorã¯ãã®äŸ¿å©ããããã«äœ¿ããããŠã³ãŒãããããã«ãããªã£ãããæ§ã
ãªæ€çŽ¢ãå¯èœãªããã«è€éãªHTMLæ§é ãæã€èŠçŽ ãèŠã€ããã®ãå°é£ãªå ŽåããããŸãã ãªã®ã§ãã§ããéãgetByRoleãªã©ã®æç€ºçãªçµã¿èŸŒã¿ãã±ãŒã¿ãŒã䜿ããŸããçµã¿èŸŒã¿ãã±ãŒã¿ãŒã¯Locatorãšæ¯ã¹ ã以äžã®ãããªã¡ãªããããããŸãã ã·ã³ãã«ã§ããããããã³ãŒããæžãã ãã¿ã³ãç¹å®ããããã«page.locator()ã䜿çšããããããpage.getByRole('button')ã®ããã«getByRoleã¡ãœããã䜿çšããæ¹ãããããããã³ãŒãã«ãªããŸãã ã¢ã¯ã»ã·ããªãã£ ã®æ¹å getByRole()ãªã©ã®çµã¿èŸŒã¿ã®ãã±ãŒã¿ãŒã¯ã Webã¢ã¯ã»ã·ããªã㣠ã®åäžãç®çãšããŠããŸãããããã®ãã±ãŒã¿ãŒã䜿çšããããšã§ã èŠèŠé害 è
ããã®ä»ã®é害ãæã€ãŠãŒã¶ãŒãWebããŒãžã䜿çšããã®ã«åœ¹ç«ã¡ãŸãã ãã±ãŒã¿ãŒã®éžæãèªååããã getByRole()ãªã©ã®çµã¿èŸŒã¿ã®ãã±ãŒã¿ãŒã䜿çšããããšã§ãPlaywrightãé©åãªãã±ãŒã¿ãŒãèªåçã«éžæããŠãããŸããgetByRole('button')ãå®è¡ããããšãPlaywrightã¯èªåçã«role="button"屿§ãæã€èŠçŽ ãæ€çŽ¢ããŸãã Playwrightã®èšå®ãç·šéããã ãã¹ãå®è¡åŸã®ã¬ããŒããèŠãŠããããš Chromium ã Firefox ã Webkit ã®3ãã©ãŠã¶ã§åãã¹ããå®è¡ãããŠããããšã確èªã§ããŸãããã¡ããè€æ°ãã©ãŠã¶ã§ãã¹ãããããšã倧äºã§ããæ¯åã¯æéããããã®ã§ãã©ãŠã¶ã倿Žãããå Žåãããã§ãããããŸãã人ã«ãã£ãŠã¯å®è¡äžã®ãã©ãŠã¶ã衚瀺ããŠæ¬²ãã人ããããšæããŸãã ãã®ãããªãã¹ãã«é¢ããèšå®ã¯ playwright.config.ts ããã§ããŸããããã©ã«ãã§ã¯äžèšã®ãããªèšå®ã«ãªã£ãŠããŸãã export default defineConfig ( { testDir: './tests' , /* Run tests in files in parallel */ fullyParallel: true , /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !! process .env.CI , /* Retry on CI only */ retries: process .env.CI ? 2 : 0 , /* Opt out of parallel tests on CI. */ workers: process .env.CI ? 1 : undefined , /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: 'html' , /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ // baseURL: 'http://127.0.0.1:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry' , } , /* Configure projects for major browsers */ projects: [ { name: 'chromium' , use: { ...devices [ 'Desktop Chrome' ] } , } , { name: 'firefox' , use: { ...devices [ 'Desktop Firefox' ] } , } , { name: 'webkit' , use: { ...devices [ 'Desktop Safari' ] } , } , ] } ); testDirã¯ãã¹ããã¡ã€ã«ãæ ŒçŽããŠãããã©ã«ãã®ããšã§ãããã«èšå®ããã ãã£ã¬ã¯ã ãªä»¥å€ã§ãã¹ããã¡ã€ã«ãäœæããŠãPlaywrightã¯èªèããŠãããªãã®ã§æ³šæã§ãã ä»ã¯ããã©ã«ãã§ã³ã¡ã³ããã€ããŠãããŠããã®ã§çç¥ããŸãã éèŠãªã®ã¯projectsã§ãããã©ã«ãã§ã¯ chromium ã firefox ã webkit ãèšå®ãããŠããŸãã chromium ã ãã§å®è¡ãããå Žåã¯ã firefox ãš webkit ã ã³ã¡ã³ãã¢ãŠã ããŸããããã ãã§å®è¡ãã©ãŠã¶ã倿Žããããšãã§ããŸãã å®è¡äžã«ãã©ãŠã¶ã衚瀺ããã®ãç°¡åã§ããreporterãšprojectsã®éã«ããuseã®äžã«äžèšãæžãå ããã ãã§ãã headless : false headlessãªãã·ã§ã³ãæžããªãå Žåã¯ããã©ã«ãã§trueã«ãªã£ãŠããã®ã§ãfalseãæžãå ããããšã§å®è¡äžã«ãã©ãŠã¶è¡šç€ºãããããšãã§ããŸãã ä¿åããŠãããäžåºŠãã¹ããå®è¡ããŠã¿ãŸãããã ãããšã chromium ã3ã€ç«ã¡äžããããã¹ãããã©ãŠã¶ã§å®è¡ãããŠããã®ã確èªã§ãããšæããŸãã3ã€ç«ã¡äžãã£ãŠããã®ã¯fullyParallelãªãã·ã§ã³ãtrueã«ãªã£ãŠã䞊ååŠçããããŠããããã§ããèŠã«ããå Žåã¯falseã«ããããšã§äžã€ãã€å®è¡ãããŸãã ãªãã·ã§ã³ã¯ä»ã«ãæ§ã
ãããŸãã®ã§ã詳ãã㯠TestConfig | Playwright ãèŠãŠãã ããã å¥ã¿ããéããã¹ããæžãã å¥ã¿ãæäœæ©èœã®æç¡ã¯E2Eãã¹ãèªååã©ã€ãã©ãªã®éžå®åºæºã®äžã€ã«ãªã£ãŠããããšãå€ããšæããŸããPlaywrightã¯å¥ã¿ãã§ã®æäœãå¯èœãšãªã£ãŠããŸãã å¥ã¿ããéãã±ãŒã¹ãšããŠã¯ãã³ãŒãããèªåã§éãã±ãŒã¹ããšããã¿ã³ãæŒããªã©ã®ããªã¬ãŒã«ããéãããã±ãŒã¹ãããããšæãããã®ã§ãã®2ãã¿ãŒã³ã玹ä»ããŸãã å¥ã¿ããã³ãŒãããéãã±ãŒã¹ ãã¹ãã¯å
å®¹ã¯æ¬¡ã®ããã«ããŸãã ããŒãžãéã å¥ã¿ããéã å¥ã¿ãã§ Google æ€çŽ¢ãšã³ãžã³ ã®ãããããŒãžãéã æ€çŽ¢é
ç®ã«ãæ ªåŒäŒç€Ÿ ã©ã¯ ã¹ããšå
¥åããEnterãã¯ãªãã¯ ãæ ªåŒäŒç€Ÿ ã©ã¯ ã¹ãã®å
¬åŒãµã€ãã®ãªã³ã¯ãã¯ãªã㯠å¥ã¿ãã®ããŒãžãæ£ãã衚瀺ãããŠããããã¹ã æåã«æžãããã¹ããå¥ã¿ãã§è¡ãã ãã§ãããã¹ãã®ã³ãŒã㯠example.spec.ts ã«æžããŠãããŸãã äŸãšããŠæžãããŠããäºã€ã¯æ¶ããŠããŸããŸãããã ããŒãžãçæããã®ã¯é£ãããããŸãããäžèšã®ããã«Browseråã䜿ãã ãã§ãã const page = await browser.newPage () ããã ããªã®ã§ããã¹ããäžèšã®ããã«ç°¡åã«æžããŸãã test ( 'å¥ã¿ãã§ã©ã¯ã¹ã®ãµã€ãã衚瀺ãããŠããã' , async ( { browser } ) => { // æåã®ã¿ããéã const page = await browser.newPage () // å¥ã¿ããéã const newPage = await browser.newPage (); // å¥ã¿ãã§Googleæ€çŽ¢ãšã³ãžã³ãéã await newPage. goto( "https://www.google.com" ); // æ€çŽ¢æ¬ã«ãæ ªåŒäŒç€Ÿã©ã¯ã¹ããå
¥å await newPage.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .click (); await newPage.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .fill ( 'æ ªåŒäŒç€Ÿã©ã¯ã¹' ); // æ€çŽ¢ãã¿ã³ãæŒã await newPage.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .press ( 'Enter' ); // æ€çŽ¢çµæããå
¬åŒãµã€ããã¯ãªã㯠await newPage.getByRole ( 'link' , { name: 'äŒæ¥ã®æé·ãæ¯æŽããã¯ã©ãŠããµãŒãã¹ | æ ªåŒäŒç€Ÿã©ã¯ã¹ ã©ã¯ã¹ https://www.rakus.co.jp' } ) .click (); // ãã¹ãïŒå
¬åŒãµã€ãã衚瀺ãããŠããã await expect ( newPage ) .toHaveURL ( "https://www.rakus.co.jp/" ); } ) å®è¡ããŠã¿ããšãå¥ã®ã¿ããéãããšã確èªã§ãããšæããŸãã å¥ã¿ãããªã³ã¯ããéãã±ãŒã¹ ã©ã¯ ã¹ã®å
¬åŒãµã€ãããå¥ã¿ããéããªã³ã¯ãæŒããã¹ãã«ããŸãããå
容ã¯ä»¥äžã®ããã«ããŸãã ã©ã¯ ã¹ã®å
¬åŒãµã€ããéã ããããŒã¡ãã¥ãŒã®ãäºæ¥å
容ãããããŒãã 衚瀺ãããæ§ã
ãªãªã³ã¯ãããæ¥œæ¥œç²Ÿç®ããã¯ãªãã¯ãã(èªåã§å¥ã¿ãã§æ¥œæ¥œç²Ÿç®ã®ããŒãžãéããã) å¥ã¿ãã®URLãæ¥œæ¥œç²Ÿç®ã®ããŒãžãšäžèŽãããããã¹ã example.spec.ts ã«æžããŠãããŸãããã å
¬åŒãµã€ããéãã®ã¯goto颿°ã§ç°¡åã«ã§ããŸãã ç¶ããŠãããããŒã¡ãã¥ãŒãšã¯ãµã€ãäžéšã®ã ã©ã¯ ã¹ã®æãããäŒç€Ÿæ
å ±ããªã©ã䞊ãã§ããéšåã§ãã äºæ¥å
容ã®ãªã³ã¯èŠçŽ ãååŸãããã§ããã³ãŒããžã§ãã¬ãŒã¿ã䜿ãã°ç°¡åã«ååŸã§ããŸãããäžèšç»åã®ããã«ã ãã¶é·ãã³ãŒãã«ãªã£ãŠããŸããŸãã ã³ãŒããžã§ãã¬ãŒã¿ã«é Œãããããšãããã«ããã³ãŒãã«ãªãããšãããã®ã§ãããŸã§ãµããŒããããã«ãããšãããšæããŸãã ã³ãŒããžã§ãã¬ãŒã¿ã§ããŸãèŠçŽ ãåãåºããªãæã«ã¯ãHTMLã確èªããŠã¿ãŸããããIDãClassãå²ãæ¯ãããŠããã°ããªãèŠçŽ ãçµãããšæããŸãã ãããã®åèŠçŽ ã«ã¯ p-header__menu__item ãšããClassãå²ãæ¯ãããŠããŸãããClassãIDã§ååŸããå Žåã«ã¯locatorã䜿ããŸãã ããšã¯ãäºæ¥å
容ããšããããã¹ããåãã°ããã®ã§æ¬¡ã®ãããªã³ãŒãã§èŠçŽ ãååŸã§ããŸãã await page.locator ( '.p-header__menu__item' ) .getByText ( "äºæ¥å
容" ) ããªãã·ã³ãã«ã«ååŸã§ããŸããä»ã«ãäžèšã®ãããªååŸæ¹æ³ããããŸãããã®å Žåã¯ãäºæ¥å
容ããšãããªã³ã¯ãããã€ãããããã®æåã®èŠçŽ ãæ¬²ããã®ã§first()ãã€ããããšã§ååŸã§ããŸãã await page.getByRole ( "link" , { name: "äºæ¥å
容" } ) .first () èŠçŽ ãååŸã§ããã®ã§ãããŒãããã ãã§ãããããŒã¯èŠçŽ ã«hover颿°ãã€ããã ããªã®ã§äžèšã®ããã«ç°¡åã«å®è£
ã§ããŸãã await page.locator ( '.p-header__menu__item' ) .getByText ( "äºæ¥å
容" ) .hover () å¥ã¿ãã§ããŒãžãéãéã«ã¯ã€ãã³ããçºçããåã«ã€ãã³ããåŸ
ã€é¢æ°ãå®çŸ©ããªããšãããŸãããããã¯äžèšã®ããã«æžãã°å®è£
ã§ããŸãã const newPagePromise = page.waitForEvent ( 'popup' ); ã€ãã³ããçºçãããŸãããããæ¥œæ¥œç²Ÿç®ããšãããªã³ã¯ãã¯ãªãã¯ããã³ãŒãã§ããããã¯äžèšã®ããã«getByRoleã§ãªã³ã¯èŠçŽ ãã€æ¥œæ¥œç²Ÿç®ãšããããã¹ãã§èŠçŽ ãçµããŸããexactãšã¯å®å
šäžèŽã瀺ããŸããexactãã€ããªããšéšåäžèŽã«ãªã£ãŠããŸããŸãã await page.getByRole ( 'link' , { name: '楜楜粟ç®' , exact: true } ) .click () å¥ã¿ãã§ã楜楜粟ç®ãã®ããŒãžãéãã¯ããªã®ã§ãã€ãã³ãã解決ããŸããããå
ã»ã©ã®newPagePromiseã¯Promise åã«ãªã£ãŠããã®ã§awaitãã€ããããšã§PageãåãåºããŸãã const rakurakuseisanPage = await newPagePromise rakurakuseisanPageã¯ã楜楜粟ç®ãã®ããŒãžã衚ããŠããã¯ãã§ãã æåŸãrakurakuseisanPageããæ¥œæ¥œç²Ÿç®ãã®ããŒãžURLãšäžèŽãããã®ãã¹ããæžããŸããããã¯ä»ã®ãã¹ããšåãããã«æžããŸãã await expect ( rakurakuseisanPage ) .toHaveURL ( /^https:\/\/www\.rakurakuseisan\.jp\/.*$/ ); ããã§ãã¹ããæžããŸããã念ã®çºããã¹ãã³ãŒããå
šãŠèŒããŠãããŸãã test ( 'å¥ã¿ãã§æ¥œæ¥œç²Ÿç®ã®ããŒãžãéãããŠããã' , async ( { page } ) => { // æåã®ã¿ãã§ã©ã¯ã¹ã®å
¬åŒãµã€ããéã await page. goto( 'https://www.rakus.co.jp/' ); // ããããŒã®ãªã³ã¯ããããŒãã await page.locator ( '.p-header__menu__item' ) .getByText ( "äºæ¥å
容" ) .hover (); // æ°ããããŒãžãéãã€ãã³ããåŸ
〠const newPagePromise = page.waitForEvent ( 'popup' ); // 楜楜粟ç®ã®ãªã³ã¯ãã¯ãªãã¯ãã(æ°ããããŒãžãéãã€ãã³ã) await page.getByRole ( 'link' , { name: '楜楜粟ç®' , exact: true } ) .click (); // ã€ãã³ãã解決ãã const rakurakuseisanPage = await newPagePromise ; // ãã¹ãïŒæ°ããããŒãžã®URLãæ¥œæ¥œç²Ÿç®ã®ããŒãžãšäžèŽããã await expect ( rakurakuseisanPage ) .toHaveURL ( /^https: \ / \ /www \ .rakurakuseisan \ .jp \ /.*$/ [ f:id:koki_matsura:20230505222421p:plain ] ); } ) ãã¹ããå®è¡ããŠã¿ãŸããããèªåã§éãå¥ã¿ãã«ã察å¿ã§ããããšã確èªã§ããŸãã ãªã¯ ãšã¹ ãã»ã¬ã¹ãã³ã¹ããã¹ãããã æ£åžžã«ãªã¯ ãšã¹ ããé£ãã§ããããã¬ã¹ãã³ã¹ãæ³å®éãè¿ã£ãŠããŠãããã確ããããæããããšæããŸãã ãã®ãããªãã¹ããã§ããã®ã§ç°¡åãªäŸãšãšãã«ç޹ä»ãããŠããã ããŸãããã¹ãå
å®¹ã¯æ¬¡ã®ããã«ãªã£ãŠããŸãã Google æ€çŽ¢ãšã³ãžã³ ã®ãããããŒãžãéã æ€çŽ¢é
ç®ã«ãPlaywrightããšå
¥åããEnterãã¯ãªã㯠ãªã¯ ãšã¹ ããšã¬ã¹ãã³ã¹ãååŸ ãªã¯ ãšã¹ ãã®paramã«ãPlaywrightããå«ãŸããŠããã ã¬ã¹ãã³ã¹ã®ã¹ããŒã¿ã¹ã200ã§è¿ã£ãŠããŠããã ãªã¯ ãšã¹ ããšã¬ã¹ãã³ã¹ãååŸããã®ã¯æ°ããããŒãžãååŸããã®ãšåãã§waitoForç³»ã®é¢æ°ã䜿ããŸãã å
·äœçã«ã¯æ¬¡ã®ãããªã³ãŒãã§æžãããšãã§ããŸãã const [ request , response ] = await Promise . all( [ page.waitForRequest ( request => request.url () .includes ( 'search?q=Playwright' )), page.waitForResponse ( response => response.url () .includes ( 'search?q=Playwright' )), // ãªã¯ãšã¹ããçºçãããã€ãã³ã page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .press ( 'Enter' ) ] ) waitForRequestãšwaitForResponseå
ã®æ¡ä»¶ã«åœãŠã¯ãŸã£ãå Žåã ãrequestãšresponseãè¿ã£ãŠããŸãã ãªã®ã§ããã®æç¹ã§paramã«ãPlaywrightããå«ãŸããŠããªããšãã¹ãã¯å€±æããŸãã ãªã¯ ãšã¹ ããšã¬ã¹ãã³ã¹ãååŸã§ããã°ãããšã¯ ã¢ãµãŒã·ã§ã³ ããã ãã§ãã ãã¹ãããã®ã¯ãªã¯ ãšã¹ ãã®paramã«ãPlaywrightããå«ãŸããŠãããã©ãããšã¬ã¹ãã³ã¹ã®ã¹ããŒã¿ã¹ã200ã§è¿ã£ãŠããŠãããã©ããã§ãã ååŸãããªã¯ ãšã¹ ããšã¬ã¹ãã³ã¹ã䜿ãã°ç°¡åã«æ¬¡ã®ããã«å®è£
ã§ããŸãã // ãªã¯ãšã¹ãã®Paramã«ãPlaywrightããå«ãŸããŠããã expect ( request.url ()) .toContain ( 'search?q=Playwright' ); // ã¬ã¹ãã³ã¹ã®ã¹ããŒã¿ã¹ã200ãã©ãã expect ( response. status()) .toBe ( 200 ); ãªã¯ ãšã¹ ãã«é¢ããŠã¯å
ã»ã©ã®waitForRequestã§paramããã§ãã¯ããŠããã®ã§ããäžåºŠç¢ºèªããå¿
èŠã¯ãªãã®ã§ããäžå¿ãæžããŠãããŸããã æ®ãã®éšåã¯ä»ãšåããªã®ã§ãã¹ãã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã test ( 'ãPlaywrightããšæ€çŽ¢ãããŠããã' , async ( { page } ) => { // Googleæ€çŽ¢ãšã³ãžã³ãéã await page. goto( 'https://www.google.com/' ); // æ€çŽ¢æ¬ã«ãPlaywrightããå
¥å await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .click (); await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .fill ( 'Playwright' ); // ãªã¯ãšã¹ãã»ã¬ã¹ãã³ã¹ãååŸ const [ request , response ] = await Promise . all( [ page.waitForRequest ( request => request.url () .includes ( 'search?q=Playwright' )), page.waitForResponse ( response => response.url () .includes ( 'search?q=Playwright' )), // æ€çŽ¢ãå®è¡ page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .press ( 'Enter' ) ] ) // ãªã¯ãšã¹ãã®Paramã«ãPlaywrightããå«ãŸããŠããã expect ( request.url ()) .toContain ( 'search?q=Playwright' ); // ã¬ã¹ãã³ã¹ã®ã¹ããŒã¿ã¹ã200ãã©ãã expect ( response. status()) .toBe ( 200 ); } ) ãã¹ããå®è¡ããŠã¿ãŸããããæ£åžžã«æ€çŽ¢ãããã°ããã¹ãã¯ééããã¯ãã§ãã ã¢ãã¯ã䜿ã£ãŠãã¹ãããã ã¢ãã¯ãšã¯ããªã¯ ãšã¹ ããã¬ã¹ãã³ã¹ããã¹ãããéã«ãå®éã®ãµãŒããŒã«æ¥ç¶ããã«ãäºåã«æºåããåœã®ã¬ã¹ãã³ã¹ãè¿ãããã«ããæ©èœã§ãã ããã䜿çšããããšã§ä»¥äžã®ãããªã¡ãªããããããŸãã ãã¹ãã®ä¿¡é Œæ§åäž å€éš API ã¯ãã¹ãå®è¡äžã«å€æŽãããããšããããŸããããã«ãããå®è¡çµæãå€åããå¯èœæ§ããããŸããã¢ãã¯ã䜿çšãããšãæ¯ååãã¬ã¹ãã³ã¹ãè¿ãããšãã§ãããã¹ãã®ä¿¡é Œæ§ãåäžãããããšãã§ããŸãã ãã¹ãã®é床åäž å€éš API ãåŒã³åºããšãå®è¡ã«æéããããå Žåãããã ã¿ã€ã ã¢ãŠã ã«ãªãå¯èœæ§ããããŸããã¢ãã¯ã䜿çšãããšã API ãåŸ
ã€å¿
èŠããªãã®ã§ãã¹ãã®é床ãåäžãããããšãã§ããŸãã å€éšãšã®äŸåæé€ ã¢ãã¯ã䜿ããšå€éš API ãžã®äŸåé¢ä¿ãæé€ããããšãã§ãããã¹ãå®è¡ç°å¢ã®å¶çŽãæžããããšãã§ããŸãã ãšã©ãŒã®çºèŠãšä¿®æ£ã®æå äŸãã°ãå€éš API ãã¬ã¹ãã³ã¹ãè¿ããªãå Žåãã¢ãã¯ã䜿çšããã°ãã® API ã®åé¡ãçºèŠããããšã容æã«ã§ããŸãã ã¢ãã¯ã¯E2Eãã¹ããšã¯åã£ãŠãåãé¢ããªãæ©èœã§ãããã²ãç©æ¥µçã«äœ¿ã£ãŠãããŸãããã æ©éã§ããããã¹ãã®å
å®¹ã¯æ¬¡ã®ããã«ããŸãã ã©ã¯ ã¹ã®ããŒãžãéã ã©ã¯ ã¹ã®ããŒãžä»¥äž( https://www.rakus.co.jp/** )ãã¢ãã¯ãã ã ã©ã¯ ã¹ã®æãã(/about)ã®å Žåã ãã¬ã¹ãã³ã¹ã404ã«ãã ã ã©ã¯ ã¹ã®æãããã¯ãªãã¯ãã 404ããŒãžã衚瀺ãããŠãããããã¹ã Playwrightã§ã¢ãã¯ãå®è£
ããã«ã¯route颿°ã䜿çšããŸãã第äžåŒæ°ã«ã¯ã¢ãã¯ãåæ ããURLãã第äºåŒæ°ã«ã¯ãã³ãã©ãŒãèšå®ããŸãã ãã®ãã¹ãã®å Žå㯠ã©ã¯ ã¹ã®ããŒãžä»¥äžãå
šãŠã¢ãã¯ããã®ã§ãäžèšã®ããã«ããŸãã await page.route ( 'https://www.rakus.co.jp/**' , rakusRouteHandler ); rakusRouteHandlerã§ã¯URLã /about ãå«ãæã ãã¬ã¹ãã³ã¹ã404ã«ãããšããèšå®ã«ãããã®ã§ã次ã®ããã«å®è£
ããŸããã const rakusRouteHandler = ( route: Route , request: Request ) => { const url = request.url (); if ( url.includes ( "about" )) { // ã¬ã¹ãã³ã¹ã®å
容 route.fulfill ( { status : 404 , } ); } else { // about以å€ã¯éåžžã®ã¬ã¹ãã³ã¹ãè¿ã route. continue(); } } ; requestã®URLã«aboutãå«ãŸããŠãããšãã ã404ãè¿ãããã以å€ã¯route.continue()ã§éåžžã®ã¬ã¹ãã³ã¹ãè¿ãããã«ããŠããŸãã ããã ãã§ç°¡åã«ã¢ãã¯ããããšãã§ããŸãã ãã¹ãã®å
šã³ãŒãã¯ä»¥äžã®ããã«ãªããŸãã test ( "ã©ã¯ã¹ã®ããŒãžãã¢ãã¯ãã" , async ( { page } ) => { // ã¢ãã¯ããããã®ã«ãŒããã³ãã©ãäœæ const rakusRouteHandler = ( route: Route , request: Request ) => { const url = request.url (); if ( url.includes ( "about" )) { // ã¬ã¹ãã³ã¹ã®å
容 route.fulfill ( { status : 404 , } ); } else { // about以å€ã¯éåžžã®ã¬ã¹ãã³ã¹ãè¿ã route. continue(); } } ; // ã©ã¯ã¹ã®ãããããŒãžãéã await page. goto( 'https://www.rakus.co.jp/' ); // ãããããŒãžä»¥äžã®ãªã¯ãšã¹ããã¢ãã¯ãã await page.route ( 'https://www.rakus.co.jp/**' , rakusRouteHandler ); // ãã©ã¯ã¹ã®æãããã¯ãªã㯠await page.locator ( '.p-header__menu__item' ) .getByText ( "ã©ã¯ã¹ã®æã" ) .first () .click (); // ãã¹ã:404ããŒãžã衚瀺ãããŠããããš await expect ( page.locator ( 'h1' )) .toHaveText ( "ãã® www.rakus.co.jp ããŒãžãèŠã€ãããŸãã" ) } ) ã¢ãµãŒã·ã§ã³ ã®éšåã¯ããŒãžã®h1ã«ããã® www.rakus.co.jp ããŒãžãèŠã€ãããŸãããã衚瀺ãããŠãããã©ãããèŠãŠããŸãã ãã¹ããå®è¡ããŠã¿ããšã以äžã®ããã«404ããŒãžã衚瀺ãããŠãããšæããŸãã ãŸãã /about 以å€ã¯éåžžã®ã¬ã¹ãã³ã¹ãè¿ããããã確èªããŠã¿ãŸãããã ã ã©ã¯ ã¹ã®æãããã¯ãªãã¯ããéšåã®ã³ãŒãã以äžã®ããã«å€ããŸãã await page.locator ( '.p-header__menu__item' ) .getByText ( "äºæ¥å
容" ) .click () ãã¹ããå®è¡ããŠã¿ããšãæ£åžžã«äºæ¥å
容ã®ããŒãžã衚瀺ãããŠãããšæããŸãã ãã³ãã©ã§å®è£
ããéãã«ã§ããŠããŸãã ä»åã¯ç°¡åã«404ãè¿ãå®è£
ã«ããŸããããroute.fulfillå
ãå€ããã ãã§æè»ã«æ§ã
ãªã¬ã¹ãã³ã¹ãå®è£
ããããšãã§ããŸãã Playwright æ¡åŒµæ©èœ ã䜿ãã VSCode 䜿ã£ãŠãã人å°çšã«ã¯ãªããŸãããPlaywrightã® æ¡åŒµæ©èœ ããšãŠã䟿å©ãªã®ã§ã玹ä»ããŸãã ãŸã㯠VSCode ã® æ¡åŒµæ©èœ ãããPlaywrightããšæ€çŽ¢ãããããããäžçªäžã«è¡šç€ºããããPlaywright Test for VSCode ããã€ã³ã¹ããŒã«ããŸãããã ã€ã³ã¹ããŒã«ãå®äºãããšãšãã£ã¿ãŒã®ãµã€ãããŒã«äžè§ããŒã«ãŒã®ã¢ã€ã³ã³ã衚瀺ãããŠãããšæããŸãã ãã¹ãã®å®è¡ ãµã€ãããŒã®äžè§ããŒã«ãŒãã¯ãªãã¯ãããšã tests/ 以äžã®ãã¹ãã衚瀺ãããŠãããšæããŸãã åçãã¿ã³ãæŒãããšã§å®è¡ããããšãå¯èœã§ãããã¹ããã¡ã€ã«ã®æ¹ã«ãåæ§ã«åãã¹ãã®å
é è¡ã«åçãã¿ã³ã衚瀺ãããŸãã æåãããã¹ãã¯ç·ã®ãã§ãã¯ããŒã¯ã倱æãããã¹ãã¯èµ€ã® ãã ããŒã¯ãã€ããŸãã å®è¡ãã©ãŠã¶ã®å€æŽ æ¡åŒµæ©èœ ãå
¥ããå㯠playwright.config.ts ã®projectsãæžãå ãããã ã³ã¡ã³ãã¢ãŠã ãããããŠå®è¡ãããã©ãŠã¶ãå€ããŠããŸããã æ¡åŒµæ©èœ ã®å Žåã¯äžè§ããŒã«ãŒãã¯ãªãã¯ãäžç»åã®ãSelect Configurationããã¯ãªãã¯ããæ¢å®ã®ãããã¡ã€ã«ã®éžæããã¯ãªãã¯ããã äžç»åã®ãããªã»ã¬ã¯ãããã¯ã¹ã衚瀺ãããã®ã§ããã§å®è¡ããããããžã§ã¯ããéžæããŠãOKãæŒãã°ç°¡åã«å®è¡ãã©ãŠã¶ãå€ããããšãå¯èœã§ãã ãããã¬ã¹ã¢ãŒãã®éžæ æ¡åŒµæ©èœ ãå
¥ããåã¯headressãfalseã«ããããšã§å®è¡äžã®ç»é¢ã衚瀺ããŠããŸãããããã¹ãã®äžã«ã¯ããããç»é¢ã§èŠãå¿
èŠã®ãªããã®ããããšæããŸãããã®ãããªãã¹ããå®è¡ãããã³ã«headressã¢ãŒãã«ãããããã®ã¯ãšãŠãé¢åã§ãã æ¡åŒµæ©èœ ã®å·ŠäžããShow browserããšãã ãã§ãã¯ããã¯ã¹ ããããŸãã ããã«ãã§ãã¯ãå
¥ãããšheadressãfalseã«ããŠããç¶æ
ãšåãã«ãªããŸãããã§ãã¯ãå€ããšheadressã¢ãŒãã«ãªããŸãã playwright.config.ts ã«æžããheadressã®èšå®ã¯æ¶ããªããšãã§ãã¯ããŠãããªããŠãç»é¢ã衚瀺ãããŠããŸãã®ã§æ³šæã§ãã èŠçŽ ã®ååŸ ãShow browserãã®äžã«ãããPick locatorããã¯ãªãã¯ãããšãã©ãŠã¶ãç«ã¡äžãããŸãããã®ãã©ãŠã¶ã§ãã¹ããããç»é¢ã«ç§»ããæ¬²ããèŠçŽ ãã¯ãªãã¯ãããšãäžç»åã®ããã« VSCode äžéšã«èŠçŽ ã®ã³ãŒããèšããŠãããŸãã ç°¡åã«èŠçŽ ãååŸãããåã«ã¯ããã ãã§ååã§ãã ãã¹ãã³ãŒãã®çæ ãPick locatorãã®äžã«ãããRecord newããã¯ãªãã¯ãããšãã©ãŠã¶ãç«ã¡äžãããŸãã ãã©ãŠã¶ãç«ã¡äžãããšãšãã«ã VSCode äžã§æ°ããªãã¹ããã¡ã€ã«ãäœæããããã¹ãã®éåœ¢ãæžãããŠãããšæããŸãã ç«ã¡äžãã£ããã©ãŠã¶äžã§æäœããããšãå
šãŠãã®ãã¡ã€ã«å
ã«ã³ãŒããçæãããŠãããŸããã³ãŒããžã§ãã¬ãŒã¿ãšåãã§ããã³ãã³ãã§ãžã§ãã¬ãŒã¿ãç«ã¡äžããªããŠæžãã®ã§ããªã楜ã§ãã ãã¹ãã®å€§æ ããžã§ãã¬ãŒã¿ã«çæããŠãããã现ããéšåãèªåã§ä¿®æ£ãããããããšã§ããªãå¹çåã§ãããšæããŸãã æ¢åã®ãã¹ããã¡ã€ã«ã«ã³ãŒããçæããŠæ¬²ããæ¹ã¯ãRecord at cursorããã¯ãªãã¯ããŠãã ããã ã³ãŒããçæããŠæ¬²ãããã¡ã€ã«ã®é©åœãªè¡ãéžæããŠãããŸãããã ç«ã¡äžãã£ããã©ãŠã¶ã§æäœãããšãéžæããè¡ã«ã³ãŒããæžãå ããããŠãããŸãã äŸãã°ããç°¡åãªãã¹ããæžãããã®ãã¹ããšåãæäœããããšäžèšã®ãããªã³ãŒãã example.spec.ts ã«çæãããŸããã await page. goto( 'https://www.google.com/' ); await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .click (); await page.getByRole ( 'combobox' , { name: 'æ€çŽ¢' } ) .press ( 'Enter' ); await page.getByRole ( 'link' , { name: 'äŒæ¥ã®æé·ãæ¯æŽããã¯ã©ãŠããµãŒãã¹ | æ ªåŒäŒç€Ÿã©ã¯ã¹ ã©ã¯ã¹ https://www.rakus.co.jp' } ) .click (); æ€çŽ¢æ¬ãžã®æåå
¥åãªã©ãèªèãããŠããŸããããããã¯èªåã§ä»ãè¶³ãã°ãç°¡åã«ãã¹ããäœããŸãã ãšãŠã䟿å©ãªã®ã§ã©ãã©ã䜿ã£ãŠãã ããã ãããã« ä»åã¯PlaywrightãåããŠæžã人ãE2Eã«èå³ãæã£ãŠããæ¹ã«åããŠãç°¡åãªãã¹ãã®äŸãš æ¡åŒµæ©èœ ã«ã€ããŠã玹ä»ãããŠããã ããŸããã Playwrightã¯çŽæçã«ãã¹ããæžãããšãã§ããã®ã§åããŠã®äººã§ãããã«é£ã³ã€ãããšãã§ããã³ãŒããžã§ãã¬ãŒã¿ãšçµã¿åãããããšã§é«éã«ãã¹ãã³ãŒããçã¿åºãããšãå¯èœã§ãã ãŸã ãŸã 玹ä»ããŠããªãæ©èœããããŸãã®ã§ã å
¬åŒãµã€ã ãèŠãŠããã ãã°ãªãšæããŸãã ãšãŠãé·ãèšäºã«ãªããŸãããããããŸã§èªãã§ãã ãã£ãæ¹ãããããšãããããŸãã ãããæ©ã«Playwrightã䜿ã£ãŠããã ããã°ããšãŠãå¬ããã§ãã