| Index: ios/chrome/browser/ui/contextual_search/contextual_search_js_unittest.mm
|
| diff --git a/ios/chrome/browser/ui/contextual_search/contextual_search_js_unittest.mm b/ios/chrome/browser/ui/contextual_search/contextual_search_js_unittest.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d22021e568cf1a9995e0deea72166884a2d58a78
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/ui/contextual_search/contextual_search_js_unittest.mm
|
| @@ -0,0 +1,493 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#import <UIKit/UIKit.h>
|
| +
|
| +#include <memory>
|
| +
|
| +#include "base/ios/ios_util.h"
|
| +#include "base/json/json_reader.h"
|
| +#include "base/mac/scoped_nsobject.h"
|
| +#include "base/strings/sys_string_conversions.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#import "base/test/ios/wait_util.h"
|
| +#include "base/values.h"
|
| +#include "components/pref_registry/pref_registry_syncable.h"
|
| +#include "components/prefs/pref_registry_simple.h"
|
| +#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
|
| +#import "ios/chrome/browser/ui/contextual_search/contextual_search_controller.h"
|
| +#import "ios/chrome/browser/ui/contextual_search/js_contextual_search_manager.h"
|
| +#import "ios/chrome/browser/ui/contextual_search/touch_to_search_permissions_mediator+testing.h"
|
| +#import "ios/chrome/browser/web/chrome_web_test.h"
|
| +#import "ios/web/public/web_state/js/crw_js_injection_manager.h"
|
| +#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
|
| +#import "ios/web/public/web_state/web_state.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "testing/gtest_mac.h"
|
| +#import "third_party/ocmock/OCMock/OCMock.h"
|
| +
|
| +// Unit tests for the resources/contextualsearch.js JavaScript file.
|
| +
|
| +struct ContextualSearchStruct {
|
| + std::string url;
|
| + std::string selectedText;
|
| + std::string surroundingText;
|
| + int offsetStart;
|
| + int offsetEnd;
|
| +};
|
| +
|
| +@interface JsContextualSearchAdditionsManager : CRWJSInjectionManager
|
| +@end
|
| +
|
| +@implementation JsContextualSearchAdditionsManager : CRWJSInjectionManager
|
| +- (NSString*)scriptPath {
|
| + return @"contextualsearch_unittest";
|
| +}
|
| +
|
| +- (NSArray*)dependencies {
|
| + return @[ [JsContextualSearchManager class] ];
|
| +}
|
| +
|
| +@end
|
| +
|
| +namespace {
|
| +
|
| +// HTML that contains script.
|
| +NSString* kHTMLSentenceWithScript =
|
| + @"<html><body>"
|
| + "This is <span id='taphere'>the</span> <script>function ignore() "
|
| + "{};</script>sentence to select."
|
| + "</body></html>";
|
| +
|
| +// HTML that contains label to be tapped.
|
| +NSString* kHTMLSentenceWithLabel =
|
| + @"<html><body>"
|
| + "<label>Click <span id='taphere'>me</span> <input type='text'/></label>."
|
| + "A sentence to select."
|
| + "</body></html>";
|
| +
|
| +// HTML that contains italic element.
|
| +NSString* kHTMLWithItalic =
|
| + @"<html><body>"
|
| + "This is <span id='taphere'>an</span> <i>italic</i> element."
|
| + "</body></html>";
|
| +
|
| +// HTML that contains a table.
|
| +NSString* kHTMLWithTable =
|
| + @"<html><body>"
|
| + "<table><tr><td>Left <span id='taphere'>cell</span></td>"
|
| + "<td>right cell</td></tr></table>"
|
| + "</body></html>";
|
| +
|
| +// HTML that will trigger an unrelated DOM mutation on tap.
|
| +NSString* kHTMLWithUnrelatedDOMMutation =
|
| + @"<html><body>"
|
| + "<span>This <span style='margin-left:50px' id='taphere'>is</span>"
|
| + " sentence</span> <span>with <span id='test' attr='before'>mutation</span>"
|
| + "</span>.</body></html>";
|
| +
|
| +// HTML that will trigger a related DOM mutation on tap.
|
| +NSString* kHTMLWithRelatedDOMMutation =
|
| + @"<html><body>"
|
| + "This <span id='test' attr='before'>"
|
| + "<span style='margin-left:50px' id='taphere'>is</span></span>"
|
| + "a sentence with mutation."
|
| + "</body></html>";
|
| +
|
| +// HTML that will trigger a related DOM mutation on tap.
|
| +NSString* kHTMLWithRelatedTextMutation =
|
| + @"<html><body>"
|
| + "This <span style='margin-left:50px' id='taphere'> text "
|
| + "<span id='test'>mutation is </span> inside </span>"
|
| + "a sentence with mutation."
|
| + "</body></html>";
|
| +
|
| +// HTML that contain a div in the middle of a sentence.
|
| +NSString* kHTMLWithDiv =
|
| + @"<html><body>"
|
| + "This<div>is</div>a <span id='taphere'>sentence</span>."
|
| + "</body></html>";
|
| +
|
| +// HTML that contain a div in the middle of a sentence.
|
| +NSString* kHTMLWithSpaceDiv =
|
| + @"<html><body>"
|
| + "This <div>is</div>a <span id='taphere'>sentence</span>."
|
| + "</body></html>";
|
| +
|
| +// HTML that contains prevent default.
|
| +NSString* kHTMLWithPreventDefault = @"<html><body>"
|
| + "<div id='interceptor'>"
|
| + "<span id='taphere'>is</span>"
|
| + "</div></body></html>";
|
| +
|
| +NSString* kStringWith50Chars =
|
| + @"Sentence $INDEX containing exactly 50 characters. ";
|
| +
|
| +class ContextualSearchJsTest : public ChromeWebTest {
|
| + public:
|
| + // Loads the given HTML, then loads the |contextualSearch| JavaScript.
|
| + void LoadHtml(NSString* html) {
|
| + ChromeWebTest::LoadHtml(html);
|
| + [jsUnittestsAdditions_ inject];
|
| + }
|
| +
|
| + bool GetContextFromId(NSString* elementID,
|
| + ContextualSearchStruct* searchContext) {
|
| + id javaScriptResult = ExecuteJavaScript([NSString
|
| + stringWithFormat:@"document.getElementById('%@').scrollIntoView();"
|
| + "__gCrWeb.contextualSearch.tapOnElement('%@');",
|
| + elementID, elementID]);
|
| + if (!javaScriptResult)
|
| + return false;
|
| + const std::string json = base::SysNSStringToUTF8(javaScriptResult);
|
| + std::unique_ptr<base::Value> parsedResult(
|
| + base::JSONReader::Read(json, false));
|
| + if (!parsedResult.get() ||
|
| + !parsedResult->IsType(base::Value::Type::DICTIONARY)) {
|
| + return false;
|
| + }
|
| +
|
| + base::DictionaryValue* resultDict =
|
| + static_cast<base::DictionaryValue*>(parsedResult.get());
|
| + const base::DictionaryValue* context = nullptr;
|
| + if (!resultDict->GetDictionary("context", &context)) {
|
| + return false;
|
| + }
|
| +
|
| + std::string error;
|
| + context->GetString("error", &error);
|
| + if (!error.empty()) {
|
| + LOG(ERROR) << "GetContext error: " << error;
|
| + return false;
|
| + }
|
| +
|
| + std::string url, selectedText;
|
| + context->GetString("url", &searchContext->url);
|
| + context->GetString("selectedText", &searchContext->selectedText);
|
| + context->GetString("surroundingText", &searchContext->surroundingText);
|
| + context->GetInteger("offsetStart", &searchContext->offsetStart);
|
| + context->GetInteger("offsetEnd", &searchContext->offsetEnd);
|
| + return true;
|
| + }
|
| +
|
| + id expandHighlight(int start, int end) {
|
| + return ExecuteJavaScript([NSString
|
| + stringWithFormat:@"__gCrWeb.contextualSearch.expandHighlight(%d, %d);"
|
| + "__gCrWeb.contextualSearch.retrieveHighlighted();",
|
| + start, end]);
|
| + }
|
| +
|
| + id highlight() {
|
| + return ExecuteJavaScript(
|
| + @"__gCrWeb.contextualSearch.setHighlighting(true);"
|
| + "__gCrWeb.contextualSearch.retrieveHighlighted();");
|
| + }
|
| +
|
| + NSInteger GetMutatedNodeCount() {
|
| + id output = ExecuteJavaScript(
|
| + @"__gCrWeb.contextualSearch.getMutatedElementCount();");
|
| + return [output integerValue];
|
| + }
|
| +
|
| + void CheckContextOffsets(const ContextualSearchStruct& searchContext,
|
| + const std::string& surroundingText) {
|
| + EXPECT_EQ(searchContext.surroundingText, surroundingText);
|
| + EXPECT_EQ(searchContext.selectedText,
|
| + searchContext.surroundingText.substr(
|
| + searchContext.offsetStart,
|
| + searchContext.offsetEnd - searchContext.offsetStart));
|
| + }
|
| +
|
| + NSString* BuildLongTestString(int startIndex,
|
| + int endIndex,
|
| + int tapOn,
|
| + bool newLine) {
|
| + NSString* longString = @"";
|
| + for (int i = startIndex; i < endIndex; i++) {
|
| + NSString* index = [NSString stringWithFormat:@"%06d", i];
|
| + if (i == tapOn) {
|
| + index =
|
| + [NSString stringWithFormat:@"<span id='taphere'>%@</span>", index];
|
| + }
|
| + NSString* sentence =
|
| + [kStringWith50Chars stringByReplacingOccurrencesOfString:@"$INDEX"
|
| + withString:index];
|
| + longString = [longString stringByAppendingString:sentence];
|
| + if (newLine) {
|
| + longString = [longString stringByAppendingString:@"<br/>"];
|
| + }
|
| + }
|
| + return longString;
|
| + }
|
| +
|
| + void SetUp() override {
|
| + ChromeWebTest::SetUp();
|
| + mockDelegate_.reset([[OCMockObject
|
| + niceMockForProtocol:@protocol(ContextualSearchControllerDelegate)]
|
| + retain]);
|
| + jsUnittestsAdditions_ = static_cast<JsContextualSearchAdditionsManager*>(
|
| + [web_state()->GetJSInjectionReceiver()
|
| + instanceOfClass:[JsContextualSearchAdditionsManager class]]);
|
| + TestChromeBrowserState::Builder test_cbs_builder;
|
| + chrome_browser_state_ = test_cbs_builder.Build();
|
| + controller_.reset([[ContextualSearchController alloc]
|
| + initWithBrowserState:chrome_browser_state_.get()
|
| + delegate:mockDelegate_]);
|
| + [controller_
|
| + setPermissions:[[MockTouchToSearchPermissionsMediator alloc]
|
| + initWithBrowserState:chrome_browser_state_.get()]];
|
| + [controller_ setWebState:web_state()];
|
| + [controller_ enableContextualSearch:YES];
|
| + }
|
| +
|
| + void TearDown() override {
|
| + [controller_ close];
|
| + // Need to tear down the controller so it deregisters its JS handlers
|
| + // before |webController_| is destroyed.
|
| + controller_.reset();
|
| + ChromeWebTest::TearDown();
|
| + }
|
| +
|
| + std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
|
| + __unsafe_unretained JsContextualSearchAdditionsManager* jsUnittestsAdditions_;
|
| + base::scoped_nsobject<ContextualSearchController> controller_;
|
| + base::scoped_nsobject<id> mockDelegate_;
|
| + base::scoped_nsobject<id> mockToolbarDelegate_;
|
| +};
|
| +
|
| +// Test that ignored elements do not trigger CS when tapped.
|
| +TEST_F(ContextualSearchJsTest, TestIgnoreTapsOnElements) {
|
| + LoadHtml(kHTMLSentenceWithLabel);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_FALSE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that ingnored element are not included in highlight or surrounding text.
|
| +TEST_F(ContextualSearchJsTest, TestIgnoreScript) {
|
| + LoadHtml(kHTMLSentenceWithScript);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +
|
| + CheckContextOffsets(searchContext, "This is the sentence to select.");
|
| + id highlighted = expandHighlight(0, searchContext.surroundingText.size());
|
| + EXPECT_NSEQ(highlighted, @"This is the sentence to select.");
|
| +};
|
| +
|
| +// Test that all span element are correctly highlighted.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightThroughSpan) {
|
| + LoadHtml(kHTMLWithItalic);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +
|
| + CheckContextOffsets(searchContext, "This is an italic element.");
|
| + NSString* highlighted =
|
| + expandHighlight(0, searchContext.surroundingText.size());
|
| + EXPECT_NSEQ(highlighted, @"This is an italic element.");
|
| +};
|
| +
|
| +// Test that all block element are highlighted. Spaces separating element must
|
| +// be ignored.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightThroughBlock) {
|
| + LoadHtml(kHTMLWithTable);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +
|
| + CheckContextOffsets(searchContext, "Left cell right cell");
|
| + NSString* highlighted =
|
| + expandHighlight(0, searchContext.surroundingText.size());
|
| + EXPECT_NSEQ(highlighted, @"Left cell right cell");
|
| +};
|
| +
|
| +// Test that blocks add spaces if there are not arround it.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightBlockAddsSpace) {
|
| + LoadHtml(kHTMLWithDiv);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| + CheckContextOffsets(searchContext, "This is a sentence.");
|
| +};
|
| +
|
| +// Test that blocks don't add spaces if there are around it.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightBlockDontAddsSpace) {
|
| + LoadHtml(kHTMLWithSpaceDiv);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| + CheckContextOffsets(searchContext, "This is a sentence.");
|
| +};
|
| +
|
| +// Test that related DOM mutation cancels contextual search.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightRelatedDOMMutation) {
|
| + LoadHtml(kHTMLWithRelatedDOMMutation);
|
| + ExecuteJavaScript(
|
| + @"document.getElementById('test').setAttribute('attr', 'after');");
|
| + ASSERT_EQ(1, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_FALSE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that unrelated DOM mutation does not cancel contextual search.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightIgnoreUnrelatedDOMMutation) {
|
| + LoadHtml(kHTMLWithUnrelatedDOMMutation);
|
| + ExecuteJavaScript(
|
| + @"document.getElementById('test').setAttribute('attr', 'after');");
|
| + ASSERT_EQ(1, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that DOM mutation with same value does not cancel contextual search.
|
| +// Mutation should not mark a node as mutated.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightIgnoreDOMMutationSameAttribute) {
|
| + LoadHtml(kHTMLWithRelatedDOMMutation);
|
| + ExecuteJavaScript(
|
| + @"document.getElementById('test').setAttribute('attr', 'before');");
|
| + ASSERT_EQ(0, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that DOM mutation between different false values does not cancel
|
| +// contextual search. Mutation should not mark a node as mutated.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightIgnoreDOMMutationBothFalse) {
|
| + LoadHtml(kHTMLWithRelatedDOMMutation);
|
| + ExecuteJavaScript(
|
| + @"document.getElementById('test').setAttribute('non_attr', '');");
|
| + ASSERT_EQ(0, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that DOM mutation with same text does not cancel contextual search.
|
| +// Mutation should not mark a node as mutated.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightIgnoreDOMMutationSameText) {
|
| + LoadHtml(kHTMLWithRelatedTextMutation);
|
| + ExecuteJavaScript(
|
| + @"document.getElementById('test').innerText = 'mutation is ';");
|
| + ASSERT_EQ(0, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that related text DOM mutation prevents contextual search.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightRelatedDOMMutationText) {
|
| + LoadHtml(kHTMLWithRelatedTextMutation);
|
| + ExecuteJavaScript(@"document.getElementById('test').innerText = 'mutated';");
|
| + ASSERT_EQ(1, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_FALSE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that unrelated text DOM mutation doesn't prevent contextual search.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightUnrelatedDOMMutationTextIgnored) {
|
| + LoadHtml(kHTMLWithUnrelatedDOMMutation);
|
| + ExecuteJavaScript(@"document.getElementById('test').innerText = 'mutated';");
|
| + ASSERT_EQ(1, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that two related DOM mutations prevent contextual search.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightTwoDOMMutations) {
|
| + LoadHtml(kHTMLWithRelatedDOMMutation);
|
| + ASSERT_EQ(0, GetMutatedNodeCount());
|
| + ExecuteJavaScript(
|
| + @"document.getElementById('taphere').innerText = 'mutated';"
|
| + "document.getElementById('test').setAttribute('attr', 'after');");
|
| + ASSERT_EQ(2, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_FALSE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that two related DOM mutations with only one change prevent contextual
|
| +// search.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightTwoDOMMutationOneChanging) {
|
| + LoadHtml(kHTMLWithRelatedDOMMutation);
|
| + ExecuteJavaScript(
|
| + @"document.getElementById('taphere').innerText = 'mutated';"
|
| + "document.getElementById('test').setAttribute('attr', 'before');");
|
| + ASSERT_EQ(1, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_FALSE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that two DOM mutations with same value does not cancel contextual
|
| +// search.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightTwoDOMMutationNoChange) {
|
| + LoadHtml(kHTMLWithRelatedDOMMutation);
|
| + ExecuteJavaScript(
|
| + @"document.getElementById('taphere').innerText = 'is';"
|
| + "document.getElementById('test').setAttribute('attr', 'before');");
|
| + ASSERT_EQ(0, GetMutatedNodeCount());
|
| + ContextualSearchStruct searchContext;
|
| +
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +// Test that non bubbling event does not trigger contextual search.
|
| +TEST_F(ContextualSearchJsTest, TestHighlightIgnorePreventDefault) {
|
| + LoadHtml(kHTMLWithPreventDefault);
|
| + // Enable touch delay.
|
| + ExecuteJavaScript(
|
| + @"__gCrWeb.contextualSearch.setBodyTouchListenerDelay(200);");
|
| + ContextualSearchStruct searchContext;
|
| + ExecuteJavaScript(@"document.getElementById('interceptor')."
|
| + @"addEventListener('touchend', function(event) "
|
| + @"{event.preventDefault();return false;}, false);");
|
| +
|
| + ASSERT_FALSE(GetContextFromId(@"taphere", &searchContext));
|
| +};
|
| +
|
| +TEST_F(ContextualSearchJsTest, Test1500CharactersCenter) {
|
| + // String should extend 15 sentences to the left and right.
|
| + NSString* stringHTML = BuildLongTestString(0, 50, 25, true);
|
| + NSString* expectedHTML = BuildLongTestString(10, 41, -1, false);
|
| + LoadHtml(stringHTML);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| + CheckContextOffsets(searchContext, base::SysNSStringToUTF8(expectedHTML));
|
| +};
|
| +
|
| +TEST_F(ContextualSearchJsTest, Test1500CharactersRight) {
|
| + // There is not enough chars on the left, so string should extend on the
|
| + // right.
|
| + NSString* stringHTML = BuildLongTestString(0, 50, 5, true);
|
| + NSString* expectedHTML = BuildLongTestString(0, 30, -1, false);
|
| + LoadHtml(
|
| + [NSString stringWithFormat:@"<html><body>%@</body></html>", stringHTML]);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| + CheckContextOffsets(searchContext, base::SysNSStringToUTF8(expectedHTML));
|
| +};
|
| +
|
| +TEST_F(ContextualSearchJsTest, Test1500CharactersLeft) {
|
| + // There is not enough chars on the right, so string should extend on the
|
| + // left.
|
| + NSString* stringHTML = BuildLongTestString(0, 50, 45, true);
|
| + NSString* expectedHTML = BuildLongTestString(20, 50, -1, false);
|
| + LoadHtml(
|
| + [NSString stringWithFormat:@"<html><body>%@</body></html>", stringHTML]);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| + CheckContextOffsets(searchContext, base::SysNSStringToUTF8(expectedHTML));
|
| +};
|
| +
|
| +TEST_F(ContextualSearchJsTest, Test1500CharactersToShort) {
|
| + // String is too short so the whole string should be in the context.
|
| + NSString* stringHTML = BuildLongTestString(0, 10, 5, true);
|
| + NSString* expectedHTML = BuildLongTestString(0, 10, -1, false);
|
| + // LoadHtml will trim the last space.
|
| + LoadHtml(
|
| + [NSString stringWithFormat:@"<html><body>%@</body></html>", stringHTML]);
|
| + ContextualSearchStruct searchContext;
|
| + ASSERT_TRUE(GetContextFromId(@"taphere", &searchContext));
|
| + CheckContextOffsets(searchContext, base::SysNSStringToUTF8(expectedHTML));
|
| +};
|
| +} // namespace
|
|
|