@testlio/cli
Version:
Official Testlio platform command-line interface
321 lines (294 loc) • 10.6 kB
JavaScript
const axios = require('axios');
const Joi = require('joi');
const fs = require('fs');
const { allAllowedProviders } = require('./utils');
const FAILURE = 1;
const SUCCESS = 0;
const allowedProviders = ['browserstack', 'local', 'sauce-labs', 'azure-playwright', 'bitbar'];
const types = ['Mobile', 'Tablet', 'Connected devices', 'Gaming', 'Wearable', 'Desktop (PC)'];
const operatingSystemFamilies = [
'Symbian',
'Android',
'Windows Phone',
'BlackBerry',
'Windows',
'Roku OS',
'Chrome OS',
'webOS',
'Brew Mobile Platform',
'Xbox system software',
'Android TV',
'Fire OS',
'Palm OS',
'iOS',
'Tizen',
'Firefox',
'watchOS',
'PlayStation system software',
'Mac OS',
'tvOS',
'Android Wear',
'Linux',
'Danger',
'Windows CE',
'Orsay (Legacy)',
'Nintendo Switch OS',
'SmartCast TV',
'Amazon Echo OS',
'Garmin OS',
'Xfinity Flex OS',
'Polar OS',
'Suunto OS',
'Google Stadia',
'Steam OS',
'Jabra Firmware',
'Plantronics Firmware',
'Sennheiser Firmware',
'Cast Firmware',
'NetCast',
'Vidaa'
];
const printHelp = () => {
console.log(`Create automated device
Usage:
testlio create-automated-device
Options:
--checkExisting (optional) If set, will return list of devices found. You can additionally narrow down the search by passing [externalId, model, manufactureName, typeName, operatingSystemName].
When --checkExisting is set to true: (You can search existing devices on basis of any of the following parameters, if no parameters are passed, it will return all the devices)
--externalId (optional) (e.g unique-provider-identifier)
--model (optional) (e.g Galaxy S21, Samsung Galaxy S23 Ultra)
--manufactureName (optional) (e.g Nokia, HTC, ZTE, Samsung, Sony, Apple)
--typeName (optional) (e.g ${types.join(', ')})
--operatingSystemName (optional) (e.g Android, iOS)
--provider (optional) (e.g ${allowedProviders.join(', ')})
When --checkExisting is not set or set to false:
--externalId (required) To create a new automated-device please provide externalId (this-can-be-unique-provider-identifier, if you don't know about it please generate a random string device-name-someGuid)
--provider (required) To create a new automated-device please provide provider (e.g ${allowedProviders.join(
', '
)})
--model (required) To create a new automated-device please provide model, model is full name of the device (e.g Galaxy S21)
--manufactureName (required) To create a new automated-device please provide manufactureName (e.g Nokia, Samsung, Apple)
--typeName (required) To create a new automated-device please provide typeName (e.g ${types.join(', ')})
--operatingSystemName (required) To create a new automated-device please provide operatingSystemName (e.g Android)
--operatingSystemVersion (required) To create a new automated-device please provide operatingSystemVersion (e.g 11)
--projectConfig [path] (optional) path to project config (default: project-config.json)
`);
};
const setAuthorizationToken = (token) => {
axios.defaults.headers.common.Authorization = `Bearer ${token}`;
};
const setBaseUri = (baseURI) => {
axios.defaults.baseURL = baseURI;
};
const projectConfigSchema = Joi.object({
baseURI: Joi.string().required()
});
const createAutomatedDeviceSchema = Joi.object({
checkExisting: Joi.boolean().optional(),
externalId: Joi.string().when('checkExisting', {
is: true,
then: Joi.optional(),
otherwise: Joi.required().label(
'To create new automated-device please provider externalId (this-can-be-unique-provider-identifier e.g (arn:local:devicefarm:us-west-2::device:D2A272886F5A411FA5ACDA7BCA314F0C) If you do not know about it please generate a random string device-name-someGuid)'
)
}),
provider: Joi.string().when('checkExisting', {
is: true,
then: Joi.optional().valid(...allAllowedProviders),
otherwise: Joi.required()
.valid(...allowedProviders)
.label(`To create new automated-browser please provider provider (e.g ${allowedProviders.join(', ')})`)
}),
model: Joi.when('checkExisting', {
is: true,
then: Joi.optional(),
otherwise: Joi.required().label(
'To create a new automated device, please provide the model. This is full name of the device (e.g Galaxy S21, Samsung Galaxy S23 Ultra, Apple iPhone 14, Samsung Galaxy Tab S4)'
)
}),
manufactureName: Joi.string().when('checkExisting', {
is: true,
then: Joi.optional(),
otherwise: Joi.required().label(
'To create a new automated device, please provide the manufacturer name (e.g Nokia, HTC, ZTE, LG, Xolo, Samsung, Sony, Apple)'
)
}),
typeName: Joi.string().when('checkExisting', {
is: true,
then: Joi.optional().valid(...types),
otherwise: Joi.required()
.valid(...types)
.label(`To create a new automated device, please provide the device type (e.g ${types.join(', ')})`)
}),
operatingSystemName: Joi.string().when('checkExisting', {
is: true,
then: Joi.optional(),
otherwise: Joi.required()
.valid(...operatingSystemFamilies)
.label(
`To create a new automated device, please provide valid operatingSystemName (${operatingSystemFamilies.join(
', '
)} )`
)
}),
operatingSystemVersion: Joi.any().when('checkExisting', {
is: true,
then: Joi.optional(),
otherwise: Joi.required().label(
'To create a new automated device, please provide the operatingSystemVersion (e.g 11, 14.5.1)'
)
}),
projectConfig: Joi.string().default('project-config.json')
});
const constructAutomatedDeviceSearchPayload = (
provider,
manufactureName,
typeName,
operatingSystemName,
model,
externalId
) => {
const payload = {};
if (provider) {
payload.provider = provider;
}
if (manufactureName) {
payload.manufacturers = [{ name: manufactureName }];
}
if (typeName) {
payload.types = [{ name: typeName }];
}
if (operatingSystemName) {
payload.operatingSystemFamilies = [{ name: operatingSystemName }];
}
if (model) {
payload.models = [{ model }];
}
if (externalId) {
payload.externalIds = [{ externalId }];
}
return payload;
};
const createAutomatedDevice = async (
provider,
externalId,
model,
manufactureName,
typeName,
operatingSystemName,
operatingSystemVersion
) => {
const { data, status } = await axios.post(`/device/v1/automated-devices`, {
provider: `${provider}`,
externalId: `${externalId}`,
model: `${model}`,
manufacturer: {
name: `${manufactureName}`
},
operatingSystem: {
name: `${operatingSystemName}`,
version: `${operatingSystemVersion}`
},
type: {
name: `${typeName}`
},
operatingSystemFamily: {
name: `${operatingSystemName}`
}
});
if (status !== 200) {
throw new Error(`Failed find the device with external id ${externalId}`);
}
return data.id;
};
const checkExistingAutomatedDevice = async (
provider,
manufactureName,
typeName,
operatingSystemName,
model,
externalId
) => {
const { data } = await axios.post(
`/device/v1/automated-devices/search`,
constructAutomatedDeviceSearchPayload(
provider,
manufactureName,
typeName,
operatingSystemName,
model,
externalId
)
);
return data?.data;
};
module.exports = async (params) => {
if (params.h || params.help) {
printHelp();
return;
}
const {
checkExisting,
externalId,
provider,
manufactureName,
typeName,
operatingSystemName,
operatingSystemVersion,
model,
projectConfig: projectConfigFilePath
} = Joi.attempt(params, createAutomatedDeviceSchema);
if (!fs.existsSync(projectConfigFilePath)) {
console.log(`File "${projectConfigFilePath}" not found!`);
return FAILURE;
}
try {
const projectConfig = JSON.parse(fs.readFileSync(projectConfigFilePath).toString());
const { baseURI } = Joi.attempt(projectConfig, projectConfigSchema.unknown());
if (!process.env.RUN_API_TOKEN) {
console.log('Please provide RUN API TOKEN');
return FAILURE;
}
setBaseUri(baseURI);
setAuthorizationToken(process.env.RUN_API_TOKEN);
if (checkExisting) {
const devices = await checkExistingAutomatedDevice(
provider,
manufactureName,
typeName,
operatingSystemName,
model
);
if (devices.length) {
console.log(`Found following devices: Please select the device you want`);
console.log(JSON.stringify(devices, null, 4));
return SUCCESS;
}
console.log(
`No device found, please check your search parameters or create a new device without checkExisting flag`
);
return FAILURE;
}
const deviceGuid = await createAutomatedDevice(
provider,
externalId,
model,
manufactureName,
typeName,
operatingSystemName,
operatingSystemVersion
);
console.log(`Device created successfully, here is the guid: ${deviceGuid}`);
return SUCCESS;
} catch (e) {
if (e.response?.data?.errors?.find((error) => error.includes('already exists'))) {
console.log(
`${e.response?.data.errors[0]}. Please use '--checkExisting true' flag to find the device you are looking for`
);
return FAILURE;
}
console.log('Something went wrong while crating an automated device', e);
return FAILURE;
}
};