Skip to content

Commit

Permalink
Compatibility fixes for deno support
Browse files Browse the repository at this point in the history
local-testing still has issues with node:child_process support
  • Loading branch information
shirish87 committed Feb 1, 2024
1 parent 1f9730e commit b0cf427
Show file tree
Hide file tree
Showing 18 changed files with 132 additions and 61 deletions.
5 changes: 5 additions & 0 deletions deno-import-map.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"imports": {
"@/": "./src/"
}
}
6 changes: 3 additions & 3 deletions src/__tests__/app-automate.test.ts
Original file line number Diff line number Diff line change
@@ -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", () => {
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/automate.test.ts
Original file line number Diff line number Diff line change
@@ -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", () => {

Expand Down
30 changes: 30 additions & 0 deletions src/__tests__/deno.ts
Original file line number Diff line number Diff line change
@@ -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());
6 changes: 3 additions & 3 deletions src/__tests__/js-testing.test.ts
Original file line number Diff line number Diff line change
@@ -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", () => {

Expand Down Expand Up @@ -67,4 +67,4 @@ describe("JSTestingClient", () => {
expectTypeOf(data).toMatchTypeOf<{ time: number }>();
});
});
}, 10_000);
}, 15_000);
6 changes: 3 additions & 3 deletions src/__tests__/local.test.ts
Original file line number Diff line number Diff line change
@@ -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 () => {
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/screenshots.test.ts
Original file line number Diff line number Diff line change
@@ -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<BrowserStackTestContext>("getBrowsers", async ({
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/setup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FlutterPlatform } from "@/app-automate";
import { FlutterPlatform } from "@/app-automate.ts"
import {
BrowserStackOptions,
AppAutomateClient,
Expand All @@ -7,7 +7,7 @@ import {
ScreenshotsClient,
JSTestingClient,
LocalTestingClient,
} from "@/index";
} from "@/index.ts"
import { assert, beforeEach } from "vitest";

export interface BrowserStackTestContext {
Expand Down
36 changes: 26 additions & 10 deletions src/api-client.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -45,15 +47,15 @@ export class APIClient {
protected readonly sdkCloud: ReturnType<typeof createClient<paths>>;

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)
) {
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");
}
Expand All @@ -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,
},
Expand All @@ -89,6 +91,8 @@ export class APIClient {
? [(FetchOptions<FilterKeys<paths[P], "get">> | undefined)?]
: [FetchOptions<FilterKeys<paths[P], "get">>]
) {
// 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`, {
Expand All @@ -112,6 +116,8 @@ export class APIClient {
? [(FetchOptions<FilterKeys<paths[P], "post">> | undefined)?]
: [FetchOptions<FilterKeys<paths[P], "post">>]
) {
// 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`, {
Expand All @@ -135,6 +141,8 @@ export class APIClient {
? [(FetchOptions<FilterKeys<paths[P], "get">> | undefined)?]
: [FetchOptions<FilterKeys<paths[P], "get">>]
) {
// 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`, {
Expand All @@ -160,6 +168,8 @@ export class APIClient {
? [(FetchOptions<FilterKeys<paths[P], "post">> | undefined)?]
: [FetchOptions<FilterKeys<paths[P], "post">>]
) {
// 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`, {
Expand All @@ -183,6 +193,8 @@ export class APIClient {
? [(FetchOptions<FilterKeys<paths[P], "put">> | undefined)?]
: [FetchOptions<FilterKeys<paths[P], "put">>]
) {
// 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`, {
Expand All @@ -206,6 +218,8 @@ export class APIClient {
? [(FetchOptions<FilterKeys<paths[P], "patch">> | undefined)?]
: [FetchOptions<FilterKeys<paths[P], "patch">>]
) {
// 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`, {
Expand All @@ -229,6 +243,8 @@ export class APIClient {
? [(FetchOptions<FilterKeys<paths[P], "delete">> | undefined)?]
: [FetchOptions<FilterKeys<paths[P], "delete">>]
) {
// 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`, {
Expand Down
6 changes: 3 additions & 3 deletions src/app-automate.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
6 changes: 3 additions & 3 deletions src/automate.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
18 changes: 18 additions & 0 deletions src/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// for compatibility with nodejs and deno

interface Dict<T> {
[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<string> = { ...proc?.env };

export const versions: Dict<string> = {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
node: "unknown",
...proc?.versions,
};
2 changes: 1 addition & 1 deletion src/error.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { paths } from "@/generated/openapi";
import { paths } from "@/generated/openapi.ts"
import { FetchOptions, FetchResponse } from "openapi-fetch";

export type ErrorContext<P extends keyof paths, T> = (FetchOptions<unknown> & {
Expand Down
26 changes: 13 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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"];

Expand Down
4 changes: 2 additions & 2 deletions src/js-testing.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
13 changes: 7 additions & 6 deletions src/local-testing.ts
Original file line number Diff line number Diff line change
@@ -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<BrowserStackOptions, "username">;

Expand All @@ -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");
}
Expand Down Expand Up @@ -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<operations["downloadLocalBinary"]>
Expand Down
13 changes: 7 additions & 6 deletions src/pkginfo.ts
Original file line number Diff line number Diff line change
@@ -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,
};

Expand Down
4 changes: 2 additions & 2 deletions src/screenshots.ts
Original file line number Diff line number Diff line change
@@ -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";

/**
Expand Down

0 comments on commit b0cf427

Please sign in to comment.