diff --git a/.gitignore b/.gitignore index 7abf360..5f5ccfc 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,7 @@ demo-vue/platforms/ /src/*.tgz /publish/package/*.tgz /publish/package/**/* -/publish/src/**/* \ No newline at end of file +/publish/src/**/* +test-results.xml +**/reports/**/* +**/mochawesome-report/**/* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 3a82761..2c590ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,17 +3,13 @@ env: - ANDROID_PACKAGE_JS='picker-debug-js.apk' - ANDROID_PACKAGE_NG='picker-debug-ng.apk' - ANDROID_PACKAGE_VUE='picker-debug-vue.apk' - - ANDROID_PACKAGE_FOLDER_JS=$TRAVIS_BUILD_DIR/demo/outputs - - ANDROID_PACKAGE_FOLDER_NG=$TRAVIS_BUILD_DIR/demo-angular/outputs - - ANDROID_PACKAGE_FOLDER_VUE=$TRAVIS_BUILD_DIR/demo-vue/outputs - - ANDROID_SAUCE_STORAGE="https://saucelabs.com/rest/v1/storage/$SAUCE_USER" + - PACKAGE_FOLDER_JS=$TRAVIS_BUILD_DIR/demo/outputs + - PACKAGE_FOLDER_NG=$TRAVIS_BUILD_DIR/demo-angular/outputs + - PACKAGE_FOLDER_VUE=$TRAVIS_BUILD_DIR/demo-vue/outputs + - SAUCE_STORAGE="https://saucelabs.com/rest/v1/storage/$SAUCE_USER" - IOS_PACKAGE_JS='picker-demo-js.zip' - IOS_PACKAGE_NG='picker-demo-ng.zip' - IOS_PACKAGE_VUE='picker-demo-vue.zip' - - IOS_PACKAGE_FOLDER_JS=$TRAVIS_BUILD_DIR/demo/outputs - - IOS_PACKAGE_FOLDER_NG=$TRAVIS_BUILD_DIR/demo-angular/outputs - - IOS_PACKAGE_FOLDER_VUE=$TRAVIS_BUILD_DIR/demo-vue/outputs - - IOS_SAUCE_STORAGE="https://saucelabs.com/rest/v1/storage/$SAUCE_USER" git: depth: 1 @@ -28,9 +24,7 @@ matrix: os: linux node_js: "8" script: - - cd src && npm run ci.tslint - - cd ../demo && npm run ci.tslint - - cd ../demo-angular && npm run ci.tslint + - cd src && npm i && npm run tslint - stage: "WebPack and Build" os: osx @@ -45,8 +39,8 @@ matrix: script: - cd src && npm run build - cd ../demo && npm i && tns build ios --bundle --env.uglify --copy-to "./outputs/demo.app" - - cd $IOS_PACKAGE_FOLDER_JS && zip -r $IOS_PACKAGE_JS demo.app - - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $IOS_SAUCE_STORAGE/$IOS_PACKAGE_JS?overwrite=true --data-binary @$IOS_PACKAGE_FOLDER_JS/$IOS_PACKAGE_JS" + - cd $PACKAGE_FOLDER_JS && zip -r $IOS_PACKAGE_JS demo.app + - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $SAUCE_STORAGE/$IOS_PACKAGE_JS?overwrite=true --data-binary @$PACKAGE_FOLDER_JS/$IOS_PACKAGE_JS" - os: osx env: - WebpackiOS="12.0" @@ -59,8 +53,8 @@ matrix: script: - cd src && npm run build - cd ../demo-vue && npm i && tns build ios --bundle --env.uglify --copy-to "./outputs/demovue.app" - - cd $IOS_PACKAGE_FOLDER_VUE && zip -r $IOS_PACKAGE_VUE demovue.app - - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $IOS_SAUCE_STORAGE/$IOS_PACKAGE_VUE?overwrite=true --data-binary @$IOS_PACKAGE_FOLDER_VUE/$IOS_PACKAGE_VUE" + - cd $PACKAGE_FOLDER_VUE && zip -r $IOS_PACKAGE_VUE demovue.app + - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $SAUCE_STORAGE/$IOS_PACKAGE_VUE?overwrite=true --data-binary @$PACKAGE_FOLDER_VUE/$IOS_PACKAGE_VUE" - os: osx env: - WebpackiOS="12.0" @@ -74,8 +68,8 @@ matrix: - cd src && npm run build && npm pack - cd ../demo-angular && tns plugin add ../src/*.tgz - npm i && tns build ios --bundle --env.uglify --env.aot --copy-to "./outputs/demoangular.app" - - cd $IOS_PACKAGE_FOLDER_NG && zip -r $IOS_PACKAGE_NG demoangular.app - - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $IOS_SAUCE_STORAGE/$IOS_PACKAGE_NG?overwrite=true --data-binary @$IOS_PACKAGE_FOLDER_NG/$IOS_PACKAGE_NG" + - cd $PACKAGE_FOLDER_NG && zip -r $IOS_PACKAGE_NG demoangular.app + - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $SAUCE_STORAGE/$IOS_PACKAGE_NG?overwrite=true --data-binary @$PACKAGE_FOLDER_NG/$IOS_PACKAGE_NG" - language: android os: linux env: @@ -86,7 +80,7 @@ matrix: script: - cd src && npm run build - cd ../demo && npm i && tns build android --bundle --env.uglify --env.snapshot --copy-to "./outputs/app-debug.apk" - - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $ANDROID_SAUCE_STORAGE/$ANDROID_PACKAGE_JS?overwrite=true --data-binary @$ANDROID_PACKAGE_FOLDER_JS/app-debug.apk" + - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $SAUCE_STORAGE/$ANDROID_PACKAGE_JS?overwrite=true --data-binary @$PACKAGE_FOLDER_JS/app-debug.apk" - language: android os: linux env: @@ -97,7 +91,7 @@ matrix: script: - cd src && npm run build - cd ../demo-vue && npm i && tns build android --bundle --env.uglify --copy-to "./outputs/app-debug.apk" - - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $ANDROID_SAUCE_STORAGE/$ANDROID_PACKAGE_VUE?overwrite=true --data-binary @$ANDROID_PACKAGE_FOLDER_VUE/app-debug.apk" + - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $SAUCE_STORAGE/$ANDROID_PACKAGE_VUE?overwrite=true --data-binary @$PACKAGE_FOLDER_VUE/app-debug.apk" - language: android os: linux env: @@ -110,17 +104,7 @@ matrix: - cd ../publish && sh pack.sh - cd ../demo-angular && tns plugin add ../publish/package/*.tgz - npm i && tns build android --bundle --env.uglify --env.snapshot --env.aot --copy-to "./outputs/app-debug.apk" - - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $ANDROID_SAUCE_STORAGE/$ANDROID_PACKAGE_NG?overwrite=true --data-binary @$ANDROID_PACKAGE_FOLDER_NG/app-debug.apk" - - language: android - env: - - BuildAndroid="28" - - Type="VanillaJS" - os: linux - jdk: oraclejdk8 - before_install: nvm install 8.11.4 - script: - - cd src && npm run build - - cd ../demo && tns build android + - "curl -u $SAUCE_USER:$SAUCE_KEY -X POST -H 'Content-Type: application/octet-stream' $SAUCE_STORAGE/$ANDROID_PACKAGE_NG?overwrite=true --data-binary @$PACKAGE_FOLDER_NG/app-debug.apk" - language: android env: - BuildAndroid="28" @@ -135,7 +119,7 @@ matrix: env: - BuildiOS="12.0" - Xcode="10.0" - - Type="VanillaJS" + - Type="Angular" osx_image: xcode10.0 language: node_js node_js: "8" @@ -143,41 +127,70 @@ matrix: before_script: pod repo update script: - cd src && npm run build - - cd ../demo && tns build ios --bundle --env.uglify - - os: osx + - cd ../demo-angular && tns build ios + - stage: "UI Tests" env: - - BuildiOS="12.0" - - Xcode="10.0" + - Android="24" - Type="Angular" - osx_image: xcode10.0 language: node_js + os: linux node_js: "8" - jdk: oraclejdk8 - before_script: pod repo update script: - - cd src && npm run build - - cd ../demo-angular && tns build ios - # - stage: "UI Tests" - # env: - # - Android="24" - # - Type="Angular" - # language: node_js - # os: linux - # node_js: "8" - # script: - # - npm i -g appium - # - cd demo-angular && npm i - # - travis_wait travis_retry npm run e2e -- --runType android24 --sauceLab --appPath $ANDROID_PACKAGE_NG - # - os: linux - # env: - # - iOS="12.0" - # - Type="Angular" - # language: node_js - # node_js: "8" - # script: - # - npm i -g appium - # - cd demo-ng && npm i - # - travis_wait travis_retry npm run e2e -- --runType sim.iPhoneX --sauceLab --appPath $IOS_PACKAGE_NG + - npm i -g appium + - cd demo-angular && npm i + - travis_wait travis_retry npm run e2e -- --runType android24.sauce --sauceLab --appPath $ANDROID_PACKAGE_NG + - os: linux + env: + - iOS="12.0" + - Type="Angular" + language: node_js + node_js: "8" + script: + - npm i -g appium + - cd demo-angular && npm i + - travis_wait travis_retry npm run e2e -- --runType sim.iPhoneX.ios12.sauce --sauceLab --appPath $IOS_PACKAGE_NG + - os: linux + env: + - Android="24" + - Type="VueJS" + language: node_js + os: linux + node_js: "8" + script: + - npm i -g appium + - cd demo-vue && npm i + - travis_wait travis_retry npm run e2e -- --runType android24.sauce --sauceLab --appPath $ANDROID_PACKAGE_VUE + - os: linux + env: + - iOS="12.0" + - Type="VueJS" + language: node_js + node_js: "8" + script: + - npm i -g appium + - cd demo-vue && npm i + - travis_wait travis_retry npm run e2e -- --runType sim.iPhoneX.ios12.sauce --sauceLab --appPath $IOS_PACKAGE_VUE + - os: linux + env: + - Android="24" + - Type="VanillaJS" + language: node_js + os: linux + node_js: "8" + script: + - npm i -g appium + - cd demo && npm i + - travis_wait travis_retry npm run e2e -- --runType android24.sauce --sauceLab --appPath $ANDROID_PACKAGE_JS + - os: linux + env: + - iOS="12.0" + - Type="VanillaJS" + language: node_js + node_js: "8" + script: + - npm i -g appium + - cd demo && npm i + - travis_wait travis_retry npm run e2e -- --runType sim.iPhoneX.ios12.sauce --sauceLab --appPath $IOS_PACKAGE_JS android: components: diff --git a/demo-angular/e2e/config/appium.capabilities.json b/demo-angular/e2e/config/appium.capabilities.json new file mode 100644 index 0000000..22c5773 --- /dev/null +++ b/demo-angular/e2e/config/appium.capabilities.json @@ -0,0 +1,123 @@ +{ + "android23": { + "platformName": "Android", + "platformVersion": "6.0", + "deviceName": "Android", + "lt": 60000, + "appActivity": "com.tns.NativeScriptActivity", + "newCommandTimeout": 720, + "noReset": true, + "fullReset": false, + "app": "" + }, + "android24": { + "platformName": "Android", + "platformVersion": "7.0", + "deviceName": "Emulator-Api24-Google", + "avd":"Emulator-Api24-Google", + "lt": 60000, + "newCommandTimeout": 720, + "appium-version": "1.8.1", + "appActivity": "com.tns.NativeScriptActivity", + "noReset": true, + "fullReset": false, + "app": "", + "automationName": "Appium", + "density": 3.2, + "offsetPixels": 51 + }, + "android24.sauce": { + "platformName": "Android", + "platformVersion": "7.0", + "deviceName": "Android GoogleAPI Emulator", + "lt": 60000, + "newCommandTimeout": 720, + "appiumVersion": "1.9.1", + "noReset": true, + "fullReset": false, + "app": "", + "idleTimeout": 120, + "automationName": "Appium" + }, + "android25": { + "platformName": "Android", + "platformVersion": "7.1", + "deviceName": "Google Pixel GoogleAPI", + "lt": 60000, + "appActivity": "com.tns.NativeScriptActivity", + "newCommandTimeout": 720, + "noReset": true, + "fullReset": false, + "app": "" + }, + "android27": { + "platformName": "Android", + "platformVersion": "8.1", + "deviceName": "Emulator-Api27-Google", + "lt": 60000, + "appActivity": "com.tns.NativeScriptActivity", + "newCommandTimeout": 720, + "noReset": true, + "fullReset": false, + "app": "" + }, + "sim.iPhoneX.iOS112": { + "platformName": "iOS", + "platformVersion": "11.2", + "deviceName": "iPhone X", + "appium-version": "1.8.0", + "density": 3, + "offsetPixels": 87, + "noReset": true, + "fullReset": false, + "app": "" + }, + "sim.iPhoneX.iOS113": { + "platformName": "iOS", + "platformVersion": "11.3", + "deviceName": "iPhone X", + "appium-version": "1.8.0", + "density": 3, + "offsetPixels": 87, + "noReset": true, + "fullReset": false, + "app": "" + }, + "sim.iPhoneX.ios11": { + "platformName": "iOS", + "platformVersion": "11.2", + "deviceName": "iPhone X", + "appium-version": "1.8.1", + "noReset": true, + "fullReset": false, + "app": "", + "idleTimeout": 120, + "automationName": "Appium" + }, + "sim.iPhoneX.ios12": { + "platformName": "iOS", + "platformVersion": "12.1", + "deviceName": "iPhone X", + "appiumVersion": "1.9.1", + "noReset": true, + "fullReset": false, + "density": 3, + "offsetPixels": 87, + "app": "", + "idleTimeout": 120, + "automationName": "Appium" + }, + "sim.iPhoneX.ios12.sauce": { + "platformName": "iOS", + "platformVersion": "12.0", + "deviceName": "iPhone X", + "appium-version": "1.9.1", + "noReset": true, + "fullReset": false, + "density": 3, + "offsetPixels": 87, + "app": "", + "idleTimeout": 120, + "automationName": "Appium" + } +} diff --git a/demo-angular/e2e/config/mocha.opts b/demo-angular/e2e/config/mocha.opts new file mode 100644 index 0000000..1605181 --- /dev/null +++ b/demo-angular/e2e/config/mocha.opts @@ -0,0 +1,5 @@ +--timeout 250000 +--recursive e2e +--reporter mocha-multi +--reporter-options mochawesome=-,mocha-junit-reporter=test-results.xml +--exit \ No newline at end of file diff --git a/demo-angular/e2e/helper.ts b/demo-angular/e2e/helper.ts new file mode 100644 index 0000000..77bff5f --- /dev/null +++ b/demo-angular/e2e/helper.ts @@ -0,0 +1,102 @@ +import { AppiumDriver, SearchOptions, Direction, UIElement } from "nativescript-dev-appium"; +import { runType } from "nativescript-dev-appium/lib/parser"; + +const isAndroid: boolean = runType.includes("android"); + +export const QUEUE_WAIT_TIME: number = 600000; // Sometimes SauceLabs threads are not available and the tests wait in a queue to start. Wait 10 min before timeout. + +export async function navigateBackToHome(driver: AppiumDriver, view?: string) { + let location = view !== undefined ? view : "PickerField - Angular"; + let homeTitle = await driver.findElementByTextIfExists(location, SearchOptions.exact); + while (homeTitle === undefined) { + await driver.navBack(); + await driver.wait(1000); + homeTitle = await driver.findElementByTextIfExists(location, SearchOptions.exact); + } +} + +export async function navigateBackToView(driver: AppiumDriver, view: string) { + await navigateBackToHome(driver, view); +} + +export async function scrollToElement(driver: AppiumDriver, element: string, direction: Direction = Direction.down) { + let listView: UIElement; + if (isAndroid) { + listView = await driver.findElementByClassName("android.widget.FrameLayout"); + } + else { + listView = await driver.findElementByClassName("XCUIElementTypeTable"); + } + const listItem = await listView.scrollTo( + direction, + () => driver.findElementByText(element, SearchOptions.contains), + 600 + ); + return listItem; +} + +export async function scrollToElementInListView(driver: AppiumDriver, element: string, direction: Direction = Direction.down) { + let listView: UIElement; + if (isAndroid) { + listView = await driver.findElementByClassName("android.widget.ListView"); + } + else { + listView = await driver.findElementByClassName("XCUIElementTypeTable"); + } + const listItem = await listView.scrollTo( + direction, + () => driver.findElementByText(element, SearchOptions.contains), + 600 + ); + return listItem; +} + +export async function swipe(driver: AppiumDriver, item: any, direction: Direction) { + const rectangle = await item.getRectangle(); + const centerX = rectangle.x + rectangle.width / 2; + const centerY = rectangle.y + rectangle.height / 2; + let swipeX; + if (direction === Direction.right) { + const windowSize = await driver.driver.getWindowSize(); + swipeX = windowSize.width - 10; + } else if (direction === Direction.left) { + swipeX = 10; + } + + if (isAndroid) { + const wd = driver.wd(); + const action = new wd.TouchAction(driver.driver); + action.press({ x: centerX, y: centerY }) + .wait(200) + .moveTo({ x: swipeX, y: centerY }) + .release(); + await action.perform(); + } + else { + await driver.driver.execute('mobile: dragFromToForDuration', { + duration: 2.0, + fromX: centerX, + fromY: centerY, + toX: swipeX, + toY: centerY + }); + } +} + +export async function swipeToElement(driver: AppiumDriver, element: string, direction: Direction = Direction.down) { + let listView; + if (isAndroid) { + listView = await driver.findElementByClassName("android.widget.FrameLayout"); + } + else { + listView = await driver.findElementByClassName("XCUIElementTypeCollectionView"); + } + + let item = await driver.findElementByTextIfExists(element, SearchOptions.exact); + while (item === undefined) { + await listView.swipe(direction); + await driver.wait(500); + item = await driver.findElementByTextIfExists(element, SearchOptions.contains); + } + return item; +} \ No newline at end of file diff --git a/demo-angular/e2e/setup.ts b/demo-angular/e2e/setup.ts new file mode 100644 index 0000000..8b26e66 --- /dev/null +++ b/demo-angular/e2e/setup.ts @@ -0,0 +1,9 @@ +import { startServer, stopServer } from "nativescript-dev-appium"; + +before("start server", async () => { + await startServer(); +}); + +after("stop server", async () => { + await stopServer(); +}); diff --git a/demo-angular/e2e/tests.e2e.ts b/demo-angular/e2e/tests.e2e.ts new file mode 100644 index 0000000..eb485a8 --- /dev/null +++ b/demo-angular/e2e/tests.e2e.ts @@ -0,0 +1,145 @@ +import { AppiumDriver, createDriver, SearchOptions, Direction, UIElement } from "nativescript-dev-appium"; +import { expect } from "chai"; +import { isSauceLab, runType } from "nativescript-dev-appium/lib/parser"; +import { navigateBackToHome, scrollToElement, scrollToElementInListView, QUEUE_WAIT_TIME } from "./helper"; +const fs = require('fs'); +const addContext = require('mochawesome/addContext'); +const rimraf = require('rimraf'); + +const isSauceRun = isSauceLab; + +describe("Picker", () => { + let driver: AppiumDriver; + + before(async function () { + this.timeout(QUEUE_WAIT_TIME); + driver = await createDriver(); + driver.defaultWaitTime = 15000; + let dir = "mochawesome-report"; + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } + rimraf('mochawesome-report/*', function () { }); + }); + + after(async () => { + if (isSauceRun) { + driver.sessionId().then(function (sessionId) { + console.log("Report https://saucelabs.com/beta/tests/" + sessionId); + }); + } + await driver.quit(); + console.log("Quit driver!"); + }); + + afterEach(async function () { + if (this.currentTest.state && this.currentTest.state === "failed") { + let png = await driver.logScreenshot(this.currentTest.title); + fs.copyFile(png, './mochawesome-report/' + this.currentTest.title + '.png', function (err) { + if (err) { + throw err; + } + console.log('Screenshot saved.'); + }); + addContext(this, './' + this.currentTest.title + '.png'); + } + }); + + const gettingStarted = "Getting Started"; + let field: UIElement; + describe(gettingStarted, () => { + it("Navigate to Getting started example", async () => { + const getStarted = await scrollToElement(driver, gettingStarted); + await getStarted.click(); + field = await driver.findElementByText("Click here"); + expect(field).to.exist; + }); + + it("Click field and select item", async function () { + this.timeout(QUEUE_WAIT_TIME); + await field.click(); + const itemText = "Item 30"; + const item30 = await scrollToElement(driver, itemText); + await item30.click(); + const title = await driver.findElementByText(gettingStarted); + expect(title).to.exist; + const item = await driver.findElementByText(itemText); + expect(item).to.exist; + }); + + it("Click field and cancel selection", async () => { + let item30 = await driver.findElementByText("Item 30"); + await item30.click(); + const cancel = await driver.findElementByAccessibilityId("Close"); + await cancel.click(); + item30 = await driver.findElementByText("Item 30"); + expect(item30).to.exist; + }); + }); + + const styling = "Styling"; + describe(styling, () => { + it("Navigate to Styling example", async () => { + await navigateBackToHome(driver); + const stylingExample = await scrollToElement(driver, styling); + await stylingExample.click(); + field = await driver.findElementByText("This is hint"); + expect(field).to.exist; + }); + + it("Click field and select item", async () => { + await field.click(); + const itemText = "Item 6"; + const item6 = await scrollToElementInListView(driver, itemText); + await item6.click(); + const title = await driver.findElementByText(styling); + expect(title).to.exist; + const item = await driver.findElementByText(itemText); + expect(item).to.exist; + }); + }); + + const valueApis = "Value APIs"; + describe(valueApis, () => { + it("Navigate to Value APIs example", async () => { + await navigateBackToHome(driver); + const valueExample = await scrollToElement(driver, valueApis); + await valueExample.click(); + field = await driver.findElementByText("Click here"); + expect(field).to.exist; + }); + + it("Click field and select item", async () => { + await field.click(); + const itemText = "Item 1"; + const item1 = await scrollToElement(driver, itemText); + await item1.click(); + const title = await driver.findElementByText(valueApis); + expect(title).to.exist; + const description = await driver.findElementByText("Description 1"); + expect(description).to.exist; + }); + }); + + const reactive = "Reactive forms"; + describe(reactive, () => { + it("Navigate to Value APIs example", async () => { + await navigateBackToHome(driver); + const reactiveExample = await scrollToElement(driver, reactive); + await reactiveExample.click(); + field = await driver.findElementByText("The Godfather"); + expect(field).to.exist; + }); + + it("Click field and select item", async () => { + await field.click(); + const itemText = "The Wizard of Oz"; + const item1 = await scrollToElementInListView(driver, itemText); + await item1.click(); + const title = await driver.findElementByText("Reactive Forms"); + expect(title).to.exist; + const pickedItem = await driver.findElementByText(itemText); + expect(pickedItem).to.exist; + }); + }); +}); \ No newline at end of file diff --git a/demo-angular/e2e/tsconfig.json b/demo-angular/e2e/tsconfig.json new file mode 100644 index 0000000..0c3f525 --- /dev/null +++ b/demo-angular/e2e/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "importHelpers": false, + "types": [ + "mocha", + "chai", + "node" + ], + "lib": [ + "es2015", + "dom" + ], + "baseUrl": "." + } +} \ No newline at end of file diff --git a/demo-angular/package.json b/demo-angular/package.json index 6b4fad6..e21d8d5 100644 --- a/demo-angular/package.json +++ b/demo-angular/package.json @@ -1,43 +1,53 @@ { - "nativescript": { - "id": "org.nativescript.picker.demoangular", - "tns-android": { - "version": "5.2.1" - }, - "tns-ios": { - "version": "5.2.0" - } + "nativescript": { + "id": "org.nativescript.picker.demoangular", + "tns-android": { + "version": "5.2.1" }, - "description": "NativeScript Application", - "scripts": { - "build.plugin": "cd ../src && npm run build", - "ci.tslint": "npm i && tslint --config '../tslint.json' 'src/**/*.ts'" - }, - "dependencies": { - "@angular/animations": "~7.2.0", - "@angular/common": "~7.2.0", - "@angular/compiler": "~7.2.0", - "@angular/core": "~7.2.0", - "@angular/forms": "~7.2.0", - "@angular/http": "~7.2.0", - "@angular/platform-browser": "~7.2.0", - "@angular/platform-browser-dynamic": "~7.2.0", - "@angular/router": "~7.2.0", - "nativescript-angular": "~7.2.1", - "nativescript-picker": "file:../src", - "nativescript-theme-core": "~1.0.4", - "reflect-metadata": "~0.1.10", - "rxjs": "~6.4.0", - "tns-core-modules": "~5.2.0", - "zone.js": "~0.8.18" - }, - "devDependencies": { - "@nativescript/schematics": "~0.5.0", - "nativescript-dev-typescript": "~0.8.0", - "nativescript-dev-webpack": "~0.20.0", - "@angular/compiler-cli": "~7.2.0", - "@ngtools/webpack": "~7.2.0", - "tslint": "~5.11.0" - }, - "readme": "NativeScript PickerField Demo NG" + "tns-ios": { + "version": "5.2.0" + } + }, + "description": "NativeScript Application", + "scripts": { + "build.plugin": "cd ../src && npm run build", + "ci.tslint": "npm i && tslint --config '../tslint.json' 'src/**/*.ts'", + "e2e": "node ./node_modules/nativescript-dev-appium/check-dev-deps.js && tsc -p e2e && mocha --opts ./e2e/config/mocha.opts ", + "e2e-watch": "tsc -p e2e --watch" + }, + "dependencies": { + "@angular/animations": "~7.2.0", + "@angular/common": "~7.2.0", + "@angular/compiler": "~7.2.0", + "@angular/core": "~7.2.0", + "@angular/forms": "~7.2.0", + "@angular/http": "~7.2.0", + "@angular/platform-browser": "~7.2.0", + "@angular/platform-browser-dynamic": "~7.2.0", + "@angular/router": "~7.2.0", + "nativescript-angular": "~7.2.1", + "nativescript-picker": "file:../src", + "nativescript-theme-core": "~1.0.4", + "reflect-metadata": "~0.1.10", + "rxjs": "~6.4.0", + "tns-core-modules": "~5.2.0", + "zone.js": "~0.8.18" + }, + "devDependencies": { + "@angular/compiler-cli": "~7.2.0", + "@nativescript/schematics": "~0.5.0", + "@ngtools/webpack": "~7.2.0", + "@types/chai": "~4.1.7", + "@types/mocha": "~5.2.5", + "@types/node": "~10.12.18", + "mocha": "~5.2.0", + "mocha-junit-reporter": "~1.18.0", + "mocha-multi": "~1.0.1", + "mochawesome": "^3.1.1", + "nativescript-dev-appium": "^5.1.0", + "nativescript-dev-typescript": "~0.8.0", + "nativescript-dev-webpack": "~0.20.0", + "tslint": "~5.11.0" + }, + "readme": "NativeScript PickerField Demo NG" } diff --git a/demo-angular/src/app/examples/styling/styling-example.component.css b/demo-angular/src/app/examples/styling/styling-example.component.css index 39c542a..11a53f4 100644 --- a/demo-angular/src/app/examples/styling/styling-example.component.css +++ b/demo-angular/src/app/examples/styling/styling-example.component.css @@ -17,17 +17,17 @@ /* Styling css start */ -.picker-field { - background-color: lightblue; - color: blue; +#picker { + color: green; } ListView.picker-field { - background-color: green; + background-color: lightblue; margin-left: 20; margin-right: 20; margin-bottom: 20; separator-color: red; + color: blue; } ActionBar.picker-field { diff --git a/demo-angular/src/app/examples/styling/styling-example.component.html b/demo-angular/src/app/examples/styling/styling-example.component.html index 2143feb..5910ddc 100644 --- a/demo-angular/src/app/examples/styling/styling-example.component.html +++ b/demo-angular/src/app/examples/styling/styling-example.component.html @@ -2,7 +2,7 @@ - diff --git a/demo-vue/app/components/GettingStarted.vue b/demo-vue/app/components/GettingStarted.vue index ab2a1fb..5440c46 100644 --- a/demo-vue/app/components/GettingStarted.vue +++ b/demo-vue/app/components/GettingStarted.vue @@ -4,7 +4,7 @@ - + > diff --git a/demo-vue/app/components/Styling.vue b/demo-vue/app/components/Styling.vue index 158196f..298445c 100644 --- a/demo-vue/app/components/Styling.vue +++ b/demo-vue/app/components/Styling.vue @@ -4,7 +4,7 @@ - - driver.findElementByText(element, SearchOptions.contains), + 600 + ); + return listItem; +} + +export async function scrollToElementInListView(driver: AppiumDriver, element: string, direction: Direction = Direction.down) { + let listView: UIElement; + if (isAndroid) { + listView = await driver.findElementByClassName("android.widget.ListView"); + } + else { + listView = await driver.findElementByClassName("XCUIElementTypeTable"); + } + const listItem = await listView.scrollTo( + direction, + () => driver.findElementByText(element, SearchOptions.contains), + 600 + ); + return listItem; +} + +export async function swipe(driver: AppiumDriver, item: any, direction: Direction) { + const rectangle = await item.getRectangle(); + const centerX = rectangle.x + rectangle.width / 2; + const centerY = rectangle.y + rectangle.height / 2; + let swipeX; + if (direction === Direction.right) { + const windowSize = await driver.driver.getWindowSize(); + swipeX = windowSize.width - 10; + } else if (direction === Direction.left) { + swipeX = 10; + } + + if (isAndroid) { + const wd = driver.wd(); + const action = new wd.TouchAction(driver.driver); + action.press({ x: centerX, y: centerY }) + .wait(200) + .moveTo({ x: swipeX, y: centerY }) + .release(); + await action.perform(); + } + else { + await driver.driver.execute('mobile: dragFromToForDuration', { + duration: 2.0, + fromX: centerX, + fromY: centerY, + toX: swipeX, + toY: centerY + }); + } +} + +export async function swipeToElement(driver: AppiumDriver, element: string, direction: Direction = Direction.down) { + let listView; + if (isAndroid) { + listView = await driver.findElementByClassName("android.widget.FrameLayout"); + } + else { + listView = await driver.findElementByClassName("XCUIElementTypeCollectionView"); + } + + let item = await driver.findElementByTextIfExists(element, SearchOptions.exact); + while (item === undefined) { + await listView.swipe(direction); + await driver.wait(500); + item = await driver.findElementByTextIfExists(element, SearchOptions.contains); + } + return item; +} \ No newline at end of file diff --git a/demo-vue/e2e/setup.ts b/demo-vue/e2e/setup.ts new file mode 100644 index 0000000..8b26e66 --- /dev/null +++ b/demo-vue/e2e/setup.ts @@ -0,0 +1,9 @@ +import { startServer, stopServer } from "nativescript-dev-appium"; + +before("start server", async () => { + await startServer(); +}); + +after("stop server", async () => { + await stopServer(); +}); diff --git a/demo-vue/e2e/tests.e2e.ts b/demo-vue/e2e/tests.e2e.ts new file mode 100644 index 0000000..b5c1f09 --- /dev/null +++ b/demo-vue/e2e/tests.e2e.ts @@ -0,0 +1,122 @@ +import { AppiumDriver, createDriver, SearchOptions, Direction, UIElement } from "nativescript-dev-appium"; +import { expect } from "chai"; +import { isSauceLab, runType } from "nativescript-dev-appium/lib/parser"; +import { navigateBackToHome, scrollToElement, scrollToElementInListView, QUEUE_WAIT_TIME } from "./helper"; +const fs = require('fs'); +const addContext = require('mochawesome/addContext'); +const rimraf = require('rimraf'); + +const isSauceRun = isSauceLab; + +describe("Picker", () => { + let driver: AppiumDriver; + + before(async function () { + this.timeout(QUEUE_WAIT_TIME); + driver = await createDriver(); + driver.defaultWaitTime = 15000; + let dir = "mochawesome-report"; + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } + rimraf('mochawesome-report/*', function () { }); + }); + + after(async () => { + if (isSauceRun) { + driver.sessionId().then(function (sessionId) { + console.log("Report https://saucelabs.com/beta/tests/" + sessionId); + }); + } + await driver.quit(); + console.log("Quit driver!"); + }); + + afterEach(async function () { + if (this.currentTest.state && this.currentTest.state === "failed") { + let png = await driver.logScreenshot(this.currentTest.title); + fs.copyFile(png, './mochawesome-report/' + this.currentTest.title + '.png', function (err) { + if (err) { + throw err; + } + console.log('Screenshot saved.'); + }); + addContext(this, './' + this.currentTest.title + '.png'); + } + }); + + const gettingStarted = "Getting Started"; + let field: UIElement; + describe(gettingStarted, () => { + it("Navigate to Getting Started example", async () => { + const getStarted = await scrollToElement(driver, gettingStarted); + await getStarted.click(); + field = await driver.findElementByText("Click here"); + expect(field).to.exist; + }); + + it("Click field and select item", async () => { + await field.click(); + const itemText = "Item 38"; + const item38 = await scrollToElement(driver, itemText); + await item38.click(); + const title = await driver.findElementByText(gettingStarted); + expect(title).to.exist; + const item = await driver.findElementByText(itemText); + expect(item).to.exist; + }); + + it("Click field and cancel selection", async () => { + let item38 = await driver.findElementByText("Item 38"); + await item38.click(); + const cancel = await driver.findElementByAccessibilityId("Close"); + await cancel.click(); + item38 = await driver.findElementByText("Item 38"); + expect(item38).to.exist; + }); + }); + + const styling = "Styling"; + describe(styling, () => { + it("Navigate to Styling example", async () => { + await navigateBackToHome(driver); + const stylingExample = await scrollToElement(driver, styling); + await stylingExample.click(); + field = await driver.findElementByText("This is hint"); + expect(field).to.exist; + }); + + it("Click field and select item", async () => { + await field.click(); + const itemText = "Item 6"; + const item6 = await scrollToElementInListView(driver, itemText); + await item6.click(); + const title = await driver.findElementByText(styling); + expect(title).to.exist; + const item = await driver.findElementByText(itemText); + expect(item).to.exist; + }); + }); + + const valueApis = "Value APIs"; + describe(valueApis, () => { + it("Navigate to Value APIs example", async () => { + await navigateBackToHome(driver); + const valueExample = await scrollToElement(driver, valueApis); + await valueExample.click(); + field = await driver.findElementByText("Click here"); + expect(field).to.exist; + }); + + it("Click field and select item", async () => { + await field.click(); + const itemText = "Item 1"; + const item1 = await scrollToElement(driver, itemText); + await item1.click(); + const title = await driver.findElementByText(valueApis); + expect(title).to.exist; + const description = await driver.findElementByText("Description 1"); + expect(description).to.exist; + }); + }); +}); \ No newline at end of file diff --git a/demo-vue/e2e/tsconfig.json b/demo-vue/e2e/tsconfig.json new file mode 100644 index 0000000..6c93b0e --- /dev/null +++ b/demo-vue/e2e/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "noEmitHelpers": true, + "importHelpers": true, + "types": [ + "mocha", + "chai", + "node" + ], + "lib": [ + "es6", + "dom", + "es2015.iterable" + ], + "baseUrl": "." + } +} \ No newline at end of file diff --git a/demo-vue/package.json b/demo-vue/package.json index b6460d0..60d76df 100644 --- a/demo-vue/package.json +++ b/demo-vue/package.json @@ -1,35 +1,44 @@ { - "nativescript": { - "id": "org.nativescript.picker.demovue", - "tns-android": { - "version": "5.2.1" - }, - "tns-ios": { - "version": "5.2.0" - } + "nativescript": { + "id": "org.nativescript.picker.demovue", + "tns-android": { + "version": "5.2.1" }, - "description": "NativeScript PickerField Demo Vue", - "scripts": { - "run.ios": "tns run ios --syncAllFiles --provision NativeScriptDevProfile --bundle", - "run.android": "tns run android --syncAllFiles --provision NativeScriptDevProfile --bundle", - "build.plugin": "cd ../src && npm run build", - "ci.tslint": "npm i && tslint --config '../tslint.json' 'src/**/*.ts'" - }, - "dependencies": { - "nativescript-picker": "file:../src", - "nativescript-theme-core": "~1.0.4", - "nativescript-vue": "~2.0.0", - "tns-core-modules": "~5.2.0" - }, - "devDependencies": { - "@babel/core": "~7.2.0", - "@babel/preset-env": "~7.2.0", - "babel-loader": "~8.0.0", - "nativescript-dev-typescript": "~0.8.0", - "nativescript-dev-webpack": "~0.20.0", - "nativescript-vue-template-compiler": "~2.0.2", - "node-sass": "~4.9.0", - "vue-loader": "~15.4.0" - }, - "readme": "NativeScript PickerField Demo Vue" + "tns-ios": { + "version": "5.2.0" + } + }, + "description": "NativeScript PickerField Demo Vue", + "scripts": { + "run.ios": "tns run ios --syncAllFiles --provision NativeScriptDevProfile --bundle", + "run.android": "tns run android --syncAllFiles --provision NativeScriptDevProfile --bundle", + "build.plugin": "cd ../src && npm run build", + "ci.tslint": "npm i && tslint --config '../tslint.json' 'src/**/*.ts'", + "e2e": "node ./node_modules/nativescript-dev-appium/check-dev-deps.js && tsc -p e2e && mocha --opts ./e2e/config/mocha.opts " + }, + "dependencies": { + "nativescript-picker": "file:../src", + "nativescript-theme-core": "~1.0.4", + "nativescript-vue": "~2.0.0", + "tns-core-modules": "~5.2.0" + }, + "devDependencies": { + "@babel/core": "~7.2.0", + "@babel/preset-env": "~7.2.0", + "@types/chai": "~4.1.7", + "@types/mocha": "~5.2.5", + "@types/node": "~10.12.18", + "babel-loader": "~8.0.0", + "mocha": "~5.2.0", + "mocha-junit-reporter": "~1.18.0", + "mocha-multi": "~1.0.1", + "mochawesome": "^3.1.1", + "nativescript-dev-appium": "^5.1.0", + "nativescript-dev-typescript": "~0.8.0", + "nativescript-dev-webpack": "~0.20.0", + "nativescript-vue-template-compiler": "~2.0.2", + "node-sass": "~4.9.0", + "vue-loader": "~15.4.0" + }, + "readme": "NativeScript PickerField Demo Vue" } diff --git a/demo-vue/tsconfig.json b/demo-vue/tsconfig.json index f9def18..c030f55 100644 --- a/demo-vue/tsconfig.json +++ b/demo-vue/tsconfig.json @@ -5,10 +5,12 @@ "experimentalDecorators": true, "emitDecoratorMetadata": true, "noEmitHelpers": true, + "importHelpers": true, "noEmitOnError": true, "lib": [ "es6", - "dom" + "dom", + "es2015.iterable" ], "baseUrl": ".", "paths": { diff --git a/demo/app/app-root.xml b/demo/app/app-root.xml index 71c0b64..151b4cb 100644 --- a/demo/app/app-root.xml +++ b/demo/app/app-root.xml @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/demo/app/app.css b/demo/app/app.css index bc89861..8869dc9 100644 --- a/demo/app/app.css +++ b/demo/app/app.css @@ -32,16 +32,16 @@ ListView.picker-field { - background-color: green; + background-color: lightblue; margin-left: 20; margin-right: 20; margin-bottom: 20; separator-color: red; + color: blue; } -.picker-field { - background-color: lightblue; - color: blue; +#picker { + color: green; } .item-template-picture { diff --git a/demo/app/examples/styling/styling-page.xml b/demo/app/examples/styling/styling-page.xml index 29aee92..226c922 100644 --- a/demo/app/examples/styling/styling-page.xml +++ b/demo/app/examples/styling/styling-page.xml @@ -1,6 +1,6 @@ - driver.findElementByText(element, SearchOptions.contains), + 600 + ); + return listItem; +} + +export async function scrollToElementInListView(driver: AppiumDriver, element: string, direction: Direction = Direction.down) { + let listView: UIElement; + if (isAndroid) { + listView = await driver.findElementByClassName("android.widget.ListView"); + } + else { + listView = await driver.findElementByClassName("XCUIElementTypeTable"); + } + const listItem = await listView.scrollTo( + direction, + () => driver.findElementByText(element, SearchOptions.contains), + 600 + ); + return listItem; +} + +export async function swipe(driver: AppiumDriver, item: any, direction: Direction) { + const rectangle = await item.getRectangle(); + const centerX = rectangle.x + rectangle.width / 2; + const centerY = rectangle.y + rectangle.height / 2; + let swipeX; + if (direction === Direction.right) { + const windowSize = await driver.driver.getWindowSize(); + swipeX = windowSize.width - 10; + } else if (direction === Direction.left) { + swipeX = 10; + } + + if (isAndroid) { + const wd = driver.wd(); + const action = new wd.TouchAction(driver.driver); + action.press({ x: centerX, y: centerY }) + .wait(200) + .moveTo({ x: swipeX, y: centerY }) + .release(); + await action.perform(); + } + else { + await driver.driver.execute('mobile: dragFromToForDuration', { + duration: 2.0, + fromX: centerX, + fromY: centerY, + toX: swipeX, + toY: centerY + }); + } +} + +export async function swipeToElement(driver: AppiumDriver, element: string, direction: Direction = Direction.down) { + let listView; + if (isAndroid) { + listView = await driver.findElementByClassName("android.widget.FrameLayout"); + } + else { + listView = await driver.findElementByClassName("XCUIElementTypeCollectionView"); + } + + let item = await driver.findElementByTextIfExists(element, SearchOptions.exact); + while (item === undefined) { + await listView.swipe(direction); + await driver.wait(500); + item = await driver.findElementByTextIfExists(element, SearchOptions.contains); + } + return item; +} \ No newline at end of file diff --git a/demo/e2e/setup.ts b/demo/e2e/setup.ts new file mode 100644 index 0000000..8b26e66 --- /dev/null +++ b/demo/e2e/setup.ts @@ -0,0 +1,9 @@ +import { startServer, stopServer } from "nativescript-dev-appium"; + +before("start server", async () => { + await startServer(); +}); + +after("stop server", async () => { + await stopServer(); +}); diff --git a/demo/e2e/tests.e2e.ts b/demo/e2e/tests.e2e.ts new file mode 100644 index 0000000..f7b6028 --- /dev/null +++ b/demo/e2e/tests.e2e.ts @@ -0,0 +1,123 @@ +import { AppiumDriver, createDriver, SearchOptions, Direction, UIElement } from "nativescript-dev-appium"; +import { expect } from "chai"; +import { isSauceLab, runType } from "nativescript-dev-appium/lib/parser"; +import { navigateBackToHome, scrollToElement, scrollToElementInListView, QUEUE_WAIT_TIME } from "./helper"; +const fs = require('fs'); +const addContext = require('mochawesome/addContext'); +const rimraf = require('rimraf'); + +const isSauceRun = isSauceLab; + +describe("Picker", () => { + let driver: AppiumDriver; + + before(async function () { + this.timeout(QUEUE_WAIT_TIME); + driver = await createDriver(); + driver.defaultWaitTime = 15000; + let dir = "mochawesome-report"; + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } + rimraf('mochawesome-report/*', function () { }); + }); + + after(async () => { + if (isSauceRun) { + driver.sessionId().then(function (sessionId) { + console.log("Report https://saucelabs.com/beta/tests/" + sessionId); + }); + } + await driver.quit(); + console.log("Quit driver!"); + }); + + afterEach(async function () { + if (this.currentTest.state && this.currentTest.state === "failed") { + let png = await driver.logScreenshot(this.currentTest.title); + fs.copyFile(png, './mochawesome-report/' + this.currentTest.title + '.png', function (err) { + if (err) { + throw err; + } + console.log('Screenshot saved.'); + }); + addContext(this, './' + this.currentTest.title + '.png'); + } + }); + + const gettingStarted = "Getting started"; + let field: UIElement; + describe(gettingStarted, () => { + it("Navigate to Getting started example", async () => { + const getStarted = await scrollToElement(driver, gettingStarted); + await getStarted.click(); + field = await driver.findElementByText("Click here"); + expect(field).to.exist; + }); + + it("Click field and select item", async function () { + this.timeout(QUEUE_WAIT_TIME); + await field.click(); + const itemText = "Item 30"; + const item30 = await scrollToElement(driver, itemText); + await item30.click(); + const title = await driver.findElementByText(gettingStarted); + expect(title).to.exist; + const item = await driver.findElementByText(itemText); + expect(item).to.exist; + }); + + it("Click field and cancel selection", async () => { + let item30 = await driver.findElementByText("Item 30"); + await item30.click(); + const cancel = await driver.findElementByAccessibilityId("Close"); + await cancel.click(); + item30 = await driver.findElementByText("Item 30"); + expect(item30).to.exist; + }); + }); + + const styling = "Styling"; + describe(styling, () => { + it("Navigate to Styling example", async () => { + await navigateBackToHome(driver); + const stylingExample = await scrollToElement(driver, styling); + await stylingExample.click(); + field = await driver.findElementByText("This is hint"); + expect(field).to.exist; + }); + + it("Click field and select item", async () => { + await field.click(); + const itemText = "Item 6"; + const item6 = await scrollToElementInListView(driver, itemText); + await item6.click(); + const title = await driver.findElementByText(styling); + expect(title).to.exist; + const item = await driver.findElementByText(itemText); + expect(item).to.exist; + }); + }); + + const valueApis = "Value APIs"; + describe(valueApis, () => { + it("Navigate to Value APIs example", async () => { + await navigateBackToHome(driver); + const valueExample = await scrollToElement(driver, valueApis); + await valueExample.click(); + field = await driver.findElementByText("Click here"); + expect(field).to.exist; + }); + + it("Click field and select item", async () => { + await field.click(); + const itemText = "Item 1"; + const item1 = await scrollToElement(driver, itemText); + await item1.click(); + const title = await driver.findElementByText(valueApis); + expect(title).to.exist; + const description = await driver.findElementByText("Description 1"); + expect(description).to.exist; + }); + }); +}); \ No newline at end of file diff --git a/demo/e2e/tsconfig.json b/demo/e2e/tsconfig.json new file mode 100644 index 0000000..0c3f525 --- /dev/null +++ b/demo/e2e/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "importHelpers": false, + "types": [ + "mocha", + "chai", + "node" + ], + "lib": [ + "es2015", + "dom" + ], + "baseUrl": "." + } +} \ No newline at end of file diff --git a/demo/package.json b/demo/package.json index b75b579..d676123 100644 --- a/demo/package.json +++ b/demo/package.json @@ -1,26 +1,36 @@ { - "nativescript": { - "id": "org.nativescript.picker.demo", - "tns-android": { - "version": "5.2.1" - }, - "tns-ios": { - "version": "5.2.0" - } + "nativescript": { + "id": "org.nativescript.picker.demo", + "tns-android": { + "version": "5.2.1" }, - "dependencies": { - "nativescript-picker": "file:../src", - "nativescript-theme-core": "~1.0.4", - "tns-core-modules": "~5.2.0" - }, - "devDependencies": { - "nativescript-dev-typescript": "~0.8.0", - "nativescript-dev-webpack": "~0.20.0", - "tslint": "~5.11.0" - }, - "scripts": { - "build.plugin": "cd ../src && npm run build", - "ci.tslint": "npm i && tslint --config '../tslint.json' 'app/**/*.ts' --exclude '**/node_modules/**' --exclude '**/platforms/**'" - }, - "readme": "NativeScript PickerField Demo Core" + "tns-ios": { + "version": "5.2.0" + } + }, + "dependencies": { + "nativescript-picker": "file:../src", + "nativescript-theme-core": "~1.0.4", + "tns-core-modules": "~5.2.0" + }, + "devDependencies": { + "@types/chai": "~4.1.7", + "@types/mocha": "~5.2.5", + "@types/node": "~10.12.18", + "mocha": "~5.2.0", + "mocha-junit-reporter": "~1.18.0", + "mocha-multi": "~1.0.1", + "mochawesome": "^3.1.1", + "nativescript-dev-appium": "5.0.0", + "nativescript-dev-typescript": "~0.8.0", + "nativescript-dev-webpack": "~0.20.0", + "tslint": "~5.11.0" + }, + "scripts": { + "build.plugin": "cd ../src && npm run build", + "ci.tslint": "npm i && tslint --config '../tslint.json' 'app/**/*.ts' --exclude '**/node_modules/**' --exclude '**/platforms/**'", + "e2e": "node ./node_modules/nativescript-dev-appium/check-dev-deps.js && tsc -p e2e && mocha --opts ./e2e/config/mocha.opts ", + "e2e-watch": "tsc -p e2e --watch" + }, + "readme": "NativeScript PickerField Demo Core" }