Skip to main content
Glama

BrowserStack MCP server

Official
getFailureLogs.test.ts12.2 kB
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { getFailureLogs } from '../../src/tools/get-failure-logs'; import * as automate from '../../src/tools/failurelogs-utils/automate'; import * as appAutomate from '../../src/tools/failurelogs-utils/app-automate'; vi.mock('../../src/config', () => ({ __esModule: true, default: { browserstackUsername: 'fake-user', browserstackAccessKey: 'fake-key', }, })); vi.mock('../../src/lib/instrumentation', () => ({ trackMCP: vi.fn() })); // Mock the utility functions with implementations vi.mock('../../src/tools/failurelogs-utils/automate', () => ({ retrieveNetworkFailures: vi.fn(), retrieveSessionFailures: vi.fn(), retrieveConsoleFailures: vi.fn(), filterSessionFailures: vi.fn((text: string) => { const lines = text.split('\n'); return lines.filter((line: string) => line.includes('ERROR') || line.includes('EXCEPTION') || line.includes('FATAL') ); }), filterConsoleFailures: vi.fn((text: string) => { const lines = text.split('\n'); return lines.filter((line: string) => line.includes('Failed to load resource') || line.includes('Uncaught TypeError') ); }), })); vi.mock('../../src/tools/failurelogs-utils/app-automate', () => ({ retrieveDeviceLogs: vi.fn(), retrieveAppiumLogs: vi.fn(), retrieveCrashLogs: vi.fn(), filterDeviceFailures: vi.fn(() => []), filterAppiumFailures: vi.fn(() => []), filterCrashFailures: vi.fn(() => []), })); // Mock fetch const mockFetch = vi.fn(); global.fetch = mockFetch; describe('BrowserStack Failure Logs', () => { const mockSessionId = 'test-session-id'; const mockBuildId = 'test-build-id'; beforeEach(() => { vi.clearAllMocks(); mockFetch.mockClear(); }); afterEach(() => { vi.resetAllMocks(); }); describe('getFailureLogs - Input Validation', () => { it('should throw error if sessionId is not provided', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; await expect(getFailureLogs({ sessionId: '', logTypes: ['networkLogs'], sessionType: 'automate' }, mockServer)).rejects.toThrow('Session ID is required'); }); it('should throw error if buildId is not provided for app-automate session', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; await expect(getFailureLogs({ sessionId: 'test-session', logTypes: ['deviceLogs'], sessionType: 'app-automate' }, mockServer)).rejects.toThrow('Build ID is required for app-automate sessions'); }); it('should return error for invalid log types', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; const result = await getFailureLogs({ sessionId: 'test-session', logTypes: ['invalidLogType'] as any, sessionType: 'automate' }, mockServer); expect(result.content?.[0]?.isError).toBe(true); expect(result.content?.[0]?.text).toContain('Invalid log type'); }); it('should return error when mixing session types', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; const automateResult = await getFailureLogs({ sessionId: 'test-session', logTypes: ['deviceLogs'], sessionType: 'automate' }, mockServer); const appAutomateResult = await getFailureLogs({ sessionId: 'test-session', buildId: 'test-build', logTypes: ['networkLogs'], sessionType: 'app-automate' }, mockServer); expect(automateResult.content?.[0]?.isError).toBe(true); expect(appAutomateResult.content?.[0]?.isError).toBe(true); }); }); describe('Automate Session Logs', () => { const mockNetworkFailures = 'Network Failures (1 found):\n' + JSON.stringify([ { startedDateTime: '2024-03-20T10:00:00Z', request: { method: 'GET', url: 'https://test.com' }, response: { status: 404, statusText: 'Not Found' }, serverIPAddress: undefined, time: undefined, }, ], null, 2); beforeEach(() => { // Reset all mocks vi.clearAllMocks(); // Setup mock implementations with string return values vi.mocked(automate.retrieveNetworkFailures).mockResolvedValue(mockNetworkFailures); vi.mocked(automate.retrieveSessionFailures).mockResolvedValue( 'Session Failures (1 found):\n' + JSON.stringify(['[ERROR] Test failed'], null, 2) ); vi.mocked(automate.retrieveConsoleFailures).mockResolvedValue( 'Console Failures (1 found):\n' + JSON.stringify(['Uncaught TypeError'], null, 2) ); }); it('should fetch network logs successfully', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; const result = await getFailureLogs({ sessionId: mockSessionId, logTypes: ['networkLogs'], sessionType: 'automate' }, mockServer); expect(automate.retrieveNetworkFailures).toHaveBeenCalledWith(mockSessionId, expect.anything()); expect(result.content?.[0]?.type).toBe('text'); expect(result.content?.[0]?.text).toContain('Network Failures (1 found)'); }); it('should fetch session logs successfully', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; const result = await getFailureLogs({ sessionId: mockSessionId, logTypes: ['sessionLogs'], sessionType: 'automate' }, mockServer); expect(automate.retrieveSessionFailures).toHaveBeenCalledWith(mockSessionId, expect.anything()); expect(result.content?.[0]?.text).toContain('Session Failures (1 found)'); expect(result.content?.[0]?.text).toContain('[ERROR] Test failed'); }); it('should fetch console logs successfully', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; const result = await getFailureLogs({ sessionId: mockSessionId, logTypes: ['consoleLogs'], sessionType: 'automate' }, mockServer); expect(automate.retrieveConsoleFailures).toHaveBeenCalledWith(mockSessionId, expect.anything()); expect(result.content?.[0]?.text).toContain('Console Failures (1 found)'); expect(result.content?.[0]?.text).toContain('Uncaught TypeError'); }); }); describe('App-Automate Session Logs', () => { beforeEach(() => { vi.mocked(appAutomate.retrieveDeviceLogs).mockResolvedValue( 'Device Failures (1 found):\n' + JSON.stringify(['Fatal Exception: NullPointerException'], null, 2) ); vi.mocked(appAutomate.retrieveAppiumLogs).mockResolvedValue( 'Appium Failures (1 found):\n' + JSON.stringify(['Error: Element not found'], null, 2) ); vi.mocked(appAutomate.retrieveCrashLogs).mockResolvedValue( 'Crash Failures (1 found):\n' + JSON.stringify(['Application crashed due to signal 11'], null, 2) ); }); it('should fetch device logs successfully', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; const result = await getFailureLogs({ sessionId: mockSessionId, buildId: mockBuildId, logTypes: ['deviceLogs'], sessionType: 'app-automate' }, mockServer); expect(appAutomate.retrieveDeviceLogs).toHaveBeenCalledWith(mockSessionId, mockBuildId, expect.anything()); expect(result.content?.[0]?.text).toContain('Device Failures (1 found)'); expect(result.content?.[0]?.text).toContain('Fatal Exception'); }); it('should fetch appium logs successfully', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; const result = await getFailureLogs({ sessionId: mockSessionId, buildId: mockBuildId, logTypes: ['appiumLogs'], sessionType: 'app-automate' }, mockServer); expect(appAutomate.retrieveAppiumLogs).toHaveBeenCalledWith(mockSessionId, mockBuildId, expect.anything()); expect(result.content?.[0]?.text).toContain('Appium Failures (1 found)'); expect(result.content?.[0]?.text).toContain('Element not found'); }); it('should fetch crash logs successfully', async () => { const mockServer = { server: { getClientVersion: () => "test-version" } }; const result = await getFailureLogs({ sessionId: mockSessionId, buildId: mockBuildId, logTypes: ['crashLogs'], sessionType: 'app-automate' }, mockServer); expect(appAutomate.retrieveCrashLogs).toHaveBeenCalledWith(mockSessionId, mockBuildId, expect.anything()); expect(result.content?.[0]?.text).toContain('Crash Failures (1 found)'); expect(result.content?.[0]?.text).toContain('signal 11'); }); }); describe('Error Handling', () => { it('should handle empty log responses', async () => { vi.mocked(automate.retrieveNetworkFailures).mockResolvedValue('No network failures found'); const mockServer = { server: { getClientVersion: () => "test-version" } }; const result = await getFailureLogs({ sessionId: mockSessionId, logTypes: ['networkLogs'], sessionType: 'automate' }, mockServer); expect(result.content?.[0]?.text).toBe('No network failures found'); }); }); describe('Log Filtering', () => { beforeEach(() => { // Reset mock implementations before each test vi.mocked(automate.filterSessionFailures).mockImplementation((text: string) => { const lines = text.split('\n'); return lines.filter((line: string) => line.includes('ERROR') || line.includes('EXCEPTION') || line.includes('FATAL') ); }); vi.mocked(automate.filterConsoleFailures).mockImplementation((text: string) => { const lines = text.split('\n'); return lines.filter((line: string) => line.includes('Failed to load resource') || line.includes('Uncaught TypeError') ); }); vi.mocked(appAutomate.filterDeviceFailures).mockReturnValue([]); vi.mocked(appAutomate.filterAppiumFailures).mockReturnValue([]); vi.mocked(appAutomate.filterCrashFailures).mockReturnValue([]); }); it('should filter session logs correctly', () => { const logText = ` [INFO] Starting test [ERROR] Test failed [INFO] Continuing [EXCEPTION] NullPointerException [FATAL] Process crashed [INFO] Test completed `; const result = vi.mocked(automate.filterSessionFailures)(logText); expect(result).toEqual([ '[ERROR] Test failed', '[EXCEPTION] NullPointerException', '[FATAL] Process crashed' ]); }); it('should filter console logs correctly', () => { const logText = ` console.log('Starting test') console.error('Failed to load resource') console.info('Test progress') console.error('Uncaught TypeError') `; const result = vi.mocked(automate.filterConsoleFailures)(logText); expect(result).toEqual([ "console.error('Failed to load resource')", "console.error('Uncaught TypeError')" ]); }); it('should handle empty inputs in filters', () => { const emptyResult: string[] = []; vi.mocked(automate.filterSessionFailures).mockReturnValue(emptyResult); vi.mocked(automate.filterConsoleFailures).mockReturnValue(emptyResult); vi.mocked(appAutomate.filterDeviceFailures).mockReturnValue(emptyResult); vi.mocked(appAutomate.filterAppiumFailures).mockReturnValue(emptyResult); vi.mocked(appAutomate.filterCrashFailures).mockReturnValue(emptyResult); expect(automate.filterSessionFailures('')).toEqual([]); expect(automate.filterConsoleFailures('')).toEqual([]); expect(appAutomate.filterDeviceFailures('')).toEqual([]); expect(appAutomate.filterAppiumFailures('')).toEqual([]); expect(appAutomate.filterCrashFailures('')).toEqual([]); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/browserstack/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server