From b0cf42708f89998bb9b4abef87348bfa033b2cd5 Mon Sep 17 00:00:00 2001 From: Shirish Kamath Date: Thu, 1 Feb 2024 16:22:19 +0530 Subject: [PATCH] Compatibility fixes for deno support local-testing still has issues with node:child_process support --- deno-import-map.json | 5 +++++ src/__tests__/app-automate.test.ts | 6 ++--- src/__tests__/automate.test.ts | 4 ++-- src/__tests__/deno.ts | 30 +++++++++++++++++++++++++ src/__tests__/js-testing.test.ts | 6 ++--- src/__tests__/local.test.ts | 6 ++--- src/__tests__/screenshots.test.ts | 4 ++-- src/__tests__/setup.ts | 4 ++-- src/api-client.ts | 36 +++++++++++++++++++++--------- src/app-automate.ts | 6 ++--- src/automate.ts | 6 ++--- src/env.ts | 18 +++++++++++++++ src/error.ts | 2 +- src/index.ts | 26 ++++++++++----------- src/js-testing.ts | 4 ++-- src/local-testing.ts | 13 ++++++----- src/pkginfo.ts | 13 ++++++----- src/screenshots.ts | 4 ++-- 18 files changed, 132 insertions(+), 61 deletions(-) create mode 100644 deno-import-map.json create mode 100644 src/__tests__/deno.ts create mode 100644 src/env.ts diff --git a/deno-import-map.json b/deno-import-map.json new file mode 100644 index 0000000..516b961 --- /dev/null +++ b/deno-import-map.json @@ -0,0 +1,5 @@ +{ + "imports": { + "@/": "./src/" + } +} diff --git a/src/__tests__/app-automate.test.ts b/src/__tests__/app-automate.test.ts index a4d81e7..7689c57 100644 --- a/src/__tests__/app-automate.test.ts +++ b/src/__tests__/app-automate.test.ts @@ -1,8 +1,8 @@ -import { FlutterPlatform } from "@/app-automate"; -import { components } from "@/generated/openapi"; +import { FlutterPlatform } from "@/app-automate.ts" +import { components } from "@/generated/openapi.ts" import { zipSync } from "fflate"; import { describe, expect, expectTypeOf, test } from "vitest"; -import type { BrowserStackTestContext } from "./setup"; +import type { BrowserStackTestContext } from "./setup.ts"; describe("AppAutomateClient", () => { describe("Devices", () => { diff --git a/src/__tests__/automate.test.ts b/src/__tests__/automate.test.ts index 5ca5bca..fb6f82a 100644 --- a/src/__tests__/automate.test.ts +++ b/src/__tests__/automate.test.ts @@ -1,6 +1,6 @@ -import { components } from "@/generated/openapi"; +import { components } from "@/generated/openapi.ts" import { describe, expect, expectTypeOf, test } from "vitest"; -import type { BrowserStackTestContext } from "./setup"; +import type { BrowserStackTestContext } from "./setup.ts"; describe("AutomateClient", () => { diff --git a/src/__tests__/deno.ts b/src/__tests__/deno.ts new file mode 100644 index 0000000..cfd5b1a --- /dev/null +++ b/src/__tests__/deno.ts @@ -0,0 +1,30 @@ +import { BrowserStack } from "@/index.ts"; +import { load } from "https://deno.land/std@0.213.0/dotenv/mod.ts"; + +const env = await load(); + +const options = { + username: env.VITE_BROWSERSTACK_USERNAME, + key: env.VITE_BROWSERSTACK_KEY, +}; + +// BrowserStack JavaScript Testing API +const jsTestingClient = new BrowserStack.Client(options); + +// BrowserStack Automate API +const automateClient = new BrowserStack.AutomateClient(options); + +// BrowserStack App Automate API +const appAutomateClient = new BrowserStack.AppAutomateClient(options); + +// BrowserStack Screenshots API +const screenshotsClient = new BrowserStack.ScreenshotsClient(options); + +// BrowserStack Local Testing API +const localTestingClient = new BrowserStack.LocalTestingClient(options); + +console.log("jsTestingClient.getBrowsers()", await jsTestingClient.getBrowsers()); +console.log("automateClient.getBrowsers()", await automateClient.getBrowsers()); +console.log("appAutomateClient.getDevices()", await appAutomateClient.getDevices()); +console.log("screenshotsClient.getBrowsers()", await screenshotsClient.getBrowsers()); +console.log("localTestingClient.getBinaryInstances()", await localTestingClient.getBinaryInstances()); diff --git a/src/__tests__/js-testing.test.ts b/src/__tests__/js-testing.test.ts index ba42278..449ee56 100644 --- a/src/__tests__/js-testing.test.ts +++ b/src/__tests__/js-testing.test.ts @@ -1,6 +1,6 @@ -import { components } from "@/generated/openapi"; +import { components } from "@/generated/openapi.ts" import { describe, expect, expectTypeOf, test } from "vitest"; -import type { BrowserStackTestContext } from "./setup"; +import type { BrowserStackTestContext } from "./setup.ts"; describe("JSTestingClient", () => { @@ -67,4 +67,4 @@ describe("JSTestingClient", () => { expectTypeOf(data).toMatchTypeOf<{ time: number }>(); }); }); -}, 10_000); +}, 15_000); diff --git a/src/__tests__/local.test.ts b/src/__tests__/local.test.ts index 99e0629..18ef7a4 100644 --- a/src/__tests__/local.test.ts +++ b/src/__tests__/local.test.ts @@ -1,8 +1,8 @@ -import { components } from "@/generated/openapi"; -import { BrowserStack } from "@/index"; +import { components } from "@/generated/openapi.ts" +import { BrowserStack } from "@/index.ts" import { stat } from "node:fs/promises"; import { beforeAll, describe, expect, expectTypeOf, test } from "vitest"; -import type { BrowserStackTestContext } from "./setup"; +import type { BrowserStackTestContext } from "./setup.ts"; describe("LocalClient", () => { beforeAll(async () => { diff --git a/src/__tests__/screenshots.test.ts b/src/__tests__/screenshots.test.ts index 31cc7c9..0bd166c 100644 --- a/src/__tests__/screenshots.test.ts +++ b/src/__tests__/screenshots.test.ts @@ -1,6 +1,6 @@ -import { components } from "@/generated/openapi"; +import { components } from "@/generated/openapi.ts" import { describe, expect, expectTypeOf, test } from "vitest"; -import type { BrowserStackTestContext } from "./setup"; +import type { BrowserStackTestContext } from "./setup.ts"; describe("ScreenshotsClient", () => { test("getBrowsers", async ({ diff --git a/src/__tests__/setup.ts b/src/__tests__/setup.ts index 63a5b7b..f141f24 100644 --- a/src/__tests__/setup.ts +++ b/src/__tests__/setup.ts @@ -1,4 +1,4 @@ -import { FlutterPlatform } from "@/app-automate"; +import { FlutterPlatform } from "@/app-automate.ts" import { BrowserStackOptions, AppAutomateClient, @@ -7,7 +7,7 @@ import { ScreenshotsClient, JSTestingClient, LocalTestingClient, -} from "@/index"; +} from "@/index.ts" import { assert, beforeEach } from "vitest"; export interface BrowserStackTestContext { diff --git a/src/api-client.ts b/src/api-client.ts index 44c2d2d..1474b46 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -1,15 +1,17 @@ -import { BrowserStackError } from "@/error"; -import { paths } from "@/generated/openapi"; -import { servers } from "@/generated/openapi.json"; -import pkginfo from "@/pkginfo"; -import createClient, { ClientOptions, FetchOptions } from "openapi-fetch"; -import { +import { env } from "@/env.ts"; +import { BrowserStackError } from "@/error.ts"; +import openapi from "@/generated/openapi.json" assert { type: "json" }; +import { paths } from "@/generated/openapi.ts"; +import pkginfo from "@/pkginfo.ts"; +import type { ClientOptions, FetchOptions } from "openapi-fetch"; +import createClient from "openapi-fetch"; +import type { FilterKeys, HasRequiredKeys, PathsWithMethod, } from "openapi-typescript-helpers"; -const [{ variables }, { variables: cloudVars }] = servers; +const [{ variables }, { variables: cloudVars }] = openapi?.servers ?? []; const defaultBaseUrl = `${variables.scheme.default}://${ variables.host.default @@ -45,7 +47,7 @@ export class APIClient { protected readonly sdkCloud: ReturnType>; constructor(options: BrowserStackOptions) { - const username = options.username ?? process.env.BROWSERSTACK_USERNAME; + const username = options.username ?? env.BROWSERSTACK_USERNAME; if ( options.usernameOptional !== true && (typeof username !== "string" || !username.trim().length) @@ -53,7 +55,7 @@ export class APIClient { throw new BrowserStackError("Missing options.username"); } - const key = options.key ?? process.env.BROWSERSTACK_KEY; + const key = options.key ?? env.BROWSERSTACK_KEY; if (typeof key !== "string" || !key.trim().length) { throw new BrowserStackError("Missing options.key"); } @@ -64,7 +66,7 @@ export class APIClient { headers: { ...options.headers, Authorization: username - ? `Basic ${Buffer.from(`${username}:${key}`).toString("base64")}` + ? `Basic ${btoa(`${username}:${key}`)}` : undefined, "User-Agent": pkginfo.userAgent, }, @@ -89,6 +91,8 @@ export class APIClient { ? [(FetchOptions> | undefined)?] : [FetchOptions>] ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const response = await this.sdk.GET(path, ...init); if (response.error || !response.data) { throw new BrowserStackError(`Request failed`, { @@ -112,6 +116,8 @@ export class APIClient { ? [(FetchOptions> | undefined)?] : [FetchOptions>] ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const response = await this.sdk.POST(path, ...init); if (response.error || !response.data) { throw new BrowserStackError(`Request failed`, { @@ -135,6 +141,8 @@ export class APIClient { ? [(FetchOptions> | undefined)?] : [FetchOptions>] ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const response = await this.sdkCloud.GET(path, ...init); if (response.error || !response.data) { throw new BrowserStackError(`Request failed`, { @@ -160,6 +168,8 @@ export class APIClient { ? [(FetchOptions> | undefined)?] : [FetchOptions>] ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const response = await this.sdkCloud.POST(path, ...init); if (response.error || !response.data) { throw new BrowserStackError(`Request failed`, { @@ -183,6 +193,8 @@ export class APIClient { ? [(FetchOptions> | undefined)?] : [FetchOptions>] ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const response = await this.sdk.PUT(path, ...init); if (response.error || !response.data) { throw new BrowserStackError(`Request failed`, { @@ -206,6 +218,8 @@ export class APIClient { ? [(FetchOptions> | undefined)?] : [FetchOptions>] ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const response = await this.sdk.PATCH(path, ...init); if (response.error || !response.data) { throw new BrowserStackError(`Request failed`, { @@ -229,6 +243,8 @@ export class APIClient { ? [(FetchOptions> | undefined)?] : [FetchOptions>] ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const response = await this.sdk.DELETE(path, ...init); if (response.error || !response.data) { throw new BrowserStackError(`Request failed`, { diff --git a/src/app-automate.ts b/src/app-automate.ts index 7540997..e1801e4 100644 --- a/src/app-automate.ts +++ b/src/app-automate.ts @@ -1,6 +1,6 @@ -import { APIClient, APIFetchOptions, BrowserStackOptions } from "@/api-client"; -import { BrowserStackError } from "@/error"; -import { components, operations } from "@/generated/openapi"; +import { APIClient, APIFetchOptions, BrowserStackOptions } from "@/api-client.ts" +import { BrowserStackError } from "@/error.ts" +import { components, operations } from "@/generated/openapi.ts" /** * AppAutomateClient represents a client for interacting with the BrowserStack App Automate API. diff --git a/src/automate.ts b/src/automate.ts index 3e53830..ce8afbb 100644 --- a/src/automate.ts +++ b/src/automate.ts @@ -1,6 +1,6 @@ -import { APIClient, BrowserStackOptions, APIFetchOptions } from "@/api-client"; -import { BrowserStackError } from "@/error"; -import { operations } from "@/generated/openapi"; +import { APIClient, BrowserStackOptions, APIFetchOptions } from "@/api-client.ts" +import { BrowserStackError } from "@/error.ts" +import { operations } from "@/generated/openapi.ts" /** * AutomateClient represents a client for interacting with the BrowserStack Automate API. diff --git a/src/env.ts b/src/env.ts new file mode 100644 index 0000000..aa360df --- /dev/null +++ b/src/env.ts @@ -0,0 +1,18 @@ +// for compatibility with nodejs and deno + +interface Dict { + [key: string]: T | undefined; +} + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +const proc = globalThis.process ?? { env: {}, versions: {} }; + +export const env: Dict = { ...proc?.env }; + +export const versions: Dict = { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + node: "unknown", + ...proc?.versions, +}; diff --git a/src/error.ts b/src/error.ts index c04d2dd..e5375bf 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1,4 +1,4 @@ -import { paths } from "@/generated/openapi"; +import { paths } from "@/generated/openapi.ts" import { FetchOptions, FetchResponse } from "openapi-fetch"; export type ErrorContext

= (FetchOptions & { diff --git a/src/index.ts b/src/index.ts index 5df4a0a..3f9e381 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,17 +1,17 @@ -import { AppAutomateClient } from "@/app-automate"; -import { AutomateClient } from "@/automate"; -import type { components } from "@/generated/openapi"; -import { JSTestingClient } from "@/js-testing"; -import { LocalTestingClient } from "@/local-testing"; -import { ScreenshotsClient } from "@/screenshots"; +import { AppAutomateClient } from "@/app-automate.ts" +import { AutomateClient } from "@/automate.ts" +import type { components } from "@/generated/openapi.ts" +import { JSTestingClient } from "@/js-testing.ts" +import { LocalTestingClient } from "@/local-testing.ts" +import { ScreenshotsClient } from "@/screenshots.ts" -export type { APIFetchOptions, BrowserStackOptions } from "@/api-client"; -export type { AppAutomateClient } from "@/app-automate"; -export type { AutomateClient } from "@/automate"; -export type { BrowserStackError, ErrorContext } from "@/error"; -export type { JSTestingClient } from "@/js-testing"; -export type { LocalTestingClient } from "@/local-testing"; -export type { ScreenshotsClient } from "@/screenshots"; +export type { APIFetchOptions, BrowserStackOptions } from "@/api-client.ts" +export type { AppAutomateClient } from "@/app-automate.ts" +export type { AutomateClient } from "@/automate.ts" +export type { BrowserStackError, ErrorContext } from "@/error.ts" +export type { JSTestingClient } from "@/js-testing.ts" +export type { LocalTestingClient } from "@/local-testing.ts" +export type { ScreenshotsClient } from "@/screenshots.ts" export type schemas = components["schemas"]; diff --git a/src/js-testing.ts b/src/js-testing.ts index 3d8315e..339577b 100644 --- a/src/js-testing.ts +++ b/src/js-testing.ts @@ -1,5 +1,5 @@ -import { APIClient, APIFetchOptions, BrowserStackOptions } from "@/api-client"; -import { components, operations } from "@/generated/openapi"; +import { APIClient, APIFetchOptions, BrowserStackOptions } from "@/api-client.ts" +import { components, operations } from "@/generated/openapi.ts" /** * Represents a client for interacting with the BrowserStack JavaScript Testing API. diff --git a/src/local-testing.ts b/src/local-testing.ts index f1a67aa..9210213 100644 --- a/src/local-testing.ts +++ b/src/local-testing.ts @@ -1,7 +1,8 @@ -import { APIClient, APIFetchOptions, BrowserStackOptions } from "@/api-client"; -import { BrowserStackError } from "@/error"; -import { components, operations } from "@/generated/openapi"; -import { ChildProcess } from "node:child_process"; +import { APIClient, APIFetchOptions, BrowserStackOptions } from "@/api-client.ts" +import { env } from "@/env.ts" +import { BrowserStackError } from "@/error.ts" +import { components, operations } from "@/generated/openapi.ts" +import type { ChildProcess } from "node:child_process"; export type LocalTestingOptions = Omit; @@ -22,7 +23,7 @@ export class LocalTestingClient extends APIClient { usernameOptional: true, }); - const authToken = options?.key ?? process.env.BROWSERSTACK_KEY; + const authToken = options?.key ?? env.BROWSERSTACK_KEY; if (typeof authToken !== "string" || !authToken.trim().length) { throw new BrowserStackError("Missing options.key"); } @@ -129,7 +130,7 @@ export class LocalTestingClient extends APIClient { */ async downloadBinary( osArch: operations["downloadLocalBinary"]["parameters"]["path"]["osArch"], - dirPath: string | Buffer | URL, + dirPath: string, filenamePrefix: string = "BrowserStackLocal", fileMode: number = 0o755, options?: APIFetchOptions diff --git a/src/pkginfo.ts b/src/pkginfo.ts index 588f495..c419b29 100644 --- a/src/pkginfo.ts +++ b/src/pkginfo.ts @@ -1,14 +1,15 @@ -import { name, version } from "@/../package.json"; +import pkg from "../package.json" assert { type: "json" }; +import { versions } from "@/env.ts" -const libVersion = [ name, version ].join("/"); +const libVersion = [ pkg?.name, pkg?.version ].filter(Boolean).join("/"); -const envVersion = [ "node", process.versions.node ].join("/"); +const envVersion = [ "node", versions.node ].filter(Boolean).join("/"); -const userAgent = [ libVersion, envVersion ].join(" "); +const userAgent = [ libVersion, envVersion ].filter(Boolean).join(" "); const pkginfo = { - name, - version, + name: pkg?.name, + version: pkg?.version, userAgent, }; diff --git a/src/screenshots.ts b/src/screenshots.ts index 5809955..16c52aa 100644 --- a/src/screenshots.ts +++ b/src/screenshots.ts @@ -1,5 +1,5 @@ -import { APIClient, BrowserStackOptions, APIFetchOptions } from "@/api-client"; -import type { operations } from "@/generated/openapi"; +import { APIClient, BrowserStackOptions, APIFetchOptions } from "@/api-client.ts" +import type { operations } from "@/generated/openapi.ts" import type { FetchOptions } from "openapi-fetch"; /**