@@ -20,9 +20,18 @@ const SERVERS = [
2020 { key : "threejs" , index : 7 , name : "Three.js Server" } ,
2121] ;
2222
23+ /**
24+ * Wait for the MCP App to load inside nested iframes.
25+ * Structure: page > iframe (sandbox) > iframe (app)
26+ */
27+ async function waitForAppLoad ( page : import ( "@playwright/test" ) . Page ) {
28+ // Wait for outer iframe (sandbox)
29+ const outerFrame = page . frameLocator ( "iframe" ) . first ( ) ;
30+ // Wait for inner iframe (app) to be visible
31+ await expect ( outerFrame . locator ( "iframe" ) ) . toBeVisible ( ) ;
32+ }
33+
2334test . describe ( "Host UI" , ( ) => {
24- // Increase timeout for iframe-heavy tests
25- test . setTimeout ( 90000 ) ;
2635 test ( "initial state shows controls" , async ( { page } ) => {
2736 await page . goto ( "/" ) ;
2837 await expect ( page . locator ( "label:has-text('Server')" ) ) . toBeVisible ( ) ;
@@ -32,57 +41,41 @@ test.describe("Host UI", () => {
3241
3342 test ( "screenshot of initial state" , async ( { page } ) => {
3443 await page . goto ( "/" ) ;
35- await page . waitForTimeout ( 1000 ) ;
44+ await expect ( page . locator ( 'button:has-text("Call Tool")' ) ) . toBeVisible ( ) ;
3645 await expect ( page ) . toHaveScreenshot ( "host-initial.png" ) ;
3746 } ) ;
3847} ) ;
3948
4049// Generate tests for each server
4150for ( const server of SERVERS ) {
4251 test . describe ( `${ server . name } ` , ( ) => {
43- test . setTimeout ( 90000 ) ;
44-
4552 test ( `loads app UI` , async ( { page } ) => {
4653 await page . goto ( "/" ) ;
4754
48- // Select server
49- const serverSelect = page . locator ( "select" ) . first ( ) ;
50- await serverSelect . selectOption ( { index : server . index } ) ;
51-
52- // Click Call Tool
55+ // Select server and call tool
56+ await page . locator ( "select" ) . first ( ) . selectOption ( { index : server . index } ) ;
5357 await page . click ( 'button:has-text("Call Tool")' ) ;
5458
55- // Wait for outer iframe
56- await page . waitForSelector ( "iframe" , { timeout : 10000 } ) ;
57-
58- // Wait for content to load (generous timeout for nested iframes)
59- await page . waitForTimeout ( 5000 ) ;
60-
61- // Verify iframe structure exists
62- const outerFrame = page . frameLocator ( "iframe" ) . first ( ) ;
63- await expect ( outerFrame . locator ( "iframe" ) ) . toBeVisible ( {
64- timeout : 10000 ,
65- } ) ;
59+ // Wait for app to load in nested iframes
60+ await waitForAppLoad ( page ) ;
6661 } ) ;
6762
6863 test ( `screenshot matches golden` , async ( { page } ) => {
6964 await page . goto ( "/" ) ;
7065
71- // Select server
72- const serverSelect = page . locator ( "select" ) . first ( ) ;
73- await serverSelect . selectOption ( { index : server . index } ) ;
74-
75- // Click Call Tool
66+ // Select server and call tool
67+ await page . locator ( "select" ) . first ( ) . selectOption ( { index : server . index } ) ;
7668 await page . click ( 'button:has-text("Call Tool")' ) ;
7769
78- // Wait for app to fully load
79- await page . waitForSelector ( "iframe" , { timeout : 10000 } ) ;
80- await page . waitForTimeout ( 6000 ) ; // Extra time for nested iframe content
70+ // Wait for app to load
71+ await waitForAppLoad ( page ) ;
72+
73+ // Brief stabilization for animations/rendering
74+ await page . waitForTimeout ( 500 ) ;
8175
8276 // Take screenshot
8377 await expect ( page ) . toHaveScreenshot ( `${ server . key } .png` , {
8478 maxDiffPixelRatio : 0.1 , // 10% tolerance for dynamic content
85- timeout : 10000 ,
8679 } ) ;
8780 } ) ;
8881 } ) ;
0 commit comments