Skip to content

Tool Name Change #44

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const AppAutomateLogType = {
CrashLogs: "crashLogs",
} as const;

export type SessionType = typeof SessionType[keyof typeof SessionType];
export type AutomateLogType = typeof AutomateLogType[keyof typeof AutomateLogType];
export type AppAutomateLogType = typeof AppAutomateLogType[keyof typeof AppAutomateLogType];
export type SessionType = (typeof SessionType)[keyof typeof SessionType];
export type AutomateLogType =
(typeof AutomateLogType)[keyof typeof AutomateLogType];
export type AppAutomateLogType =
(typeof AppAutomateLogType)[keyof typeof AppAutomateLogType];
15 changes: 10 additions & 5 deletions src/tools/automate-utils/fetch-screenshots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { assertOkResponse, maybeCompressBase64 } from "../../lib/utils.js";
import { SessionType } from "../../lib/constants.js";

//Extracts screenshot URLs from BrowserStack session logs
async function extractScreenshotUrls(sessionId: string, sessionType: SessionType): Promise<string[]> {

async function extractScreenshotUrls(
sessionId: string,
sessionType: SessionType,
): Promise<string[]> {
const credentials = `${config.browserstackUsername}:${config.browserstackAccessKey}`;
const auth = Buffer.from(credentials).toString("base64");

const baseUrl = `https://api.browserstack.com/${sessionType === SessionType.Automate ? 'automate' : 'app-automate'}`;
const baseUrl = `https://api.browserstack.com/${sessionType === SessionType.Automate ? "automate" : "app-automate"}`;

const url = `${baseUrl}/sessions/${sessionId}/logs`;
const response = await fetch(url, {
Expand All @@ -21,7 +23,7 @@ async function extractScreenshotUrls(sessionId: string, sessionType: SessionType
await assertOkResponse(response, "Session");

const text = await response.text();

const urls: string[] = [];
const SCREENSHOT_PATTERN = /REQUEST.*GET.*\/screenshot/;
const RESPONSE_VALUE_PATTERN = /"value"\s*:\s*"([^"]+)"/;
Expand Down Expand Up @@ -68,7 +70,10 @@ async function convertUrlsToBase64(
}

//Fetches and converts screenshot URLs to base64 encoded images
export async function fetchAutomationScreenshots(sessionId: string, sessionType: SessionType = SessionType.Automate) {
export async function fetchAutomationScreenshots(
sessionId: string,
sessionType: SessionType = SessionType.Automate,
) {
const urls = await extractScreenshotUrls(sessionId, sessionType);
if (urls.length === 0) {
return [];
Expand Down
18 changes: 14 additions & 4 deletions src/tools/automate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ export async function fetchAutomationScreenshotsTool(args: {
sessionType: SessionType;
}): Promise<CallToolResult> {
try {
const screenshots = await fetchAutomationScreenshots(args.sessionId, args.sessionType);
const screenshots = await fetchAutomationScreenshots(
args.sessionId,
args.sessionType,
);

if (screenshots.length === 0) {
return {
Expand Down Expand Up @@ -60,14 +63,21 @@ export default function addAutomationTools(server: McpServer) {
.describe("The BrowserStack session ID to fetch screenshots from"),
sessionType: z
.enum([SessionType.Automate, SessionType.AppAutomate])
.describe("Type of BrowserStack session")
.describe("Type of BrowserStack session"),
},
async (args) => {
try {
trackMCP("fetchAutomationScreenshots", server.server.getClientVersion()!);
trackMCP(
"fetchAutomationScreenshots",
server.server.getClientVersion()!,
);
return await fetchAutomationScreenshotsTool(args);
} catch (error) {
trackMCP("fetchAutomationScreenshots", server.server.getClientVersion()!,error);
trackMCP(
"fetchAutomationScreenshots",
server.server.getClientVersion()!,
error,
);
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
return {
Expand Down
6 changes: 5 additions & 1 deletion src/tools/getFailureLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import {
retrieveCrashLogs,
} from "./failurelogs-utils/app-automate.js";
import { trackMCP } from "../lib/instrumentation.js";
import { AppAutomateLogType, AutomateLogType, SessionType } from "../lib/constants.js";
import {
AppAutomateLogType,
AutomateLogType,
SessionType,
} from "../lib/constants.js";

type LogType = AutomateLogType | AppAutomateLogType;
type SessionTypeValues = SessionType;
Expand Down
10 changes: 5 additions & 5 deletions src/tools/testmanagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,18 +250,18 @@ export async function addTestResultTool(
/**
* Uploads files such as PDRs or screenshots to BrowserStack Test Management and get file mapping ID back.
*/
export async function uploadFileTestManagementTool(
export async function uploadProductRequirementFileTool(
args: z.infer<typeof UploadFileSchema>,
): Promise<CallToolResult> {
try {
trackMCP(
"uploadFileTestManagement",
"uploadProductRequirementFile",
serverInstance.server.getClientVersion()!,
);
return await uploadFile(args);
} catch (err) {
trackMCP(
"uploadFileTestManagement",
"uploadProductRequirementFile",
serverInstance.server.getClientVersion()!,
err,
);
Expand Down Expand Up @@ -367,10 +367,10 @@ export default function addTestManagementTools(server: McpServer) {
);

server.tool(
"uploadFileTestManagement",
"uploadProductRequirementFile",
"Upload files such as PDRs or PDFs to BrowserStack Test Management and get file mapping ID back. Its Used for generating test cases from file.",
UploadFileSchema.shape,
uploadFileTestManagementTool,
uploadProductRequirementFileTool,
);
server.tool(
"createTestCasesFromFile",
Expand Down
8 changes: 4 additions & 4 deletions tests/tools/testmanagement.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
addTestResultTool,
listTestRunsTool,
updateTestRunTool,
uploadFileTestManagementTool,
uploadProductRequirementFileTool,
createTestCasesFromFileTool
} from '../../src/tools/testmanagement';
import addTestManagementTools from '../../src/tools/testmanagement';
Expand Down Expand Up @@ -443,12 +443,12 @@ const mockFileId = 12345;
const mockDownloadUrl = "https://cdn.browserstack.com/mock.pdf";
const mockContext = { sendNotification: vi.fn(), _meta: { progressToken: "test-progress-token" } };

describe("uploadFileTestManagementTool", () => {
describe("uploadProductRequirementFileTool", () => {
beforeEach(() => vi.resetAllMocks());

it("returns error when file does not exist", async () => {
(fs.existsSync as Mock).mockReturnValue(false);
const res = await uploadFileTestManagementTool({ project_identifier: testProjectId, file_path: testFilePath });
const res = await uploadProductRequirementFileTool({ project_identifier: testProjectId, file_path: testFilePath });
expect(res.isError).toBe(true);
expect(res.content[0].text).toContain("does not exist");
});
Expand All @@ -472,7 +472,7 @@ describe("uploadFileTestManagementTool", () => {
};
mockedAxios.get.mockResolvedValue({ data: { success: true, projects: [{ identifier: testProjectId, id: "999" }] } });
mockedAxios.post.mockResolvedValue(mockUpload);
const res = await uploadFileTestManagementTool({ project_identifier: testProjectId, file_path: testFilePath });
const res = await uploadProductRequirementFileTool({ project_identifier: testProjectId, file_path: testFilePath });
expect(res.isError ?? false).toBe(false);
expect(res.content[1].text).toContain("documentID");
});
Expand Down