Skip to content
niryuu edited this page May 25, 2026 · 2 revisions

E2E テスト拡充計画

issue #411「テストを追加する」の umbrella issue を親として、E2E を段階的に拡充する計画。PR #489 (foundation) はマージ済みで以降のフェーズはこれを土台とする。

現状 (master 時点)

テストファイル (4 spec / 10 ケース)

ファイル テスト数 内容
e2e/basic.spec.ts 4 基本表示・デフォルト中心・コンソールエラー無し・Shadow DOM 内 Attribution
e2e/map.spec.ts 2 nocontrol で地図生成・WebGL ピクセル検証
e2e/external-style.spec.ts 2 外部スタイル URL 表示・リクエスト検証
e2e/sample.spec.ts 2 PR0 helper sanity check (mockGeoloniaTiles, recordRequests)

HTML ページ (4 ファイル)

ファイル 用途
docs/e2e/basic.html scriptタグの API キー、.geolonia クラス
docs/e2e/data-key.html data-key 属性での API キー (現状未使用)
docs/e2e/nocontrol.html 全コントロール無効
docs/e2e/external-style.html 外部スタイル URL

ヘルパー (e2e/helper.ts)

PR #489 で導入された関数群:

export const TEST_URL = 'http://localhost:3000/e2e';
export const LOAD_TIMEOUT = 5000;

export async function waitForMapLoad(page, selector?);
export async function waitForStyleLoad(page, selector?);
export async function hasMapInstance(page, selector?): Promise<boolean>;
export async function getCenter(page, selector?): Promise<{lat, lng}>;
export async function getZoom(page, selector?): Promise<number>;
export async function getBearing(page, selector?): Promise<number>;
export async function getPitch(page, selector?): Promise<number>;
export async function getStyleLayerIds(page, selector?): Promise<string[]>;
export async function hasLayer(page, layerId, selector?): Promise<boolean>;
export async function hasSource(page, sourceId, selector?): Promise<boolean>;
export async function mockGeoloniaTiles(page): Promise<void>;
export function recordRequests(page, predicate?): string[];

Playwright 設定

  • playwright.config.ts: chromium のみ (firefox / webkit は削除済み)
  • 理由: embed は maplibre-gl の薄いラッパーであり、クロスブラウザ互換は maplibre 本体のテストに委ねる。e2e は iteration 速度を優先

CI

#480 (Merge PR geolonia/embed/ci/add-e2e-tests) で CI に E2E ジョブ追加済み。publish / deploy にも組み込まれている。reporter は list (CI 用)。

カバーされていない領域

ユニットテスト + 現状の E2E でカバーされていない/弱い領域:

モジュール 主要未カバー機能
geolonia-map.ts (430行) data-* 属性別の挙動、transformRequest、コントロール、マーカー、ポップアップ、3D、ジェスチャー、エラーハンドリング
render.ts (122行) DOM 走査、lazy-loading、プラグイン、MutationObserver クリーンアップ
simplestyle-vector.ts (257行) ベクトルタイル描画全般
embed-core.ts (23行) プログラム的利用、new GeoloniaMap()

拡充計画 (P0〜P3、約 57 追加ケース)

Phase 1 (P0): 基本機能 — 21 ケース

#1 data-* 属性による地図設定 (e2e/data-attributes.spec.ts)

HTML: docs/e2e/data-attributes.html (新規)

# テスト 検証
1.1 data-lat / data-lng で中心座標 map.getCenter() 一致
1.2 data-zoom map.getZoom() 一致
1.3 data-min-zoom / data-max-zoom ズーム範囲制限
1.4 data-bearing / data-pitch 回転・傾き
1.5 data-hash="on" URL hash に座標反映
1.6 data-lang でスタイル言語切替 スタイル URL に言語パラメータ
1.7 data-style で Geolonia スタイル名指定 論理名が CDN URL に解決
1.8 data-key で API キー指定 タイルリクエストにキー含む

#2 マーカーとポップアップ (e2e/marker-popup.spec.ts)

HTML: docs/e2e/marker.html, docs/e2e/popup.html (新規)

