run.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * Copyright © 2016-2019 Threema GmbH (https://threema.ch/).
  3. *
  4. * This file is part of Threema Web.
  5. */
  6. // tslint:disable:no-reference
  7. // tslint:disable:no-console
  8. // tslint:disable:no-unused-expression
  9. /// <reference path="../../src/threema.d.ts" />
  10. import { expect } from 'chai';
  11. import { Builder, By, Key, until, WebDriver, WebElement } from 'selenium-webdriver';
  12. import * as TermColor from 'term-color';
  13. import { extractText as extractTextFunc } from '../../src/helpers';
  14. // Script arguments
  15. const browser = process.argv[2];
  16. const filterQuery = process.argv[3];
  17. // Type aliases
  18. type Testfunc = (driver: WebDriver) => void;
  19. // Shared selectors
  20. const composeArea = By.css('div.compose');
  21. const emojiKeyboard = By.css('.emoji-keyboard');
  22. const emojiTrigger = By.css('.emoji-trigger');
  23. /**
  24. * Helper function to extract text.
  25. */
  26. async function extractText(driver: WebDriver): Promise<string> {
  27. const script = `
  28. ${extractTextFunc.toString()}
  29. const element = document.querySelector("div.compose");
  30. return extractText(element);
  31. `;
  32. return driver.executeScript<string>(script);
  33. }
  34. /**
  35. * The emoji trigger should toggle the emoji keyboard.
  36. */
  37. async function showEmojiSelector(driver: WebDriver) {
  38. // Initially not visible
  39. expect(
  40. await driver.findElement(emojiKeyboard).isDisplayed()
  41. ).to.be.false;
  42. // Show
  43. await driver.findElement(emojiTrigger).click();
  44. expect(
  45. await driver.findElement(emojiKeyboard).isDisplayed()
  46. ).to.be.true;
  47. // Hide
  48. await driver.findElement(emojiTrigger).click();
  49. expect(
  50. await driver.findElement(emojiKeyboard).isDisplayed()
  51. ).to.be.false;
  52. }
  53. /**
  54. * Insert two emoji and some text.
  55. */
  56. async function insertEmoji(driver: WebDriver) {
  57. // Show emoji keyboard
  58. await driver.findElement(emojiTrigger).click();
  59. // Insert woman zombie emoji
  60. await driver.findElement(By.css('.e1._1f9df-2640')).click();
  61. // Insert text
  62. await driver.findElement(composeArea).sendKeys('hi');
  63. // Insert beer
  64. await driver.findElement(By.className('e1-food')).click();
  65. await driver.findElement(By.css('.e1._1f37b')).click();
  66. // Validate emoji
  67. const emoji = await driver.findElement(composeArea).findElements(By.xpath('*'));
  68. expect(emoji.length).to.equal(2);
  69. expect(await emoji[0].getAttribute('title')).to.equal(':woman_zombie:');
  70. expect(await emoji[1].getAttribute('title')).to.equal(':beers:');
  71. // Validate text
  72. const html = await driver.findElement(composeArea).getAttribute('innerHTML');
  73. expect(/>hi<img/.test(html)).to.be.true;
  74. }
  75. /**
  76. * Insert a newline using shift-enter.
  77. */
  78. async function insertNewline(driver: WebDriver) {
  79. // Insert text
  80. await driver.findElement(composeArea).click();
  81. await driver.findElement(composeArea).sendKeys('hello');
  82. await driver.findElement(composeArea).sendKeys(Key.SHIFT, Key.ENTER);
  83. await driver.findElement(composeArea).sendKeys('threema');
  84. await driver.findElement(composeArea).sendKeys(Key.SHIFT, Key.ENTER);
  85. await driver.findElement(composeArea).sendKeys('web');
  86. const text = await extractText(driver);
  87. expect(text).to.equal('hello\nthreema\nweb');
  88. }
  89. /**
  90. * Insert an emoji after some newlines.
  91. * Regression test for #574.
  92. */
  93. async function regression574(driver: WebDriver) {
  94. // Insert text
  95. await driver.findElement(composeArea).click();
  96. await driver.findElement(composeArea).sendKeys('hello');
  97. await driver.findElement(composeArea).sendKeys(Key.SHIFT, Key.ENTER);
  98. await driver.findElement(composeArea).sendKeys('threema');
  99. await driver.findElement(composeArea).sendKeys(Key.SHIFT, Key.ENTER);
  100. await driver.findElement(composeArea).sendKeys('web');
  101. await driver.findElement(composeArea).sendKeys(Key.SHIFT, Key.ENTER);
  102. // Insert emoji
  103. await driver.findElement(emojiTrigger).click();
  104. await driver.findElement(By.css('.e1[title=":smile:"]')).click();
  105. const text = await extractText(driver);
  106. expect(text).to.equal('hello\nthreema\nweb\n😄');
  107. }
  108. /**
  109. * Insert two emoji in the middle of existing text.
  110. * Regression test for #671.
  111. */
  112. async function regression671(driver: WebDriver) {
  113. // Insert text
  114. await driver.findElement(composeArea).click();
  115. await driver.findElement(composeArea).sendKeys('helloworld');
  116. await driver.findElement(composeArea).sendKeys(Key.LEFT, Key.LEFT, Key.LEFT, Key.LEFT, Key.LEFT);
  117. // Insert emoji
  118. await driver.findElement(emojiTrigger).click();
  119. const emoji = await driver.findElement(By.css('.e1[title=":smile:"]'));
  120. await emoji.click();
  121. await emoji.click();
  122. const text = await extractText(driver);
  123. expect(text).to.equal('hello😄😄world');
  124. }
  125. /**
  126. * Insert two emoji between two lines of text.
  127. * Regression test for #672.
  128. */
  129. async function regression672(driver: WebDriver) {
  130. // Insert text
  131. await driver.findElement(composeArea).click();
  132. await driver.findElement(composeArea).sendKeys('hello');
  133. await driver.findElement(composeArea).sendKeys(Key.SHIFT, Key.ENTER);
  134. await driver.findElement(composeArea).sendKeys(Key.SHIFT, Key.ENTER);
  135. await driver.findElement(composeArea).sendKeys('world');
  136. await driver.findElement(composeArea).sendKeys(Key.UP);
  137. // Insert two emoji
  138. await driver.findElement(emojiTrigger).click();
  139. const emoji = await driver.findElement(By.css('.e1[title=":tired_face:"]'));
  140. await emoji.click();
  141. await emoji.click();
  142. const text = await extractText(driver);
  143. expect(text).to.equal('hello\n😫😫\nworld');
  144. }
  145. // Register tests here
  146. const TESTS: Array<[string, Testfunc]> = [
  147. ['Show and hide emoji selector', showEmojiSelector],
  148. ['Insert emoji and text', insertEmoji],
  149. ['Insert three lines of text', insertNewline],
  150. ['Regression test #574', regression574],
  151. ['Regression test #671', regression671],
  152. ['Regression test #672', regression672],
  153. ];
  154. // Test runner
  155. const TEST_URL = 'http://localhost:7777/tests/ui/compose_area.html';
  156. (async function() {
  157. const driver: WebDriver = await new Builder().forBrowser(browser).build();
  158. let i = 0;
  159. let success = 0;
  160. let failed = 0;
  161. let skipped = 0;
  162. console.info('\n====== THREEMA WEB UI TESTS ======\n');
  163. if (filterQuery !== undefined) {
  164. console.info(`Filter query: "${filterQuery}"\n`);
  165. }
  166. try {
  167. for (const [name, testfunc] of TESTS) {
  168. try {
  169. if (filterQuery === undefined || name.toLowerCase().indexOf(filterQuery.toLowerCase()) !== -1) {
  170. i++;
  171. console.info(TermColor.blue(`» ${i}: Running test: ${name}`));
  172. await driver.get(TEST_URL);
  173. await testfunc(driver);
  174. success++;
  175. } else {
  176. skipped++;
  177. }
  178. } catch (e) {
  179. console.error(TermColor.red(`\nTest failed:`));
  180. console.error(e);
  181. failed++;
  182. }
  183. }
  184. } finally {
  185. await driver.quit();
  186. }
  187. const colorFunc = failed > 0 ? TermColor.red : TermColor.green;
  188. console.info(colorFunc(`\nSummary: ${i} tests run, ${success} succeeded, ${failed} failed, ${skipped} skipped`));
  189. process.exit(failed > 0 ? 1 : 0);
  190. })();