同步 sgs-frontend-mobile 源码
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
lyf
2026-07-27 11:26:01 +08:00
parent 575dca430f
commit 9ea1bfab71
181 changed files with 24395 additions and 5212 deletions

View File

@@ -10,10 +10,33 @@ interface PoiCandidate {
interface GuideDiagnostics {
isInitialModelReady: () => boolean
getFloors: () => Array<{ floorId: string }>
getReport: () => { floorId: string; activeFocusPoiId: string }
getFloors: () => Array<{ floorId: string; label: string }>
getReport: () => {
floorId: string
activeFocusPoiId: string
activeView: 'overview' | 'floor' | 'multi'
visibleVisualMarkerWithoutTextCount: number
}
resetToViewBaseline: (options: { view: 'floor'; floorId: string; reason: 'floor-reset' }) => Promise<unknown>
switchFloor: (floorId: string) => Promise<unknown>
showMultiFloor: () => Promise<unknown>
getFloorPois: (floorId: string) => Promise<PoiCandidate[]>
getVisiblePoiScreenPositions: () => Array<{
poiId: string
screen: { x: number; y: number }
}>
getPoiFocusState: (poiId?: string) => {
poiId: string
selectedPoiId: string
dataTier: 'fast' | 'full' | null
focusStartedDataTier: 'fast' | 'full' | null
markerCount: number
displayPositionCount: number
baseAffordanceCount: number
pulseAffordanceCount: number
glowAffordanceCount: number
modelHighlightRootCount: number
}
focusTargetPoi: (request: PoiCandidate & { requestId: string }) => Promise<unknown>
clearTargetFocus: () => void
}
@@ -27,12 +50,57 @@ const openGuide = async (page: Page) => {
)), { timeout: 180_000 }).toBe(true)
}
const resetToActiveFloor = async (page: Page) => page.evaluate(async () => {
const resetToFloorWithLandmarkLabels = async (page: Page) => page.evaluate(async () => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
await api.resetToViewBaseline({ view: 'floor', floorId: api.getReport().floorId, reason: 'floor-reset' })
return api.getReport().floorId
for (const floor of api.getFloors()) {
const pois = await api.getFloorPois(floor.floorId)
const hasLandmark = pois.some((poi) => poi.primaryCategory.startsWith('exhibition_hall'))
if (!hasLandmark) continue
await api.resetToViewBaseline({ view: 'floor', floorId: floor.floorId, reason: 'floor-reset' })
return floor.floorId
}
throw new Error('No floor contains landmark POIs')
})
const resetToB2WithDuplicatedBusinessName = async (page: Page) => page.evaluate(async () => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
const floor = api.getFloors().find((candidate) => candidate.label === 'B2')
if (floor) {
await api.resetToViewBaseline({ view: 'floor', floorId: floor.floorId, reason: 'floor-reset' })
return floor.floorId
}
throw new Error('B2 landmark floor is unavailable')
})
const resetToFloorByLabel = async (page: Page, label: string) => page.evaluate(async (floorLabel) => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
const floor = api.getFloors().find((candidate) => candidate.label === floorLabel)
if (!floor) throw new Error(`Floor ${floorLabel} is unavailable`)
await api.resetToViewBaseline({ view: 'floor', floorId: floor.floorId, reason: 'floor-reset' })
return floor.floorId
}, label)
test('uses the current backend name for the exterior Honghuatan Road label', async ({ page }) => {
await openGuide(page)
const roadLabel = page.locator(
'[data-poi-label-kind="ambient"][data-poi-id="overview-honghua-road"]:visible'
)
await expect(roadLabel).toBeVisible({ timeout: 30_000 })
await expect(roadLabel.locator('.three-poi-dom-label__title')).toHaveText('红花潭路')
await expect(roadLabel.locator('.three-poi-dom-label__icon')).toHaveAttribute('data-poi-icon', 'road')
})
for (const deviceScaleFactor of [1, 3]) {
@@ -41,18 +109,49 @@ for (const deviceScaleFactor of [1, 3]) {
test('renders measured native labels and clears focused labels without residue', async ({ page }, testInfo) => {
await openGuide(page)
const floorId = await resetToActiveFloor(page)
const floorId = await resetToFloorWithLandmarkLabels(page)
await expect.poll(async () => page.evaluate(() => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getPoiFocusState().dataTier || null
)), { timeout: 30_000 }).toBe('full')
// Exterior labels are scene-owned. Once an indoor floor commits, no
// exterior DOM label may survive an earlier asynchronous load.
await expect(page.locator('.three-poi-dom-label--overview')).toHaveCount(0)
const labels = page.locator('[data-poi-label-kind="ambient"]:visible')
await expect(labels.first()).toBeVisible({ timeout: 30_000 })
const hall = page.locator('[data-poi-label-kind="ambient"].three-poi-dom-label--hall:visible').first()
const facility = page.locator('[data-poi-label-kind="ambient"].three-poi-dom-label--service').first()
const markerPositions = new Map<string, { x: number; y: number }>()
;(await page.evaluate(() => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getVisiblePoiScreenPositions() || []
))).forEach((marker) => {
// A merged logical POI can have several physical markers, while its
// single DOM label is anchored to the first (canonical) marker.
if (!markerPositions.has(marker.poiId)) markerPositions.set(marker.poiId, marker.screen)
})
const labelCount = await labels.count()
await expect(labels.first().locator('.three-poi-dom-label__icon')).toBeVisible()
for (let index = 0; index < labelCount; index += 1) {
const label = labels.nth(index)
const poiId = await label.getAttribute('data-poi-id')
const bounds = await label.boundingBox()
const marker = poiId ? markerPositions.get(poiId) : null
if (!bounds || !marker) continue
// Only the one calibrated B2 pair may use a compact screen-only
// offset; all other labels keep their management-calibrated anchor.
expect(Math.abs(bounds.x + bounds.width / 2 - marker.x)).toBeLessThanOrEqual(44)
expect(Math.abs(bounds.y + bounds.height - marker.y)).toBeLessThanOrEqual(25)
await expect(page.locator(`[data-poi-leader-for="${poiId}"]`)).toHaveCount(0)
}
const hall = page.locator('[data-poi-label-kind="ambient"].three-poi-dom-label--landmark:visible').first()
await expect(hall).toBeVisible()
for (const locator of [hall, facility]) {
for (const locator of [hall]) {
await expect(locator).toHaveCSS('pointer-events', 'none')
const fontSize = await locator.evaluate((element) => Number.parseFloat(getComputedStyle(element).fontSize))
expect(fontSize).toBeGreaterThanOrEqual(locator === hall ? 14 : 13)
expect(fontSize).toBeGreaterThanOrEqual(12)
}
for (const locator of [hall]) {
@@ -64,7 +163,7 @@ for (const deviceScaleFactor of [1, 3]) {
expect(box!.y + box!.height).toBeLessThanOrEqual(844)
}
const poiId = await facility.getAttribute('data-poi-id')
const poiId = await hall.getAttribute('data-poi-id')
expect(poiId).toBeTruthy()
await page.evaluate(async ({ floorId: targetFloorId, targetPoiId }) => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
@@ -75,11 +174,12 @@ for (const deviceScaleFactor of [1, 3]) {
await api.focusTargetPoi({ ...poi, requestId: `poi-dom-label-${targetPoiId}` })
}, { floorId, targetPoiId: poiId! })
const focus = page.locator('[data-poi-label-kind="focus"][data-focus-label="active"]')
const focus = page.locator(`[data-poi-label-kind="ambient"][data-poi-id="${poiId}"]`)
await expect(focus).toBeVisible({ timeout: 20_000 })
await expect(focus).toHaveCSS('pointer-events', 'none')
await expect(focus.locator('.three-poi-dom-label__title')).toHaveCSS('font-size', '16px')
await expect(focus.locator('.three-poi-dom-label__meta')).toHaveCSS('font-size', '13px')
await expect(focus).toHaveClass(/three-poi-dom-label--selected/)
await expect(focus.locator('.three-poi-dom-label__title')).toHaveCSS('font-size', '12px')
await expect(focus.locator('.three-poi-dom-label__meta')).toHaveCount(0)
await page.screenshot({ path: testInfo.outputPath(`poi-dom-labels-dpr-${deviceScaleFactor}-focus.png`) })
await page.evaluate(() => {
@@ -87,8 +187,311 @@ for (const deviceScaleFactor of [1, 3]) {
.__GUIDE_3D_VISUAL_STABILITY__
api?.clearTargetFocus()
})
await expect(focus).toHaveCount(0)
await expect(focus).not.toHaveClass(/three-poi-dom-label--selected/)
await page.screenshot({ path: testInfo.outputPath(`poi-dom-labels-dpr-${deviceScaleFactor}-ambient.png`) })
})
test('keeps the B2 landmark pair separate and merges duplicate business labels', async ({ page }, testInfo) => {
await openGuide(page)
await resetToB2WithDuplicatedBusinessName(page)
const vr = page.locator('[data-poi-label-kind="ambient"]', { hasText: 'XR虚拟现实影院' })
const youth = page.locator('[data-poi-label-kind="ambient"]', { hasText: '青少年探索中心' })
await expect(vr).toBeVisible({ timeout: 30_000 })
await expect(youth).toBeVisible({ timeout: 30_000 })
await expect.poll(async () => {
const vrBox = await vr.boundingBox()
const youthBox = await youth.boundingBox()
if (!vrBox || !youthBox) return null
return vrBox.x < youthBox.x + youthBox.width
&& vrBox.x + vrBox.width > youthBox.x
&& vrBox.y < youthBox.y + youthBox.height
&& vrBox.y + vrBox.height > youthBox.y
}, { timeout: 30_000 }).toBe(false)
await expect(page.locator('[data-poi-label-kind="ambient"]:visible', { hasText: '秦匠' })).toHaveCount(1)
const artisan = await page.evaluate(async () => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
const floorId = api.getReport().floorId
return (await api.getFloorPois(floorId)).find((poi) => poi.name === '秦匠') || null
})
expect(artisan).not.toBeNull()
await page.evaluate(async (request) => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api || !request) throw new Error('ThreeMap diagnostics unavailable')
await api.focusTargetPoi({ ...request, requestId: 'poi-dom-label-merged-business' })
}, artisan!)
await expect.poll(async () => page.evaluate(() => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getReport().activeFocusPoiId || ''
))).toBe(artisan!.poiId)
await expect.poll(async () => page.evaluate((poiId) => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getPoiFocusState(poiId).dataTier || null
), artisan!.poiId), { timeout: 30_000 }).toBe('full')
const focusState = await page.evaluate((poiId) => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getPoiFocusState(poiId) || null
), artisan!.poiId)
expect(focusState).toMatchObject({
poiId: artisan!.poiId,
selectedPoiId: artisan!.poiId,
dataTier: 'full',
markerCount: 1,
displayPositionCount: 2,
baseAffordanceCount: 0,
pulseAffordanceCount: 0,
glowAffordanceCount: 0,
modelHighlightRootCount: 2
})
await page.screenshot({ path: testInfo.outputPath(`qinjiang-focus-dpr-${deviceScaleFactor}.png`) })
})
})
}
test('keeps floor ambient labels scene-owned across floor, multi, and floor transitions', async ({ page }) => {
test.setTimeout(240_000)
await openGuide(page)
const floorId = await resetToFloorWithLandmarkLabels(page)
const ambientLabels = page.locator('[data-poi-label-kind="ambient"]:visible')
await expect(ambientLabels.first()).toBeVisible({ timeout: 30_000 })
await expect.poll(async () => page.evaluate(() => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getReport().visibleVisualMarkerWithoutTextCount ?? -1
))).toBe(0)
await page.evaluate(async () => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
await api.showMultiFloor()
})
await expect.poll(async () => page.evaluate(() => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getReport().activeView || ''
)), { timeout: 120_000 }).toBe('multi')
await expect(ambientLabels).toHaveCount(0)
await page.waitForTimeout(1500)
await expect(ambientLabels).toHaveCount(0)
await page.evaluate(async (targetFloorId) => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
await api.resetToViewBaseline({ view: 'floor', floorId: targetFloorId, reason: 'floor-reset' })
}, floorId)
await expect(ambientLabels.first()).toBeVisible({ timeout: 30_000 })
const visibleFloorIds = await ambientLabels.evaluateAll((elements) => (
elements.map((element) => (element as HTMLElement).dataset.floorId || '')
))
expect(new Set(visibleFloorIds)).toEqual(new Set([floorId]))
})
test('shows the eleven fresh B2 default destinations after the map floor changes', async ({ page }) => {
test.setTimeout(240_000)
await openGuide(page)
const b2FloorId = await page.evaluate(async () => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
const floor = api.getFloors().find((candidate) => candidate.label === 'B2')
if (!floor) throw new Error('B2 is unavailable')
await api.switchFloor(floor.floorId)
return floor.floorId
})
await expect.poll(async () => page.evaluate(() => {
const report = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getReport()
return report ? `${report.activeView}:${report.floorId}` : ''
}), { timeout: 120_000 }).toBe(`floor:${b2FloorId}`)
await page.locator('.search-box').click()
await expect(page.locator('[data-testid="poi-result-list"] .result-row')).toHaveCount(11, {
timeout: 30_000
})
await expect(page.locator('.result-count')).toContainText('11 处地点')
})
test('merges the four numbered L1 ticket machines across labels, markers, and search', async ({ page }) => {
await openGuide(page)
const l1FloorId = await resetToFloorByLabel(page, '1F')
await expect.poll(async () => page.evaluate(() => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getPoiFocusState('5682').dataTier || null
)), { timeout: 30_000 }).toBe('full')
await expect(page.locator('[data-poi-label-kind="ambient"][data-poi-id="5682"]:visible')).toHaveCount(1, {
timeout: 30_000
})
await expect(page.locator('[data-poi-label-kind="ambient"][data-poi-id="5591"]:visible')).toHaveCount(1)
await expect(page.locator(
'[data-poi-label-kind="ambient"][data-poi-id="352502409978861752"]:visible'
)).toHaveCount(1)
const l1Pois = await page.evaluate(async () => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
const floor = api.getFloors().find((candidate) => candidate.label === '1F')
if (!floor) throw new Error('1F is unavailable')
return api.getFloorPois(floor.floorId)
})
expect(l1Pois.find((poi) => poi.poiId === '5591')?.positionGltf).toEqual([
3.587204,
1.205524,
13.269173
])
const floorExits = [
['floor-exit-2077983437229297849', '展览入口'],
['floor-exit-2077983437229297850', '观众次入口'],
['floor-exit-2077983437229297851', '影剧院入口']
] as const
for (const [poiId, name] of floorExits) {
const exitPoi = l1Pois.find((poi) => poi.poiId === poiId)
expect(exitPoi).toMatchObject({ name, primaryCategory: 'navigation_anchor' })
}
const floorExitStates = await page.evaluate((poiIds) => {
const api = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__
if (!api) throw new Error('ThreeMap diagnostics unavailable')
return poiIds.map((poiId) => api.getPoiFocusState(poiId))
}, floorExits.map(([poiId]) => poiId))
expect(floorExitStates).toEqual(expect.arrayContaining([
expect.objectContaining({ markerCount: 1, displayPositionCount: 1 }),
expect.objectContaining({ markerCount: 1, displayPositionCount: 1 }),
expect.objectContaining({ markerCount: 1, displayPositionCount: 1 })
]))
await expect(page.locator(
'[data-poi-label-kind="ambient"][data-poi-id="floor-exit-2077983437229297849"]:visible'
)).toHaveCount(1)
await expect(page.locator(
'[data-poi-label-kind="ambient"][data-poi-id="floor-exit-2077983437229297851"]:visible'
)).toHaveCount(1)
const markerState = await page.evaluate(() => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getPoiFocusState('5682') || null
))
expect(markerState).toMatchObject({
dataTier: 'full',
markerCount: 4,
displayPositionCount: 4
})
await page.getByTestId('poi-category-ticket-office').first().click()
await expect(page.getByTestId('poi-result-5682')).toHaveCount(1, { timeout: 30_000 })
await expect(page.getByTestId('poi-result-5683')).toHaveCount(0, { timeout: 30_000 })
await expect(page.getByTestId('poi-result-5684')).toHaveCount(0, { timeout: 30_000 })
await expect(page.getByTestId('poi-result-5685')).toHaveCount(0, { timeout: 30_000 })
await expect(page.getByTestId('poi-result-5591')).toHaveCount(1, { timeout: 30_000 })
await expect(page.getByTestId('poi-result-352502409978861752')).toHaveCount(1, { timeout: 30_000 })
await expect(page.getByTestId('poi-result-5682').locator('.result-name')).toHaveText('售票机')
await expect(page.getByTestId('poi-result-5682').locator('.result-meta')).toHaveText('1F · 售票处')
await expect(page.locator('.home-category-results-meta')).toHaveText('当前楼层 1F · 3 处地点')
await expect(page.locator('.floor-switcher')).toBeVisible()
await expect(page.locator('.clear-button')).toHaveCount(0)
await expect(page.getByTestId('poi-category-cancel')).toHaveCount(1)
await page.locator('canvas').hover()
await page.mouse.wheel(0, 3000)
await expect.poll(async () => page.evaluate(() => {
const report = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getReport()
return report ? `${report.activeView}:${report.floorId}` : ''
}), { timeout: 30_000 }).toBe(`floor:${l1FloorId}`)
await expect(page.locator('.floor-switcher')).toBeVisible()
await expect(page.locator('.home-category-results-meta')).toHaveText('当前楼层 1F · 3 处地点')
})
test('keeps the floor mode toggle light while committing multi and single views', async ({ page }) => {
await openGuide(page)
const l1FloorId = await resetToFloorByLabel(page, '1F')
const floorHeader = page.locator('.floor-header')
await page.getByTestId('poi-category-ticket-office').first().click()
await expect(page.getByTestId('poi-result-5682')).toBeVisible({ timeout: 30_000 })
await expect(floorHeader).toBeVisible({ timeout: 30_000 })
await expect(floorHeader.locator('.floor-header-label')).toHaveText('多层')
const singleLayout = await floorHeader.evaluate((element) => {
const icon = element.querySelector('.floor-header-icon')?.getBoundingClientRect()
const label = element.querySelector('.floor-header-label')?.getBoundingClientRect()
if (!icon || !label) return null
return {
iconBottom: icon.bottom,
labelTop: label.top,
iconCenter: icon.left + icon.width / 2,
labelCenter: label.left + label.width / 2
}
})
expect(singleLayout).not.toBeNull()
expect(singleLayout!.iconBottom).toBeLessThanOrEqual(singleLayout!.labelTop)
expect(Math.abs(singleLayout!.iconCenter - singleLayout!.labelCenter)).toBeLessThan(1)
await floorHeader.click()
await expect.poll(async () => page.evaluate(() => (
(window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getReport().activeView || ''
)), { timeout: 120_000 }).toBe('multi')
await expect(floorHeader).toHaveClass(/active/)
await expect(floorHeader.locator('.floor-header-label')).toHaveText('单层')
await expect(floorHeader).toHaveCSS('background-color', 'rgb(237, 241, 255)')
await page.getByTestId('poi-category-cancel').click()
await expect(page.locator('.home-category-results')).toHaveCount(0)
await expect(floorHeader).toBeVisible()
await floorHeader.click()
await expect.poll(async () => page.evaluate(() => {
const report = (window as Window & { __GUIDE_3D_VISUAL_STABILITY__?: GuideDiagnostics })
.__GUIDE_3D_VISUAL_STABILITY__?.getReport()
return report ? `${report.activeView}:${report.floorId}` : ''
}), { timeout: 120_000 }).toBe(`floor:${l1FloorId}`)
await expect(floorHeader).not.toHaveClass(/active/)
await expect(floorHeader.locator('.floor-header-label')).toHaveText('多层')
await expect(floorHeader).toHaveCSS('background-color', 'rgb(255, 255, 255)')
})
test('uses one visual specification for landmark and service labels', async ({ page }) => {
await openGuide(page)
await resetToFloorByLabel(page, '1F')
await expect.poll(async () => page.locator(
'[data-poi-label-kind="ambient"]:visible'
).count(), { timeout: 30_000 }).toBeGreaterThan(3)
const metrics = await page.locator('[data-poi-label-kind="ambient"]:visible').evaluateAll((elements) => (
elements.map((element) => {
const icon = element.querySelector('.three-poi-dom-label__icon')
const style = window.getComputedStyle(element)
const iconStyle = icon ? window.getComputedStyle(icon) : null
return {
height: element.getBoundingClientRect().height,
fontSize: style.fontSize,
lineHeight: style.lineHeight,
iconWidth: iconStyle?.width || '',
iconHeight: iconStyle?.height || ''
}
})
))
expect(metrics).toEqual(expect.arrayContaining([
expect.objectContaining({ height: 22, fontSize: '12px', lineHeight: '15px', iconWidth: '16px', iconHeight: '16px' })
]))
for (const metric of metrics) {
expect(metric).toEqual({
height: 22,
fontSize: '12px',
lineHeight: '15px',
iconWidth: '16px',
iconHeight: '16px'
})
}
})