Skip to main content
Glama
tools-utils.test.ts5.25 kB
/** * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { waitForCompletion, generateLocator, callOnPageNoTrace } from '../src/tools/utils.js'; import type { Tab } from '../src/tab.js'; import { EventEmitter } from 'events'; describe('Tool Utils', () => { let mockTab: Tab; let mockPage: any; beforeEach(() => { mockPage = new EventEmitter(); mockPage.url = () => 'https://example.com'; mockPage.waitForLoadState = vi.fn().mockResolvedValue(undefined); mockPage.evaluate = vi.fn().mockResolvedValue(undefined); mockPage._wrapApiCall = vi.fn().mockImplementation(cb => cb()); mockTab = { page: mockPage, waitForLoadState: vi.fn().mockResolvedValue(undefined), waitForTimeout: vi.fn().mockResolvedValue(undefined), } as any; }); describe('waitForCompletion', () => { it('should wait for callback to complete', async () => { const callback = vi.fn().mockResolvedValue('result'); const result = await waitForCompletion(mockTab, callback); expect(callback).toHaveBeenCalled(); expect(result).toBe('result'); }); it('should wait for pending requests to finish', async () => { const callback = vi.fn().mockImplementation(() => { const request = { url: 'https://api.example.com' }; mockPage.emit('request', request); setTimeout(() => mockPage.emit('requestfinished', request), 10); return Promise.resolve('result'); }); const result = await waitForCompletion(mockTab, callback); expect(result).toBe('result'); }); it('should ignore sub-frame navigation', async () => { const callback = vi.fn().mockImplementation(() => { const subFrame = { parentFrame: () => ({}) }; mockPage.emit('framenavigated', subFrame); return Promise.resolve('result'); }); await waitForCompletion(mockTab, callback); // Should not wait for load state for sub-frames expect(mockTab.waitForTimeout).toHaveBeenCalled(); }); it('should timeout after 10 seconds', async () => { vi.useFakeTimers(); const callback = vi.fn().mockImplementation(() => { const request = { url: 'https://slow-api.example.com' }; mockPage.emit('request', request); // Never finish the request return Promise.resolve('result'); }); const promise = waitForCompletion(mockTab, callback); vi.advanceTimersByTime(10000); await promise; expect(callback).toHaveBeenCalled(); vi.useRealTimers(); }); it('should wait 1 second after completion', async () => { const callback = vi.fn().mockResolvedValue('result'); await waitForCompletion(mockTab, callback); expect(mockTab.waitForTimeout).toHaveBeenCalledWith(1000); }); }); describe('generateLocator', () => { it('should generate locator string', async () => { const mockLocator = { _resolveSelector: vi.fn().mockResolvedValue({ resolvedSelector: 'button[name="submit"]', }), } as any; // Mock the asLocator function vi.mock('playwright-core/lib/utils', () => ({ asLocator: (lang: string, selector: string) => `locator('${selector}')`, })); const result = await generateLocator(mockLocator); expect(mockLocator._resolveSelector).toHaveBeenCalled(); expect(result).toBeDefined(); }); it('should throw error for invalid locator', async () => { const mockLocator = { _resolveSelector: vi.fn().mockRejectedValue(new Error('Selector not found')), } as any; await expect(generateLocator(mockLocator)).rejects.toThrow('Ref not found'); }); }); describe('callOnPageNoTrace', () => { it('should call function on page without tracing', async () => { const callback = vi.fn().mockResolvedValue('result'); const result = await callOnPageNoTrace(mockPage, callback); expect(callback).toHaveBeenCalledWith(mockPage); expect(result).toBe('result'); expect(mockPage._wrapApiCall).toHaveBeenCalled(); }); it('should pass through errors', async () => { const callback = vi.fn().mockRejectedValue(new Error('Test error')); await expect(callOnPageNoTrace(mockPage, callback)).rejects.toThrow('Test error'); }); it('should mark call as internal', async () => { const callback = vi.fn().mockResolvedValue('result'); await callOnPageNoTrace(mockPage, callback); expect(mockPage._wrapApiCall).toHaveBeenCalledWith( expect.any(Function), { internal: true } ); }); }); });

Latest Blog Posts

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/JustasMonkev/mcp-accessibility-scanner'

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