import { describe, it, expect } from 'vitest'
import { render } from '@testing-library/react'
import React from 'react'
import { ClaudeEmbed } from '../claude-embed'
import { FigmaEmbed } from '../figma-embed'
/**
* A Claude artifact must sit in the SAME chrome as every other embed viewer,
* and — unlike the first-party vendors — must stay SANDBOXED, because an
* artifact is HTML and JS written by a user of ours.
*/
const PUBLISHED = 'https://claude.ai/public/artifacts/abc-123'
const CODE_ARTIFACT = 'https://claude.ai/code/artifact/abc-123'
describe('ClaudeEmbed', () => {
it('renders the shared frame, with the same wrapper and title element figma uses', () => {
const claude = render().container
const figma = render().container
expect(claude.firstElementChild?.className).toBe(figma.firstElementChild?.className)
// Same heading treatment (`titleVariant="h6"`), not an h2.
expect(claude.querySelector('span.text-h6')).not.toBeNull()
expect(claude.querySelector('h2')).toBeNull()
})
it('SANDBOXES the artifact, and never grants it top-navigation', () => {
const { container } = render()
const iframe = container.querySelector('iframe')!
const sandbox = iframe.getAttribute('sandbox') ?? ''
// `allow-same-origin` + `allow-scripts` is what Anthropic's own embed
// snippet uses; on a cross-origin frame it grants claude.ai's origin,
// never ours.
expect(sandbox.split(' ').sort()).toEqual(
['allow-forms', 'allow-popups', 'allow-same-origin', 'allow-scripts'],
)
// The point of sandboxing at all: an artifact cannot navigate the page
// that embeds it.
expect(sandbox).not.toContain('allow-top-navigation')
expect(iframe.getAttribute('loading')).toBe('lazy')
expect(iframe.getAttribute('allow')).toContain('clipboard')
})
it('frames the /embed route, never the artifact page itself', () => {
const { container } = render()
expect(container.querySelector('iframe')!.getAttribute('src')).toBe(
'https://claude.ai/public/artifacts/abc-123/embed',
)
})
it('a NON-embeddable artifact keeps the action and shows the shared empty state', () => {
const { container, getByText } = render()
expect(container.querySelector('iframe')).toBeNull()
getByText(/Open this one in Claude/)
// The way out is always present.
expect(container.textContent).toContain('Open in Claude')
})
it('occupies the SAME height as a figma embed, framed or not', () => {
// Two embeds in one doc must read as two equal blocks — including when one
// of them has no embeddable view and falls back to the empty state.
const figmaBox = render()
.container.querySelector('[style*="70vh"]')
const framed = render()
.container.querySelector('[style*="70vh"]')
const empty = render()
.container.querySelector('[style*="70vh"]')
for (const box of [figmaBox, framed, empty]) {
expect(box).not.toBeNull()
expect((box as HTMLElement).style.height).toBe('70vh')
}
// …and the empty box carries the same rounded border the iframe box does.
expect((empty as HTMLElement).className).toContain('rounded-lg')
expect((empty as HTMLElement).className).toContain('border-ods-border')
})
it('uses the author\'s name when there is one, and the kind otherwise', () => {
expect(render().container.textContent)
.toContain('Suppression brief')
expect(render().container.textContent).toContain('Claude Artifact')
expect(render().container.textContent).toContain('Claude Design')
})
})