test(zip): 통합/메타 스냅샷 테스트 추가(exportPage+buildZip, SEO/OG/Analytics 보존)
This commit is contained in:
@@ -0,0 +1,53 @@
|
|||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import JSZip from 'jszip'
|
||||||
|
import { exportPage } from '@/lib/exporter/html'
|
||||||
|
import { buildZip } from '@/lib/exporter/zip'
|
||||||
|
import { AssetManager } from '@/lib/assets/assetManager'
|
||||||
|
import { pageSchema, type Page } from '@/lib/schema/page'
|
||||||
|
|
||||||
|
function makePageWithLocalAsset(): { page: Page; am: AssetManager } {
|
||||||
|
const am = new AssetManager({ maxBytes: 1024 * 1024, allowedExts: ['png','svg','jpg','jpeg','webp'] })
|
||||||
|
// simulate adding a local image and referencing it by original name via local: prefix
|
||||||
|
const bytes = new Uint8Array([7,8,9])
|
||||||
|
// add as "hero.png"
|
||||||
|
am.add({ name: 'hero.png', type: 'image/png', bytes })
|
||||||
|
|
||||||
|
const base: Page = pageSchema.parse({
|
||||||
|
title: 'Integrated ZIP',
|
||||||
|
locale: 'en',
|
||||||
|
theme: { primaryColor: '#2563eb', fontFamily: 'Inter' },
|
||||||
|
sections: [
|
||||||
|
{ type: 'hero', props: { heading: 'Hello', subheading: 'World', imageUrl: 'local:hero.png' } },
|
||||||
|
{ type: 'cta', props: { text: 'Go', href: '#' } },
|
||||||
|
],
|
||||||
|
form: { actionUrl: '', fields: [], spamProtection: { honeypotFieldName: '_hp', minSubmitSeconds: 2 } },
|
||||||
|
analytics: { ga4MeasurementId: 'G-TEST', metaPixelId: '', customHeadHtml: '' },
|
||||||
|
seo: { title: 't', description: 'd' },
|
||||||
|
})
|
||||||
|
return { page: base, am }
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Export ZIP 통합 검증', () => {
|
||||||
|
it('exportPage 출력 + buildZip 결과에서 assets 경로/메타가 보존된다', async () => {
|
||||||
|
const { page, am } = makePageWithLocalAsset()
|
||||||
|
const out = exportPage(page, { assetManager: am })
|
||||||
|
const assets = am.toZipStructure()
|
||||||
|
const zipBytes = await buildZip({ html: out.html, css: out.css, js: out.js, assets })
|
||||||
|
|
||||||
|
const zip = await JSZip.loadAsync(zipBytes)
|
||||||
|
const names = Object.keys(zip.files)
|
||||||
|
// assets 파일이 존재해야 함
|
||||||
|
const assetKey = Object.keys(assets)[0]
|
||||||
|
expect(names).toContain(assetKey)
|
||||||
|
|
||||||
|
// index.html에 canonical/meta/ga4 스니펫 보존
|
||||||
|
const html = await zip.files['index.html'].async('string')
|
||||||
|
expect(html).toMatch(/<link rel="canonical" href="\//)
|
||||||
|
expect(html).toMatch(/<meta name="description" content="d"/)
|
||||||
|
expect(html).toMatch(/gtag\('config', 'G-TEST'\)/)
|
||||||
|
|
||||||
|
// hero 이미지가 재작성된 경로를 사용한다
|
||||||
|
const match = html.match(/<img[^>]*src="([^"]+)"/)
|
||||||
|
expect(match && match[1]).toBe(assetKey)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import JSZip from 'jszip'
|
||||||
|
import { buildZip } from '@/lib/exporter/zip'
|
||||||
|
|
||||||
|
describe('Export ZIP 메타 보존 검증', () => {
|
||||||
|
it('index.html의 SEO/OG/Analytics 메타가 그대로 보존된다', async () => {
|
||||||
|
const html = `<!DOCTYPE html><html><head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="canonical" href="/" />
|
||||||
|
<meta name="description" content="desc" />
|
||||||
|
<meta property="og:title" content="OT" />
|
||||||
|
<meta property="og:description" content="OD" />
|
||||||
|
<script>window.dataLayer=[];function gtag(){dataLayer.push(arguments);}gtag('js',new Date());</script>
|
||||||
|
</head><body>ok</body></html>`
|
||||||
|
const css = 'body{color:#222}'
|
||||||
|
const js = 'console.log("ok")'
|
||||||
|
|
||||||
|
const zipBytes = await buildZip({ html, css, js, assets: {} })
|
||||||
|
const zip = await JSZip.loadAsync(zipBytes)
|
||||||
|
const htmlContent = await zip.files['index.html'].async('string')
|
||||||
|
|
||||||
|
expect(htmlContent).toMatch(/<link rel="canonical" href="\//)
|
||||||
|
expect(htmlContent).toMatch(/<meta name="description" content="desc"/)
|
||||||
|
expect(htmlContent).toMatch(/<meta property="og:title" content="OT"/)
|
||||||
|
expect(htmlContent).toMatch(/<meta property="og:description" content="OD"/)
|
||||||
|
expect(htmlContent).toMatch(/window\.dataLayer=\[\];/)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user