visiblePage.test.ts•10.2 kB
import { VisibleTextTool, VisibleHtmlTool } from '../../../tools/browser/visiblePage.js';
import { ToolContext } from '../../../tools/common/types.js';
import { Page, Browser, ElementHandle } from 'playwright';
import { jest } from '@jest/globals';
// Mock the Page object
const mockEvaluate = jest.fn() as jest.MockedFunction<(pageFunction: Function | string, arg?: any) => Promise<any>>;
const mockContent = jest.fn();
const mockIsClosed = jest.fn().mockReturnValue(false);
const mock$ = jest.fn() as jest.MockedFunction<(selector: string) => Promise<ElementHandle | null>>;
const mockPage = {
evaluate: mockEvaluate,
content: mockContent,
isClosed: mockIsClosed,
$: mock$
} as unknown as Page;
// Mock the browser
const mockIsConnected = jest.fn().mockReturnValue(true);
const mockBrowser = {
isConnected: mockIsConnected
} as unknown as Browser;
// Mock the server
const mockServer = {
sendMessage: jest.fn()
};
// Mock context
const mockContext = {
page: mockPage,
browser: mockBrowser,
server: mockServer
} as ToolContext;
describe('VisibleTextTool', () => {
let visibleTextTool: VisibleTextTool;
beforeEach(() => {
jest.clearAllMocks();
visibleTextTool = new VisibleTextTool(mockServer);
// Reset mocks
mockIsConnected.mockReturnValue(true);
mockIsClosed.mockReturnValue(false);
mockEvaluate.mockImplementation(() => Promise.resolve('Sample visible text content'));
});
test('should retrieve visible text content', async () => {
const args = {};
const result = await visibleTextTool.execute(args, mockContext);
expect(mockEvaluate).toHaveBeenCalled();
expect(result.isError).toBe(false);
expect(result.content[0].text).toContain('Visible text content');
expect(result.content[0].text).toContain('Sample visible text content');
});
test('should handle missing page', async () => {
const args = {};
// Context with browser but without page
const contextWithoutPage = {
browser: mockBrowser,
server: mockServer
} as unknown as ToolContext;
const result = await visibleTextTool.execute(args, contextWithoutPage);
expect(mockEvaluate).not.toHaveBeenCalled();
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Page is not available');
});
test('should handle disconnected browser', async () => {
const args = {};
// Mock disconnected browser
mockIsConnected.mockReturnValueOnce(false);
const result = await visibleTextTool.execute(args, mockContext);
expect(mockEvaluate).not.toHaveBeenCalled();
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Browser is not connected');
});
test('should handle closed page', async () => {
const args = {};
// Mock closed page
mockIsClosed.mockReturnValueOnce(true);
const result = await visibleTextTool.execute(args, mockContext);
expect(mockEvaluate).not.toHaveBeenCalled();
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Page is not available or has been closed');
});
test('should handle evaluation errors', async () => {
const args = {};
// Mock evaluation error
mockEvaluate.mockImplementationOnce(() => Promise.reject(new Error('Evaluation failed')));
const result = await visibleTextTool.execute(args, mockContext);
expect(mockEvaluate).toHaveBeenCalled();
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Failed to get visible text content');
expect(result.content[0].text).toContain('Evaluation failed');
});
});
describe('VisibleHtmlTool', () => {
let visibleHtmlTool: VisibleHtmlTool;
beforeEach(() => {
jest.clearAllMocks();
visibleHtmlTool = new VisibleHtmlTool(mockServer);
// Reset mocks
mockIsConnected.mockReturnValue(true);
mockIsClosed.mockReturnValue(false);
mockContent.mockImplementation(() => Promise.resolve('<html><body>Sample HTML content</body></html>'));
});
test('should retrieve HTML content', async () => {
const args = { removeScripts: false };
const result = await visibleHtmlTool.execute(args, mockContext);
expect(mockContent).toHaveBeenCalled();
expect(result.isError).toBe(false);
expect(result.content[0].text).toContain('HTML content');
expect(result.content[0].text).toContain('<html><body>Sample HTML content</body></html>');
});
test('should supply the correct filters', async () => {
const args = {
removeScripts: true,
removeComments: true,
removeStyles: true,
removeMeta: true,
minify: true,
cleanHtml: true
};
// Mock the page.evaluate to capture the filter arguments
mockEvaluate.mockImplementationOnce((callback, params) => {
expect(params).toEqual({
html: '<html><body>Sample HTML content</body></html>',
removeScripts: true,
removeComments: true,
removeStyles: true,
removeMeta: true,
minify: true
});
return Promise.resolve('<html><body>Processed HTML content</body></html>');
});
const result = await visibleHtmlTool.execute(args, mockContext);
expect(mockContent).toHaveBeenCalled();
expect(mockEvaluate).toHaveBeenCalled();
expect(result.isError).toBe(false);
expect(result.content[0].text).toContain('HTML content');
expect(result.content[0].text).toContain('Processed HTML content');
});
test('should handle individual filter combinations', async () => {
const args = {
removeScripts: true,
minify: true
};
// Mock content to return HTML
mockContent.mockImplementationOnce(() =>
Promise.resolve('<html><body>Sample HTML content</body></html>')
);
mockEvaluate.mockImplementationOnce((callback, params: any) => {
expect(params).toEqual({
html: '<html><body>Sample HTML content</body></html>',
removeScripts: true,
removeComments: undefined,
removeStyles: undefined,
removeMeta: undefined,
minify: true
});
return Promise.resolve('<html><body>Filtered content</body></html>');
});
const result = await visibleHtmlTool.execute(args, mockContext);
expect(result.isError).toBe(false);
expect(result.content[0].text).toContain('Filtered content');
});
test('should handle selector parameter', async () => {
const args = {
selector: '#main-content',
removeScripts: true
};
// Mock element selection
const mockElement = {
outerHTML: '<div id="main-content">Selected content</div>'
} as unknown as ElementHandle<Element>;
mock$.mockResolvedValueOnce(mockElement);
// Mock evaluate for filtering
mockEvaluate.mockImplementation((_: any, params: any) =>
Promise.resolve('<div>Processed selected content</div>')
);
const result = await visibleHtmlTool.execute(args, mockContext);
expect(mock$).toHaveBeenCalledWith('#main-content');
expect(result.isError).toBe(false);
expect(result.content[0].text).toContain('Processed selected content');
});
test('should handle empty HTML content', async () => {
const args = {
removeScripts: true
};
// Mock content to return empty HTML
mockContent.mockImplementationOnce(() => Promise.resolve(''));
mockEvaluate.mockImplementationOnce((callback, params: any) => {
expect(params.html).toBe('');
return Promise.resolve('');
});
const result = await visibleHtmlTool.execute(args, mockContext);
expect(result.isError).toBe(false);
expect(result.content[0].text).toContain('HTML content');
});
test('should handle cleanHtml flag setting all filters', async () => {
const args = {
cleanHtml: true
};
mockEvaluate.mockImplementationOnce((callback, params) => {
expect(params).toEqual({
html: '<html><body>Sample HTML content</body></html>',
removeScripts: true,
removeComments: true,
removeStyles: true,
removeMeta: true,
minify: undefined
});
return Promise.resolve('<html><body>Processed HTML content</body></html>');
});
const result = await visibleHtmlTool.execute(args, mockContext);
expect(result.isError).toBe(false);
});
test('should handle missing page', async () => {
const args = {};
// Context with browser but without page
const contextWithoutPage = {
browser: mockBrowser,
server: mockServer
} as unknown as ToolContext;
const result = await visibleHtmlTool.execute(args, contextWithoutPage);
expect(mockContent).not.toHaveBeenCalled();
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Page is not available');
});
test('should handle disconnected browser', async () => {
const args = {};
// Mock disconnected browser
mockIsConnected.mockReturnValueOnce(false);
const result = await visibleHtmlTool.execute(args, mockContext);
expect(mockContent).not.toHaveBeenCalled();
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Browser is not connected');
});
test('should handle closed page', async () => {
const args = {};
// Mock closed page
mockIsClosed.mockReturnValueOnce(true);
const result = await visibleHtmlTool.execute(args, mockContext);
expect(mockContent).not.toHaveBeenCalled();
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Page is not available or has been closed');
});
test('should handle content retrieval errors', async () => {
const args = {};
// Mock content error
mockContent.mockImplementationOnce(() => Promise.reject(new Error('Content retrieval failed')));
const result = await visibleHtmlTool.execute(args, mockContext);
expect(mockContent).toHaveBeenCalled();
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain('Failed to get visible HTML content');
expect(result.content[0].text).toContain('Content retrieval failed');
});
});