ionic.snapshot.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. var q = require('q');
  2. var IonicSnapshot = function(options) {
  3. // modules
  4. var _ = require('lodash');
  5. var request = require('request');
  6. var colors = require('gulp-util').colors;
  7. var log = console.log.bind(console);
  8. var IonicReporter = function(options) {
  9. var self = this;
  10. // set options and defaults
  11. self.domain = options.domain || 'ionic-snapshot-go.appspot.com';
  12. self.groupId = options.groupId || 'test_group';
  13. self.appId = options.appId || 'test_app';
  14. self.build = (browser.params.dev === 'true') ? 'Development' : 'Production';
  15. self.sleepBetweenSpecs = self.build === 'Development' ? 3000 : (options.sleepBetweenSpecs || 500);
  16. self.testId = browser.params.test_id || 'test_id';
  17. self.shouldUpload = browser.params.upload !== 'false';
  18. self.platformId = browser.params.platform_id;
  19. self.platformIndex = browser.params.platform_index;
  20. self.platformCount = browser.params.platform_count;
  21. self.width = browser.params.width || -1;
  22. self.height = browser.params.height || -1;
  23. self.screenshotRequestPromises = [];
  24. self.results = {};
  25. self.mismatches = [];
  26. self.highestMismatch = 0;
  27. self.flow = protractor.promise.controlFlow();
  28. if(self.width > 0 && self.height > 0) {
  29. self.flow.execute(function(){
  30. return browser.driver.manage().window().setSize(self.width, self.height);
  31. });
  32. }
  33. self.flow.execute(function(){
  34. return browser.getCapabilities().then(function (capabilities) {
  35. self.testData = {
  36. group_id: self.groupId,
  37. app_id: self.appId,
  38. test_id: self.testId,
  39. platform_id: self.platformId,
  40. platform_index: self.platformIndex,
  41. platform_count: self.platformCount,
  42. width: self.width,
  43. height: self.height,
  44. browser: capabilities.get('browserName'),
  45. platform: capabilities.get('platform'),
  46. version: capabilities.get('version'),
  47. access_key: options.accessKey
  48. };
  49. });
  50. });
  51. process.on('exit', function(code) {
  52. if (!self.shouldUpload || code === 1) return;
  53. if (self.highestMismatch > 1) {
  54. log(colors.red('Highest Mismatch: ' + self.highestMismatch + '%'));
  55. } else if (self.highestMismatch > 0) {
  56. log(colors.yellow('Highest Mismatch: ' + self.highestMismatch + '%'));
  57. } else {
  58. log(colors.green('No Mismatches!!'));
  59. }
  60. if (!self.mismatches.length) return;
  61. self.mismatches.sort();
  62. for (var x = 0; x < self.mismatches.length; x++) {
  63. var result = self.results[self.mismatches[x]];
  64. if (result.mismatch > 1) {
  65. log(colors.red('Mismatch:'), colors.red(result.mismatch + '%'), result.name);
  66. } else {
  67. log(colors.yellow('Mismatch:'), colors.yellow(result.mismatch + '%'), result.name);
  68. }
  69. log(' ', colors.gray(result.compareUrl));
  70. }
  71. });
  72. log(colors.green('Start ' + self.build + ' Snapshot - ' + self.sleepBetweenSpecs + ' between Specs:'),
  73. self.groupId, self.appId, self.platformId, self.testId, '(' + self.width + 'x' + self.height + ')');
  74. };
  75. IonicReporter.prototype.reportSpecResults = function(spec) {
  76. var self = this;
  77. if(!self.testData.total_specs) {
  78. self.testData.total_specs = 0;
  79. var allSpecs = jasmine.getEnv().currentRunner().specs();
  80. for(var sId in allSpecs) {
  81. self.testData.total_specs++;
  82. }
  83. }
  84. self.flow.execute(function(){
  85. var d = protractor.promise.defer();
  86. browser.getCurrentUrl().then(function(currentUrl) {
  87. browser.sleep(self.sleepBetweenSpecs).then(function(){
  88. if (!self.shouldUpload) {
  89. return d.fulfill();
  90. }
  91. browser.takeScreenshot().then(function(pngBase64) {
  92. var specIdString = '[' + (spec.id+1) + '/' + self.testData.total_specs + ']';
  93. self.testData.spec_index = spec.id;
  94. // console.log('spec.id: ', spec.id);
  95. self.testData.highest_mismatch = self.highestMismatch;
  96. self.testData.png_base64 = pngBase64;
  97. self.testData.description = spec.getFullName().replace('components/', '').replace('test/', '').replace('www', '');
  98. self.testData.url = currentUrl.replace('dist', '').replace('components/', '').replace('test/', '').replace('&ionicanimate=false', '').replace('www/', '');
  99. //console.log('self.testData.description: ', self.testData.description);
  100. //console.log('self.testData.url: ', self.testData.url);
  101. pngBase64 = null;
  102. var requestDeferred = q.defer();
  103. self.screenshotRequestPromises.push(requestDeferred.promise);
  104. request.post(
  105. 'http://' + self.domain + '/screenshot',
  106. { form: self.testData },
  107. function (error, response, body) {
  108. try {
  109. if (error) {
  110. log(specIdString, colors.red('error posting screenshot:'), error);
  111. } else if (response.statusCode >= 400) {
  112. log(specIdString, colors.red('error posting screenshot:'), response.statusCode, body);
  113. } else {
  114. var rspData = JSON.parse(body);
  115. self.highestMismatch = Math.max(self.highestMismatch, rspData.Mismatch);
  116. var mismatch = Math.round(rspData.Mismatch * 100) / 100;
  117. if (rspData.Mismatch > 1) {
  118. log(specIdString, colors.red('Mismatch: ' + mismatch + '%'), colors.gray(spec.getFullName()));
  119. } else if (rspData.Mismatch > 0) {
  120. log(specIdString, colors.yellow('Mismatch: ' + mismatch + '%'), colors.gray(spec.getFullName()));
  121. } else {
  122. log(specIdString, colors.green('Mismatch: ' + mismatch + '%'), colors.gray(spec.getFullName()));
  123. }
  124. var resultKey = (((rspData.Mismatch * 1000) + 1000000) + '').split('.')[0] + '-' + spec.id;
  125. self.results[resultKey] = {
  126. index: spec.id,
  127. name: spec.getFullName(),
  128. mismatch: mismatch,
  129. compareUrl: rspData.CompareUrl,
  130. screenshotUrl: rspData.ScreenshotUrl,
  131. };
  132. if (rspData.IsMismatch) {
  133. self.mismatches.push(resultKey);
  134. }
  135. }
  136. } catch(e) {
  137. log(specIdString, colors.red('error parsing screenshot response:'), e);
  138. process.exit(1);
  139. }
  140. requestDeferred.resolve();
  141. }
  142. );
  143. d.fulfill();
  144. });
  145. });
  146. });
  147. return d.promise;
  148. });
  149. };
  150. IonicReporter.prototype.reportRunnerResults = function() {
  151. var self = this;
  152. if (!self.shouldUpload) return;
  153. self.flow.execute(function() {
  154. var d = protractor.promise.defer();
  155. log('Waiting for all screenshots to be posted...');
  156. // allSettled waits until all the promises are done, whether they are rejected or resolved
  157. q.allSettled(self.screenshotRequestPromises).then(function(all) {
  158. d.fulfill();
  159. log('Finished!');
  160. });
  161. });
  162. };
  163. this.jasmine.getEnv().addReporter( new IonicReporter(options) );
  164. };
  165. module.exports = IonicSnapshot;