diff --git a/.npmignore b/.npmignore
index c187208c..f208fe2f 100644
--- a/.npmignore
+++ b/.npmignore
@@ -2,3 +2,4 @@ tags
.zedstate
/scripts
/temp
+/test
diff --git a/.travis.yml b/.travis.yml
index 4348c023..50e474fe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,43 @@
-language: node_js
-node_js:
-- lts/*
+sudo: false
+
+language: objective-c
+os: osx
+osx_image: xcode9.1
+
+cache: false
+
+addons:
+ sauce_connect:
+ username: silkimen
+ jwt: TwUj8A5qAR53BRhVwcdLCM64kI+f8beOLbZ2VmLJ557ptGAxvkHrhQ19uLEQakL64SWoeznObJjTG/Sp8zbO6O9xkfTw5mbNPk7FBTMd77x62l/PHZSWuwiFEVPfLnG2jSGWBqrLxr/g8cIiruzHSXS9J4C86SYIKIGnz9atJxB7XswwzAkvmyzgzC6iRCFhoAgmnhtY+Xr+QHcbpESoiUPv/MQ8CFNpk65CX+fuvVunWX70e3Qlelcs7nkbF/soFwD1WExCbTaPlaNvKqBIc1YuO4qdNy4Uff4mZZLsARH0X618EwFAVN4VM7AIqeUp3NoQYDw9vpkR7lmoOUJzI0aovasXa8frDNvm8GSP17jtCTQzfYEMK+B9rIA9oBRd46dyGujZtbKoTpDdTMIe0ayqb38NRuNwDzEV7WVMCcUgux0Q8NIAkWYYb21QN9z7XOOznP7BatK7mlJ0V6J7taBW2EBOwQzHWRG7n9GknGXsPzwxDW6aBCiOem/AcxZkajDPcRu/3diq5ZSZcC7cTVBxCZZCqpPCsZH0l47jW8MNh+CYw+i5TGsp7g0YHVmbWzE8dv73tMD9zQP0pUjOSkY55xbS7kTCXvFqP0OdMccpzdZY5h7JER95tIPz3gZwVFCoBg0GvwTqTxhGKR+jNosUD2n6WhCVFAU+AspgCKo=
+
+before_install:
+- export LANG=en_US.UTF-8
+- brew update
+
+install:
+- npm install
+- brew install gradle
+- wget http://dl.google.com/android/android-sdk_r24.4-macosx.zip
+- tar -xvf android-sdk_r24.4-macosx.zip
+- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter platform-tools
+- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter build-tools-25.0.0
+- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter android-25
+- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-android-support
+- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-android-m2repository
+- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-google-m2repository
+- export ANDROID_HOME=./android-sdk-macosx
+- export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/23.0.2
+
+script:
+- scripts/build-test-app.sh
+- scripts/upload-artifact.sh
+- scripts/test.sh --ios --emulator
+
+after_success:
+
+deploy:
+
notifications:
slack:
secure: lXE+2AgsxZU5G5dI91LkMAIgo8MAWfdM7DB5UOtn5LpuNln+2FmJo1gOI7tkdmLOqpXTGYnpI2VyQN3H4nOF21YhuouzD1Sh8n2wtQg1iTm353kuQpqiVhSBX8ZJ7Be1e1G8OsnxoYOxbs4Zo9qI40EruwkvqLCBHWM5MRGyd4M7EFWwb9Z29VZN0y1Nt5g/c3bT76kdKmF+JCLur2OeEKxAity7sIKgZekSqeIMwEVLSxXnda6Dbjc/cg0MJ0iDArkD7iu6fz/Fcrrxgm/pUxjcgvqze7Gy5i31mjEfspnrglWV1cshMd48BTDKCJ2AMmxH8O3GPSWE2txjIvGRWUve7iViNylvmQCVz3Eyf99+4EuuVGa+5PSodQ/CqODx/65EwtcN3PE1tNz2puKOK8nrOJcFkcbG8KTHKUlQtHCkjitbykUnj/hvhLK5/oWlQYVOLWWrHwdGUh8FI8aFPVGjRjWbHbhdayjEIqxwr1ns+6mYrP1EFNXbaeZxnLNC59XpJl1ifuezqYAk7YEiU5j4rtC7YKgyQ3ueb7anOHTJoTMyDn8mpZXgwuyhoBaeEYytQVgRyMtL6Y5cP98Jn2kv0+vdne3rkk9/JEBTo32HOjvoij6rsqEvXC0LhUDJSNadOVdHht0jjoN6zBH37HIE5/3zysLlPcAcHAS83ow=
diff --git a/package.json b/package.json
index 46cc120c..52b4bd91 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "1.6.1",
"description": "Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning",
"scripts": {
- "test": "./scripts/test-installation.sh"
+ "test": "./scripts/build-test-app.sh && ./scripts/test.sh --ios --emulator"
},
"cordova": {
"id": "cordova-plugin-advanced-http",
@@ -49,9 +49,14 @@
},
"homepage": "https://github.com/silkimen/cordova-plugin-advanced-http#readme",
"devDependencies": {
+ "chai": "4.1.2",
+ "chai-as-promised": "7.1.1",
+ "colors": "1.1.2",
"cordova": "7.0.1",
+ "mocha": "4.0.0",
"mz": "2.7.0",
"umd-tough-cookie": "2.3.2",
+ "wd": "1.4.1",
"xml2js": "0.4.19"
}
}
diff --git a/release.sh b/release.sh
index 75969241..f73fb031 100755
--- a/release.sh
+++ b/release.sh
@@ -5,5 +5,6 @@ VERSION=$(node -e "console.log(require('./package.json').version)")
./scripts/update-tough-cookie.sh
node ./scripts/update-plugin-xml.js $VERSION
-npm publish
+git commit -a -m "release v$VERSION"
git tag "v$VERSION"
+npm publish
diff --git a/scripts/build-test-app.sh b/scripts/build-test-app.sh
new file mode 100755
index 00000000..ef062fac
--- /dev/null
+++ b/scripts/build-test-app.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+set -e
+
+PLATFORM=$([[ "${@#--android}" = "$@" ]] && echo "ios" || echo "android")
+TARGET=$([[ "${@#--device}" = "$@" ]] && echo "emulator" || echo "device")
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/..
+CDV=$ROOT/node_modules/.bin/cordova
+
+rm -rf $ROOT/temp
+mkdir $ROOT/temp
+cp -r $ROOT/test/app-template/ $ROOT/temp/
+cp $ROOT/test/test-definitions.js $ROOT/temp/www/js/
+cd $ROOT/temp
+$CDV prepare
+$CDV plugins add $ROOT
+$CDV build $PLATFORM --$TARGET
diff --git a/scripts/test-installation.sh b/scripts/test-installation.sh
deleted file mode 100755
index 7e57faf4..00000000
--- a/scripts/test-installation.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/..
-CDV=$ROOT/node_modules/.bin/cordova
-
-rm -rf $ROOT/temp
-$CDV create $ROOT/temp
-cd $ROOT/temp
-$CDV platforms add android
-$CDV platforms add ios
-$CDV plugins add $ROOT
diff --git a/scripts/test.sh b/scripts/test.sh
new file mode 100755
index 00000000..15404bae
--- /dev/null
+++ b/scripts/test.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -e
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/..
+
+pushd $ROOT
+./node_modules/.bin/mocha ./test/mocha-specs/test.js "$@"
+popd
diff --git a/scripts/upload-artifact.sh b/scripts/upload-artifact.sh
new file mode 100755
index 00000000..ffab5aac
--- /dev/null
+++ b/scripts/upload-artifact.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+set -e
+
+ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/..
+TEMP=$ROOT/temp
+
+rm -rf $TEMP/HttpDemo.app.zip
+pushd $TEMP/platforms/ios/build/emulator
+zip -r $TEMP/HttpDemo.app.zip ./HttpDemo.app
+popd
+
+curl -u $SAUCE_USERNAME:$SAUCE_ACCESS_KEY \
+ -X POST \
+ -H "Content-Type: application/octet-stream" \
+ https://saucelabs.com/rest/v1/storage/$SAUCE_USERNAME/HttpDemo.app.zip?overwrite=true \
+ --data-binary @$TEMP/HttpDemo.app.zip
diff --git a/test/app-template/config.xml b/test/app-template/config.xml
new file mode 100644
index 00000000..6baa9538
--- /dev/null
+++ b/test/app-template/config.xml
@@ -0,0 +1,27 @@
+
+
+ HttpDemo
+
+ A sample Apache Cordova application that demonstrates advanced HTTP plugin.
+
+
+ Sefa Ilkimen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/app-template/package.json b/test/app-template/package.json
new file mode 100644
index 00000000..568e628f
--- /dev/null
+++ b/test/app-template/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "com.ilkimen.http.demo",
+ "displayName": "HttpDemo",
+ "version": "1.0.0",
+ "description": "A sample Apache Cordova application that demonstrates advanced HTTP plugin.",
+ "main": "index.js",
+ "scripts": {
+ "build": "scripts/build.sh",
+ "test": "npm run build && scripts/test.sh"
+ },
+ "author": "Sefa Ilkimen",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "cordova": "7.0.1",
+ "cordova-android": "6.2.3",
+ "cordova-ios": "4.4.0"
+ },
+ "cordova": {
+ "platforms": [
+ "android",
+ "ios"
+ ]
+ },
+ "devDependencies": {}
+}
diff --git a/test/app-template/www/css/index.css b/test/app-template/www/css/index.css
new file mode 100644
index 00000000..37f86e19
--- /dev/null
+++ b/test/app-template/www/css/index.css
@@ -0,0 +1,24 @@
+* {
+ -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
+}
+
+body {
+ -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
+ -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
+ -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
+ height:100%;
+ margin:0px;
+ padding:20px 0;
+ width:100%;
+ font-family: sans-serif;
+}
+
+button, input, textarea {
+ display: block;
+ width: 100%;
+}
+
+h1 {
+ font-size: 12pt;
+ text-align: center;
+}
diff --git a/test/app-template/www/img/logo.png b/test/app-template/www/img/logo.png
new file mode 100644
index 00000000..9519e7dd
Binary files /dev/null and b/test/app-template/www/img/logo.png differ
diff --git a/test/app-template/www/index.html b/test/app-template/www/index.html
new file mode 100644
index 00000000..4c33ca9a
--- /dev/null
+++ b/test/app-template/www/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+ Advanced HTTP test suite
+
+
+
+
+
+
+
+
diff --git a/test/app-template/www/js/index.js b/test/app-template/www/js/index.js
new file mode 100644
index 00000000..9c8d0dfe
--- /dev/null
+++ b/test/app-template/www/js/index.js
@@ -0,0 +1,51 @@
+const app = {
+ testIndex: -1,
+
+ initialize: function() {
+ document.getElementById('nextBtn').addEventListener('click', app.onNextBtnClick);
+ },
+
+ print: function(prefix, content) {
+ const text = '\n' + prefix + ': ' + JSON.stringify(content);
+
+ document.getElementById('resultTextarea').value += text;
+ },
+
+ reject: function(content) {
+ app.print('result - rejected', content);
+ },
+
+ resolve: function(content) {
+ app.print('result - resolved', content);
+ },
+
+ runTest: function(index) {
+ const testDefinition = tests[index];
+ const titleText = app.testIndex + ': ' + testDefinition.description;
+ const resultText = 'expectation - ' + testDefinition.expected;
+
+ document.getElementById('resultTextarea').value = resultText;
+ document.getElementById('descriptionLbl').innerText = titleText;
+ testDefinition.func(index);
+ },
+
+ onFinishedAllTests: function() {
+ const titleText = 'No more tests';
+ const resultText = 'You have run all available tests.';
+
+ document.getElementById('resultTextarea').value = resultText;
+ document.getElementById('descriptionLbl').innerText = titleText;
+ },
+
+ onNextBtnClick: function() {
+ app.testIndex += 1;
+
+ if (app.testIndex < tests.length) {
+ app.runTest(app.testIndex);
+ } else {
+ app.onFinishedAllTests();
+ }
+ }
+};
+
+app.initialize();
diff --git a/test/mocha-specs/helpers/apps.js b/test/mocha-specs/helpers/apps.js
new file mode 100644
index 00000000..711b7d87
--- /dev/null
+++ b/test/mocha-specs/helpers/apps.js
@@ -0,0 +1,10 @@
+const path = require('path');
+
+if (process.env.SAUCE_USERNAME) {
+ exports.iosTestApp = 'sauce-storage:HttpDemo.app.zip';
+ exports.androidTestApp = 'sauce-storage:HttpDemo.apk';
+} else {
+ // these paths are relative to working directory
+ exports.iosTestApp = path.resolve('temp/platforms/ios/build/emulator/HttpDemo.app');
+ exports.androidTestApp = path.resolve('temp/platforms/android/build/outputs/apk/android-debug.apk');
+}
diff --git a/test/mocha-specs/helpers/caps.js b/test/mocha-specs/helpers/caps.js
new file mode 100644
index 00000000..069ddcd1
--- /dev/null
+++ b/test/mocha-specs/helpers/caps.js
@@ -0,0 +1,65 @@
+const local = {
+ iosDevice: {
+ browserName: '',
+ 'appium-version': '1.7.1',
+ platformName: 'iOS',
+ platformVersion: '10.3',
+ deviceName: 'iPhone 6',
+ autoWebview: true,
+ app: undefined // will be set later
+ },
+ iosEmulator: {
+ browserName: '',
+ 'appium-version': '1.7.1',
+ platformName: 'iOS',
+ platformVersion: '11.0',
+ deviceName: 'iPhone Simulator',
+ autoWebview: true,
+ app: undefined // will be set later
+ },
+ androidEmulator: {
+ browserName: '',
+ 'appium-version': '1.7.1',
+ platformName: 'Android',
+ platformVersion: '5.1',
+ deviceName: 'Android Emulator',
+ autoWebview: true,
+ app: undefined // will be set later
+ }
+};
+
+const sauce = {
+ iosDevice: {
+ browserName: '',
+ 'appium-version': '1.7.1',
+ platformName: 'iOS',
+ platformVersion: '10.3',
+ deviceName: 'iPhone 6',
+ autoWebview: true,
+ app: undefined // will be set later
+ },
+ iosEmulator: {
+ browserName: '',
+ 'appium-version': '1.7.1',
+ platformName: 'iOS',
+ platformVersion: '10.3',
+ deviceName: 'iPhone Simulator',
+ autoWebview: true,
+ app: undefined // will be set later
+ },
+ androidEmulator: {
+ browserName: '',
+ 'appium-version': '1.7.1',
+ platformName: 'Android',
+ platformVersion: '5.1',
+ deviceName: 'Android Emulator',
+ autoWebview: true,
+ app: undefined // will be set later
+ }
+};
+
+if (process.env.SAUCE_USERNAME) {
+ module.exports = sauce;
+} else {
+ module.exports = local;
+}
diff --git a/test/mocha-specs/helpers/logging.js b/test/mocha-specs/helpers/logging.js
new file mode 100644
index 00000000..11a7be13
--- /dev/null
+++ b/test/mocha-specs/helpers/logging.js
@@ -0,0 +1,13 @@
+exports.configure = driver => {
+ driver.on('status', info => {
+ console.log(info.cyan);
+ });
+
+ driver.on('command', (meth, path, data) => {
+ console.log(' > ' + meth.yellow, path.grey, data || '');
+ });
+
+ driver.on('http', (meth, path, data) => {
+ console.log(' > ' + meth.magenta, path, (data || '').grey);
+ });
+};
diff --git a/test/mocha-specs/helpers/server.js b/test/mocha-specs/helpers/server.js
new file mode 100644
index 00000000..f96ab11d
--- /dev/null
+++ b/test/mocha-specs/helpers/server.js
@@ -0,0 +1,16 @@
+const local = {
+ host: 'localhost',
+ port: 4723
+};
+
+const sauce = {
+ host: 'ondemand.saucelabs.com',
+ port: 80,
+ auth: process.env.SAUCE_USERNAME + ":" + process.env.SAUCE_ACCESS_KEY
+};
+
+if (process.env.SAUCE_USERNAME) {
+ module.exports = sauce;
+} else {
+ module.exports = local;
+}
diff --git a/test/mocha-specs/helpers/setup.js b/test/mocha-specs/helpers/setup.js
new file mode 100644
index 00000000..3e09b7fa
--- /dev/null
+++ b/test/mocha-specs/helpers/setup.js
@@ -0,0 +1,12 @@
+const wd = require("wd");
+
+require('colors');
+
+const chai = require('chai');
+const chaiAsPromised = require('chai-as-promised');
+chai.use(chaiAsPromised);
+
+const should = chai.should();
+chaiAsPromised.transferPromiseness = wd.transferPromiseness;
+
+exports.should = should;
diff --git a/test/mocha-specs/test.js b/test/mocha-specs/test.js
new file mode 100644
index 00000000..36dbf31b
--- /dev/null
+++ b/test/mocha-specs/test.js
@@ -0,0 +1,71 @@
+require('./helpers/setup');
+
+const wd = require('wd');
+const apps = require('./helpers/apps');
+const caps = Object.assign({}, require('./helpers/caps'));
+const serverConfig = require('./helpers/server');
+const testDefinitions = require('../test-definitions');
+
+describe('Advanced HTTP', function() {
+ let driver;
+ let allPassed = true;
+
+ this.timeout(300000);
+
+ const getCaps = appName => {
+ const isDevice = process.argv.includes('--device');
+ const isAndroid = process.argv.includes('--android');
+ const desiredCaps = caps[(isAndroid ? 'android' : 'ios') + (isDevice ? 'Device' : 'Emulator')];
+ const desiredApp = apps[(isAndroid ? 'android' : 'ios') + appName];
+
+ desiredCaps.app = desiredApp;
+
+ return desiredCaps;
+ };
+
+ const validateTestIndex = number => driver
+ .elementById('descriptionLbl')
+ .text()
+ .then(text => parseInt(text.match(/(\d):/)[1], 10))
+ .should.eventually.become(number);
+
+ const validateTestTitle = testTitle => driver
+ .elementById('descriptionLbl')
+ .text()
+ .then(text => text.match(/\d:\ (.*)/)[1])
+ .should.eventually.become(testTitle);
+
+ const validateResult = text => driver
+ .elementById('resultTextarea')
+ .getAttribute('value')
+ .should.eventually.include(text);
+
+ const clickNext = () => driver
+ .elementById('nextBtn')
+ .click()
+ .sleep(1000);
+
+ before(() => {
+ driver = wd.promiseChainRemote(serverConfig);
+ require('./helpers/logging').configure(driver);
+
+ return driver.init(getCaps('TestApp'));
+ });
+
+ after(() => driver
+ .quit()
+ .finally(function () {
+ if (process.env.SAUCE_USERNAME) {
+ return driver.sauceJobStatus(allPassed);
+ }
+ }));
+
+ testDefinitions.forEach((definition, index) => {
+ it(definition.description, function() {
+ return clickNext()
+ .then(() => validateTestIndex(index))
+ .then(() => validateTestTitle(this.test.title))
+ .then(() => validateResult(definition.expected))
+ });
+ });
+});
diff --git a/test/test-definitions.js b/test/test-definitions.js
new file mode 100644
index 00000000..7ec72b12
--- /dev/null
+++ b/test/test-definitions.js
@@ -0,0 +1,27 @@
+const tests = [
+ {
+ description: 'should reject self signed cert (GET)',
+ expected: 'rejected: {"status":-1,"error":"cancelled"}',
+ func: function() { cordova.plugin.http.get('https://self-signed.badssl.com/', {}, {}, app.resolve, app.reject); }
+ },{
+ description: 'should reject self signed cert (PUT)',
+ expected: 'rejected: {"status":-1,"error":"cancelled"}',
+ func: function() { cordova.plugin.http.put('https://self-signed.badssl.com/', { test: 'testString' }, {}, app.resolve, app.reject); }
+ },{
+ description: 'should reject self signed cert (POST)',
+ expected: 'rejected: {"status":-1,"error":"cancelled"}',
+ func: function() { cordova.plugin.http.post('https://self-signed.badssl.com/', { test: 'testString' }, {}, app.resolve, app.reject); }
+ },{
+ description: 'should reject self signed cert (PATCH)',
+ expected: 'rejected: {"status":-1,"error":"cancelled"}',
+ func: function() { cordova.plugin.http.patch('https://self-signed.badssl.com/', { test: 'testString' }, {}, app.resolve, app.reject); }
+ },{
+ description: 'should reject self signed cert (DELETE)',
+ expected: 'rejected: {"status":-1,"error":"cancelled"}',
+ func: function() { cordova.plugin.http.delete('https://self-signed.badssl.com/', {}, {}, app.resolve, app.reject); }
+ }
+];
+
+if (module && module.exports) {
+ module.exports = tests;
+}