chore: fill CSS contain test gaps + unskip clippedBy e2e test
- Add 4 unit tests in predicates.test.ts for new contain metrics: inside hasClippedOverflow (with/without clipping) clippedBy clipKind (contain:paint=1, overflow=2) - Unskip and implement clippedBy e2e test with overflow:hidden container in e2e-edge.test.ts (was stale skipped with 'not yet implemented')
This commit is contained in:
@@ -477,4 +477,125 @@ describe('spatial alias predicates', () => {
|
||||
assert.strictEqual(result.metrics?.max, 540);
|
||||
});
|
||||
});
|
||||
|
||||
// --- CSS contain metrics tests ------------------------------------------
|
||||
|
||||
describe('CSS contain metrics', () => {
|
||||
beforeEach(() => {
|
||||
clearPredicateRegistry();
|
||||
registerDefaultPredicates();
|
||||
});
|
||||
|
||||
it('inside reports hasClippedOverflow when reference clips and subject overflows', () => {
|
||||
const evaluator = getPredicateEvaluator('inside')!;
|
||||
// Subject 1 (10,10)-(90,30) is NOT fully inside Reference 2 (0,0)-(50,50)
|
||||
// overflowLeft=0, overflowTop=0, overflowRight=40, overflowBottom=0
|
||||
// Reference 2 clips (overflow:hidden → clipKind=1)
|
||||
const world = makeWorld({
|
||||
boxes: {
|
||||
boxId: [100, 200],
|
||||
subjectId: [1, 2],
|
||||
frameId: [1, 1],
|
||||
borderLeft: [10, 0],
|
||||
borderTop: [10, 0],
|
||||
borderRight: [90, 50],
|
||||
borderBottom: [30, 50],
|
||||
paddingLeft: [0, 0], paddingTop: [0, 0], paddingRight: [0, 0], paddingBottom: [0, 0],
|
||||
contentLeft: [10, 0], contentTop: [10, 0], contentRight: [90, 50], contentBottom: [30, 50],
|
||||
},
|
||||
visualBoxes: {
|
||||
boxId: [100, 200],
|
||||
subjectId: [1, 2],
|
||||
frameId: [1, 1],
|
||||
borderLeft: [10, 0], borderTop: [10, 0], borderRight: [90, 50], borderBottom: [30, 50],
|
||||
paddingLeft: [0, 0], paddingTop: [0, 0], paddingRight: [0, 0], paddingBottom: [0, 0],
|
||||
contentLeft: [10, 0], contentTop: [10, 0], contentRight: [90, 50], contentBottom: [30, 50],
|
||||
},
|
||||
subjects: { ids: [1, 2], domNodeId: [10, 20], subjectKind: [1, 1], primaryBoxId: [100, 200], firstFragmentId: [0, 0], fragmentCount: [0, 0] },
|
||||
dom: { nodeId: [10, 20], parentNodeId: [0, 0], childCount: [0, 0], tagNameStringId: [0, 0] },
|
||||
clipping: {
|
||||
clipNodeId: [0],
|
||||
subjectId: [2], // reference 2 is a clipping container (overflow:hidden)
|
||||
clipKind: [1],
|
||||
clipLeft: [0], clipTop: [0], clipRight: [50], clipBottom: [50],
|
||||
parentClipNodeId: [0],
|
||||
},
|
||||
});
|
||||
const result = evaluator.evaluateTuple(world, [1, 2]);
|
||||
assert.strictEqual(result.truth, 'false');
|
||||
assert.strictEqual(result.metrics?.overflowRight, 40);
|
||||
assert.strictEqual(result.metrics?.hasClippedOverflow, 1);
|
||||
});
|
||||
|
||||
it('inside does not report hasClippedOverflow when reference does not clip', () => {
|
||||
const evaluator = getPredicateEvaluator('inside')!;
|
||||
// Reference 2 does NOT clip (no clipping entry)
|
||||
const world = makeWorld({
|
||||
boxes: {
|
||||
boxId: [100, 200],
|
||||
subjectId: [1, 2],
|
||||
frameId: [1, 1],
|
||||
borderLeft: [10, 0],
|
||||
borderTop: [10, 0],
|
||||
borderRight: [90, 50],
|
||||
borderBottom: [30, 50],
|
||||
paddingLeft: [0, 0], paddingTop: [0, 0], paddingRight: [0, 0], paddingBottom: [0, 0],
|
||||
contentLeft: [10, 0], contentTop: [10, 0], contentRight: [90, 50], contentBottom: [30, 50],
|
||||
},
|
||||
visualBoxes: {
|
||||
boxId: [100, 200],
|
||||
subjectId: [1, 2],
|
||||
frameId: [1, 1],
|
||||
borderLeft: [10, 0], borderTop: [10, 0], borderRight: [90, 50], borderBottom: [30, 50],
|
||||
paddingLeft: [0, 0], paddingTop: [0, 0], paddingRight: [0, 0], paddingBottom: [0, 0],
|
||||
contentLeft: [10, 0], contentTop: [10, 0], contentRight: [90, 50], contentBottom: [30, 50],
|
||||
},
|
||||
subjects: { ids: [1, 2], domNodeId: [10, 20], subjectKind: [1, 1], primaryBoxId: [100, 200], firstFragmentId: [0, 0], fragmentCount: [0, 0] },
|
||||
dom: { nodeId: [10, 20], parentNodeId: [0, 0], childCount: [0, 0], tagNameStringId: [0, 0] },
|
||||
});
|
||||
const result = evaluator.evaluateTuple(world, [1, 2]);
|
||||
assert.strictEqual(result.truth, 'false');
|
||||
assert.strictEqual(result.metrics?.overflowRight, 40);
|
||||
assert.strictEqual(result.metrics?.hasClippedOverflow, undefined);
|
||||
});
|
||||
|
||||
it('clippedBy reports clipKind=1 for contain:paint clip', () => {
|
||||
const evaluator = getPredicateEvaluator('clippedBy')!;
|
||||
// Subject 1 is clipped by Reference 2 (contain:paint → clipKind=5)
|
||||
const world = makeWorld({
|
||||
subjects: { ids: [1, 2], domNodeId: [10, 20], subjectKind: [1, 1], primaryBoxId: [100, 200], firstFragmentId: [0, 0], fragmentCount: [0, 0] },
|
||||
dom: { nodeId: [10, 20], parentNodeId: [0, 0], childCount: [0, 0], tagNameStringId: [0, 0] },
|
||||
topology: { clippingRootOf: [2], stackingContextOf: [], scrollContainerOf: [], containingBlockOf: [], formattingContextOf: [], nearestPositionedAncestorOf: [], paintOrderBucket: [], paintOrderIndex: [] },
|
||||
clipping: {
|
||||
clipNodeId: [0],
|
||||
subjectId: [2],
|
||||
clipKind: [5], // Contain=5
|
||||
clipLeft: [0], clipTop: [0], clipRight: [100], clipBottom: [100],
|
||||
parentClipNodeId: [0],
|
||||
},
|
||||
});
|
||||
const result = evaluator.evaluateTuple(world, [1, 2]);
|
||||
assert.strictEqual(result.truth, 'true');
|
||||
assert.strictEqual(result.metrics?.clipKind, 1); // 1=contain:paint in predicate encoding
|
||||
});
|
||||
|
||||
it('clippedBy reports clipKind=2 for overflow:hidden clip', () => {
|
||||
const evaluator = getPredicateEvaluator('clippedBy')!;
|
||||
const world = makeWorld({
|
||||
subjects: { ids: [1, 2], domNodeId: [10, 20], subjectKind: [1, 1], primaryBoxId: [100, 200], firstFragmentId: [0, 0], fragmentCount: [0, 0] },
|
||||
dom: { nodeId: [10, 20], parentNodeId: [0, 0], childCount: [0, 0], tagNameStringId: [0, 0] },
|
||||
topology: { clippingRootOf: [2], stackingContextOf: [], scrollContainerOf: [], containingBlockOf: [], formattingContextOf: [], nearestPositionedAncestorOf: [], paintOrderBucket: [], paintOrderIndex: [] },
|
||||
clipping: {
|
||||
clipNodeId: [0],
|
||||
subjectId: [2],
|
||||
clipKind: [1], // Overflow=1
|
||||
clipLeft: [0], clipTop: [0], clipRight: [100], clipBottom: [100],
|
||||
parentClipNodeId: [0],
|
||||
},
|
||||
});
|
||||
const result = evaluator.evaluateTuple(world, [1, 2]);
|
||||
assert.strictEqual(result.truth, 'true');
|
||||
assert.strictEqual(result.metrics?.clipKind, 2); // 2=overflow in predicate encoding
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user