Skip to content
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

Flashlight iOS on AWS #147

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
44 changes: 44 additions & 0 deletions packages/aws-device-farm/iosResources/appiumTest/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { RemoteOptions, remote } from "webdriverio";

const capabilities = {
/*
platformName: "iOS",
"appium:automationName": "XCUITest",
"appium:xcodeOrgId": "Z445H6455F",
"appium:xcodeSigningId": "iPhone Developer",
"appium:bundleId": "org.reactjs.native.example.fakeStoreBam",
"appium:udid": "00008020-001C48210CF3002E", //process.env.DEVICEFARM_DEVICE_UDID_FOR_APPIUM,
"appium:deviceName": "iPhone de Developers (3) (16.1)", //process.env.DEVICEFARM_DEVICE_NAME,
//"appium:platformVersion": process.env.DEVICEFARM_DEVICE_OS_VERSION,
//"appium:app": process.env.DEVICEFARM_APP_PATH,
*/
};

const wdOpts: RemoteOptions = {
hostname: "0.0.0.0",
port: 4723,
logLevel: "info",
capabilities,
};

async function runTest() {
const driver = await remote(wdOpts);
try {
const buttonItem = await driver.$('//XCUIElementTypeButton[@name="VIENS ON PETE TOUT"]');
await buttonItem.click();
const textButton = "ON A TOUT PETE";
await driver.waitUntil(
async () => {
const text = await buttonItem.getText();
return text === textButton;
},
{ timeout: 5000, timeoutMsg: "Expected text to be different after 5s" }
);
} finally {
await driver.pause(1000);
await driver.deleteSession();
}
}

runTest().catch(console.error);
15 changes: 15 additions & 0 deletions packages/aws-device-farm/iosResources/appiumTest/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "appiumTest",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"webdriverio": "^8.14.3"
},
"resolutions": {
"strip-ansi": "^6.0.0"
},
"bundledDependencies": [
"webdriverio"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"compilerOptions": {
"module": "commonjs"
}
}
Binary file not shown.
111 changes: 111 additions & 0 deletions packages/aws-device-farm/iosResources/ios.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
version: 0.1

# Phases are collection of commands that get executed on Device Farm.
phases:
# The install phase includes commands that install dependencies that your tests use.
# Default dependencies for testing frameworks supported on Device Farm are already installed.
install:
commands:
# This test execution environment uses Appium version 1.9.1 by default, however we enable you to change it using the Appium version manager (avm)
# An example "avm" command below changes the version to 1.19.0
# For your convenience, we have pre-installed the following Appium versions: 1.9.1, 1.10.1, 1.11.1, 1.12.1, 1.13.0, 1.14.1, 1.14.2, 1.15.1, 1.16.0, 1.17.1, 1.18.0, 1.18.1, 1.18.2, 1.18.3, and 1.19.0
# For iOS Devices on OS version 14.2 and above, please use Appium Version 1.19.0 or higher.
# For iOS devices on OS version 14.0 and above, please use Appium version 1.18.0 or higher.
# For iOS devices on OS version 13.4 through 13.7, please use Appium version 1.17.1 or higher.
# Additionally, for iOS devices on OS version 13.0 through 13.3, please use Appium version 1.16.0 or higher.
# To use one of these Appium versions, change the version number in the "avm" command below to your desired version:
- export NVM_DIR=$HOME/.nvm
- . $NVM_DIR/nvm.sh
- nvm install 20
- uname -m
- export APPIUM_VERSION=2.0.1
- avm $APPIUM_VERSION
- echo $APPIUM_VERSION
- mkdir /usr/local/avm/versions/$APPIUM_VERSION/node_modules/appium/bin
- ln -s /usr/local/avm/versions/$APPIUM_VERSION/node_modules/.bin/appium /usr/local/avm/versions/$APPIUM_VERSION/node_modules/appium/bin/appium.js

