From 5b61c1bf46c14ffae2d6d9bbf53323d26087421a Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Wed, 3 Jun 2026 14:32:35 +0300 Subject: [PATCH] test(dom-css): expand fixture matrix --- packages/dom-css/src/to-scene-graph.ts | 40 +++++- tests/e2e/dom-css/browser-runtime.spec.ts | 157 +++++++++++++++++++- tests/engine/dom-css/conversion.test.ts | 106 +++++++++++++- tests/helpers/dom-css.ts | 166 +++++++++++++++++++++- 4 files changed, 460 insertions(+), 9 deletions(-) diff --git a/packages/dom-css/src/to-scene-graph.ts b/packages/dom-css/src/to-scene-graph.ts index fb278e460..302bb6d02 100644 --- a/packages/dom-css/src/to-scene-graph.ts +++ b/packages/dom-css/src/to-scene-graph.ts @@ -137,8 +137,16 @@ function counterAxisAlignFromCSS(value: string | undefined): SceneNode['counterA return 'MIN' } +function applyPadding(node: SceneNode, style: DesignStyleDeclaration): void { + node.paddingTop = firstCSSNumber(style, 'padding-top', 'padding-block', 'padding') ?? 0 + node.paddingRight = firstCSSNumber(style, 'padding-right', 'padding-inline', 'padding') ?? 0 + node.paddingBottom = firstCSSNumber(style, 'padding-bottom', 'padding-block', 'padding') ?? 0 + node.paddingLeft = firstCSSNumber(style, 'padding-left', 'padding-inline', 'padding') ?? 0 +} + function applyElementStyle(node: SceneNode, style: DesignStyleDeclaration): void { setNodeBox(node, style) + applyPadding(node, style) const fills = fillsFromStyle(style, 'background-color') if (fills.length > 0) node.fills = fills @@ -168,10 +176,6 @@ function applyElementStyle(node: SceneNode, style: DesignStyleDeclaration): void node.primaryAxisAlign = primaryAxisAlignFromCSS(pickStyle(style, 'justify-content')) node.counterAxisAlign = counterAxisAlignFromCSS(pickStyle(style, 'align-items')) node.itemSpacing = firstCSSNumber(style, 'gap', 'column-gap', 'row-gap') ?? 0 - node.paddingTop = firstCSSNumber(style, 'padding-top', 'padding') ?? 0 - node.paddingRight = firstCSSNumber(style, 'padding-right', 'padding') ?? 0 - node.paddingBottom = firstCSSNumber(style, 'padding-bottom', 'padding') ?? 0 - node.paddingLeft = firstCSSNumber(style, 'padding-left', 'padding') ?? 0 } } @@ -225,9 +229,35 @@ function createTextNode( return node } +function hasBoxStyle(style: DesignStyleDeclaration): boolean { + return [ + 'background-color', + 'border-color', + 'border-width', + 'border-top-width', + 'border-right-width', + 'border-bottom-width', + 'border-left-width', + 'border-radius', + 'box-shadow', + 'display', + 'height', + 'padding', + 'padding-top', + 'padding-right', + 'padding-bottom', + 'padding-left', + 'width' + ].some((property) => pickStyle(style, property) !== undefined) +} + function createElementNode(graph: SceneGraph, parentId: string, element: DesignElement): SceneNode { const style = mergedStyle(element) - if (isTextLikeElement(element) && element.children.every((child) => child.type === 'text')) { + if ( + isTextLikeElement(element) && + !hasBoxStyle(style) && + element.children.every((child) => child.type === 'text') + ) { return createTextNode(graph, parentId, textContent(element), style) } diff --git a/tests/e2e/dom-css/browser-runtime.spec.ts b/tests/e2e/dom-css/browser-runtime.spec.ts index 837057ef8..3c92c93cf 100644 --- a/tests/e2e/dom-css/browser-runtime.spec.ts +++ b/tests/e2e/dom-css/browser-runtime.spec.ts @@ -2,7 +2,15 @@ import type { Page } from '@playwright/test' import { compileTailwindCSS } from '@open-pencil/dom-css' -import { tailwindButtonClasses, tailwindCardClasses } from '#tests/helpers/dom-css' +import { + fixtureMatrixCSS, + fixtureMatrixHTML, + tailwindBadgeClasses, + tailwindButtonClasses, + tailwindCardClasses, + tailwindInputClasses, + tailwindNavClasses +} from '#tests/helpers/dom-css' import { expect, test } from '../fixtures' @@ -91,6 +99,153 @@ test.describe('@open-pencil/dom-css browser CSS runtime oracle', () => { expect(styles.color).toBe('rgb(255, 255, 255)') }) + test('resolves fixture matrix layout, form, badge, and dialog styles', async ({ page }) => { + await setStyledContent(page, fixtureMatrixCSS, fixtureMatrixHTML) + + const navbar = await computedStyleProperties(page, '.navbar', [ + 'align-items', + 'border-radius', + 'display', + 'height', + 'justify-content', + 'padding-left', + 'width' + ]) + expect(navbar.display).toBe('flex') + expect(navbar['align-items']).toBe('center') + expect(navbar['justify-content']).toBe('space-between') + expect(navbar.width).toBe('416px') + expect(navbar.height).toBe('48px') + expect(navbar['padding-left']).toBe('16px') + expect(navbar['border-radius']).toBe('12px') + + const badge = await computedStyleProperties(page, '.badge', [ + 'align-items', + 'background-color', + 'border-radius', + 'color', + 'display', + 'font-size', + 'font-weight', + 'height', + 'justify-content', + 'padding-left' + ]) + expect(badge.display).toBe('flex') + expect(badge['align-items']).toBe('center') + expect(badge['justify-content']).toBe('center') + expect(badge.height).toBe('24px') + expect(badge['padding-left']).toBe('10px') + expect(badge['border-radius']).toBe('9999px') + expect(badge['font-size']).toBe('12px') + expect(badge['font-weight']).toBe('600') + expect(badge['background-color']).toBe('rgb(224, 242, 254)') + expect(badge.color).toBe('rgb(3, 105, 161)') + + const input = await computedStyleProperties(page, '.input', [ + 'border-bottom-width', + 'border-radius', + 'font-size', + 'height', + 'padding-left', + 'width' + ]) + expect(input.width).toBe('312px') + expect(input.height).toBe('40px') + expect(input['padding-left']).toBe('12px') + expect(input['border-radius']).toBe('8px') + expect(input['border-bottom-width']).toBe('1px') + expect(input['font-size']).toBe('14px') + + const dialog = await computedStyleProperties(page, '.dialog', [ + 'box-shadow', + 'display', + 'flex-direction', + 'gap', + 'max-width', + 'min-width', + 'padding-top', + 'width' + ]) + expect(dialog.display).toBe('flex') + expect(dialog['flex-direction']).toBe('column') + expect(dialog.gap).toBe('16px') + expect(dialog.width).toBe('360px') + expect(dialog['min-width']).toBe('320px') + expect(dialog['max-width']).toBe('420px') + expect(dialog['padding-top']).toBe('24px') + expect(dialog['box-shadow']).toContain('rgba(15, 23, 42, 0.16)') + }) + + test('resolves Tailwind input, badge, and nav utilities in a real browser', async ({ page }) => { + const inputClasses = [...tailwindInputClasses] + const badgeClasses = [...tailwindBadgeClasses] + const navClasses = [...tailwindNavClasses] + const css = await compileTailwindCSS([...inputClasses, ...badgeClasses, ...navClasses]) + await setStyledContent( + page, + css, + ` + + + ` + ) + + const nav = await computedStyleProperties(page, 'nav', [ + 'align-items', + 'border-radius', + 'display', + 'height', + 'justify-content', + 'padding-left', + 'width' + ]) + expect(nav.display).toBe('flex') + expect(nav['align-items']).toBe('center') + expect(nav['justify-content']).toBe('space-between') + expect(nav.width).toBe('384px') + expect(nav.height).toBe('48px') + expect(nav['padding-left']).toBe('16px') + expect(nav['border-radius']).toBe('12px') + + const badge = await computedStyleProperties(page, 'nav span:last-child', [ + 'align-items', + 'border-radius', + 'display', + 'font-size', + 'font-weight', + 'height', + 'justify-content', + 'padding-left' + ]) + expect(badge.display).toBe('flex') + expect(badge['align-items']).toBe('center') + expect(badge['justify-content']).toBe('center') + expect(badge.height).toBe('24px') + expect(badge['padding-left']).toBe('10px') + expect(badge['border-radius']).toMatch(/^3\.\d+e\+\d+px$/) + expect(badge['font-size']).toBe('12px') + expect(badge['font-weight']).toBe('600') + + const input = await computedStyleProperties(page, 'input', [ + 'border-bottom-width', + 'border-radius', + 'font-size', + 'height', + 'padding-left', + 'width' + ]) + expect(input.width).toBe('320px') + expect(input.height).toBe('40px') + expect(input['padding-left']).toBe('12px') + expect(input['border-radius']).toBe('6px') + expect(input['border-bottom-width']).toBe('1px') + expect(input['font-size']).toBe('14px') + }) + test('resolves custom properties when assigned to real CSS properties', async ({ page }) => { await page.setContent(`