wait_for_react_state
Monitor React applications for state changes, data loading completion, or navigation events during web scraping and testing workflows.
Instructions
Wait for React component state changes, data loading, or navigation
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| browser | No | Browser engine to use | chromium |
| condition | Yes | Type of condition to wait for | |
| selector | No | CSS selector or testID to wait for (for custom condition) | |
| timeout | No | Maximum time to wait in milliseconds | |
| url | Yes | URL to monitor |
Implementation Reference
- server.js:893-964 (handler)The main handler function 'waitForReactState' that implements the core logic of the 'wait_for_react_state' tool. It launches a browser, navigates to the URL, and waits for the specified condition (hydration, navigation, data-loading, animation, or custom selector) using Playwright methods.async waitForReactState(args) { this.validateArgs(args, ['url', 'condition']); const { url, condition, selector, timeout = TIMEOUTS.HYDRATION, browser: browserType = 'chromium' } = args; const { browser, context } = await this.getBrowser(browserType); const page = await context.newPage(); try { await this.setupMobileViewport(page); await page.goto(url, { waitUntil: 'networkidle' }); const startTime = Date.now(); let result = ''; switch (condition) { case 'hydration': const hydrated = await this.waitForReactHydration(page, timeout); result = hydrated ? '✅ React hydration completed' : '❌ React hydration timeout'; break; case 'navigation': await page.waitForFunction(() => { return !document.querySelector('[aria-label*="loading"]') && !document.querySelector('[data-testid*="loading"]'); }, { timeout }); result = '✅ Navigation completed'; break; case 'data-loading': await page.waitForFunction(() => { const loadingElements = document.querySelectorAll( '[data-testid*="loading"], [aria-label*="loading"], .loading, .spinner' ); return loadingElements.length === 0; }, { timeout }); result = '✅ Data loading completed'; break; case 'animation': await page.waitForTimeout(2000); result = '✅ Animation wait completed'; break; case 'custom': if (!selector) throw new Error('Selector required for custom condition'); const { usedSelector } = await this.findElement(page, selector, timeout); result = `✅ Custom condition met: ${usedSelector}`; break; default: throw new Error(`Unknown condition: ${condition}`); } const waitTime = Date.now() - startTime; return { content: [{ type: 'text', text: `${result}\nWait time: ${waitTime}ms` }] }; } finally { await context.close(); await browser.close(); } }
- server.js:242-275 (registration)Tool registration in the ListTools response, including the name, description, and inputSchema definition for 'wait_for_react_state'.{ name: 'wait_for_react_state', description: 'Wait for React component state changes, data loading, or navigation', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'URL to monitor' }, condition: { type: 'string', enum: ['hydration', 'navigation', 'data-loading', 'animation', 'custom'], description: 'Type of condition to wait for' }, selector: { type: 'string', description: 'CSS selector or testID to wait for (for custom condition)' }, timeout: { type: 'number', default: 15000, description: 'Maximum time to wait in milliseconds' }, browser: { type: 'string', enum: ['chromium', 'firefox', 'webkit'], default: 'chromium', description: 'Browser engine to use' } }, required: ['url', 'condition'] } },
- server.js:606-607 (registration)Registration/dispatch in the CallToolRequestSchema switch statement that maps the tool name to the handler method.case 'wait_for_react_state': return await this.waitForReactState(args);
- server.js:245-274 (schema)Input schema definition specifying parameters: url (required), condition (required, enum: ['hydration', 'navigation', 'data-loading', 'animation', 'custom']), selector (optional), timeout (default 15000), browser (default 'chromium').inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'URL to monitor' }, condition: { type: 'string', enum: ['hydration', 'navigation', 'data-loading', 'animation', 'custom'], description: 'Type of condition to wait for' }, selector: { type: 'string', description: 'CSS selector or testID to wait for (for custom condition)' }, timeout: { type: 'number', default: 15000, description: 'Maximum time to wait in milliseconds' }, browser: { type: 'string', enum: ['chromium', 'firefox', 'webkit'], default: 'chromium', description: 'Browser engine to use' } }, required: ['url', 'condition'] }
- server.js:101-133 (helper)Helper function 'waitForReactHydration' used by the handler (and others) to detect React hydration completion via checks for React global, devtools hook, data-reactroot, etc., and waits for loading indicators to detach.async waitForReactHydration(page, timeout = TIMEOUTS.HYDRATION) { try { await page.waitForFunction(() => { return window.React || window.__REACT_DEVTOOLS_GLOBAL_HOOK__ || document.querySelector('[data-reactroot]') || document.querySelector('#root [data-testid]') || document.querySelector('.expo-web-view'); }, { timeout }); await page.waitForTimeout(1000); const loadingSelectors = [ '[data-testid*="loading"]', '[data-testid*="spinner"]', '.loading', '.spinner', '[aria-label*="loading"]' ]; for (const selector of loadingSelectors) { try { await page.waitForSelector(selector, { state: 'detached', timeout: 5000 }); } catch (e) { // Loading indicator might not exist, continue } } return true; } catch (error) { console.warn('React hydration wait failed:', error.message); return false; } }