# Device farm provides different pre-built versions of WebDriverAgent, and each is suggested for different versions of Appium:
# DEVICEFARM_WDA_DERIVED_DATA_PATH_V6: this version is suggested for Appium 1.18.2, 1.18.3, and 1.19.0. V6 is built from the following source code: https://github.com/appium/WebDriverAgent/releases/tag/v2.20.8
# DEVICEFARM_WDA_DERIVED_DATA_PATH_V5: this version is suggested for Appium 1.18.0 and 1.18.1. V5 is built from the following source code: https://github.com/appium/WebDriverAgent/releases/tag/v2.20.2
# DEVICEFARM_WDA_DERIVED_DATA_PATH_V4: this version is suggested for Appium 1.17.1. V4 is built from the following source code: https://github.com/appium/WebDriverAgent/releases/tag/v2.14.1
# DEVICEFARM_WDA_DERIVED_DATA_PATH_V3: this version is suggested for Appium 1.16.0. V3 is built from the following source code: https://github.com/appium/WebDriverAgent/releases/tag/v2.3.2
# DEVICEFARM_WDA_DERIVED_DATA_PATH_V2: this version is suggested for Appium 1.15.1. V2 is built from the following source code: https://github.com/appium/WebDriverAgent/tree/v1.3.5
# DEVICEFARM_WDA_DERIVED_DATA_PATH_V1: this version is suggested for Appium 1.9.1 through 1.14.2. V1 is built from the following source code: https://github.com/appium/WebDriverAgent/tree/2dbbf917ec2e4707bae9260f701d43c82b55e1b9
# We will automatically configure your WebDriverAgent version based on your Appium version using the following code.

# For users of Appium versions 1.15.0 and higher, your Appium version requires that the UDID of the device not contain any "-" characters
# So, we will create a new environment variable of the UDID specifically for Appium based on your Appium version
- >-
DEVICEFARM_DEVICE_UDID_FOR_APPIUM=$(echo $DEVICEFARM_DEVICE_UDID | tr -d "-");
DEVICEFARM_WDA_DERIVED_DATA_PATH=$DEVICEFARM_WDA_DERIVED_DATA_PATH_V6;

# By default the node version installed is 10.9.0
# you can switch to an alternate node version using below command.
# - nvm install 10.13.0

# Unpackage and install the node modules that you uploaded in the test phase.
- echo "Navigate to test package directory"
- cd $DEVICEFARM_TEST_PACKAGE_PATH
- npm install *.tgz
# Install appium driver for xcuitest
- appium driver install xcuitest

# The pre-test phase includes commands that set up your test environment.
pre_test:
commands:
# We recommend starting the appium server process in the background using the command below.
# Appium server log will go to $DEVICEFARM_LOG_DIR directory.
# The environment variables below will be auto-populated during run time.
- echo "Start appium server"
- echo $DEVICEFARM_DEVICE_PLATFORM_NAME
- >-
appium server --log-timestamp --default-capabilities "{\"appium:usePrebuiltWDA\": true, \"appium:derivedDataPath\":\"$DEVICEFARM_WDA_DERIVED_DATA_PATH\",
\"appium:deviceName\": \"$DEVICEFARM_DEVICE_NAME\", \"appium:platformName\":\"$DEVICEFARM_DEVICE_PLATFORM_NAME\", \"appium:app\":\"$DEVICEFARM_APP_PATH\",
\"appium:automationName\":\"XCUITest\", \"appium:udid\":\"$DEVICEFARM_DEVICE_UDID_FOR_APPIUM\", \"appium:platformVersion\":\"$DEVICEFARM_DEVICE_OS_VERSION\"}"
>> $DEVICEFARM_LOG_DIR/appiumlog.txt 2>&1 &

- >-
start_appium_timeout=0;
while [ true ];
do
if [ $start_appium_timeout -gt 60 ];
then
echo "appium server never started in 60 seconds. Exiting";
exit 1;
fi;
grep -i "Appium REST http interface listener started on http://0.0.0.0:4723" $DEVICEFARM_LOG_DIR/appiumlog.txt >> /dev/null 2>&1;
if [ $? -eq 0 ];
then
echo "Appium REST http interface listener started on http://0.0.0.0:4723";
break;
else
echo "Waiting for appium server to start. Sleeping for 1 second";
sleep 1;
start_appium_timeout=$((start_appium_timeout+1));
fi;
done;

