diff --git a/plugins/interface/components/primitives.test.tsx b/plugins/interface/components/primitives.test.tsx
new file mode 100644
index 0000000..0e26beb
--- /dev/null
+++ b/plugins/interface/components/primitives.test.tsx
@@ -0,0 +1,165 @@
+import { describe, expect, it } from 'vitest'
+import { renderToString } from 'hono/jsx/dom/server'
+import { Avatar } from './avatar'
+import { Card } from './card'
+import { Input } from './input/Input'
+import { Label } from './label/Label'
+import { Loader } from './loader/Loader'
+import { Toggle } from './toggle'
+import { cn, getAssetImportTagsFromManifest } from '../utils'
+
+describe('interface primitives', () => {
+ it('merges Tailwind utility classes predictably', () => {
+ expect(cn('px-2 text-sm', false && 'hidden', 'px-4')).toBe(
+ 'text-sm px-4'
+ )
+ })
+
+ it('renders avatar initials and image variants', () => {
+ const initialAvatar = renderToString(
+
+ )
+ expect(initialAvatar).toContain('
')
+
+ const imageAvatar = renderToString(
+
+ )
+ expect(imageAvatar).toContain(' {
+ const card = renderToString(
+
+ Summary
+
+ )
+ expect(card).toContain('Summary
')
+
+ const linkCard = renderToString(
+
+ Settings
+
+ )
+ expect(linkCard).toContain('Settings')
+ })
+
+ it('renders labels with conditional required copy', () => {
+ const invalidLabel = renderToString(
+
+ )
+ expect(invalidLabel).toContain('
+ )
+ expect(validLabel).not.toContain('text-ob-destructive')
+ })
+
+ it('renders loader sizing through inline styles', () => {
+ const loader = renderToString()
+ expect(loader).toContain('