refactor(transit): isolate native rendering from playback

This commit is contained in:
German Khokhlov committed 2026-10-29 17:12:18 +04:00
1 parent 694616d5c2
commit b8560e5b26
21 files changed
+465 -256

No files matched your search

+2
View File
@@ -828,6 +828,8 @@
"src/layers/transit/policy.js",
"src/layers/transit/queries.js",
"src/layers/transit/rendering.js",
"src/layers/transit/render/cesium.js",
"src/layers/transit/render/cesium.test.mjs",
"src/layers/transit/selection.js",
"src/layers/transit/state.js",
"src/layers/transit/testing.js",
+6 -6
View File
@@ -2459,6 +2459,7 @@
"src/data/transitPresetStyle.js",
"src/layers/transit/controls.js",
"src/layers/transit/height.js",
"src/layers/transit/render/cesium.js",
"src/layers/transit/index.js",
"src/layers/transit/ingestion.js",
"src/layers/transit/lifecycle.js",
@@ -3172,6 +3173,7 @@
"src/data/transitPresetStyle.js",
"src/layers/transit/controls.js",
"src/layers/transit/height.js",
"src/layers/transit/render/cesium.js",
"src/layers/transit/index.js",
"src/layers/transit/ingestion.js",
"src/layers/transit/lifecycle.js",
@@ -3848,6 +3850,8 @@
"src/data/transitProxy.js",
"src/layers/transit/controls.js",
"src/layers/transit/height.js",
"src/layers/shared/color.js",
"src/layers/transit/render/cesium.js",
"src/layers/transit/index.js",
"src/layers/transit/ingestion.js",
"src/layers/transit/lifecycle.js",
@@ -3903,14 +3907,13 @@
"transit-layer": {
"exports": ["./layers/transit"],
"modules": [
"src/data/iconOrientation.js",
"src/data/render/cesiumProjection.js",
"src/data/inputOwnership.js",
"src/data/transitFeeds.js",
"src/data/transitIcons.js",
"src/data/transitPresetStyle.js",
"src/layers/transit/controls.js",
"src/layers/transit/height.js",
"src/layers/shared/color.js",
"src/layers/transit/index.js",
"src/layers/transit/ingestion.js",
"src/layers/transit/lifecycle.js",
@@ -3921,10 +3924,8 @@
"src/layers/transit/state.js",
"src/layers/transit/testing.js",
"src/layers/transit/viewport.js",
"src/data/cameraSensitivity.js",
"src/data/contactPlayback.js",
"src/data/contactTrailRenderer.js",
"src/data/render/cesiumContactTrailRenderer.js",
"src/data/transitProxy.js",
"src/data/gtfsRealtime.js",
"src/layers/transit/trails.js",
@@ -3952,8 +3953,7 @@
"src/geo/check.js",
"src/geo/debug.js",
"src/geo/developerError.js",
"src/globe/contract.js",
"src/globe/cesium/engineFromViewer.js"
"src/globe/contract.js"
],
"external": ["cesium", "pbf"]
},
+10
View File
@@ -1,3 +1,13 @@
export function transitQaBase(value) {
if (!value) throw new Error('Transit QA requires an explicit QA_BASE_URL');
const url = new URL(value);
if (
['4173', '4185', '4186', '4187', '4188', '4189', '4194'].includes(url.port)
)
throw new Error('Transit QA may not use a reserved port');
return url.href.replace(/\/$/, '');
}
/** Bound page promises as well as CDP itself; labels identify a stalled section. */
export function boundPageEvaluations(page, defaultTimeoutMs = 30000) {
const evaluate = page.evaluate.bind(page);
+10 -1
View File
@@ -1,15 +1,24 @@
import puppeteer from 'puppeteer';
import { blockPaidQaMaps } from './qa-map-policy.mjs';
import { transitQaBase } from './qa-transit-browser.mjs';
/** Prove parked and moving headings in the real scene, without live feeds. */
export async function runTransitHeadingRegression(base, check) {
base = transitQaBase(base);
const browser = await puppeteer.launch({
headless: true,
executablePath:
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
args: ['--no-sandbox', '--disable-background-timer-throttling'],
args: [
'--no-sandbox',
'--disable-background-timer-throttling',
'--use-angle=metal',
'--enable-gpu',
],
});
try {
const page = await browser.newPage();
await blockPaidQaMaps(page);
await page.setViewport({ width: 1280, height: 800 });
await page.goto(
`${base}/?welcome=0#lat=42.3601&lon=-71.0589&alt=1200&heading=0&pitch=-90`,
+7 -2
View File
@@ -2,21 +2,26 @@
import puppeteer from 'puppeteer';
import { mkdir, writeFile } from 'node:fs/promises';
import { reduceTrailPixels } from '../src/layers/transit/qaMetrics.js';
import { blockPaidQaMaps } from './qa-map-policy.mjs';
import { transitQaBase } from './qa-transit-browser.mjs';
const base = process.env.QA_BASE_URL || 'http://localhost:4305';
const base = transitQaBase(process.env.QA_BASE_URL);
const shots = process.env.QA_SHOTS || 'qa-shots/transit-recovery';
await mkdir(shots, { recursive: true });
const browser = await puppeteer.launch({
headless: process.env.QA_HEADFUL === '1' ? false : true,
headless: true,
executablePath:
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
args: [
'--use-angle=metal',
'--enable-gpu',
'--disable-background-timer-throttling',
'--disable-renderer-backgrounding',
],
});
try {
const page = await browser.newPage();
await blockPaidQaMaps(page);
await page.setViewport({ width: 1920, height: 1080 });
const errors = [];
page.on('pageerror', (error) => errors.push(error.message));
+10 -4
View File
@@ -6,6 +6,7 @@ import {
restoreRetainedTransit,
sampleTransitPixels,
readTransitFleetStyle,
transitQaBase,
} from './qa-transit-browser.mjs';
import {
BOSTON,
@@ -22,7 +23,7 @@ import {
/**
* Browser proof for the Transit layer against a running app.
*
* npm run qa:transit (defaults to http://localhost:4173)
* QA_BASE_URL=http://localhost:4305 npm run qa:transit
* QA_BASE_URL=http://localhost:4305 node scripts/qa-transit.mjs
*
* Drives the real layer toggle and the real CONTEXT chooser, watches the real
@@ -36,6 +37,7 @@ import {
*/
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import puppeteer from 'puppeteer';
import { blockPaidQaMaps } from './qa-map-policy.mjs';
import { createTransitHistory } from '../server/providers/transitHistory.js';
import { DETECTION_THEME_MAP } from '../src/overlays/worldOverlayTokens.js';
import { transitModeTier } from '../src/data/transitPresetStyle.js';
@@ -50,9 +52,9 @@ import {
reduceFleet,
} from '../src/layers/transit/qaMetrics.js';
const BASE = process.env.QA_BASE_URL || 'http://localhost:4173';
const BASE = transitQaBase(process.env.QA_BASE_URL);
const SHOTS = process.env.QA_SHOTS || 'qa-shots/transit';
const TAG = process.env.QA_TAG || 'keyed';
const TAG = process.env.QA_TAG || 'keyless';
/** Which sections to run: all, or a comma list of cities,playback,disable,context. */
const SECTIONS = new Set((process.env.QA_SECTIONS || 'all').split(','));
const runs = (section) => SECTIONS.has('all') || SECTIONS.has(section);
@@ -260,12 +262,14 @@ historyProbe.clear();
await mkdir(SHOTS, { recursive: true });
const browser = await puppeteer.launch({
headless: process.env.QA_HEADFUL === '1' ? false : true,
headless: true,
protocolTimeout: 150000,
executablePath:
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
args: [
'--no-sandbox',
'--use-angle=metal',
'--enable-gpu',
'--disable-background-timer-throttling',
'--disable-renderer-backgrounding',
'--window-size=1920,1080',
@@ -273,6 +277,7 @@ const browser = await puppeteer.launch({
],
});
const page = await browser.newPage();
await blockPaidQaMaps(page);
boundPageEvaluations(page);
await page.setViewport({ width: 1920, height: 1080 });
const pageErrors = [];
@@ -1018,6 +1023,7 @@ try {
if (runs('history')) {
console.log('\n== retained history reload ==');
const recovery = await browser.newPage();
await blockPaidQaMaps(recovery);
boundPageEvaluations(recovery);
try {
await recovery.goto(view(BOSTON), { waitUntil: 'domcontentloaded' });