-
Notifications
You must be signed in to change notification settings - Fork 7
test: e2e foundation (chromium限定化 + helper関数拡充) #489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,155 @@ | ||
| import { Page } from '@playwright/test'; | ||
| // テスト用の設定 | ||
|
|
||
| export const TEST_URL = 'http://localhost:3000/e2e'; | ||
| export const LOAD_TIMEOUT = 5000; | ||
|
|
||
| // ヘルパー関数 | ||
| /** 地図コンテナと canvas の出現を待つ。既存テスト互換。 */ | ||
| export async function waitForMapLoad(page: Page, selector = '.geolonia') { | ||
| // 地図コンテナの存在を確認 | ||
| await page.waitForSelector(selector); | ||
| // Maplibreのcanvasが表示されるまで待機 | ||
| await page.waitForSelector(`${selector} canvas`, { timeout: LOAD_TIMEOUT }); | ||
| } | ||
|
|
||
| /** Maplibre Map の load + isStyleLoaded を待つ。スタイル依存テスト向け。 */ | ||
| export async function waitForStyleLoad(page: Page, selector = '#map') { | ||
| await page.waitForFunction( | ||
| (sel) => { | ||
| const el = document.querySelector(sel) as any; | ||
| return !!(el && el.geoloniaMap && el.geoloniaMap.loaded() && el.geoloniaMap.isStyleLoaded()); | ||
| }, | ||
| selector, | ||
| { timeout: LOAD_TIMEOUT }, | ||
| ); | ||
| } | ||
|
|
||
| /** container.geoloniaMap が生成済みか確認。 */ | ||
| export async function hasMapInstance(page: Page, selector = '#map'): Promise<boolean> { | ||
| return page.evaluate((sel) => { | ||
| const el = document.querySelector(sel) as any; | ||
| return !!(el && el.geoloniaMap); | ||
| }, selector); | ||
| } | ||
|
|
||
| export async function getCenter(page: Page, selector = '#map'): Promise<{ lat: number; lng: number }> { | ||
| return page.evaluate((sel) => { | ||
| const el = document.querySelector(sel) as any; | ||
| const c = el.geoloniaMap.getCenter(); | ||
| return { lat: c.lat, lng: c.lng }; | ||
| }, selector); | ||
| } | ||
|
|
||
| export async function getZoom(page: Page, selector = '#map'): Promise<number> { | ||
| return page.evaluate((sel) => { | ||
| const el = document.querySelector(sel) as any; | ||
| return el.geoloniaMap.getZoom(); | ||
| }, selector); | ||
| } | ||
|
|
||
| export async function getBearing(page: Page, selector = '#map'): Promise<number> { | ||
| return page.evaluate((sel) => { | ||
| const el = document.querySelector(sel) as any; | ||
| return el.geoloniaMap.getBearing(); | ||
| }, selector); | ||
| } | ||
|
|
||
| export async function getPitch(page: Page, selector = '#map'): Promise<number> { | ||
| return page.evaluate((sel) => { | ||
| const el = document.querySelector(sel) as any; | ||
| return el.geoloniaMap.getPitch(); | ||
| }, selector); | ||
| } | ||
|
|
||
| export async function getStyleLayerIds(page: Page, selector = '#map'): Promise<string[]> { | ||
| return page.evaluate((sel) => { | ||
| const el = document.querySelector(sel) as any; | ||
| return el.geoloniaMap.getStyle().layers.map((l: any) => l.id); | ||
| }, selector); | ||
| } | ||
|
|
||
| export async function hasLayer(page: Page, layerId: string, selector = '#map'): Promise<boolean> { | ||
| return page.evaluate( | ||
| ({ sel, id }) => { | ||
| const el = document.querySelector(sel) as any; | ||
| return !!el.geoloniaMap.getLayer(id); | ||
| }, | ||
| { sel: selector, id: layerId }, | ||
| ); | ||
| } | ||
|
|
||
| export async function hasSource(page: Page, sourceId: string, selector = '#map'): Promise<boolean> { | ||
| return page.evaluate( | ||
| ({ sel, id }) => { | ||
| const el = document.querySelector(sel) as any; | ||
| return !!el.geoloniaMap.getSource(id); | ||
| }, | ||
| { sel: selector, id: sourceId }, | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Geolonia のスタイル/タイル/スプライト等を最小レスポンスでモックする。 | ||
| * テスト先頭の beforeEach で呼ぶ前提。 | ||
| * | ||
| * 返すスタイルは layers=[background] のみのミニマル style v8。 | ||
| * 認証URL検証など transformRequest の挙動は実リクエスト前にここで握る。 | ||
| */ | ||
| export async function mockGeoloniaTiles(page: Page) { | ||
| // スタイル JSON (cdn.geolonia.com/style/...) | ||
| await page.route(/cdn\.geolonia\.com\/style\/.+\.json/, (route) => | ||
| route.fulfill({ | ||
| status: 200, | ||
| contentType: 'application/json', | ||
| body: JSON.stringify({ | ||
| version: 8, | ||
| sources: {}, | ||
| layers: [ | ||
| { id: 'background', type: 'background', paint: { 'background-color': '#cccccc' } }, | ||
| ], | ||
| }), | ||
| }), | ||
| ); | ||
|
|
||
| // スプライト / グリフ / フォント関連は 404 でよい (background のみなので参照されない) | ||
| await page.route(/cdn\.geolonia\.com\/(sprite|glyph|font)/, (route) => | ||
| route.fulfill({ status: 404, body: '' }), | ||
| ); | ||
|
|
||
| // TileJSON | ||
| await page.route(/tileserver\.geolonia\.com\/.*/, (route) => | ||
| route.fulfill({ | ||
| status: 200, | ||
| contentType: 'application/json', | ||
| body: JSON.stringify({ | ||
| tilejson: '2.2.0', | ||
| tiles: ['https://tiles.geolonia.com/{z}/{x}/{y}.pbf'], | ||
| minzoom: 0, | ||
| maxzoom: 14, | ||
| }), | ||
| }), | ||
| ); | ||
|
|
||
| // ベクトルタイル | ||
| await page.route(/\.tiles\.geolonia\.com\/.*\.pbf/, (route) => | ||
| route.fulfill({ status: 204, body: '' }), | ||
| ); | ||
|
|
||
| // api.geolonia.com (legacy / permission check 等) | ||
| await page.route(/api\.geolonia\.com\/.*/, (route) => | ||
| route.fulfill({ status: 200, contentType: 'application/json', body: '{}' }), | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * 指定 predicate にマッチしたリクエスト URL を記録する。 | ||
| * 呼び出し時点で配列を返し、以降の page 操作中に push される。 | ||
| * 認証パラメータ注入の検証などに使用。 | ||
| */ | ||
| export function recordRequests( | ||
| page: Page, | ||
| predicate: (url: string) => boolean = () => true, | ||
| ): string[] { | ||
| const urls: string[] = []; | ||
| page.on('request', (req) => { | ||
| if (predicate(req.url())) urls.push(req.url()); | ||
| }); | ||
| return urls; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /** | ||
| * PR0 sanity-check: helper.ts のヘルパー群が機能していることを確認する最小テスト。 | ||
| * 後続フェーズで具体的なテストが充実したら削除してよい。 | ||
| */ | ||
| import { test, expect } from '@playwright/test'; | ||
| import { | ||
| TEST_URL, | ||
| mockGeoloniaTiles, | ||
| waitForStyleLoad, | ||
| hasMapInstance, | ||
| getStyleLayerIds, | ||
| recordRequests, | ||
| } from './helper'; | ||
|
|
||
| test.describe('PR0 helper sanity', () => { | ||
| test('mockGeoloniaTiles を適用すると minimal style だけが読み込まれる', async ({ page }) => { | ||
| await mockGeoloniaTiles(page); | ||
| await page.goto(`${TEST_URL}/nocontrol.html`); | ||
| await waitForStyleLoad(page); | ||
|
|
||
| expect(await hasMapInstance(page)).toBe(true); | ||
| const layers = await getStyleLayerIds(page); | ||
| expect(layers).toEqual(['background']); | ||
| }); | ||
|
|
||
| test('recordRequests で geolonia 系へのリクエストを観測できる', async ({ page }) => { | ||
| await mockGeoloniaTiles(page); | ||
| const styleRequests = recordRequests(page, (url) => url.includes('cdn.geolonia.com/style/')); | ||
| await page.goto(`${TEST_URL}/nocontrol.html`); | ||
| await waitForStyleLoad(page); | ||
|
|
||
| expect(styleRequests.length).toBeGreaterThan(0); | ||
| expect(styleRequests[0]).toMatch(/cdn\.geolonia\.com\/style\/.+\.json/); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.