# テスト 検証
2.1 デフォルトマーカー表示 (data-marker="on") .maplibregl-marker 要素
2.2 マーカー非表示 (data-marker="off") 要素なし
2.3 カスタムマーカー色 (data-marker-color) SVG fill 色一致
2.4 ポップアップ表示 (data-open-popup="on") ロード時にポップアップ開く
2.5 ポップアップ内容 (innerHTML content) popup 内に HTML 表示
2.6 マーカークリックでポップアップ開閉 toggle 動作

#3 コントロール (e2e/controls.spec.ts)

HTML: docs/e2e/controls.html (新規)

# テスト 検証
3.1 デフォルトでナビゲーション表示 .maplibregl-ctrl-zoom-in 存在
3.2 data-navigation-control="off" で非表示 要素なし
3.3 data-fullscreen-control="on" フルスクリーンボタン
3.4 data-scale-control="on" スケールバー
3.5 data-geolocate-control="on" 位置情報ボタン
3.6 コントロール位置指定 (top-left 等) 指定位置に配置
3.7 GeoloniaControl にロゴ表示 .geolonia-ctrl 内に img

Phase 2 (P1): 認証とデータ — 12 ケース

#4 API キー認証 (e2e/authentication.spec.ts)

HTML: docs/e2e/auth-missing-key.html (新規)

# テスト 検証
4.1 scriptタグから API キー取得 タイル URL に key=
4.2 data-key 属性で上書き data-key の値が使用される
4.3 sessionId 付与 URL に sessionId=
4.4 外部 URL にはキー付与しない 外部タイル URL に key/session なし

#5 GeoJSON / SimpleStyle (e2e/geojson.spec.ts)

HTML: docs/e2e/geojson-inline.html, docs/e2e/geojson-url.html (新規)

# テスト 検証
5.1 data-geojson URL で読込 source / layer 追加
5.2 インライン GeoJSON (CSS selector) 要素から取得・描画
5.3 クラスタ表示 (data-cluster="on") クラスタレイヤ存在
5.4 ポイントクリックで popup description 表示
5.5 GeoJSON 取得失敗時 console error あるが crash しない

#6 ベクトルタイル (e2e/vector-tiles.spec.ts)

HTML: docs/e2e/simple-vector.html (新規)

# テスト 検証
6.1 data-simple-vector で読込 ベクトルソース追加
6.2 自動ズーム (fitBounds) bounds 調整
6.3 フィーチャークリックで popup popup 表示

Phase 3 (P2): ライフサイクル — 8 ケース

#7 遅延読み込み (e2e/lazy-loading.spec.ts)

HTML: docs/e2e/lazy-loading.html (新規)

# テスト 検証
7.1 data-lazy-loading="on" (default) でビューポート外未初期化 スクロール前 canvas なし
7.2 スクロール後初期化 canvas 出現
7.3 data-lazy-loading="off" で即時初期化 ロード直後 canvas

#8 複数地図 (e2e/multiple-maps.spec.ts)

HTML: docs/e2e/multiple-maps.html (新規)

# テスト 検証
8.1 同一ページに複数 .geolonia 全地図独立描画
8.2 異なるスタイルの地図 各々正しいスタイル使用
8.3 異なる data-* の地図 各々独立設定

#9 ジェスチャーハンドリング (e2e/gesture-handling.spec.ts)

HTML: docs/e2e/gesture.html (新規)

# テスト 検証
9.1 data-gesture-handling="on" でホイールズーム無効 ホイールイベント無視
9.2 data-interactive="off" で全操作無効 drag/zoom/rotate 無効
9.3 Ctrl+ホイールでズーム可能 Ctrl 押下中はズーム動作

Phase 4 (P3): 高度な機能 — 13 ケース

#10 クリーンアップ (e2e/cleanup.spec.ts)

HTML: docs/e2e/cleanup.html (新規)

# テスト 検証
10.1 コンテナを DOM から削除 MutationObserver で map.remove() 発火
10.2 同一コンテナに再初期化しない container.geoloniaMap で重複防止

#11 プログラマティック利用 (e2e/programmatic.spec.ts)

HTML: docs/e2e/programmatic.html (新規、JavaScript で new GeoloniaMap())

