android.spec.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. /*
  2. *
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. *
  20. */
  21. // these tests are meant to be executed by Cordova ParaMedic Appium runner
  22. // you can find it here: https://github.com/apache/cordova-paramedic/
  23. // it is not necessary to do a full CI setup to run these tests
  24. // Run:
  25. // node cordova-paramedic/main.js --platform android --plugin cordova-plugin-camera --skipMainTests --target <emulator name>
  26. // Please note only Android 5.1 and 4.4 are supported at this point.
  27. 'use strict';
  28. var wdHelper = global.WD_HELPER;
  29. var screenshotHelper = global.SCREENSHOT_HELPER;
  30. var wd = wdHelper.getWD();
  31. var cameraConstants = require('../../www/CameraConstants');
  32. var cameraHelper = require('../helpers/cameraHelper');
  33. var MINUTE = 60 * 1000;
  34. var BACK_BUTTON = 4;
  35. var DEFAULT_SCREEN_WIDTH = 360;
  36. var DEFAULT_SCREEN_HEIGHT = 567;
  37. var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
  38. var PROMISE_PREFIX = 'appium_camera_promise_';
  39. var CONTEXT_NATIVE_APP = 'NATIVE_APP';
  40. describe('Camera tests Android.', function () {
  41. var driver;
  42. // the name of webview context, it will be changed to match needed context if there are named ones:
  43. var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
  44. // this indicates that the device library has the test picture:
  45. var isTestPictureSaved = false;
  46. // we need to know the screen width and height to properly click on an image in the gallery:
  47. var screenWidth = DEFAULT_SCREEN_WIDTH;
  48. var screenHeight = DEFAULT_SCREEN_HEIGHT;
  49. // promise count to use in promise ID
  50. var promiseCount = 0;
  51. // determine if Appium session is created successfully
  52. var appiumSessionStarted = false;
  53. // determine if camera is present on the device/emulator
  54. var cameraAvailable = false;
  55. // determine if emulator is within a range of acceptable resolutions able to run these tests
  56. var isResolutionBad = true;
  57. // a path to the image we add to the gallery before test run
  58. var fillerImagePath;
  59. var isAndroid7 = getIsAndroid7();
  60. function getIsAndroid7() {
  61. if (global.USE_SAUCE) {
  62. return global.SAUCE_CAPS && (parseFloat(global.SAUCE_CAPS.platformVersion) >= 7);
  63. } else {
  64. // this is most likely null, meaning we cannot determine if it is Android 7 or not
  65. // paramedic needs to be modified to receive and pass the platform version when testing locally
  66. return global.PLATFORM_VERSION && (parseFloat(global.PLATFORM_VERSION) >= 7);
  67. }
  68. }
  69. function getNextPromiseId() {
  70. promiseCount += 1;
  71. return getCurrentPromiseId();
  72. }
  73. function getCurrentPromiseId() {
  74. return PROMISE_PREFIX + promiseCount;
  75. }
  76. function gracefullyFail(error) {
  77. fail(error);
  78. return driver
  79. .quit()
  80. .then(function () {
  81. return getDriver();
  82. });
  83. }
  84. // combinines specified options in all possible variations
  85. // you can add more options to test more scenarios
  86. function generateOptions() {
  87. var sourceTypes = [
  88. cameraConstants.PictureSourceType.CAMERA,
  89. cameraConstants.PictureSourceType.PHOTOLIBRARY
  90. ];
  91. var destinationTypes = cameraConstants.DestinationType;
  92. var encodingTypes = cameraConstants.EncodingType;
  93. var allowEditOptions = [ true, false ];
  94. var correctOrientationOptions = [ true, false ];
  95. return cameraHelper.generateSpecs(sourceTypes, destinationTypes, encodingTypes, allowEditOptions, correctOrientationOptions);
  96. }
  97. // invokes Camera.getPicture() with the specified options
  98. // and goes through all UI interactions unless 'skipUiInteractions' is true
  99. function getPicture(options, skipUiInteractions) {
  100. var promiseId = getNextPromiseId();
  101. if (!options) {
  102. options = {};
  103. }
  104. // assign default values
  105. if (!options.hasOwnProperty('allowEdit')) {
  106. options.allowEdit = true;
  107. }
  108. if (!options.hasOwnProperty('destinationType')) {
  109. options.destinationType = cameraConstants.DestinationType.FILE_URI;
  110. }
  111. if (!options.hasOwnProperty('sourceType')) {
  112. options.destinationType = cameraConstants.PictureSourceType.CAMERA;
  113. }
  114. return driver
  115. .context(webviewContext)
  116. .execute(cameraHelper.getPicture, [options, promiseId])
  117. .context(CONTEXT_NATIVE_APP)
  118. .then(function () {
  119. if (skipUiInteractions) {
  120. return;
  121. }
  122. // selecting a picture from gallery
  123. if (options.hasOwnProperty('sourceType') &&
  124. (options.sourceType === cameraConstants.PictureSourceType.PHOTOLIBRARY ||
  125. options.sourceType === cameraConstants.PictureSourceType.SAVEDPHOTOALBUM)) {
  126. var tapTile = new wd.TouchAction();
  127. var swipeRight = new wd.TouchAction();
  128. tapTile
  129. .tap({
  130. x: Math.round(screenWidth / 4),
  131. y: Math.round(screenHeight / 4)
  132. });
  133. swipeRight
  134. .press({x: 10, y: Math.round(screenHeight / 4)})
  135. .wait(300)
  136. .moveTo({x: Math.round(screenWidth - (screenWidth / 8)), y: 0})
  137. .wait(1500)
  138. .release()
  139. .wait(1000);
  140. if (options.allowEdit) {
  141. return driver
  142. // always wait before performing touchAction
  143. .sleep(7000)
  144. .performTouchAction(tapTile);
  145. }
  146. return driver
  147. .waitForElementByAndroidUIAutomator('new UiSelector().text("Gallery");', 20000)
  148. .fail(function () {
  149. // If the Gallery button is not present, swipe right to reveal the Gallery button!
  150. return driver
  151. .performTouchAction(swipeRight)
  152. .waitForElementByAndroidUIAutomator('new UiSelector().text("Gallery");', 20000)
  153. })
  154. .click()
  155. // always wait before performing touchAction
  156. .sleep(7000)
  157. .performTouchAction(tapTile);
  158. }
  159. // taking a picture from camera
  160. return driver
  161. .waitForElementByAndroidUIAutomator('new UiSelector().resourceIdMatches(".*shutter.*")', MINUTE / 2)
  162. .click()
  163. .waitForElementByAndroidUIAutomator('new UiSelector().resourceIdMatches(".*done.*")', MINUTE / 2)
  164. .click()
  165. .then(function () {
  166. if (isAndroid7 && options.allowEdit) {
  167. return driver
  168. .elementByAndroidUIAutomator('new UiSelector().text("Crop picture");', 20000)
  169. .click()
  170. .fail(function () {
  171. // don't freak out just yet...
  172. return driver;
  173. })
  174. .elementByAndroidUIAutomator('new UiSelector().text("JUST ONCE");', 20000)
  175. .click()
  176. .fail(function () {
  177. // maybe someone's hit that "ALWAYS" button?
  178. return driver;
  179. });
  180. }
  181. return driver;
  182. });
  183. })
  184. .then(function () {
  185. if (skipUiInteractions) {
  186. return;
  187. }
  188. if (options.allowEdit) {
  189. var saveText = isAndroid7 ? 'SAVE' : 'Save';
  190. return driver
  191. .waitForElementByAndroidUIAutomator('new UiSelector().text("' + saveText + '")', MINUTE)
  192. .click();
  193. }
  194. })
  195. .fail(function (failure) {
  196. throw failure;
  197. });
  198. }
  199. // checks if the picture was successfully taken
  200. // if shouldLoad is falsy, ensures that the error callback was called
  201. function checkPicture(shouldLoad, options) {
  202. if (!options) {
  203. options = {};
  204. }
  205. return driver
  206. .context(webviewContext)
  207. .setAsyncScriptTimeout(MINUTE / 2)
  208. .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId(), options, isAndroid7])
  209. .then(function (result) {
  210. if (shouldLoad) {
  211. if (result !== 'OK') {
  212. fail(result);
  213. }
  214. } else if (result.indexOf('ERROR') === -1) {
  215. throw 'Unexpected success callback with result: ' + result;
  216. }
  217. });
  218. }
  219. // deletes the latest image from the gallery
  220. function deleteImage() {
  221. var holdTile = new wd.TouchAction();
  222. holdTile
  223. .press({x: Math.round(screenWidth / 4), y: Math.round(screenHeight / 5)})
  224. .wait(1000)
  225. .release();
  226. return driver
  227. // always wait before performing touchAction
  228. .sleep(7000)
  229. .performTouchAction(holdTile)
  230. .elementByAndroidUIAutomator('new UiSelector().text("Delete")')
  231. .then(function (element) {
  232. return element
  233. .click()
  234. .elementByAndroidUIAutomator('new UiSelector().text("OK")')
  235. .click();
  236. }, function () {
  237. // couldn't find Delete menu item. Possibly there is no image.
  238. return driver;
  239. });
  240. }
  241. function getDriver() {
  242. driver = wdHelper.getDriver('Android');
  243. return driver.getWebviewContext()
  244. .then(function(context) {
  245. webviewContext = context;
  246. return driver.context(webviewContext);
  247. })
  248. .waitForDeviceReady()
  249. .injectLibraries()
  250. .then(function () {
  251. var options = {
  252. quality: 50,
  253. allowEdit: false,
  254. sourceType: cameraConstants.PictureSourceType.SAVEDPHOTOALBUM,
  255. saveToPhotoAlbum: false,
  256. targetWidth: 210,
  257. targetHeight: 210
  258. };
  259. return driver
  260. .then(function () { return getPicture(options, true); })
  261. .context(CONTEXT_NATIVE_APP)
  262. // case insensitive select, will be handy with Android 7 support
  263. .elementByXPath('//android.widget.Button[translate(@text, "alow", "ALOW")="ALLOW"]')
  264. .click()
  265. .fail(function noAlert() { })
  266. .deviceKeyEvent(BACK_BUTTON)
  267. .sleep(2000)
  268. .elementById('action_bar_title')
  269. .then(function () {
  270. // success means we're still in native app
  271. return driver
  272. .deviceKeyEvent(BACK_BUTTON);
  273. }, function () {
  274. // error means we're already in webview
  275. return driver;
  276. });
  277. })
  278. .then(function () {
  279. // doing it inside a function because otherwise
  280. // it would not hook up to the webviewContext var change
  281. // in the first methods of this chain
  282. return driver.context(webviewContext);
  283. })
  284. .deleteFillerImage(fillerImagePath)
  285. .then(function () {
  286. fillerImagePath = null;
  287. })
  288. .addFillerImage()
  289. .then(function (result) {
  290. if (result && result.indexOf('ERROR:') === 0) {
  291. throw new Error(result);
  292. } else {
  293. fillerImagePath = result;
  294. }
  295. });
  296. }
  297. function recreateSession() {
  298. return driver
  299. .quit()
  300. .finally(function () {
  301. return getDriver();
  302. });
  303. }
  304. function tryRunSpec(spec) {
  305. return driver
  306. .then(spec)
  307. .fail(function () {
  308. return recreateSession()
  309. .then(spec)
  310. .fail(function() {
  311. return recreateSession()
  312. .then(spec);
  313. });
  314. })
  315. .fail(gracefullyFail);
  316. }
  317. // produces a generic spec function which
  318. // takes a picture with specified options
  319. // and then verifies it
  320. function generateSpec(options) {
  321. return function () {
  322. return driver
  323. .then(function () {
  324. return getPicture(options);
  325. })
  326. .then(function () {
  327. return checkPicture(true, options);
  328. });
  329. };
  330. }
  331. function checkSession(done, skipResolutionCheck) {
  332. if (!appiumSessionStarted) {
  333. fail('Failed to start a session ' + (lastFailureReason ? lastFailureReason : ''));
  334. done();
  335. }
  336. if (!skipResolutionCheck && isResolutionBad) {
  337. fail('The resolution of this target device is not within the appropriate range of width: blah-blah and height: bleh-bleh. The target\'s current resolution is: ' + isResolutionBad);
  338. }
  339. }
  340. function checkCamera(options, pending) {
  341. if (!cameraAvailable) {
  342. pending('Skipping because this test requires a functioning camera on the Android device/emulator, and this test suite\'s functional camera test failed on your target environment.');
  343. } else if (isAndroid7 && options.allowEdit) {
  344. // TODO: Check if it is fixed some day
  345. pending('Skipping because can\'t test with allowEdit=true on Android 7: getting unexpected "Camera cancelled" message.');
  346. } else if (isAndroid7 && (options.sourceType !== cameraConstants.PictureSourceType.CAMERA)) {
  347. pending('Skipping because can\'t click on the gallery tile on Android 7.');
  348. }
  349. }
  350. afterAll(function (done) {
  351. checkSession(done);
  352. driver
  353. .quit()
  354. .done(done);
  355. }, MINUTE);
  356. it('camera.ui.util configuring driver and starting a session', function (done) {
  357. // retry up to 3 times
  358. getDriver()
  359. .fail(function () {
  360. return getDriver()
  361. .fail(function () {
  362. return getDriver()
  363. .fail(fail);
  364. });
  365. })
  366. .then(function () {
  367. appiumSessionStarted = true;
  368. })
  369. .done(done);
  370. }, 30 * MINUTE);
  371. it('camera.ui.util determine screen dimensions', function (done) {
  372. checkSession(done, /*skipResolutionCheck?*/ true); // skip the resolution check here since we are about to find out in this spec!
  373. driver
  374. .context(CONTEXT_NATIVE_APP)
  375. .getWindowSize()
  376. .then(function (size) {
  377. screenWidth = Number(size.width);
  378. screenHeight = Number(size.height);
  379. isResolutionBad = false;
  380. /*
  381. TODO: what are acceptable resolution values?
  382. need to check what the emulators used in CI return.
  383. and also what local device definitions work and dont
  384. */
  385. })
  386. .done(done);
  387. }, MINUTE);
  388. it('camera.ui.util determine camera availability', function (done) {
  389. checkSession(done);
  390. var opts = {
  391. sourceType: cameraConstants.PictureSourceType.CAMERA,
  392. saveToPhotoAlbum: false
  393. };
  394. return driver
  395. .then(function () {
  396. return getPicture(opts);
  397. })
  398. .then(function () {
  399. cameraAvailable = true;
  400. }, function () {
  401. return recreateSession();
  402. })
  403. .done(done);
  404. }, 5 * MINUTE);
  405. describe('Specs.', function () {
  406. // getPicture() with saveToPhotoLibrary = true
  407. it('camera.ui.spec.1 Saving a picture to the photo library', function (done) {
  408. var opts = {
  409. quality: 50,
  410. allowEdit: false,
  411. sourceType: cameraConstants.PictureSourceType.CAMERA,
  412. saveToPhotoAlbum: true
  413. };
  414. checkSession(done);
  415. checkCamera(opts, pending);
  416. var spec = generateSpec(opts);
  417. tryRunSpec(spec)
  418. .then(function () {
  419. isTestPictureSaved = true;
  420. })
  421. .done(done);
  422. }, 10 * MINUTE);
  423. // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY
  424. it('camera.ui.spec.2 Selecting only videos', function (done) {
  425. checkSession(done);
  426. var spec = function () {
  427. var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
  428. mediaType: cameraConstants.MediaType.VIDEO };
  429. return driver
  430. .then(function () {
  431. return getPicture(options, true);
  432. })
  433. .context(CONTEXT_NATIVE_APP)
  434. .then(function () {
  435. // try to find "Gallery" menu item
  436. // if there's none, the gallery should be already opened
  437. return driver
  438. .waitForElementByAndroidUIAutomator('new UiSelector().text("Gallery")', 20000)
  439. .then(function (element) {
  440. return element.click();
  441. }, function () {
  442. return driver;
  443. });
  444. })
  445. .then(function () {
  446. // if the gallery is opened on the videos page,
  447. // there should be a "Choose video" or "Select video" caption
  448. var videoSelector = isAndroid7 ? 'new UiSelector().text("Select video")' : 'new UiSelector().text("Choose video")';
  449. return driver
  450. .elementByAndroidUIAutomator(videoSelector)
  451. .fail(function () {
  452. throw 'Couldn\'t find a "Choose/select video" element.';
  453. });
  454. })
  455. .deviceKeyEvent(BACK_BUTTON)
  456. .elementByAndroidUIAutomator('new UiSelector().text("Gallery")')
  457. .deviceKeyEvent(BACK_BUTTON)
  458. .finally(function () {
  459. return driver
  460. .elementById('action_bar_title')
  461. .then(function () {
  462. // success means we're still in native app
  463. return driver
  464. .deviceKeyEvent(BACK_BUTTON)
  465. // give native app some time to close
  466. .sleep(2000)
  467. // try again! because every ~30th build
  468. // on Sauce Labs this backbutton doesn't work
  469. .elementById('action_bar_title')
  470. .then(function () {
  471. // success means we're still in native app
  472. return driver
  473. .deviceKeyEvent(BACK_BUTTON);
  474. }, function () {
  475. // error means we're already in webview
  476. return driver;
  477. });
  478. }, function () {
  479. // error means we're already in webview
  480. return driver;
  481. });
  482. });
  483. };
  484. tryRunSpec(spec).done(done);
  485. }, 10 * MINUTE);
  486. // getPicture(), then dismiss
  487. // wait for the error callback to be called
  488. it('camera.ui.spec.3 Dismissing the camera', function (done) {
  489. var options = {
  490. quality: 50,
  491. allowEdit: true,
  492. sourceType: cameraConstants.PictureSourceType.CAMERA,
  493. destinationType: cameraConstants.DestinationType.FILE_URI
  494. };
  495. checkSession(done);
  496. checkCamera(options, pending);
  497. var spec = function () {
  498. return driver
  499. .then(function () {
  500. return getPicture(options, true);
  501. })
  502. .context(CONTEXT_NATIVE_APP)
  503. .waitForElementByAndroidUIAutomator('new UiSelector().resourceIdMatches(".*cancel.*")', MINUTE / 2)
  504. .click()
  505. .then(function () {
  506. return checkPicture(false);
  507. });
  508. };
  509. tryRunSpec(spec).done(done);
  510. }, 10 * MINUTE);
  511. // getPicture(), then take picture but dismiss the edit
  512. // wait for the error callback to be called
  513. it('camera.ui.spec.4 Dismissing the edit', function (done) {
  514. var options = {
  515. quality: 50,
  516. allowEdit: true,
  517. sourceType: cameraConstants.PictureSourceType.CAMERA,
  518. destinationType: cameraConstants.DestinationType.FILE_URI
  519. };
  520. checkSession(done);
  521. checkCamera(options, pending);
  522. var spec = function () {
  523. return driver
  524. .then(function () {
  525. return getPicture(options, true);
  526. })
  527. .waitForElementByAndroidUIAutomator('new UiSelector().resourceIdMatches(".*shutter.*")', MINUTE / 2)
  528. .click()
  529. .waitForElementByAndroidUIAutomator('new UiSelector().resourceIdMatches(".*done.*")', MINUTE / 2)
  530. .click()
  531. .then(function () {
  532. if (isAndroid7 && options.allowEdit) {
  533. return driver
  534. .waitForElementByAndroidUIAutomator('new UiSelector().text("Crop picture");', 20000)
  535. .click()
  536. .waitForElementByAndroidUIAutomator('new UiSelector().text("JUST ONCE");', 20000)
  537. .click()
  538. .deviceKeyEvent(BACK_BUTTON);
  539. }
  540. return driver
  541. .waitForElementByAndroidUIAutomator('new UiSelector().resourceIdMatches(".*discard.*")', MINUTE / 2)
  542. .click();
  543. })
  544. .then(function () {
  545. return checkPicture(false);
  546. });
  547. };
  548. tryRunSpec(spec).done(done);
  549. }, 10 * MINUTE);
  550. it('camera.ui.spec.5 Verifying target image size, sourceType=CAMERA', function (done) {
  551. var opts = {
  552. quality: 50,
  553. allowEdit: false,
  554. sourceType: cameraConstants.PictureSourceType.CAMERA,
  555. saveToPhotoAlbum: false,
  556. targetWidth: 210,
  557. targetHeight: 210
  558. };
  559. checkSession(done);
  560. checkCamera(opts, pending);
  561. var spec = generateSpec(opts);
  562. tryRunSpec(spec).done(done);
  563. }, 10 * MINUTE);
  564. it('camera.ui.spec.6 Verifying target image size, sourceType=PHOTOLIBRARY', function (done) {
  565. var opts = {
  566. quality: 50,
  567. allowEdit: false,
  568. sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
  569. saveToPhotoAlbum: false,
  570. targetWidth: 210,
  571. targetHeight: 210
  572. };
  573. checkSession(done);
  574. checkCamera(opts, pending);
  575. var spec = generateSpec(opts);
  576. tryRunSpec(spec).done(done);
  577. }, 10 * MINUTE);
  578. it('camera.ui.spec.7 Verifying target image size, sourceType=CAMERA, DestinationType=NATIVE_URI', function (done) {
  579. var opts = {
  580. quality: 50,
  581. allowEdit: true,
  582. sourceType: cameraConstants.PictureSourceType.CAMERA,
  583. destinationType: cameraConstants.DestinationType.NATIVE_URI,
  584. saveToPhotoAlbum: false,
  585. targetWidth: 210,
  586. targetHeight: 210
  587. };
  588. checkSession(done);
  589. checkCamera(opts, pending);
  590. var spec = generateSpec(opts);
  591. tryRunSpec(spec).done(done);
  592. }, 10 * MINUTE);
  593. it('camera.ui.spec.8 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI', function (done) {
  594. var opts = {
  595. quality: 50,
  596. allowEdit: false,
  597. sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
  598. destinationType: cameraConstants.DestinationType.NATIVE_URI,
  599. saveToPhotoAlbum: false,
  600. targetWidth: 210,
  601. targetHeight: 210
  602. };
  603. checkSession(done);
  604. checkCamera(opts, pending);
  605. var spec = generateSpec(opts);
  606. tryRunSpec(spec).done(done);
  607. }, 10 * MINUTE);
  608. it('camera.ui.spec.9 Verifying target image size, sourceType=CAMERA, DestinationType=NATIVE_URI, quality=100', function (done) {
  609. var opts = {
  610. quality: 50,
  611. allowEdit: true,
  612. sourceType: cameraConstants.PictureSourceType.CAMERA,
  613. destinationType: cameraConstants.DestinationType.NATIVE_URI,
  614. saveToPhotoAlbum: false,
  615. targetWidth: 305,
  616. targetHeight: 305
  617. };
  618. checkSession(done);
  619. checkCamera(opts, pending);
  620. var spec = generateSpec(opts);
  621. tryRunSpec(spec).done(done);
  622. }, 10 * MINUTE);
  623. it('camera.ui.spec.10 Verifying target image size, sourceType=PHOTOLIBRARY, DestinationType=NATIVE_URI, quality=100', function (done) {
  624. var opts = {
  625. quality: 100,
  626. allowEdit: true,
  627. sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY,
  628. destinationType: cameraConstants.DestinationType.NATIVE_URI,
  629. saveToPhotoAlbum: false,
  630. targetWidth: 305,
  631. targetHeight: 305
  632. };
  633. checkSession(done);
  634. checkCamera(opts, pending);
  635. var spec = generateSpec(opts);
  636. tryRunSpec(spec).done(done);
  637. }, 10 * MINUTE);
  638. // combine various options for getPicture()
  639. generateOptions().forEach(function (spec) {
  640. it('camera.ui.spec.11.' + spec.id + ' Combining options. ' + spec.description, function (done) {
  641. checkSession(done);
  642. checkCamera(spec.options, pending);
  643. var s = generateSpec(spec.options);
  644. tryRunSpec(s).done(done);
  645. }, 10 * MINUTE);
  646. });
  647. it('camera.ui.util Delete filler picture from device library', function (done) {
  648. if (isAndroid7 || global.USE_SAUCE) {
  649. pending();
  650. }
  651. driver
  652. .context(webviewContext)
  653. .deleteFillerImage(fillerImagePath)
  654. .done(done);
  655. }, MINUTE);
  656. it('camera.ui.util Delete taken picture from device library', function (done) {
  657. if (isAndroid7 || global.USE_SAUCE) {
  658. pending();
  659. }
  660. checkSession(done);
  661. if (!isTestPictureSaved) {
  662. // couldn't save test picture earlier, so nothing to delete here
  663. done();
  664. return;
  665. }
  666. // delete exactly one latest picture
  667. // this should be the picture we've taken in the first spec
  668. driver
  669. .context(CONTEXT_NATIVE_APP)
  670. .deviceKeyEvent(BACK_BUTTON)
  671. .sleep(1000)
  672. .deviceKeyEvent(BACK_BUTTON)
  673. .sleep(1000)
  674. .deviceKeyEvent(BACK_BUTTON)
  675. .elementById('Apps')
  676. .click()
  677. .then(function () {
  678. return driver
  679. .elementByXPath('//android.widget.Button[@text="OK"]')
  680. .click()
  681. .fail(function () {
  682. // no cling is all right
  683. // it is not a brand new emulator, then
  684. });
  685. })
  686. .elementByAndroidUIAutomator('new UiSelector().text("Gallery")')
  687. .click()
  688. .elementByAndroidUIAutomator('new UiSelector().textContains("Pictures")')
  689. .click()
  690. .then(deleteImage)
  691. .deviceKeyEvent(BACK_BUTTON)
  692. .sleep(1000)
  693. .deviceKeyEvent(BACK_BUTTON)
  694. .sleep(1000)
  695. .deviceKeyEvent(BACK_BUTTON)
  696. .fail(fail)
  697. .finally(done);
  698. }, 3 * MINUTE);
  699. });
  700. });