diff --git a/craft/package.json b/craft/package.json index ed01c9a..2f4f453 100644 --- a/craft/package.json +++ b/craft/package.json @@ -23,6 +23,7 @@ "test:browser:sitesmith": "node scripts/e2e-sitesmith.mjs", "test:browser:sitesmith-editor-assets": "node scripts/e2e-sitesmith-editor-assets.mjs", "test:browser:sitesmith-cleaned": "node scripts/e2e-sitesmith-cleaned.mjs", + "test:browser:preview-assets": "node scripts/e2e-preview-assets.mjs", "test:unit:watch": "vitest" }, "dependencies": { diff --git a/craft/scripts/e2e-preview-assets-entry.ts b/craft/scripts/e2e-preview-assets-entry.ts new file mode 100644 index 0000000..203d882 --- /dev/null +++ b/craft/scripts/e2e-preview-assets-entry.ts @@ -0,0 +1,47 @@ +// Bundled (esbuild, node) by scripts/e2e-preview-assets.mjs: a version-history snapshot whose header, body and +// design carry uploads exactly as the AssetPicker stores them (the same-origin panel proxy URL), turned into the +// Preview document by the REAL buildSnapshotPreviewHtml (the same export + absolute-URL step as TopBar's Preview), +// plus the published body for the backend publish check. +import { editorProxyUrl } from '../src/sitesmith/editor-asset-urls'; +import { buildSnapshotPreviewHtml, type Snapshot } from '../src/utils/history-restore'; +import { exportBodyHtml } from '../src/utils/html-export'; +import { flattenTreeForCraft } from '../src/utils/craft-tree'; +import { inlinePreviewAssets, collectPreviewAssetUrls } from '../src/utils/preview-assets'; + +export const SITE_ID = 7; +export const FILES = ['1700000000_aa11bb22_hero.png', '1700000001_bb22cc33_logo+v2.png', 'my photo.png', 'café.png', 'poster.png', 'fav.png']; +export const OTHER_SITE_FILE = 'other-site.png'; +const U = (i: number) => editorProxyUrl(SITE_ID, FILES[i]); +const n = (type: string, props: Record, nodes?: any[]) => ({ type: { resolvedName: type }, props, ...(nodes ? { nodes } : {}) }); +const state = (tree: any) => JSON.stringify(flattenTreeForCraft(tree).nodes); + +const header = state(n('Container', { node_id: 'ROOT', tag: 'div' }, [ + n('Navbar', { node_id: 'nav', logoType: 'image', logoImage: U(1), logoUrl: '/', links: [{ text: 'Home', href: '/' }] }), +])); +const page = state(n('Container', { node_id: 'ROOT', tag: 'div' }, [ + n('BackgroundSection', { node_id: 'bg', bgImage: U(0), overlayOpacity: 0.2 }, [n('Heading', { node_id: 'h', text: 'Hello', level: 'h1' })]), + n('ImageBlock', { node_id: 'i1', src: U(0), alt: 'plain' }), + n('ImageBlock', { node_id: 'i2', src: U(1), alt: 'plus' }), + n('ImageBlock', { node_id: 'i3', src: U(2), alt: 'space' }), + n('ImageBlock', { node_id: 'i4', src: U(3), alt: 'unicode' }), + n('Container', { node_id: 'c', tag: 'div', style: { minHeight: '60px', backgroundImage: `url(${U(0)})` } }), + n('HtmlBlock', { node_id: 'html', code: + `richsrcset` + + `` + + `full size` + + `other` }), + n('ImageBlock', { node_id: 'i5', src: editorProxyUrl(SITE_ID, 'does-not-exist.png'), alt: 'missing' }), +])); + +export const SNAPSHOT: Snapshot = { + pages_craft_state: [{ id: 'p1', name: 'Home', slug: 'index', craftState: page }], + header_craft_state: header, + footer_craft_state: null, + design: { favicon: U(5) }, +} as unknown as Snapshot; + +/** The Preview document as origin/main hands it to the sandboxed tab (proxy URLs made absolute on `origin`). */ +export function previewHtml(origin: string): string { return buildSnapshotPreviewHtml(SNAPSHOT, 0, origin); } +/** The page body Save/Publish sends (no Preview step involved). */ +export function publishBody(): string { return exportBodyHtml(header).html + exportBodyHtml(page).html; } +export { inlinePreviewAssets, collectPreviewAssetUrls }; diff --git a/craft/scripts/e2e-preview-assets.mjs b/craft/scripts/e2e-preview-assets.mjs new file mode 100644 index 0000000..9d9f229 --- /dev/null +++ b/craft/scripts/e2e-preview-assets.mjs @@ -0,0 +1,193 @@ +#!/usr/bin/env node +/** + * Real-browser check (Chromium AND Firefox, headless) that uploaded images render in PREVIEW, the way the editor + * really opens it: a click opens a panel-origin tab (window.open('')), which holds an + *