# テスト 検証
11.1 new GeoloniaMap('#map') で初期化 描画される
11.2 new GeoloniaMap(element) 描画される
11.3 new GeoloniaMap({container, ...options}) maplibre options 反映
11.4 setStyle() でスタイル切替 動的に変更
11.5 window.geolonia 公開 embed.js 読込後に存在

#12 プラグイン (e2e/plugin.spec.ts)

HTML: docs/e2e/plugin.html (新規)

# テスト 検証
12.1 registerPlugin() 登録 全地図でコールバック発火
12.2 DOMContentLoaded 前の登録 描画後実行
12.3 map, target, atts 受領 引数型・値が正しい

#13 3D レイヤー (e2e/3d-layers.spec.ts)

HTML: docs/e2e/3d.html (新規)

# テスト 検証
13.1 data-3d="on" で pitch 付き pitch ≠ 0
13.2 visible-on-3d メタデータレイヤ visibility: visible
13.3 hide-on-3d メタデータレイヤ visibility: none

ネットワーク戦略

mockGeoloniaTiles(page) の動作

await page.route(/cdn\.geolonia\.com\/style\/.+\.json/, fulfillMinimalStyle);
await page.route(/cdn\.geolonia\.com\/(sprite|glyph|font)/, fulfill404);
await page.route(/tileserver\.geolonia\.com\/.*/, fulfillTileJSON);
await page.route(/(?:[^/]+\.)?tiles\.geolonia\.com\/.*\.pbf/, fulfill204);
await page.route(/api\.geolonia\.com\/.*/, fulfillEmptyJSON);

GEOLONIA_TILE_HOST = 'tiles.geolonia.com' を single source として GEOLONIA_TILE_URL_TEMPLATE と PBF 捕捉 regex を派生 (PR #489 で導入)。

テスト設計の指針

  • 認証パラメータ検証 → recordRequests(page, url => url.includes('key=')) で観測
  • DOM 検証 → page.evaluate でなるべく helper 関数 (hasLayer, getCenter 等) を使う
  • ネットワーク依存テスト → mockGeoloniaTiles を beforeEach で必ず呼ぶ
  • 外部スタイル (OpenStreetMap 等) を含むテストは実ネットワーク前提 (フェイク不可)
  • 3D など maplibre 内部実装に依存するものは、可能なら getLayoutProperty 経由で検証

Issue / PR 分割方針

# Issue / PR 内容 Phase 依存
PR0 (#489) Foundation: chromium 限定化, helper 拡充 (済)
PR1a #1 data-* 属性 Phase 1 PR0 マージ後
PR1b #2 マーカー / popup Phase 1 PR0 マージ後 (PR1a と並行可)
PR1c #3 コントロール Phase 1 PR0 マージ後 (並行可)
PR2a #4 認証 Phase 2 PR0
PR2b #5 GeoJSON Phase 2 PR0
PR2c #6 ベクター Phase 2 PR0
PR3a #10 クリーンアップ Phase 4 → 前倒し PR0
PR3b #11 プログラマティック Phase 4 → 前倒し PR0
PR4 残り (#7, #8, #9, #12, #13) Phase 3, 4 PR0

maps-core 境界で重要な #4 (認証), #11 (プログラマティック), #10 (クリーンアップ) を Phase 2-3 として前倒し。

Issue / PR 運用

  • 各 PR は子 issue を起こして #411 をリンク (例: PR0 は子 issue #488)
  • PR 本文で Closes #<child> / Part of #411
  • commit メッセージで Refs #<child>, #411

chromium 限定方針

PR0 で firefox/webkit を削除 (playwright.config.ts)。理由:

  • embed は maplibre-gl の薄いラッパー → cross-browser 互換は maplibre 本体が担当
  • iteration 速度を 3 倍に
  • E2E のテスト数増加 (57 ケース → chromium のみで ~57 vs 全ブラウザで ~171)

将来必要になったら戻す。

参照

  • Core-vs-Wrapper — maps-core 境界 (どのテストが lib 側で書けるか)
  • Data-Attributes — テストすべき data-* 属性
  • URL-Rewrite-Spec — 認証テストのモック設計
  • Hidden-Spec — 隠れ仕様もテスト網に入れる項目

Clone this wiki locally