Skip to content

Commit 67950dc

Browse files
Sync public snapshot from freebuff-private
Source: CodebuffAI/freebuff-private@b3a2a67adce0339131bbd5e54290a2c334b50fc4
1 parent c408de4 commit 67950dc

3 files changed

Lines changed: 356 additions & 35 deletions

File tree

bun.lock

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/src/components/__tests__/ad-banner.test.tsx

Lines changed: 200 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,202 @@
1-
import { describe, expect, test } from 'bun:test'
1+
import { beforeAll, describe, expect, test } from 'bun:test'
2+
import { createTestRenderer } from '@opentui/core/testing'
3+
import { createRoot, flushSync } from '@opentui/react'
4+
import React from 'react'
25

3-
import { getAdDisplayLabel, getInlineAdLayout } from '../ad-banner'
6+
import {
7+
AD_CARD_HEIGHT,
8+
AdCard,
9+
getAdDisplayLabel,
10+
getCardAdLayout,
11+
getInlineAdLayout,
12+
} from '../ad-banner'
13+
import { initializeThemeStore } from '../../hooks/use-theme'
14+
15+
beforeAll(() => {
16+
initializeThemeStore()
17+
})
18+
19+
describe('card ad layout', () => {
20+
const ad = {
21+
adText:
22+
'Automate mobile UI testing with plain-English test steps and AI-powered execution.',
23+
title: 'Test every release before you ship',
24+
cta: 'Try free',
25+
url: 'https://www.drizz.dev/ios',
26+
}
27+
28+
test('renders the headline for the creative the console asks for', () => {
29+
// The regression this whole function exists for: with a CTA and a landing
30+
// URL both set, the headline used to reach neither the CTA fallback nor
31+
// the destination label, so it rendered nowhere at all.
32+
const layout = getCardAdLayout(ad, 78)
33+
34+
expect(layout.headline).toBe('Test every release before you ship')
35+
expect(layout.ctaText).toBe('Try free')
36+
expect(layout.labelText).toBe('drizz.dev')
37+
})
38+
39+
test('gives up a description line to make room for the headline', () => {
40+
expect(getCardAdLayout(ad, 78).descriptionLines).toBe(1)
41+
})
42+
43+
test('keeps both description lines when the ad has no headline', () => {
44+
const layout = getCardAdLayout({ ...ad, title: '' }, 78)
45+
46+
expect(layout.headline).toBe('')
47+
expect(layout.descriptionLines).toBe(2)
48+
})
49+
50+
test('the interior always sums to the reserved card height', () => {
51+
// The landing screen subtracts AD_CARD_HEIGHT from the model picker's
52+
// budget, so a layout that needs a row it was not given clips silently.
53+
for (const title of ['A headline', '']) {
54+
const layout = getCardAdLayout({ ...ad, title }, 78)
55+
const headlineRows = layout.headline ? 1 : 0
56+
const borderRows = 2
57+
const ctaRow = 1
58+
59+
expect(borderRows + headlineRows + layout.descriptionLines + ctaRow).toBe(
60+
AD_CARD_HEIGHT,
61+
)
62+
}
63+
})
64+
65+
test('falls back to Learn more rather than reprinting the headline', () => {
66+
// `ad.cta || ad.title` put the same string in two rows of a five-row card.
67+
expect(getCardAdLayout({ ...ad, cta: '' }, 78).ctaText).toBe('Learn more')
68+
})
69+
70+
test('drops the destination label when it would repeat the headline', () => {
71+
// With no URL the label falls back to the title, which now has its own row.
72+
const layout = getCardAdLayout({ ...ad, url: '' }, 78)
73+
74+
expect(layout.headline).toBe('Test every release before you ship')
75+
expect(layout.labelText).toBe('')
76+
})
77+
78+
test('keeps the Sponsored label when there is no headline and no URL', () => {
79+
const layout = getCardAdLayout({ ...ad, title: '', url: '' }, 78)
80+
81+
expect(layout.labelText).toBe('Sponsored')
82+
})
83+
84+
test('survives a provider that omits fields the type says are required', () => {
85+
// `AdResponse` types these as required strings, but the Gravity provider
86+
// casts `response.json()` instead of parsing it and copies `cta: raw.cta`
87+
// with no default — while Carbon beside it writes `?? 'Learn more'`. A
88+
// throw here is a throw inside AdCard's render on the landing screen.
89+
const layout = getCardAdLayout(
90+
{} as Parameters<typeof getCardAdLayout>[0],
91+
78,
92+
)
93+
94+
expect(layout.headline).toBe('')
95+
expect(layout.description).toBe('')
96+
expect(layout.ctaText).toBe('Learn more')
97+
expect(layout.labelText).toBe('Sponsored')
98+
expect(layout.descriptionLines).toBe(2)
99+
})
100+
101+
test('falls back to Learn more when only the CTA is missing', () => {
102+
const layout = getCardAdLayout(
103+
{ ...ad, cta: undefined } as unknown as Parameters<
104+
typeof getCardAdLayout
105+
>[0],
106+
78,
107+
)
108+
109+
expect(layout.ctaText).toBe('Learn more')
110+
expect(layout.headline).toBe('Test every release before you ship')
111+
})
112+
113+
test('truncates the headline to the interior width', () => {
114+
const layout = getCardAdLayout(
115+
{
116+
...ad,
117+
title:
118+
'A headline considerably longer than this narrow card could ever hold',
119+
},
120+
60,
121+
)
122+
123+
expect(layout.headline.length).toBeLessThanOrEqual(60 - 8)
124+
expect(layout.headline.endsWith('…')).toBe(true)
125+
})
126+
})
127+
128+
describe('card ad render', () => {
129+
// getCardAdLayout being correct proves nothing on its own: the bug it fixes
130+
// was that the JSX never referenced the title at all. This renders a real
131+
// character frame, so a refactor that drops the headline row goes red here
132+
// rather than shipping an advertiser a field that renders nowhere.
133+
const ad = {
134+
adText: 'Automate mobile UI testing with plain-English test steps.',
135+
title: 'Test every release before you ship',
136+
cta: 'Try free',
137+
url: 'https://www.drizz.dev/ios',
138+
favicon: '',
139+
clickUrl: 'https://www.drizz.dev/ios?click=1',
140+
impUrl: 'imp-1',
141+
}
142+
143+
const renderCard = async (
144+
overrides: Partial<typeof ad>,
145+
width = 78,
146+
): Promise<string> => {
147+
const setup = await createTestRenderer({ width, height: AD_CARD_HEIGHT })
148+
const root = createRoot(setup.renderer)
149+
flushSync(() => {
150+
root.render(<AdCard ad={{ ...ad, ...overrides }} width={width} />)
151+
})
152+
try {
153+
await setup.renderOnce()
154+
return setup.captureCharFrame()
155+
} finally {
156+
flushSync(() => root.unmount())
157+
setup.renderer.destroy()
158+
}
159+
}
160+
161+
test('draws the headline, the body, the CTA and the destination', async () => {
162+
const frame = await renderCard({})
163+
164+
expect(frame).toContain('Test every release before you ship')
165+
expect(frame).toContain('Automate mobile UI testing')
166+
expect(frame).toContain('Try free')
167+
expect(frame).toContain('drizz.dev')
168+
})
169+
170+
test('still discloses itself as an ad', async () => {
171+
expect(await renderCard({})).toContain('Ad')
172+
})
173+
174+
test('does not print the headline twice when there is no CTA', async () => {
175+
const frame = await renderCard({ cta: '' })
176+
177+
expect(frame).toContain('Test every release before you ship')
178+
expect(frame).toContain('Learn more')
179+
})
180+
181+
test('renders rather than throwing when the provider omits a CTA', async () => {
182+
// The regression this guards: `ad.cta.trim()` threw inside render, and
183+
// cli/src/components/error-boundary.tsx does not catch render errors, so
184+
// one malformed Gravity creative took down the landing screen.
185+
const frame = await renderCard({
186+
cta: undefined,
187+
} as Partial<typeof ad>)
188+
189+
expect(frame).toContain('Learn more')
190+
expect(frame).toContain('Test every release before you ship')
191+
})
192+
193+
test('renders a title-less ad without a blank first row', async () => {
194+
const frame = await renderCard({ title: '' })
195+
196+
expect(frame).toContain('Automate mobile UI testing')
197+
expect(frame).toContain('Ad')
198+
})
199+
})
4200

5201
describe('ad banner display label', () => {
6202
test('uses the display domain when the ad has a URL', () => {
@@ -69,7 +265,8 @@ describe('inline ad layout', () => {
69265
test('uses the full detail row when no destination domain is available', () => {
70266
const layout = getInlineAdLayout(
71267
{
72-
adText: 'A Carbon ad whose tracked destination is intentionally hidden.',
268+
adText:
269+
'A Carbon ad whose tracked destination is intentionally hidden.',
73270
title: 'Example Sponsor',
74271
url: '',
75272
},

0 commit comments

Comments
 (0)