testhelper.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Class that allows for simple text editing tests.
  16. *
  17. * @author robbyw@google.com (Robby Walker)
  18. */
  19. goog.setTestOnly('goog.testing.editor.TestHelper');
  20. goog.provide('goog.testing.editor.TestHelper');
  21. goog.require('goog.Disposable');
  22. goog.require('goog.dom');
  23. goog.require('goog.dom.Range');
  24. goog.require('goog.editor.BrowserFeature');
  25. goog.require('goog.editor.node');
  26. goog.require('goog.editor.plugins.AbstractBubblePlugin');
  27. goog.require('goog.testing.dom');
  28. /**
  29. * Create a new test controller.
  30. * @param {Element} root The root editable element.
  31. * @constructor
  32. * @extends {goog.Disposable}
  33. * @final
  34. */
  35. goog.testing.editor.TestHelper = function(root) {
  36. if (!root) {
  37. throw Error('Null root');
  38. }
  39. goog.Disposable.call(this);
  40. /**
  41. * Convenience variable for root DOM element.
  42. * @type {!Element}
  43. * @private
  44. */
  45. this.root_ = root;
  46. /**
  47. * The starting HTML of the editable element.
  48. * @type {string}
  49. * @private
  50. */
  51. this.savedHtml_ = '';
  52. };
  53. goog.inherits(goog.testing.editor.TestHelper, goog.Disposable);
  54. /**
  55. * Selects a new root element.
  56. * @param {Element} root The root editable element.
  57. */
  58. goog.testing.editor.TestHelper.prototype.setRoot = function(root) {
  59. if (!root) {
  60. throw Error('Null root');
  61. }
  62. this.root_ = root;
  63. };
  64. /**
  65. * Make the root element editable. Also saves its HTML to be restored
  66. * in tearDown.
  67. */
  68. goog.testing.editor.TestHelper.prototype.setUpEditableElement = function() {
  69. this.savedHtml_ = this.root_.innerHTML;
  70. if (goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
  71. this.root_.contentEditable = true;
  72. } else {
  73. this.root_.ownerDocument.designMode = 'on';
  74. }
  75. this.root_.setAttribute('g_editable', 'true');
  76. };
  77. /**
  78. * Reset the element previously initialized, restoring its HTML and making it
  79. * non editable.
  80. * @suppress {accessControls} Private state of
  81. * {@link goog.editor.plugins.AbstractBubblePlugin} is accessed for test
  82. * purposes.
  83. */
  84. goog.testing.editor.TestHelper.prototype.tearDownEditableElement = function() {
  85. if (goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
  86. this.root_.contentEditable = false;
  87. } else {
  88. this.root_.ownerDocument.designMode = 'off';
  89. }
  90. goog.dom.removeChildren(this.root_);
  91. this.root_.innerHTML = this.savedHtml_;
  92. this.root_.removeAttribute('g_editable');
  93. if (goog.editor.plugins && goog.editor.plugins.AbstractBubblePlugin) {
  94. // Remove old bubbles.
  95. for (var key in goog.editor.plugins.AbstractBubblePlugin.bubbleMap_) {
  96. goog.editor.plugins.AbstractBubblePlugin.bubbleMap_[key].dispose();
  97. }
  98. // Ensure we get a new bubble for each test.
  99. goog.editor.plugins.AbstractBubblePlugin.bubbleMap_ = {};
  100. }
  101. };
  102. /**
  103. * Assert that the html in 'root' is substantially similar to htmlPattern.
  104. * This method tests for the same set of styles, and for the same order of
  105. * nodes. Breaking whitespace nodes are ignored. Elements can be annotated
  106. * with classnames corresponding to keys in goog.userAgent and will be
  107. * expected to show up in that user agent and expected not to show up in
  108. * others.
  109. * @param {string} htmlPattern The pattern to match.
  110. */
  111. goog.testing.editor.TestHelper.prototype.assertHtmlMatches = function(
  112. htmlPattern) {
  113. goog.testing.dom.assertHtmlContentsMatch(htmlPattern, this.root_);
  114. };
  115. /**
  116. * Finds the first text node descendant of root with the given content.
  117. * @param {string|RegExp} textOrRegexp The text to find, or a regular
  118. * expression to find a match of.
  119. * @return {Node} The first text node that matches, or null if none is found.
  120. */
  121. goog.testing.editor.TestHelper.prototype.findTextNode = function(textOrRegexp) {
  122. return goog.testing.dom.findTextNode(textOrRegexp, this.root_);
  123. };
  124. /**
  125. * Select from the given {@code fromOffset} in the given {@code from} node to
  126. * the given {@code toOffset} in the optionally given {@code to} node. If nodes
  127. * are passed in, uses them, otherwise uses findTextNode to find the nodes to
  128. * select. Selects a caret if opt_to and opt_toOffset are not given.
  129. * @param {Node|string} from Node or text of the node to start the selection at.
  130. * @param {number} fromOffset Offset within the above node to start the
  131. * selection at.
  132. * @param {Node|string=} opt_to Node or text of the node to end the selection
  133. * at.
  134. * @param {number=} opt_toOffset Offset within the above node to end the
  135. * selection at.
  136. * @return {!goog.dom.AbstractRange}
  137. */
  138. goog.testing.editor.TestHelper.prototype.select = function(
  139. from, fromOffset, opt_to, opt_toOffset) {
  140. var end;
  141. var start = end = goog.isString(from) ? this.findTextNode(from) : from;
  142. var endOffset;
  143. var startOffset = endOffset = fromOffset;
  144. if (opt_to && goog.isNumber(opt_toOffset)) {
  145. end = goog.isString(opt_to) ? this.findTextNode(opt_to) : opt_to;
  146. endOffset = opt_toOffset;
  147. }
  148. var range =
  149. goog.dom.Range.createFromNodes(start, startOffset, end, endOffset);
  150. range.select();
  151. return range;
  152. };
  153. /** @override */
  154. goog.testing.editor.TestHelper.prototype.disposeInternal = function() {
  155. if (goog.editor.node.isEditableContainer(this.root_)) {
  156. this.tearDownEditableElement();
  157. }
  158. delete this.root_;
  159. goog.testing.editor.TestHelper.base(this, 'disposeInternal');
  160. };