diff --git a/.eslintignore b/.eslintignore index abb583ead..bd0869654 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ /node_modules/* /lib/* -/ui/* \ No newline at end of file +/ui/* +/test/* diff --git a/dashboard-frontend b/dashboard-frontend index b03b00768..4cfae8b86 160000 --- a/dashboard-frontend +++ b/dashboard-frontend @@ -1 +1 @@ -Subproject commit b03b00768e50b6b28a43fd87b030082a9cf4658f +Subproject commit 4cfae8b869b5730fac913ea0a9599ad54315a95b diff --git a/src/CapabilityManager.ts b/src/CapabilityManager.ts index f6f82a960..8b8d15bf7 100644 --- a/src/CapabilityManager.ts +++ b/src/CapabilityManager.ts @@ -118,8 +118,8 @@ export async function iOSCapabilities( delete caps.firstMatch[0]['appium:wdaLocalPort']; } } - if(!freeDevice.realDevice) { - caps.firstMatch[0]['appium:derivedDataPath'] =`${freeDevice.derivedDataPath}`; + if (!freeDevice.realDevice) { + caps.firstMatch[0]['appium:derivedDataPath'] = `${freeDevice.derivedDataPath}`; } const deleteMatch = [ diff --git a/src/app/index.ts b/src/app/index.ts index 3e4600fd4..7ae302f32 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -13,7 +13,7 @@ import { registerAuthenticationRoutes } from '../auth/routers'; import { userService } from '../auth/services/user.service'; import { IPluginArgs } from '../interfaces/IPluginArgs'; -let dashboardPluginUrl: any = null; +const dashboardPluginUrl: any = null; const ASYNC_LOCK = new AsyncLock(); diff --git a/src/app/routers/grid.ts b/src/app/routers/grid.ts index 3ba809eb0..6b3916df4 100644 --- a/src/app/routers/grid.ts +++ b/src/app/routers/grid.ts @@ -34,7 +34,7 @@ async function getSavedDevices(request: Request, response: Response) { async function getDevices(request: Request, response: Response) { const { user } = request as AuthenticatedRequest; const filterOptions = user?.role === 'admin' ? {} : { userId: user?.userId }; - let devices = await getAllDevices(filterOptions as any); + const devices = await getAllDevices(filterOptions as any); const { sessionId } = request.query; if (sessionId) { return response.json(devices.find((value) => value.session_id === sessionId)); diff --git a/src/config.ts b/src/config.ts index 2c37fc0a1..ec0cce910 100644 --- a/src/config.ts +++ b/src/config.ts @@ -21,7 +21,7 @@ function getDeviceFarmHome() { export function getServerMetadata() { const metaFile = path.join(getDeviceFarmHome(), 'metadata.json'); - let defaultMetadata = { + const defaultMetadata = { id: uuid(), }; if (fs.existsSync(metaFile)) { diff --git a/src/data-service/node-service.ts b/src/data-service/node-service.ts index 6e7240c59..180164078 100644 --- a/src/data-service/node-service.ts +++ b/src/data-service/node-service.ts @@ -63,7 +63,7 @@ export class NodeService { } } - static async getAllNodes(secure: boolean = true) { + static async getAllNodes(secure = true) { return prisma.node.findMany({ select: { id: true, diff --git a/src/helpers.ts b/src/helpers.ts index c14a48d30..9bd3a9bf2 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1,19 +1,19 @@ /* eslint-disable no-prototype-builtins */ -import os from 'os'; -import path from 'path'; -import tcpPortUsed from 'tcp-port-used'; -import getPort from 'get-port'; import AsyncLock from 'async-lock'; -import { IDevice } from './interfaces/IDevice'; +import asyncWait from 'async-wait-until'; +import axios from 'axios'; +import getPort from 'get-port'; import _ from 'lodash'; -import log from './logger'; -import Cloud from './enums/Cloud'; import normalizeUrl from 'normalize-url'; import ora from 'ora'; -import asyncWait from 'async-wait-until'; -import axios from 'axios'; +import os from 'os'; +import path from 'path'; +import tcpPortUsed from 'tcp-port-used'; +import Cloud from './enums/Cloud'; import { FakeModuleLoader } from './fake-module-loader'; +import { IDevice } from './interfaces/IDevice'; import { IExternalModuleLoader } from './interfaces/IExternalModule'; +import log from './logger'; const APPIUM_VENDOR_PREFIX = 'appium:'; @@ -35,8 +35,8 @@ class PortManager { */ async getAndAllocateFreePort(portRange?: string): Promise { return this.lock.acquire('port-allocation', async () => { + // eslint-disable-next-line no-constant-condition while (true) { - let port: number; let portOptions: number[] | undefined; // Determine which ports to try @@ -59,7 +59,7 @@ class PortManager { } // Get a free port from the system - port = portOptions ? await getPort({ port: portOptions }) : await getPort(); + const port = portOptions ? await getPort({ port: portOptions }) : await getPort(); // Atomically allocate it (we're in the lock, so this is safe) if (!this.allocatedPorts.has(port)) { diff --git a/src/modules b/src/modules index f553e00da..a348094f2 160000 --- a/src/modules +++ b/src/modules @@ -1 +1 @@ -Subproject commit f553e00da2e9f44e4c90c0aadb60403f39aacde2 +Subproject commit a348094f2e4b0d72e611dea2ff3a95e27d0df883 diff --git a/src/plugin.ts b/src/plugin.ts index 5c5ab7453..544661805 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -587,7 +587,9 @@ class DevicePlugin extends BasePlugin { let jwt = ''; if (this.pluginArgs.enableAuthentication) { const user = await getUserFromCapabilities(mergedCapabilites); - jwt = await generateTokenForNode(device.nodeId!, user?.id!); + if (user) { + jwt = await generateTokenForNode(device.nodeId!, user.id); + } } if (capabilitiesToCreateSession.capabilities.alwaysMatch) { capabilitiesToCreateSession.capabilities.alwaysMatch['df:udid'] = device.udid; diff --git a/src/scripts/ios-sign.ts b/src/scripts/ios-sign.ts index fca37b0f6..e2cea7d72 100644 --- a/src/scripts/ios-sign.ts +++ b/src/scripts/ios-sign.ts @@ -20,7 +20,7 @@ const execAsync = util.promisify(exec); const WDA_BUILD_PATH = '/appium_wda_ios/Build/Products/Debug-iphoneos'; let bundleIdName: { uuid: string; name: string }[] | null = null; let freeBundleID: { uuid: string; name: string } | null = null; -let isFreeAccount: boolean = false; +let isFreeAccount = false; async function getXcodeMajorVersion(): Promise { const { stdout } = await execAsync('xcodebuild -version'); const match = stdout.match(/Xcode (\d+)\./); @@ -235,7 +235,7 @@ async function zipPayloadDirectory( // Replace CFBundleIdentifier infoPlistContent = infoPlistContent.replace( /CFBundleIdentifier<\/key>\n\s*(.*?)<\/string>/, - `CFBundleIdentifier<\/key>\n${bundleId}<\/string>`, + `CFBundleIdentifier\n${bundleId}`, ); // Write Info.plist diff --git a/src/usbmux.ts b/src/usbmux.ts index 9053010ed..2fc57ccdf 100644 --- a/src/usbmux.ts +++ b/src/usbmux.ts @@ -1,6 +1,6 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-nocheck import * as net from 'net'; -import * as util from 'util'; import { EventEmitter } from 'events'; import * as Q from 'q'; import * as plist from 'plist'; @@ -218,8 +218,8 @@ class UsbmuxdError extends Error { this.number = number; this.message += ', Err #' + number; } - if (number === 2) this.message += ": Device isn't connected"; - if (number === 3) this.message += ": Port isn't available or open"; + if (number === 2) this.message += ': Device is not connected'; + if (number === 3) this.message += ': Port is not available or open'; if (number === 5) this.message += ': Malformed request'; } } diff --git a/test/e2e/android/cloud/confIOS.ts b/test/e2e/android/cloud/confIOS.ts index 45dfd58b1..e08413953 100644 --- a/test/e2e/android/cloud/confIOS.ts +++ b/test/e2e/android/cloud/confIOS.ts @@ -53,7 +53,7 @@ describe('Plugin Test', () => { it('Vertical swipe test', async () => { console.log(await driver.capabilities.deviceUDID); - let textButton = await driver.$('~Text Button'); + const textButton = await driver.$('~Text Button'); await textButton.waitForDisplayed({ timeout: 30000 }); await textButton.click(); }); diff --git a/test/e2e/plugin-harness.ts b/test/e2e/plugin-harness.ts index 635d529a3..c0b89308e 100644 --- a/test/e2e/plugin-harness.ts +++ b/test/e2e/plugin-harness.ts @@ -53,7 +53,7 @@ export function pluginE2EHarness(opts: E2ESetupOpts & { enableGoIos?: boolean }) enableGoIos, } = opts; - let server: AppiumServer | undefined = undefined; + const server: AppiumServer | undefined = undefined; async function goIosPath() { const appium_path = path.dirname(require.resolve('appium')); diff --git a/test/unit/DeviceModel.spec.ts b/test/unit/DeviceModel.spec.ts index 18976342f..0442c3328 100644 --- a/test/unit/DeviceModel.spec.ts +++ b/test/unit/DeviceModel.spec.ts @@ -10,7 +10,7 @@ import { import { IDevice } from '../../src/interfaces/IDevice'; import { prisma } from '../../src/prisma'; import { deviceMock } from './fixtures/devices'; -var sandbox = sinon.createSandbox(); +const sandbox = sinon.createSandbox(); describe('Model Test', async () => { before('Add device collection', async () => { @@ -172,7 +172,7 @@ describe('Model Test', async () => { it('Should handle concurrent update to device list', async () => { // create bunch of devices using loop - let newDeviceList = [] as unknown as IDevice[]; + const newDeviceList = [] as unknown as IDevice[]; for (let i = 0; i < 10; i++) { newDeviceList.push({ id: `dev-loop-${i}`, diff --git a/typings/appium-xcuitest-driver/index.d.ts b/typings/appium-xcuitest-driver/index.d.ts index 60492b882..222943c4b 100644 --- a/typings/appium-xcuitest-driver/index.d.ts +++ b/typings/appium-xcuitest-driver/index.d.ts @@ -1 +1 @@ -declare module 'appium-xcuitest-driver'; \ No newline at end of file +declare module 'appium-xcuitest-driver'; diff --git a/typings/node-simctl/index.d.ts b/typings/node-simctl/index.d.ts index f7497bf88..6885ed968 100644 --- a/typings/node-simctl/index.d.ts +++ b/typings/node-simctl/index.d.ts @@ -2,77 +2,77 @@ declare module 'node-simctl'; // Why do we have to do this? Because the typings for node-simctl are not imported automatically. export default Simctl; export type XCRun = { - /** - * Full path to the xcrun script - */ - path: string | null; + /** + * Full path to the xcrun script + */ + path: string | null; }; export type TAsyncOpts = { - asynchronous: true; + asynchronous: true; }; export type ExecOpts = { - /** - * - The list of additional subcommand arguments. - * It's empty by default. - */ - args?: string[] | undefined; - /** - * - Environment variables mapping. All these variables - * will be passed Simulator and used in the executing function. - */ - env?: Record | undefined; - /** - * - Set it to _false_ to throw execution errors - * immediately without logging any additional information. - */ - logErrors?: boolean | undefined; - /** - * - Whether to execute the given command - * 'synchronously' or 'asynchronously'. Affects the returned result of the function. - */ - asynchronous?: boolean | undefined; - /** - * - Explicitly sets streams encoding for the executed - * command input and outputs. - */ - encoding?: string | undefined; - /** - * - One or more architecture names to be enforced while - * executing xcrun. See https://github.com/appium/appium/issues/18966 for more details. - */ - architectures?: string | string[] | undefined; + /** + * - The list of additional subcommand arguments. + * It's empty by default. + */ + args?: string[] | undefined; + /** + * - Environment variables mapping. All these variables + * will be passed Simulator and used in the executing function. + */ + env?: Record | undefined; + /** + * - Set it to _false_ to throw execution errors + * immediately without logging any additional information. + */ + logErrors?: boolean | undefined; + /** + * - Whether to execute the given command + * 'synchronously' or 'asynchronously'. Affects the returned result of the function. + */ + asynchronous?: boolean | undefined; + /** + * - Explicitly sets streams encoding for the executed + * command input and outputs. + */ + encoding?: string | undefined; + /** + * - One or more architecture names to be enforced while + * executing xcrun. See https://github.com/appium/appium/issues/18966 for more details. + */ + architectures?: string | string[] | undefined; }; export type SimctlOpts = { - /** - * - The xcrun properties. Currently only one property - * is supported, which is `path` and it by default contains `null`, which enforces - * the instance to automatically detect the full path to `xcrun` tool and to throw - * an exception if it cannot be detected. If the path is set upon instance creation - * then it is going to be used by `exec` and no autodetection will happen. - */ - xcrun?: XCRun | undefined; - /** - * - The maximum number of milliseconds - * to wait for single synchronous xcrun command. - */ - execTimeout?: number | undefined; - /** - * - Whether to wire xcrun error messages - * into debug log before throwing them. - */ - logErrors?: boolean | undefined; - /** - * - The unique identifier of the current device, which is - * going to be implicitly passed to all methods, which require it. It can either be set - * upon instance creation if it is already known in advance or later when/if needed via the - * corresponding instance setter. - */ - udid?: string | null | undefined; - /** - * - Full path to the set of devices that you want to manage. - * By default this path usually equals to ~/Library/Developer/CoreSimulator/Devices - */ - devicesSetPath?: string | null | undefined; + /** + * - The xcrun properties. Currently only one property + * is supported, which is `path` and it by default contains `null`, which enforces + * the instance to automatically detect the full path to `xcrun` tool and to throw + * an exception if it cannot be detected. If the path is set upon instance creation + * then it is going to be used by `exec` and no autodetection will happen. + */ + xcrun?: XCRun | undefined; + /** + * - The maximum number of milliseconds + * to wait for single synchronous xcrun command. + */ + execTimeout?: number | undefined; + /** + * - Whether to wire xcrun error messages + * into debug log before throwing them. + */ + logErrors?: boolean | undefined; + /** + * - The unique identifier of the current device, which is + * going to be implicitly passed to all methods, which require it. It can either be set + * upon instance creation if it is already known in advance or later when/if needed via the + * corresponding instance setter. + */ + udid?: string | null | undefined; + /** + * - Full path to the set of devices that you want to manage. + * By default this path usually equals to ~/Library/Developer/CoreSimulator/Devices + */ + devicesSetPath?: string | null | undefined; }; /** * @typedef {Object} XCRun @@ -115,83 +115,142 @@ export type SimctlOpts = { * By default this path usually equals to ~/Library/Developer/CoreSimulator/Devices */ export class Simctl { - /** - * @param {SimctlOpts} [opts={}] - */ - constructor(opts?: SimctlOpts | undefined); - /** @type {XCRun} */ - xcrun: XCRun; - /** @type {number} */ - execTimeout: number; - /** @type {boolean} */ - logErrors: boolean; - /** @type {string?} */ - _udid: string | null; - /** @type {string?} */ - _devicesSetPath: string | null; - set udid(arg: string | null); - get udid(): string | null; - set devicesSetPath(arg: string | null); - get devicesSetPath(): string | null; - /** - * @param {string?} [commandName=null] - * @returns {string} - */ - requireUdid(commandName?: string | null | undefined): string; - /** - * @returns {Promise} - */ - requireXcrun(): Promise; - /** - * Execute the particular simctl command. - * - * @template {ExecOpts} TExecOpts - * @param {string} subcommand - One of available simctl subcommands. - * Execute `xcrun simctl` in Terminal to see the full list of available subcommands. - * @param {TExecOpts} [opts] - * @return {Promise} - * Either the result of teen process's `exec` or - * `SubProcess` instance depending of `opts.asynchronous` value. - * @throws {Error} If the simctl subcommand command returns non-zero return code. - */ - exec(subcommand: string, opts?: TExecOpts | undefined): Promise>; - addMedia: (this: Simctl, filePath: string) => Promise>; - appInfo: (this: Simctl, bundleId: string) => Promise; - bootDevice: (this: Simctl) => Promise; - startBootMonitor: (this: Simctl, opts?: import("./subcommands/bootstatus").BootMonitorOptions | undefined) => Promise; - createDevice: (this: Simctl, name: string, deviceTypeId: string, platformVersion: string, opts?: import("./subcommands/create").SimCreationOpts | undefined) => Promise; - deleteDevice: (this: Simctl, udid: string) => Promise; - eraseDevice: (this: Simctl, timeout?: number | undefined) => Promise; - getAppContainer: (this: Simctl, bundleId: string, containerType?: string | null | undefined) => Promise; - getEnv: (this: Simctl, varName: string) => Promise; - installApp: (this: Simctl, appPath: string) => Promise; - getScreenshot: (this: Simctl) => Promise; - addRootCertificate: (this: Simctl, cert: string, opts?: import("./subcommands/keychain").CertOptions | undefined) => Promise; - addCertificate: (this: Simctl, cert: string, opts?: import("./subcommands/keychain").CertOptions | undefined) => Promise; - resetKeychain: (this: Simctl) => Promise; - launchApp: (this: Simctl, bundleId: string, tries?: number | undefined) => Promise; - getDevicesByParsing: (this: Simctl, platform?: string | null | undefined) => Promise>; - getDevices: (this: Simctl, forSdk?: string | null | undefined, platform?: string | null | undefined) => Promise; - getRuntimeForPlatformVersionViaJson: (this: Simctl, platformVersion: string, platform?: string | undefined) => Promise; - getRuntimeForPlatformVersion: (this: Simctl, platformVersion: string, platform?: string | undefined) => Promise; - getDeviceTypes: (this: Simctl) => Promise; - list: (this: Simctl) => Promise; - setLocation: (this: Simctl, latitude: string | number, longitude: string | number) => Promise; - clearLocation: (this: Simctl) => Promise; - openUrl: (this: Simctl, url: string) => Promise>; - setPasteboard: (this: Simctl, content: string, encoding?: BufferEncoding | undefined) => Promise; - getPasteboard: (this: Simctl, encoding?: string | undefined) => Promise; - grantPermission: (this: Simctl, bundleId: string, perm: string) => Promise; - revokePermission: (this: Simctl, bundleId: string, perm: string) => Promise; - resetPermission: (this: Simctl, bundleId: string, perm: string) => Promise; - pushNotification: (this: Simctl, payload: any) => Promise; - shutdownDevice: (this: Simctl) => Promise; - spawnProcess: (this: Simctl, args: string | string[], env?: any) => Promise>; - spawnSubProcess: (this: Simctl, args: string | string[], env?: any) => Promise; - terminateApp: (this: Simctl, bundleId: string) => Promise; - getAppearance: (this: Simctl) => Promise; - setAppearance: (this: Simctl, appearance: string) => Promise; - removeApp: (this: Simctl, bundleId: string) => Promise; + /** + * @param {SimctlOpts} [opts={}] + */ + constructor(opts?: SimctlOpts | undefined); + /** @type {XCRun} */ + xcrun: XCRun; + /** @type {number} */ + execTimeout: number; + /** @type {boolean} */ + logErrors: boolean; + /** @type {string?} */ + _udid: string | null; + /** @type {string?} */ + _devicesSetPath: string | null; + set udid(arg: string | null); + get udid(): string | null; + set devicesSetPath(arg: string | null); + get devicesSetPath(): string | null; + /** + * @param {string?} [commandName=null] + * @returns {string} + */ + requireUdid(commandName?: string | null | undefined): string; + /** + * @returns {Promise} + */ + requireXcrun(): Promise; + /** + * Execute the particular simctl command. + * + * @template {ExecOpts} TExecOpts + * @param {string} subcommand - One of available simctl subcommands. + * Execute `xcrun simctl` in Terminal to see the full list of available subcommands. + * @param {TExecOpts} [opts] + * @return {Promise} + * Either the result of teen process's `exec` or + * `SubProcess` instance depending of `opts.asynchronous` value. + * @throws {Error} If the simctl subcommand command returns non-zero return code. + */ + exec( + subcommand: string, + opts?: TExecOpts | undefined, + ): Promise< + TExecOpts extends TAsyncOpts ? SubProcess : import('teen_process').TeenProcessExecResult + >; + addMedia: ( + this: Simctl, + filePath: string, + ) => Promise>; + appInfo: (this: Simctl, bundleId: string) => Promise; + bootDevice: (this: Simctl) => Promise; + startBootMonitor: ( + this: Simctl, + opts?: import('./subcommands/bootstatus').BootMonitorOptions | undefined, + ) => Promise; + createDevice: ( + this: Simctl, + name: string, + deviceTypeId: string, + platformVersion: string, + opts?: import('./subcommands/create').SimCreationOpts | undefined, + ) => Promise; + deleteDevice: (this: Simctl, udid: string) => Promise; + eraseDevice: (this: Simctl, timeout?: number | undefined) => Promise; + getAppContainer: ( + this: Simctl, + bundleId: string, + containerType?: string | null | undefined, + ) => Promise; + getEnv: (this: Simctl, varName: string) => Promise; + installApp: (this: Simctl, appPath: string) => Promise; + getScreenshot: (this: Simctl) => Promise; + addRootCertificate: ( + this: Simctl, + cert: string, + opts?: import('./subcommands/keychain').CertOptions | undefined, + ) => Promise; + addCertificate: ( + this: Simctl, + cert: string, + opts?: import('./subcommands/keychain').CertOptions | undefined, + ) => Promise; + resetKeychain: (this: Simctl) => Promise; + launchApp: (this: Simctl, bundleId: string, tries?: number | undefined) => Promise; + getDevicesByParsing: ( + this: Simctl, + platform?: string | null | undefined, + ) => Promise>; + getDevices: ( + this: Simctl, + forSdk?: string | null | undefined, + platform?: string | null | undefined, + ) => Promise; + getRuntimeForPlatformVersionViaJson: ( + this: Simctl, + platformVersion: string, + platform?: string | undefined, + ) => Promise; + getRuntimeForPlatformVersion: ( + this: Simctl, + platformVersion: string, + platform?: string | undefined, + ) => Promise; + getDeviceTypes: (this: Simctl) => Promise; + list: (this: Simctl) => Promise; + setLocation: ( + this: Simctl, + latitude: string | number, + longitude: string | number, + ) => Promise; + clearLocation: (this: Simctl) => Promise; + openUrl: ( + this: Simctl, + url: string, + ) => Promise>; + setPasteboard: ( + this: Simctl, + content: string, + encoding?: BufferEncoding | undefined, + ) => Promise; + getPasteboard: (this: Simctl, encoding?: string | undefined) => Promise; + grantPermission: (this: Simctl, bundleId: string, perm: string) => Promise; + revokePermission: (this: Simctl, bundleId: string, perm: string) => Promise; + resetPermission: (this: Simctl, bundleId: string, perm: string) => Promise; + pushNotification: (this: Simctl, payload: any) => Promise; + shutdownDevice: (this: Simctl) => Promise; + spawnProcess: ( + this: Simctl, + args: string | string[], + env?: any, + ) => Promise>; + spawnSubProcess: (this: Simctl, args: string | string[], env?: any) => Promise; + terminateApp: (this: Simctl, bundleId: string) => Promise; + getAppearance: (this: Simctl) => Promise; + setAppearance: (this: Simctl, appearance: string) => Promise; + removeApp: (this: Simctl, bundleId: string) => Promise; } import { SubProcess } from 'teen_process'; -//# sourceMappingURL=simctl.d.ts.map \ No newline at end of file +//# sourceMappingURL=simctl.d.ts.map diff --git a/typings/usbmux/index.d.ts b/typings/usbmux/index.d.ts index 766779365..d65db1c08 100644 --- a/typings/usbmux/index.d.ts +++ b/typings/usbmux/index.d.ts @@ -1 +1 @@ -declare module 'usbmux'; \ No newline at end of file +declare module 'usbmux';