Skip to content

Commit 74d7000

Browse files
committed
test: update journal viewer tests to include pre-fetch for resource optimization and improve message validation
1 parent 1959c0a commit 74d7000

File tree

4 files changed

+54
-134
lines changed

4 files changed

+54
-134
lines changed

exercises/03.complex/02.problem.ready/test/index.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ test('journal viewer sends ui-lifecycle-iframe-ready message', async () => {
5656
.object({ resource: z.object({}).passthrough() })
5757
.parse(result.content[0])
5858

59+
// pre-fetch because vite may need to optimize deps 🙃 https://x.com/kentcdodds/status/1972793943265038731
60+
await fetch(resource.text as string, { method: 'HEAD' })
61+
5962
const url = new URL('http://localhost:7787/mcp-ui-renderer')
6063
url.searchParams.set('resourceData', JSON.stringify(resource))
6164

exercises/03.complex/02.solution.ready/test/index.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ test('journal viewer sends ui-lifecycle-iframe-ready message', async () => {
5656
.object({ resource: z.object({}).passthrough() })
5757
.parse(result.content[0])
5858

59+
// pre-fetch because vite may need to optimize deps 🙃 https://x.com/kentcdodds/status/1972793943265038731
60+
await fetch(resource.text as string, { method: 'HEAD' })
61+
5962
const url = new URL('http://localhost:7787/mcp-ui-renderer')
6063
url.searchParams.set('resourceData', JSON.stringify(resource))
6164

exercises/03.complex/04.problem.dynamic-sizing/test/index.test.ts

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ async function setupClient() {
4242
}
4343
}
4444

45-
test('view_journal sends ui-size-change message', async () => {
45+
test('journal viewer sends ui-size-change message', async () => {
4646
await using setup = await setupClient()
4747
const { client } = setup
4848

@@ -53,79 +53,36 @@ test('view_journal sends ui-size-change message', async () => {
5353
invariant(Array.isArray(result.content), '🚨 content is not an array')
5454

5555
const { resource } = z
56-
.object({ resource: z.object({ text: z.string() }) })
56+
.object({ resource: z.object({}).passthrough() })
5757
.parse(result.content[0])
5858

59-
const urlString = resource.text
59+
// pre-fetch because vite may need to optimize deps 🙃 https://x.com/kentcdodds/status/1972793943265038731
60+
await fetch(resource.text as string, { method: 'HEAD' })
61+
62+
const url = new URL('http://localhost:7787/mcp-ui-renderer')
63+
url.searchParams.set('resourceData', JSON.stringify(resource))
6064

6165
await using browserSetup = await setupBrowser()
6266
const { page } = browserSetup
6367

64-
await page.addInitScript(() => {
65-
// one per document; created before app code runs
66-
window.__uiReadyDeferred = new Promise((resolve) => {
67-
window.__resolveUiReady = resolve
68-
})
69-
70-
window.addEventListener('message', (event: MessageEvent) => {
71-
if (event?.data?.type === 'ui-size-change') {
72-
window.__resolveUiReady?.(event.data)
73-
}
74-
})
68+
await page.goto(url.toString())
69+
const message = page.getByRole('log').getByText('ui-size-change')
70+
await message.waitFor({ timeout: 1000 }).catch((e) => {
71+
throw new Error(
72+
'🚨 ui-size-change was never received. Make sure to call postMessage with "ui-size-change" with width and height and the target set to "*".',
73+
{ cause: e },
74+
)
7575
})
7676

77-
await page.goto(urlString)
78-
79-
const message = await Promise.race([
80-
page.evaluate(() => {
81-
return window.__uiReadyDeferred
82-
}),
83-
new Promise((r, reject) =>
84-
setTimeout(() => reject('🚨 timed out waiting for message'), 3000),
85-
),
86-
])
87-
88-
invariant(
89-
typeof message === 'object' && message !== null,
90-
'🚨 message not received',
91-
)
92-
93-
const parsedMessage = z
94-
.object({
95-
type: z.string().optional(),
96-
payload: z.object({ height: z.number(), width: z.number() }).optional(),
97-
})
98-
.parse(message)
99-
100-
expect(parsedMessage.type, '🚨 message type is not ui-size-change').toBe(
101-
'ui-size-change',
102-
)
77+
const textContent = JSON.parse(await message.textContent())
10378
expect(
104-
parsedMessage.payload,
105-
'🚨 message payload does not have a height property',
106-
).toHaveProperty('height')
107-
expect(
108-
parsedMessage.payload,
109-
'🚨 message payload does not have a width property',
110-
).toHaveProperty('width')
79+
textContent,
80+
'🚨 the ui-size-change message is not the correct format',
81+
).toEqual({
82+
type: 'ui-size-change',
83+
payload: {
84+
height: expect.any(Number),
85+
width: expect.any(Number),
86+
},
87+
})
11188
})
112-
113-
declare global {
114-
interface Window {
115-
__uiReadyDeferred?: Promise<{
116-
type: string
117-
payload: { height: number; width: number }
118-
}>
119-
__resolveUiReady?: (data: {
120-
type: string
121-
payload: { height: number; width: number }
122-
}) => void
123-
addEventListener(
124-
type: string,
125-
listener: (event: MessageEvent) => void,
126-
options?: { once?: boolean },
127-
): void
128-
}
129-
130-
var window: Window & typeof globalThis
131-
}

exercises/03.complex/04.solution.dynamic-sizing/test/index.test.ts

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ async function setupClient() {
4242
}
4343
}
4444

45-
test('view_journal sends ui-size-change message', async () => {
45+
test('journal viewer sends ui-size-change message', async () => {
4646
await using setup = await setupClient()
4747
const { client } = setup
4848

@@ -53,79 +53,36 @@ test('view_journal sends ui-size-change message', async () => {
5353
invariant(Array.isArray(result.content), '🚨 content is not an array')
5454

5555
const { resource } = z
56-
.object({ resource: z.object({ text: z.string() }) })
56+
.object({ resource: z.object({}).passthrough() })
5757
.parse(result.content[0])
5858

59-
const urlString = resource.text
59+
// pre-fetch because vite may need to optimize deps 🙃 https://x.com/kentcdodds/status/1972793943265038731
60+
await fetch(resource.text as string, { method: 'HEAD' })
61+
62+
const url = new URL('http://localhost:7787/mcp-ui-renderer')
63+
url.searchParams.set('resourceData', JSON.stringify(resource))
6064

6165
await using browserSetup = await setupBrowser()
6266
const { page } = browserSetup
6367

64-
await page.addInitScript(() => {
65-
// one per document; created before app code runs
66-
window.__uiReadyDeferred = new Promise((resolve) => {
67-
window.__resolveUiReady = resolve
68-
})
69-
70-
window.addEventListener('message', (event: MessageEvent) => {
71-
if (event?.data?.type === 'ui-size-change') {
72-
window.__resolveUiReady?.(event.data)
73-
}
74-
})
68+
await page.goto(url.toString())
69+
const message = page.getByRole('log').getByText('ui-size-change')
70+
await message.waitFor({ timeout: 1000 }).catch((e) => {
71+
throw new Error(
72+
'🚨 ui-size-change was never received. Make sure to call postMessage with "ui-size-change" with width and height and the target set to "*".',
73+
{ cause: e },
74+
)
7575
})
7676

77-
await page.goto(urlString)
78-
79-
const message = await Promise.race([
80-
page.evaluate(() => {
81-
return window.__uiReadyDeferred
82-
}),
83-
new Promise((r, reject) =>
84-
setTimeout(() => reject('🚨 timed out waiting for message'), 3000),
85-
),
86-
])
87-
88-
invariant(
89-
typeof message === 'object' && message !== null,
90-
'🚨 message not received',
91-
)
92-
93-
const parsedMessage = z
94-
.object({
95-
type: z.string().optional(),
96-
payload: z.object({ height: z.number(), width: z.number() }).optional(),
97-
})
98-
.parse(message)
99-
100-
expect(parsedMessage.type, '🚨 message type is not ui-size-change').toBe(
101-
'ui-size-change',
102-
)
77+
const textContent = JSON.parse(await message.textContent())
10378
expect(
104-
parsedMessage.payload,
105-
'🚨 message payload does not have a height property',
106-
).toHaveProperty('height')
107-
expect(
108-
parsedMessage.payload,
109-
'🚨 message payload does not have a width property',
110-
).toHaveProperty('width')
79+
textContent,
80+
'🚨 the ui-size-change message is not the correct format',
81+
).toEqual({
82+
type: 'ui-size-change',
83+
payload: {
84+
height: expect.any(Number),
85+
width: expect.any(Number),
86+
},
87+
})
11188
})
112-
113-
declare global {
114-
interface Window {
115-
__uiReadyDeferred?: Promise<{
116-
type: string
117-
payload: { height: number; width: number }
118-
}>
119-
__resolveUiReady?: (data: {
120-
type: string
121-
payload: { height: number; width: number }
122-
}) => void
123-
addEventListener(
124-
type: string,
125-
listener: (event: MessageEvent) => void,
126-
options?: { once?: boolean },
127-
): void
128-
}
129-
130-
var window: Window & typeof globalThis
131-
}

0 commit comments

Comments
 (0)