fix: la carte détaillée d'un événement débordait sous le canvas au survol
ItemBoardToken._showExpanded() ancrait TOUJOURS la carte détaillée vers le
BAS du jeton compact, quel que soit son emplacement sur le plateau —
adapté aux boutiques d'objets/bâtiments (positionnées en haut du canvas),
mais pas à la main de cartes Événement (positionnée en BAS du canvas,
voir eventHandLayout.js) : la carte (jusqu'à 266px de haut avec le bouton
JOUER) débordait alors largement sous le bas de l'écran, la rendant
invisible et son bouton totalement injoignable au clic.
- Ajout du paramètre vAnchor ('bottom' par défaut, 'top' pour les jetons
proches du bas de l'écran) sur ItemBoardToken, symétrique au hAnchor déjà
existant pour l'axe horizontal. La main d'événements passe désormais
vAnchor='top' pour que la carte s'étende vers le HAUT au lieu du bas.
- Extraction du calcul de décalage (expandedCardOffset) et des constantes
de dimensionnement (EXPANDED_W/H, BUY_BTN_H) dans tokenLayout.js (module
pur, sans dépendance Phaser) pour pouvoir le couvrir par de vrais tests
unitaires Vitest.
- 11 nouveaux tests unitaires (tokenLayout.test.js) : orientation dx/dy
selon hAnchor/vAnchor, alignement exact du bord du jeton avec le bord de
la carte, et surtout la régression elle-même — un test vérifie que
vAnchor='top' maintient la carte dans les limites du canvas pour un
jeton en bas d'écran (1080p et 720p), et qu'un test symétrique confirme
que l'ancien comportement implicite (vAnchor='bottom') débordait bien
sous le canvas dans ce même scénario.
- 54 tests unitaires client au vert au total (43 précédents + 11 nouveaux),
vérification privilégiée par rapport à une nouvelle suite E2E (lente vu
la pioche aléatoire à stabiliser dans ce projet).
This commit is contained in:
1 parent
1a91a0f876
commit
33a3c20dcb
4 files changed
+204
-41
No files matched your search
@@ -1,5 +1,5 @@
|
|||||||
import Phaser from 'phaser'
|
import Phaser from 'phaser'
|
||||||
import { ICON_SIZE } from './tokenLayout'
|
import { ICON_SIZE, EXPANDED_W, EXPANDED_H, BUY_BTN_H, EXPANDED_H_WITH_BTN, expandedCardOffset } from './tokenLayout'
|
||||||
|
|
||||||
const ATTR_COLORS = {
|
const ATTR_COLORS = {
|
||||||
food: 0xf0c030,
|
food: 0xf0c030,
|
||||||
@@ -15,25 +15,18 @@ const ATTR_LABELS = {
|
|||||||
diplo: 'Diplomatie'
|
diplo: 'Diplomatie'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-export pour compatibilité : ICON_SIZE est désormais défini dans
|
// Re-export pour compatibilité : ces constantes/fonctions de géométrie sont
|
||||||
// tokenLayout.js (module pur, sans dépendance Phaser) afin que les modules
|
// désormais définies dans tokenLayout.js (module pur, sans dépendance
|
||||||
// de calcul de géométrie (ex: eventHandLayout.js) puissent l'importer sans
|
// Phaser) afin que les modules de calcul (ex: eventHandLayout.js) et leurs
|
||||||
// jamais charger Phaser — nécessaire pour rester testables en Vitest/jsdom,
|
// tests Vitest puissent les importer sans jamais charger Phaser —
|
||||||
// qui échoue à l'import de Phaser (canvas natif requis, absent de jsdom).
|
// nécessaire car Phaser échoue à l'import en environnement jsdom (canvas
|
||||||
|
// natif requis, absent de jsdom).
|
||||||
export { ICON_SIZE }
|
export { ICON_SIZE }
|
||||||
|
|
||||||
// Taille de la carte détaillée affichée au survol. Volontairement grande et
|
// Hauteur de la zone image dans la carte détaillée (reste local : ne
|
||||||
// avec des polices généreuses pour que la description de l'effet reste
|
// dépend d'aucun calcul de positionnement externe, contrairement aux
|
||||||
// lisible même pour les mini-jetons (mes objets / ceux des adversaires),
|
// constantes ci-dessus).
|
||||||
// qui utilisent un displayScale réduit pour le jeton compact SANS que cela
|
|
||||||
// ne réduise la taille réelle de la carte détaillée (voir _showExpanded).
|
|
||||||
const EXPANDED_W = 190
|
|
||||||
const EXPANDED_H = 230
|
|
||||||
const EXPANDED_IMAGE_H = 110
|
const EXPANDED_IMAGE_H = 110
|
||||||
const BUY_BTN_H = 26
|
|
||||||
|
|
||||||
// La carte agrandie s'allonge pour laisser la place au bouton ACHETER
|
|
||||||
const EXPANDED_H_WITH_BTN = EXPANDED_H + BUY_BTN_H + 10
|
|
||||||
|
|
||||||
// Délai avant de refermer la carte agrandie, pour tolérer le passage de la
|
// Délai avant de refermer la carte agrandie, pour tolérer le passage de la
|
||||||
// souris entre le jeton compact et la carte agrandie sans clignotement.
|
// souris entre le jeton compact et la carte agrandie sans clignotement.
|
||||||
@@ -85,15 +78,24 @@ const HOVER_SHOW_DELAY = 80
|
|||||||
* également sur le bord DROIT) sur le bord DROIT du canvas, sinon la
|
* également sur le bord DROIT) sur le bord DROIT du canvas, sinon la
|
||||||
* carte déborderait hors du canvas et son bouton deviendrait injoignable
|
* carte déborderait hors du canvas et son bouton deviendrait injoignable
|
||||||
* au clic.
|
* au clic.
|
||||||
|
* vAnchor: 'bottom' (défaut) ou 'top'. Détermine de quel côté du jeton
|
||||||
|
* compact la carte détaillée s'étend verticalement au survol. 'bottom' =
|
||||||
|
* la carte s'étend vers le BAS (jeton ancré sur son coin haut) — adapté
|
||||||
|
* aux boutiques d'objets/bâtiments, positionnées en haut du canvas.
|
||||||
|
* 'top' = la carte s'étend vers le HAUT (jeton ancré sur son coin bas) —
|
||||||
|
* nécessaire pour la main de cartes Événement (positionnée en BAS du
|
||||||
|
* canvas), sinon la carte déborderait sous le bas du canvas et resterait
|
||||||
|
* invisible/injoignable au clic.
|
||||||
*/
|
*/
|
||||||
export class ItemBoardToken extends Phaser.GameObjects.Container {
|
export class ItemBoardToken extends Phaser.GameObjects.Container {
|
||||||
constructor(scene, x, y, itemData, status = 'available', affordable = true, displayScale = 1, kind = 'item', hAnchor = 'left') {
|
constructor(scene, x, y, itemData, status = 'available', affordable = true, displayScale = 1, kind = 'item', hAnchor = 'left', vAnchor = 'bottom') {
|
||||||
super(scene, x, y)
|
super(scene, x, y)
|
||||||
this.itemData = itemData
|
this.itemData = itemData
|
||||||
this.status = status
|
this.status = status
|
||||||
this.affordable = affordable
|
this.affordable = affordable
|
||||||
this.kind = kind
|
this.kind = kind
|
||||||
this.hAnchor = hAnchor
|
this.hAnchor = hAnchor
|
||||||
|
this.vAnchor = vAnchor
|
||||||
this._displayScale = displayScale
|
this._displayScale = displayScale
|
||||||
this._expanded = null
|
this._expanded = null
|
||||||
this._hideTimer = null
|
this._hideTimer = null
|
||||||
@@ -275,13 +277,15 @@ export class ItemBoardToken extends Phaser.GameObjects.Container {
|
|||||||
* displayScale du jeton d'où elle a été ouverte (jeton boutique à taille
|
* displayScale du jeton d'où elle a été ouverte (jeton boutique à taille
|
||||||
* normale, ou mini-jeton "posé sur la table" pour moi/les adversaires).
|
* normale, ou mini-jeton "posé sur la table" pour moi/les adversaires).
|
||||||
*
|
*
|
||||||
* Elle est ancrée sur un coin (haut-gauche ou haut-droit selon hAnchor) du
|
* Elle est ancrée sur un coin du jeton compact (dont la taille visuelle
|
||||||
* jeton compact (dont la taille visuelle dépend de displayScale) plutôt
|
* dépend de displayScale) plutôt que centrée dessus, pour rester dans les
|
||||||
* que centrée dessus, pour rester dans les limites du canvas quel que
|
* limites du canvas quel que soit l'emplacement du jeton : horizontalement
|
||||||
* soit l'emplacement du jeton : elle s'étend toujours vers le bas, et
|
* à l'opposé du bord de canvas le plus proche (vers la droite pour la
|
||||||
* horizontalement à l'opposé du bord de canvas le plus proche (vers la
|
* boutique d'objets à gauche, vers la gauche pour la boutique de
|
||||||
* droite pour la boutique d'objets à gauche, vers la gauche pour la
|
* bâtiments à droite — voir hAnchor), et verticalement vers le bas par
|
||||||
* boutique de bâtiments à droite — voir hAnchor).
|
* défaut ('bottom', pour les jetons en haut du canvas) ou vers le haut
|
||||||
|
* ('top', pour la main d'événements en bas du canvas — sinon la carte
|
||||||
|
* déborderait sous le bas du canvas, invisible/injoignable au clic).
|
||||||
*/
|
*/
|
||||||
_showExpanded() {
|
_showExpanded() {
|
||||||
if (this._expanded) return
|
if (this._expanded) return
|
||||||
@@ -293,13 +297,13 @@ export class ItemBoardToken extends Phaser.GameObjects.Container {
|
|||||||
const buildingExtraH = this.kind === 'building' ? 18 : 0
|
const buildingExtraH = this.kind === 'building' ? 18 : 0
|
||||||
const cardH = (isAvailable ? EXPANDED_H_WITH_BTN : EXPANDED_H) + buildingExtraH
|
const cardH = (isAvailable ? EXPANDED_H_WITH_BTN : EXPANDED_H) + buildingExtraH
|
||||||
|
|
||||||
// Demi-taille visuelle réelle du jeton compact (après displayScale) :
|
// Décalage (dx, dy) du centre de la carte par rapport au centre du
|
||||||
// sert à aligner le coin du jeton (gauche ou droit selon hAnchor) sur le
|
// jeton compact — calcul délégué à tokenLayout.js (fonction pure,
|
||||||
// coin correspondant de la carte détaillée, tel qu'il apparaît réellement
|
// couverte par des tests unitaires) pour garantir que le jeton (dont la
|
||||||
// à l'écran.
|
// taille visuelle dépend de displayScale) reste toujours aligné avec le
|
||||||
const iconHalf = (ICON_SIZE * this._displayScale) / 2
|
// coin correspondant de la carte détaillée, tel qu'il apparaît
|
||||||
const dx = (this.hAnchor === 'right' ? -1 : 1) * (EXPANDED_W / 2 - iconHalf)
|
// réellement à l'écran.
|
||||||
const dy = cardH / 2 - iconHalf
|
const { dx, dy } = expandedCardOffset(cardH, this._displayScale, this.hAnchor, this.vAnchor)
|
||||||
|
|
||||||
const attrColor = this._attrColor()
|
const attrColor = this._attrColor()
|
||||||
const c = this.scene.add.container(dx, dy)
|
const c = this.scene.add.container(dx, dy)
|
||||||
|
|||||||
@@ -1,10 +1,44 @@
|
|||||||
/**
|
/**
|
||||||
* Taille du jeton compact utilisé par ItemBoardToken (objets, bâtiments,
|
* Constantes et calculs de géométrie purs pour ItemBoardToken (objets,
|
||||||
* cartes Événement). Extraite dans son propre module SANS dépendance à
|
* bâtiments, cartes Événement), extraits dans leur propre module SANS
|
||||||
* Phaser (contrairement à ItemBoardToken.js qui importe `phaser`), pour
|
* dépendance à Phaser (contrairement à ItemBoardToken.js qui importe
|
||||||
* pouvoir être importée par des modules de calcul de géométrie purs (ex:
|
* `phaser`), pour pouvoir être importés par des modules de calcul de
|
||||||
* eventHandLayout.js) et testée unitairement avec Vitest sans échouer à
|
* géométrie (ex: eventHandLayout.js) et testés unitairement avec Vitest
|
||||||
* charger Phaser dans l'environnement de test (jsdom n'a pas de canvas
|
* sans échouer à charger Phaser dans l'environnement de test (jsdom n'a
|
||||||
* natif, ce que Phaser requiert dès son import).
|
* pas de canvas natif, ce que Phaser requiert dès son import).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Taille du jeton compact affiché en permanence sur le plateau (avant mise
|
||||||
|
// à l'échelle éventuelle via displayScale).
|
||||||
export const ICON_SIZE = 46
|
export const ICON_SIZE = 46
|
||||||
|
|
||||||
|
// Taille de la carte détaillée affichée au survol (voir ItemBoardToken._showExpanded).
|
||||||
|
export const EXPANDED_W = 190
|
||||||
|
export const EXPANDED_H = 230
|
||||||
|
export const BUY_BTN_H = 26
|
||||||
|
|
||||||
|
// La carte agrandie s'allonge pour laisser la place au bouton ACHETER/JOUER.
|
||||||
|
export const EXPANDED_H_WITH_BTN = EXPANDED_H + BUY_BTN_H + 10
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Décalage (dx, dy) du centre de la carte détaillée par rapport au centre
|
||||||
|
* du jeton compact, selon hAnchor/vAnchor. Fonction pure extraite de
|
||||||
|
* ItemBoardToken._showExpanded pour être testée unitairement — notamment la
|
||||||
|
* régression corrigée : avec vAnchor='bottom' (comportement par défaut,
|
||||||
|
* adapté aux jetons en haut du canvas), la carte s'étend TOUJOURS vers le
|
||||||
|
* bas, ce qui la faisait déborder sous le canvas pour les jetons déjà
|
||||||
|
* positionnés en bas d'écran (main de cartes Événement) — d'où l'ajout de
|
||||||
|
* vAnchor='top' pour ces jetons-là.
|
||||||
|
*
|
||||||
|
* @param {number} cardH hauteur réelle de la carte détaillée (dépend de
|
||||||
|
* isAvailable/kind, voir EXPANDED_H / EXPANDED_H_WITH_BTN)
|
||||||
|
* @param {number} displayScale échelle du jeton compact (0 < scale <= 1)
|
||||||
|
* @param {'left'|'right'} hAnchor
|
||||||
|
* @param {'bottom'|'top'} vAnchor
|
||||||
|
*/
|
||||||
|
export function expandedCardOffset(cardH, displayScale, hAnchor = 'left', vAnchor = 'bottom') {
|
||||||
|
const iconHalf = (ICON_SIZE * displayScale) / 2
|
||||||
|
const dx = (hAnchor === 'right' ? -1 : 1) * (EXPANDED_W / 2 - iconHalf)
|
||||||
|
const dy = (vAnchor === 'top' ? -1 : 1) * (cardH / 2 - iconHalf)
|
||||||
|
return { dx, dy }
|
||||||
|
}
|
||||||
@@ -764,7 +764,10 @@ export class GameScene extends Phaser.Scene {
|
|||||||
// hAnchor='right' : la main est ancrée sur le bord DROIT du canvas
|
// hAnchor='right' : la main est ancrée sur le bord DROIT du canvas
|
||||||
// (voir eventHandLayout.js), la carte détaillée doit donc s'étendre
|
// (voir eventHandLayout.js), la carte détaillée doit donc s'étendre
|
||||||
// vers la GAUCHE au survol pour ne jamais déborder hors du canvas.
|
// vers la GAUCHE au survol pour ne jamais déborder hors du canvas.
|
||||||
const token = new ItemBoardToken(this, startX + i * spacing, y, eventData, 'available', true, 1, 'event', 'right')
|
// vAnchor='top' : la main est aussi ancrée en BAS du canvas — sans ce
|
||||||
|
// paramètre, la carte détaillée s'étend vers le bas par défaut et
|
||||||
|
// déborde largement sous le canvas, la rendant invisible/injoignable.
|
||||||
|
const token = new ItemBoardToken(this, startX + i * spacing, y, eventData, 'available', true, 1, 'event', 'right', 'top')
|
||||||
token.on('play', (data) => this._onEventCardPlay(token, data))
|
token.on('play', (data) => this._onEventCardPlay(token, data))
|
||||||
this.eventCards.push(token)
|
this.eventCards.push(token)
|
||||||
})
|
})
|
||||||
@@ -799,7 +802,7 @@ export class GameScene extends Phaser.Scene {
|
|||||||
this.eventCards.forEach(c => c.destroy())
|
this.eventCards.forEach(c => c.destroy())
|
||||||
this.eventCards = eventIds.map((eventId, i) => {
|
this.eventCards = eventIds.map((eventId, i) => {
|
||||||
const eventData = getEventById(eventId)
|
const eventData = getEventById(eventId)
|
||||||
const token = new ItemBoardToken(this, startX + i * spacing, y, eventData, 'available', false, 1, 'event', 'right')
|
const token = new ItemBoardToken(this, startX + i * spacing, y, eventData, 'available', false, 1, 'event', 'right', 'top')
|
||||||
token.on('play', (data) => this._onEventCardPlay(token, data))
|
token.on('play', (data) => this._onEventCardPlay(token, data))
|
||||||
return token
|
return token
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import {
|
||||||
|
ICON_SIZE,
|
||||||
|
EXPANDED_W,
|
||||||
|
EXPANDED_H,
|
||||||
|
BUY_BTN_H,
|
||||||
|
EXPANDED_H_WITH_BTN,
|
||||||
|
expandedCardOffset
|
||||||
|
} from '../../src/game/objects/tokenLayout'
|
||||||
|
|
||||||
|
describe('game/objects/tokenLayout', () => {
|
||||||
|
describe('constantes', () => {
|
||||||
|
it('EXPANDED_H_WITH_BTN est plus grand que EXPANDED_H (place pour le bouton)', () => {
|
||||||
|
expect(EXPANDED_H_WITH_BTN).toBeGreaterThan(EXPANDED_H)
|
||||||
|
expect(EXPANDED_H_WITH_BTN).toBe(EXPANDED_H + BUY_BTN_H + 10)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('expandedCardOffset', () => {
|
||||||
|
const cardH = EXPANDED_H_WITH_BTN
|
||||||
|
|
||||||
|
it('hAnchor="left" (défaut) : la carte s\'étend vers la DROITE (dx positif)', () => {
|
||||||
|
const { dx } = expandedCardOffset(cardH, 1, 'left', 'bottom')
|
||||||
|
expect(dx).toBeGreaterThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('hAnchor="right" : la carte s\'étend vers la GAUCHE (dx négatif)', () => {
|
||||||
|
const { dx } = expandedCardOffset(cardH, 1, 'right', 'bottom')
|
||||||
|
expect(dx).toBeLessThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('vAnchor="bottom" (défaut) : la carte s\'étend vers le BAS (dy positif)', () => {
|
||||||
|
const { dy } = expandedCardOffset(cardH, 1, 'left', 'bottom')
|
||||||
|
expect(dy).toBeGreaterThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('vAnchor="top" : la carte s\'étend vers le HAUT (dy négatif) — régression corrigée', () => {
|
||||||
|
// Bug corrigé : la main de cartes Événement (positionnée en bas du
|
||||||
|
// canvas) utilisait implicitement vAnchor="bottom" (comportement par
|
||||||
|
// défaut, pensé pour les jetons en haut du canvas comme la boutique
|
||||||
|
// d'objets), faisant déborder la carte détaillée sous le bas du
|
||||||
|
// canvas — invisible et injoignable au clic (bouton JOUER inatteignable).
|
||||||
|
const { dy } = expandedCardOffset(cardH, 1, 'left', 'top')
|
||||||
|
expect(dy).toBeLessThan(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('dx et dy ont la même magnitude quel que soit le signe de l\'ancrage (symétrie)', () => {
|
||||||
|
const left = expandedCardOffset(cardH, 1, 'left', 'bottom')
|
||||||
|
const right = expandedCardOffset(cardH, 1, 'right', 'bottom')
|
||||||
|
expect(Math.abs(left.dx)).toBeCloseTo(Math.abs(right.dx), 10)
|
||||||
|
|
||||||
|
const bottom = expandedCardOffset(cardH, 1, 'left', 'bottom')
|
||||||
|
const top = expandedCardOffset(cardH, 1, 'left', 'top')
|
||||||
|
expect(Math.abs(bottom.dy)).toBeCloseTo(Math.abs(top.dy), 10)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('un displayScale réduit rapproche le décalage de 0 (jeton plus petit, moins de compensation nécessaire)', () => {
|
||||||
|
const fullScale = expandedCardOffset(cardH, 1, 'left', 'bottom')
|
||||||
|
const halfScale = expandedCardOffset(cardH, 0.5, 'left', 'bottom')
|
||||||
|
expect(halfScale.dx).toBeGreaterThan(fullScale.dx)
|
||||||
|
expect(halfScale.dy).toBeGreaterThan(fullScale.dy)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('avec displayScale=1, le coin du jeton (ICON_SIZE/2) s\'aligne exactement sur le coin de la carte', () => {
|
||||||
|
// Vérifie la propriété fondamentale de ce calcul : le bord du jeton
|
||||||
|
// compact doit coïncider avec le bord correspondant de la carte
|
||||||
|
// détaillée, sans espace ni chevauchement.
|
||||||
|
const { dx, dy } = expandedCardOffset(cardH, 1, 'left', 'bottom')
|
||||||
|
const iconHalf = ICON_SIZE / 2
|
||||||
|
// hAnchor='left' : le bord gauche du jeton (-iconHalf, relatif au
|
||||||
|
// centre du jeton) coïncide avec le bord gauche de la carte
|
||||||
|
// (dx - EXPANDED_W/2, puisque le container carte est positionné à (dx, dy)).
|
||||||
|
expect(-iconHalf).toBeCloseTo(dx - EXPANDED_W / 2, 10)
|
||||||
|
// vAnchor='bottom' : le bord HAUT du jeton (-iconHalf) coïncide avec
|
||||||
|
// le bord HAUT de la carte (dy - cardH/2) — la carte s'étend vers le
|
||||||
|
// BAS à partir du haut du jeton.
|
||||||
|
expect(-iconHalf).toBeCloseTo(dy - cardH / 2, 10)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('non-régression : carte de la main d\'événements reste dans le canvas (vAnchor="top")', () => {
|
||||||
|
it('pour un jeton positionné en bas du canvas, la carte détaillée (vAnchor="top") ne déborde jamais sous le canvas', () => {
|
||||||
|
const canvasH = 1080
|
||||||
|
const marginBottom = 60
|
||||||
|
const tokenY = canvasH - marginBottom - ICON_SIZE / 2 // même formule que eventHandGeometry
|
||||||
|
|
||||||
|
const { dy } = expandedCardOffset(EXPANDED_H_WITH_BTN, 1, 'right', 'top')
|
||||||
|
const cardCenterY = tokenY + dy
|
||||||
|
const cardBottom = cardCenterY + EXPANDED_H_WITH_BTN / 2
|
||||||
|
const cardTop = cardCenterY - EXPANDED_H_WITH_BTN / 2
|
||||||
|
|
||||||
|
expect(cardBottom).toBeLessThanOrEqual(canvasH)
|
||||||
|
expect(cardTop).toBeGreaterThanOrEqual(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('avec l\'ancien comportement implicite (vAnchor="bottom"), la carte aurait débordé — confirme la nécessité du fix', () => {
|
||||||
|
const canvasH = 1080
|
||||||
|
const marginBottom = 60
|
||||||
|
const tokenY = canvasH - marginBottom - ICON_SIZE / 2
|
||||||
|
|
||||||
|
const { dy } = expandedCardOffset(EXPANDED_H_WITH_BTN, 1, 'right', 'bottom')
|
||||||
|
const cardCenterY = tokenY + dy
|
||||||
|
const cardBottom = cardCenterY + EXPANDED_H_WITH_BTN / 2
|
||||||
|
|
||||||
|
expect(cardBottom).toBeGreaterThan(canvasH) // déborde bien, confirmant le bug d'origine
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sur une petite résolution (720p), la carte (vAnchor="top") reste aussi dans les limites', () => {
|
||||||
|
const canvasH = 720
|
||||||
|
const marginBottom = 60
|
||||||
|
const tokenY = canvasH - marginBottom - ICON_SIZE / 2
|
||||||
|
|
||||||
|
const { dy } = expandedCardOffset(EXPANDED_H_WITH_BTN, 1, 'right', 'top')
|
||||||
|
const cardCenterY = tokenY + dy
|
||||||
|
const cardBottom = cardCenterY + EXPANDED_H_WITH_BTN / 2
|
||||||
|
const cardTop = cardCenterY - EXPANDED_H_WITH_BTN / 2
|
||||||
|
|
||||||
|
expect(cardBottom).toBeLessThanOrEqual(canvasH)
|
||||||
|
expect(cardTop).toBeGreaterThanOrEqual(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in new issue
Block a user