ios.spec.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /*jshint node: true, jasmine: true */
  2. /*
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one
  5. * or more contributor license agreements. See the NOTICE file
  6. * distributed with this work for additional information
  7. * regarding copyright ownership. The ASF licenses this file
  8. * to you under the Apache License, Version 2.0 (the
  9. * "License"); you may not use this file except in compliance
  10. * with the License. You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing,
  15. * software distributed under the License is distributed on an
  16. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17. * KIND, either express or implied. See the License for the
  18. * specific language governing permissions and limitations
  19. * under the License.
  20. *
  21. */
  22. // these tests are meant to be executed by Cordova Medic Appium runner
  23. // you can find it here: https://github.com/apache/cordova-medic/
  24. // it is not necessary to do a full CI setup to run these tests
  25. // just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-camera"
  26. 'use strict';
  27. var wdHelper = global.WD_HELPER;
  28. var screenshotHelper = global.SCREENSHOT_HELPER;
  29. var isDevice = global.DEVICE;
  30. var cameraConstants = require('../../www/CameraConstants');
  31. var cameraHelper = require('../helpers/cameraHelper');
  32. var MINUTE = 60 * 1000;
  33. var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW_1';
  34. var PROMISE_PREFIX = 'appium_camera_promise_';
  35. describe('Camera tests iOS.', function () {
  36. var driver;
  37. var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
  38. // promise count to use in promise ID
  39. var promiseCount = 0;
  40. // going to set this to false if session is created successfully
  41. var failedToStart = true;
  42. function getNextPromiseId() {
  43. promiseCount += 1;
  44. return getCurrentPromiseId();
  45. }
  46. function getCurrentPromiseId() {
  47. return PROMISE_PREFIX + promiseCount;
  48. }
  49. function saveScreenshotAndFail(error) {
  50. fail(error);
  51. return screenshotHelper
  52. .saveScreenshot(driver)
  53. .quit()
  54. .then(function () {
  55. return getDriver();
  56. });
  57. }
  58. // generates test specs by combining all the specified options
  59. // you can add more options to test more scenarios
  60. function generateOptions() {
  61. var sourceTypes = cameraConstants.PictureSourceType;
  62. var destinationTypes = cameraConstants.DestinationType;
  63. var encodingTypes = cameraConstants.EncodingType;
  64. var allowEditOptions = [ true, false ];
  65. var correctOrientationOptions = [ true, false ];
  66. return cameraHelper.generateSpecs(sourceTypes, destinationTypes, encodingTypes, allowEditOptions, correctOrientationOptions);
  67. }
  68. function usePicture() {
  69. return driver
  70. .elementByXPath('//*[@label="Use"]')
  71. .click()
  72. .fail(function () {
  73. // For some reason "Choose" element is not clickable by standard Appium methods
  74. return wdHelper.tapElementByXPath('//UIAButton[@label="Choose"]', driver);
  75. });
  76. }
  77. function getPicture(options, cancelCamera, skipUiInteractions) {
  78. var promiseId = getNextPromiseId();
  79. if (!options) {
  80. options = {};
  81. }
  82. return driver
  83. .context(webviewContext)
  84. .execute(cameraHelper.getPicture, [options, promiseId])
  85. .context('NATIVE_APP')
  86. .then(function () {
  87. if (skipUiInteractions) {
  88. return;
  89. }
  90. if (options.hasOwnProperty('sourceType') && options.sourceType === cameraConstants.PictureSourceType.PHOTOLIBRARY) {
  91. return driver
  92. .waitForElementByXPath('//*[@label="Camera Roll"]', MINUTE / 2)
  93. .click()
  94. .elementByXPath('//UIACollectionCell')
  95. .click()
  96. .then(function () {
  97. if (!options.allowEdit) {
  98. return driver;
  99. }
  100. return usePicture();
  101. });
  102. }
  103. if (options.hasOwnProperty('sourceType') && options.sourceType === cameraConstants.PictureSourceType.SAVEDPHOTOALBUM) {
  104. return driver
  105. .waitForElementByXPath('//UIACollectionCell', MINUTE / 2)
  106. .click()
  107. .then(function () {
  108. if (!options.allowEdit) {
  109. return driver;
  110. }
  111. return usePicture();
  112. });
  113. }
  114. if (cancelCamera) {
  115. return driver
  116. .waitForElementByXPath('//*[@label="Cancel"]', MINUTE / 2)
  117. .elementByXPath('//*[@label="Cancel"]')
  118. .elementByXPath('//*[@label="Cancel"]')
  119. .click();
  120. }
  121. return driver
  122. .waitForElementByXPath('//*[@label="Take Picture"]', MINUTE / 2)
  123. .click()
  124. .waitForElementByXPath('//*[@label="Use Photo"]', MINUTE / 2)
  125. .click();
  126. })
  127. .fail(fail);
  128. }
  129. // checks if the picture was successfully taken
  130. // if shouldLoad is falsy, ensures that the error callback was called
  131. function checkPicture(shouldLoad, options) {
  132. if (!options) {
  133. options = {};
  134. }
  135. return driver
  136. .context(webviewContext)
  137. .setAsyncScriptTimeout(MINUTE / 2)
  138. .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId(), options])
  139. .then(function (result) {
  140. if (shouldLoad) {
  141. if (result !== 'OK') {
  142. fail(result);
  143. }
  144. } else if (result.indexOf('ERROR') === -1) {
  145. throw 'Unexpected success callback with result: ' + result;
  146. }
  147. });
  148. }
  149. // takes a picture with the specified options
  150. // and then verifies it
  151. function runSpec(options) {
  152. return driver
  153. .then(function () {
  154. return getPicture(options);
  155. })
  156. .then(function () {
  157. return checkPicture(true, options);
  158. })
  159. .fail(saveScreenshotAndFail);
  160. }
  161. function getDriver() {
  162. driver = wdHelper.getDriver('iOS');
  163. return wdHelper.getWebviewContext(driver)
  164. .then(function(context) {
  165. webviewContext = context;
  166. return driver.context(webviewContext);
  167. })
  168. .then(function () {
  169. return wdHelper.waitForDeviceReady(driver);
  170. })
  171. .then(function () {
  172. return wdHelper.injectLibraries(driver);
  173. });
  174. }
  175. function checkSession(done) {
  176. if (failedToStart) {
  177. fail('Failed to start a session');
  178. done();
  179. }
  180. }
  181. it('camera.ui.util configure driver and start a session', function (done) {
  182. getDriver()
  183. .then(function () {
  184. failedToStart = false;
  185. }, fail)
  186. .done(done);
  187. }, 10 * MINUTE);
  188. describe('Specs.', function () {
  189. // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY
  190. it('camera.ui.spec.1 Selecting only videos', function (done) {
  191. checkSession(done);
  192. var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
  193. mediaType: cameraConstants.MediaType.VIDEO };
  194. driver
  195. // skip ui unteractions
  196. .then(function () { return getPicture(options, false, true); })
  197. .waitForElementByXPath('//*[contains(@label,"Videos")]', MINUTE / 2)
  198. .elementByXPath('//*[@label="Cancel"]')
  199. .click()
  200. .fail(saveScreenshotAndFail)
  201. .done(done);
  202. }, 3 * MINUTE);
  203. // getPicture(), then dismiss
  204. // wait for the error callback to be called
  205. it('camera.ui.spec.2 Dismissing the camera', function (done) {
  206. checkSession(done);
  207. if (!isDevice) {
  208. pending('Camera is not available on iOS simulator');
  209. }
  210. var options = { sourceType: cameraConstants.PictureSourceType.CAMERA,
  211. saveToPhotoAlbum: false };
  212. driver
  213. .then(function () {
  214. return getPicture(options, true);
  215. })
  216. .then(function () {
  217. return checkPicture(false);
  218. })
  219. .fail(saveScreenshotAndFail)
  220. .done(done);
  221. }, 3 * MINUTE);
  222. it('camera.ui.spec.3 Verifying target image size, sourceType=CAMERA', function (done) {
  223. checkSession(done);
  224. if (!isDevice) {
  225. pending('Camera is not available on iOS simulator');
  226. }
  227. var options = {
  228. quality: 50,
  229. allowEdit: false,
  230. sourceType: cameraConstants.PictureSourceType.CAMERA,
  231. saveToPhotoAlbum: false,
  232. targetWidth: 210,
  233. targetHeight: 210
  234. };
  235. runSpec(options).done(done);
  236. }, 3 * MINUTE);
  237. it('camera.ui.spec.4 Verifying target image size, sourceType=SAVEDPHOTOALBUM', function (done) {
  238. checkSession(done);
  239. var options = {
  240. quality: 50,
  241. allowEdit: false,
  242. sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM,
  243. saveToPhotoAlbum: false,
  244. targetWidth: 210,
  245. targetHeight: 210
  246. };
  247. runSpec(options).done(done);
  248. }, 3 * MINUTE);
  249. it('camera.ui.spec.5 Verifying target image size, sourceType=PHOTOLIBRARY', function (done) {
  250. checkSession(done);
  251. var options = {
  252. quality: 50,
  253. allowEdit: false,
  254. sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
  255. saveToPhotoAlbum: false,
  256. targetWidth: 210,
  257. targetHeight: 210
  258. };
  259. runSpec(options).done(done);
  260. }, 3 * MINUTE);
  261. it('camera.ui.spec.6 Verifying target image size, sourceType=CAMERA, destinationType=FILE_URL', function (done) {
  262. // remove this line if you don't mind the tests leaving a photo saved on device
  263. pending('Cannot prevent iOS from saving the picture to photo library');
  264. checkSession(done);
  265. if (!isDevice) {
  266. pending('Camera is not available on iOS simulator');
  267. }
  268. var options = {
  269. quality: 50,
  270. allowEdit: false,
  271. sourceType: cameraConstants.PictureSourceType.CAMERA,
  272. destinationType: cameraConstants.DestinationType.FILE_URL,
  273. saveToPhotoAlbum: false,
  274. targetWidth: 210,
  275. targetHeight: 210
  276. };
  277. runSpec(options).done(done);
  278. }, 3 * MINUTE);
  279. it('camera.ui.spec.7 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=FILE_URL', function (done) {
  280. checkSession(done);
  281. var options = {
  282. quality: 50,
  283. allowEdit: false,
  284. sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM,
  285. destinationType: cameraConstants.DestinationType.FILE_URL,
  286. saveToPhotoAlbum: false,
  287. targetWidth: 210,
  288. targetHeight: 210
  289. };
  290. runSpec(options).done(done);
  291. }, 3 * MINUTE);
  292. it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=FILE_URL', function (done) {
  293. checkSession(done);
  294. var options = {
  295. quality: 50,
  296. allowEdit: false,
  297. sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
  298. destinationType: cameraConstants.DestinationType.FILE_URL,
  299. saveToPhotoAlbum: false,
  300. targetWidth: 210,
  301. targetHeight: 210
  302. };
  303. runSpec(options).done(done);
  304. }, 3 * MINUTE);
  305. it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, destinationType=FILE_URL, quality=100', function (done) {
  306. // remove this line if you don't mind the tests leaving a photo saved on device
  307. pending('Cannot prevent iOS from saving the picture to photo library');
  308. checkSession(done);
  309. if (!isDevice) {
  310. pending('Camera is not available on iOS simulator');
  311. }
  312. var options = {
  313. quality: 100,
  314. allowEdit: false,
  315. sourceType: cameraConstants.PictureSourceType.CAMERA,
  316. destinationType: cameraConstants.DestinationType.FILE_URL,
  317. saveToPhotoAlbum: false,
  318. targetWidth: 305,
  319. targetHeight: 305
  320. };
  321. runSpec(options).done(done);
  322. }, 3 * MINUTE);
  323. it('camera.ui.spec.10 Verifying target image size, sourceType=SAVEDPHOTOALBUM, destinationType=FILE_URL, quality=100', function (done) {
  324. checkSession(done);
  325. var options = {
  326. quality: 100,
  327. allowEdit: false,
  328. sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM,
  329. destinationType: cameraConstants.DestinationType.FILE_URL,
  330. saveToPhotoAlbum: false,
  331. targetWidth: 305,
  332. targetHeight: 305
  333. };
  334. runSpec(options).done(done);
  335. }, 3 * MINUTE);
  336. it('camera.ui.spec.11 Verifying target image size, sourceType=PHOTOLIBRARY, destinationType=FILE_URL, quality=100', function (done) {
  337. checkSession(done);
  338. var options = {
  339. quality: 100,
  340. allowEdit: false,
  341. sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
  342. destinationType: cameraConstants.DestinationType.FILE_URL,
  343. saveToPhotoAlbum: false,
  344. targetWidth: 305,
  345. targetHeight: 305
  346. };
  347. runSpec(options).done(done);
  348. }, 3 * MINUTE);
  349. // combine various options for getPicture()
  350. generateOptions().forEach(function (spec) {
  351. it('camera.ui.spec.12.' + spec.id + ' Combining options. ' + spec.description, function (done) {
  352. checkSession(done);
  353. if (!isDevice && spec.options.sourceType === cameraConstants.PictureSourceType.CAMERA) {
  354. pending('Camera is not available on iOS simulator');
  355. }
  356. // remove this check if you don't mind the tests leaving a photo saved on device
  357. if (spec.options.sourceType === cameraConstants.PictureSourceType.CAMERA &&
  358. spec.options.destinationType === cameraConstants.DestinationType.NATIVE_URI) {
  359. pending('Skipping: cannot prevent iOS from saving the picture to photo library and cannot delete it. ' +
  360. 'For more info, see iOS quirks here: https://github.com/apache/cordova-plugin-camera#ios-quirks-1');
  361. }
  362. runSpec(spec.options).done(done);
  363. }, 3 * MINUTE);
  364. });
  365. });
  366. it('camera.ui.util Destroy the session', function (done) {
  367. checkSession(done);
  368. driver
  369. .quit()
  370. .done(done);
  371. }, 5 * MINUTE);
  372. });