Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 'use strict'; | 5 'use strict'; |
| 6 | 6 |
| 7 // This file provides |assert_selection(sample, tester, expectedText, options)| | 7 // This file provides |assert_selection(sample, tester, expectedText, options)| |
| 8 // assertion to W3C test harness to write editing test cases easier. | 8 // assertion to W3C test harness to write editing test cases easier. |
| 9 // | 9 // |
| 10 // |sample| is an HTML fragment text which is inserted as |innerHTML|. It should | 10 // |sample| is an HTML fragment text which is inserted as |innerHTML|. It should |
| 11 // have at least one focus boundary point marker "|" and at most one anchor | 11 // have at least one focus boundary point marker "|" and at most one anchor |
| 12 // boundary point marker "^". | 12 // boundary point marker "^". |
| 13 // | 13 // |
| 14 // |tester| is either name with parameter of execCommand or function taking | 14 // |tester| is either name with parameter of execCommand or function taking |
| 15 // one parameter |Selection|. | 15 // one parameter |Selection|. |
| 16 // | 16 // |
| 17 // |expectedText| is an HTML fragment text containing at most one focus marker | 17 // |expectedText| is an HTML fragment text containing at most one focus marker |
| 18 // and anchor marker. If resulting selection is none, you don't need to have | 18 // and anchor marker. If resulting selection is none, you don't need to have |
| 19 // anchor and focus markers. | 19 // anchor and focus markers. |
| 20 // | 20 // |
| 21 // |options| is a string as description, undefined, or a dictionary containing: | 21 // |options| is a string as description, undefined, or a dictionary containing: |
| 22 // description: A description | 22 // description: A description |
| 23 // dumpAs: 'domtree' or 'flattree'. Default is 'domtree'. | 23 // dumpAs: 'domtree' or 'flattree'. Default is 'domtree'. |
| 24 // removeSampleIfSucceeded: A boolean. Default is true. | 24 // removeSampleIfSucceeded: A boolean. Default is true. |
| 25 // dumpFromRoot: A boolean. Default is false. | |
|
yosin_UTC9
2017/03/17 10:04:11
Could you move "assert_selection.js" change to ano
| |
| 25 // | 26 // |
| 26 // Example: | 27 // Example: |
| 27 // test(() => { | 28 // test(() => { |
| 28 // assert_selection( | 29 // assert_selection( |
| 29 // '|foo', | 30 // '|foo', |
| 30 // (selection) => selection.modify('extent', 'forward, 'character'), | 31 // (selection) => selection.modify('extent', 'forward, 'character'), |
| 31 // '<a href="http://bar">^f|oo</a>' | 32 // '<a href="http://bar">^f|oo</a>' |
| 32 // }); | 33 // }); |
| 33 // | 34 // |
| 34 // test(() => { | 35 // test(() => { |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 612 } | 613 } |
| 613 this.emit(endMarker); | 614 this.emit(endMarker); |
| 614 this.emit(value.substr(end)); | 615 this.emit(value.substr(end)); |
| 615 } | 616 } |
| 616 this.emit('</textarea>'); | 617 this.emit('</textarea>'); |
| 617 } | 618 } |
| 618 | 619 |
| 619 /** | 620 /** |
| 620 * @public | 621 * @public |
| 621 * @param {!HTMLDocument} document | 622 * @param {!HTMLDocument} document |
| 623 * @param {boolean} dumpFromRoot | |
| 622 */ | 624 */ |
| 623 serialize(document) { | 625 serialize(document, dumpFromRoot) { |
| 624 if (document.body) | 626 if (document.body && !dumpFromRoot) |
| 625 this.serializeChildren(document.body); | 627 this.serializeChildren(document.body); |
| 626 else | 628 else |
| 627 this.serializeInternal(document.documentElement); | 629 this.serializeInternal(document.documentElement); |
| 628 return this.strings_.join(''); | 630 return this.strings_.join(''); |
| 629 } | 631 } |
| 630 | 632 |
| 631 /** | 633 /** |
| 632 * @private | 634 * @private |
| 633 * @param {!HTMLElement} element | 635 * @param {!HTMLElement} element |
| 634 */ | 636 */ |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 } | 783 } |
| 782 | 784 |
| 783 /** | 785 /** |
| 784 * @public | 786 * @public |
| 785 */ | 787 */ |
| 786 remove() { this.iframe_.remove(); } | 788 remove() { this.iframe_.remove(); } |
| 787 | 789 |
| 788 /** | 790 /** |
| 789 * @public | 791 * @public |
| 790 * @param {!Traversal} traversal | 792 * @param {!Traversal} traversal |
| 793 * @param {boolean} dumpFromRoot | |
| 791 * @return {string} | 794 * @return {string} |
| 792 */ | 795 */ |
| 793 serialize(traversal) { | 796 serialize(traversal, dumpFromRoot) { |
| 794 /** @type {!SampleSelection} */ | 797 /** @type {!SampleSelection} */ |
| 795 const selection = traversal.fromDOMSelection(this.selection_); | 798 const selection = traversal.fromDOMSelection(this.selection_); |
| 796 /** @type {!Serializer} */ | 799 /** @type {!Serializer} */ |
| 797 const serializer = new Serializer(selection, traversal); | 800 const serializer = new Serializer(selection, traversal); |
| 798 return serializer.serialize(this.document_); | 801 return serializer.serialize(this.document_, dumpFromRoot); |
| 799 } | 802 } |
| 800 } | 803 } |
| 801 | 804 |
| 802 function assembleDescription() { | 805 function assembleDescription() { |
| 803 function getStack() { | 806 function getStack() { |
| 804 let stack; | 807 let stack; |
| 805 try { | 808 try { |
| 806 throw new Error('get line number'); | 809 throw new Error('get line number'); |
| 807 } catch (error) { | 810 } catch (error) { |
| 808 stack = error.stack.split('\n').slice(1); | 811 stack = error.stack.split('\n').slice(1); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 866 * @param {function(!Selection)|string} | 869 * @param {function(!Selection)|string} |
| 867 * @param {string} expectedText | 870 * @param {string} expectedText |
| 868 * @param {Object=} opt_options | 871 * @param {Object=} opt_options |
| 869 * @return {!Sample} | 872 * @return {!Sample} |
| 870 */ | 873 */ |
| 871 function assertSelection( | 874 function assertSelection( |
| 872 inputText, tester, expectedText, opt_options = {}) { | 875 inputText, tester, expectedText, opt_options = {}) { |
| 873 const kDescription = 'description'; | 876 const kDescription = 'description'; |
| 874 const kDumpAs = 'dumpAs'; | 877 const kDumpAs = 'dumpAs'; |
| 875 const kRemoveSampleIfSucceeded = 'removeSampleIfSucceeded'; | 878 const kRemoveSampleIfSucceeded = 'removeSampleIfSucceeded'; |
| 879 const kDumpFromRoot = 'dumpFromRoot'; | |
| 876 /** @type {!Object} */ | 880 /** @type {!Object} */ |
| 877 const options = typeof(opt_options) === 'string' | 881 const options = typeof(opt_options) === 'string' |
| 878 ? {description: opt_options} : opt_options; | 882 ? {description: opt_options} : opt_options; |
| 879 /** @type {string} */ | 883 /** @type {string} */ |
| 880 const description = kDescription in options | 884 const description = kDescription in options |
| 881 ? options[kDescription] : assembleDescription(); | 885 ? options[kDescription] : assembleDescription(); |
| 882 /** @type {boolean} */ | 886 /** @type {boolean} */ |
| 883 const removeSampleIfSucceeded = kRemoveSampleIfSucceeded in options | 887 const removeSampleIfSucceeded = kRemoveSampleIfSucceeded in options |
| 884 ? !!options[kRemoveSampleIfSucceeded] : true; | 888 ? !!options[kRemoveSampleIfSucceeded] : true; |
| 885 /** @type {DumpAs} */ | 889 /** @type {DumpAs} */ |
| 886 const dumpAs = options[kDumpAs] || DumpAs.DOM_TREE; | 890 const dumpAs = options[kDumpAs] || DumpAs.DOM_TREE; |
| 891 /** @type {boolean} */ | |
| 892 const dumpFromRoot = options[kDumpFromRoot] || false; | |
| 887 | 893 |
| 888 checkExpectedText(expectedText); | 894 checkExpectedText(expectedText); |
| 889 const sample = new Sample(inputText); | 895 const sample = new Sample(inputText); |
| 890 if (typeof(tester) === 'function') { | 896 if (typeof(tester) === 'function') { |
| 891 tester.call(window, sample.selection); | 897 tester.call(window, sample.selection); |
| 892 } else if (typeof(tester) === 'string') { | 898 } else if (typeof(tester) === 'string') { |
| 893 const strings = tester.split(/ (.+)/); | 899 const strings = tester.split(/ (.+)/); |
| 894 sample.document.execCommand(strings[0], false, strings[1]); | 900 sample.document.execCommand(strings[0], false, strings[1]); |
| 895 } else { | 901 } else { |
| 896 throw new Error(`Invalid tester: ${tester}`); | 902 throw new Error(`Invalid tester: ${tester}`); |
| 897 } | 903 } |
| 898 | 904 |
| 899 /** @type {!Traversal} */ | 905 /** @type {!Traversal} */ |
| 900 const traversal = (() => { | 906 const traversal = (() => { |
| 901 switch (dumpAs) { | 907 switch (dumpAs) { |
| 902 case DumpAs.DOM_TREE: | 908 case DumpAs.DOM_TREE: |
| 903 return new DOMTreeTraversal(); | 909 return new DOMTreeTraversal(); |
| 904 case DumpAs.FLAT_TREE: | 910 case DumpAs.FLAT_TREE: |
| 905 if (!window.internals) | 911 if (!window.internals) |
| 906 throw new Error('This test requires window.internals.'); | 912 throw new Error('This test requires window.internals.'); |
| 907 return new FlatTreeTraversal(); | 913 return new FlatTreeTraversal(); |
| 908 default: | 914 default: |
| 909 throw `${kDumpAs} must be one of ` + | 915 throw `${kDumpAs} must be one of ` + |
| 910 `{${Object.values(DumpAs).join(', ')}}` + | 916 `{${Object.values(DumpAs).join(', ')}}` + |
| 911 ` instead of '${dumpAs}'`; | 917 ` instead of '${dumpAs}'`; |
| 912 } | 918 } |
| 913 })(); | 919 })(); |
| 914 | 920 |
| 915 /** @type {string} */ | 921 /** @type {string} */ |
| 916 const actualText = sample.serialize(traversal); | 922 const actualText = sample.serialize(traversal, dumpFromRoot); |
| 917 // We keep sample HTML when assertion is false for ease of debugging test | 923 // We keep sample HTML when assertion is false for ease of debugging test |
| 918 // case. | 924 // case. |
| 919 if (actualText === expectedText) { | 925 if (actualText === expectedText) { |
| 920 if (removeSampleIfSucceeded) | 926 if (removeSampleIfSucceeded) |
| 921 sample.remove(); | 927 sample.remove(); |
| 922 return sample; | 928 return sample; |
| 923 } | 929 } |
| 924 throw new Error(`${description}\n` + | 930 throw new Error(`${description}\n` + |
| 925 `\t expected ${expectedText},\n` + | 931 `\t expected ${expectedText},\n` + |
| 926 `\t but got ${actualText},\n` + | 932 `\t but got ${actualText},\n` + |
| 927 `\t sameupto ${commonPrefixOf(expectedText, actualText)}`); | 933 `\t sameupto ${commonPrefixOf(expectedText, actualText)}`); |
| 928 } | 934 } |
| 929 | 935 |
| 930 // Export symbols | 936 // Export symbols |
| 931 window.Sample = Sample; | 937 window.Sample = Sample; |
| 932 window.assert_selection = assertSelection; | 938 window.assert_selection = assertSelection; |
| 933 })(); | 939 })(); |
| OLD | NEW |