# The test phase includes commands that start your test suite execution.
test:
commands:
# Your test package is downloaded in $DEVICEFARM_TEST_PACKAGE_PATH
# However, we must navigate to its subdirectory "node_modules/*", as this directory has your test code and dependency node modules
- echo "Navigate to test code directory"
- cd $DEVICEFARM_TEST_PACKAGE_PATH/node_modules/*
- npm install

- echo "Start Appium Node test"
# Enter the command below to start the tests . The command should be similar to what you use to run the tests locally.
# For e.g. assuming you run your tests locally using command "node YOUR_TEST_FILENAME.js.", enter the same command below:
- npx ts-node index.ts

# The post test phase includes commands that are run after your tests are executed.
post_test:
commands:

# The artifacts phase lets you specify the location where your tests logs, device logs will be stored.
# And also let you specify the location of your test logs and artifacts which you want to be collected by Device Farm.
# These logs and artifacts will be available through ListArtifacts API in Device Farm.
artifacts:
# By default, Device Farm will collect your artifacts from following directories
- $DEVICEFARM_LOG_DIR
13 changes: 11 additions & 2 deletions packages/aws-device-farm/src/commands/runTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
createDefaultNodeTestPackage,
DEFAULT_TEST_PACKAGE_NAME,
} from "./createDefaultNodeTestPackage";
import { getUploadType } from "../utils/getUploadType";

export const DEFAULT_RUN_TEST_OPTIONS = {
projectName: "Flashlight",
Expand Down Expand Up @@ -77,17 +78,22 @@ export const runTest = async ({
filePath: testFolderZipPath,
type: UploadType.APPIUM_NODE_TEST_PACKAGE,
});
fs.rmSync(testFolderZipPath);
}

let apkUploadArn;

if (apkUploadArnGiven) {
apkUploadArn = apkUploadArnGiven;
} else if (apkPath) {
const uploadType = getUploadType(apkPath);
if (!uploadType) {
throw new Error(`Cannot find upload type for file: ${apkPath}`);
}
apkUploadArn = await uploadRepository.upload({
projectArn,
filePath: apkPath,
type: UploadType.ANDROID_APP,
type: uploadType,
});
} else {
throw new Error("Neither apkUploadArn nor apkPath was passed.");
Expand All @@ -105,7 +111,10 @@ export const runTest = async ({
filePath: testSpecPath,
type: UploadType.APPIUM_NODE_TEST_SPEC,
});
fs.rmSync(testSpecPath);
// Clean up test spec file only if it was created on the fly
if (!testSpecsPathGiven) {
fs.rmSync(testSpecPath);
}

Logger.info("Starting test run...");
const testRunArn = await testRepository.scheduleRun({
Expand Down
11 changes: 11 additions & 0 deletions packages/aws-device-farm/src/utils/getUploadType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { UploadType } from "@aws-sdk/client-device-farm";
// Will be useful when we replace all apkPath with appPath to have a clear distinction between Android and iOS
export const getUploadType = (
appPath: string
): UploadType.ANDROID_APP | UploadType.IOS_APP | undefined => {
return appPath.endsWith(".apk")
? UploadType.ANDROID_APP
: appPath.endsWith(".ipa")
? UploadType.IOS_APP
: undefined;
};
13 changes: 6 additions & 7 deletions packages/aws-device-farm/src/utils/unzip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import fs from "fs";

export const unzip = (path: string, destinationFolder: string) => {
const zip = new AdmZip(path);
const zipEntries = zip.getEntries();

for (const zipEntry of zipEntries) {
const parts = zipEntry.entryName.split("/");

fs.writeFileSync(`${destinationFolder}/${parts[parts.length - 1]}`, zipEntry.getData());
}
zip.getEntries().forEach((zipEntry) => {
if (!zipEntry.isDirectory) {
const parts = zipEntry.entryName.split("/");
fs.writeFileSync(`${destinationFolder}/${parts[parts.length - 1]}`, zipEntry.getData());
}
});
};
4 changes: 3 additions & 1 deletion packages/aws-device-farm/src/zipTestFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ export const zipTestFolder = (folderPath: string) => {
Logger.info(`Compressing into zip`);

const zipPath = `${path.basename(path.resolve(folderPath))}.zip`;
execSync(`cd ${folderPath} && zip -r ${zipPath} *.tgz && rm ${folderPath}/*.tgz`);
execSync(`cd ${folderPath} && zip -r ${zipPath} *.tgz`);
// Had to separate into two commands because else it would fail
execSync(`rm ${folderPath}/*.tgz`);
Logger.success(`Zip created, ready for upload: ${zipPath}`);

return `${folderPath}/${zipPath}`;
Expand Down