/* * Copyright (C) 2022 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #if PLATFORM(IOS_FAMILY) #import "TestWKWebView.h" #import "UIKitSPI.h" #import "WKWebViewConfigurationExtras.h" #import @interface TestWKWebView (TextAlternatives) - (NSUInteger)dictationAlternativesMarkerCount:(NSString *)evaluateNodeExpression; @end @implementation TestWKWebView (TextAlternatives) - (NSUInteger)dictationAlternativesMarkerCount:(NSString *)evaluateNodeExpression { NSString *scriptToEvaluate = [NSString stringWithFormat:@"internals.markerCountForNode((() => %@)(), 'dictationalternatives')", evaluateNodeExpression]; NSNumber *result = [self objectByEvaluatingJavaScript:scriptToEvaluate]; return result.unsignedIntegerValue; } @end namespace TestWebKitAPI { static RetainPtr createWebViewForTestingTextAlternatives() { auto configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 568) configuration:configuration]); [webView _setEditable:YES]; return webView; } TEST(TextAlternatives, AddAndRemoveTextAlternativesWithMatch) { auto webView = createWebViewForTestingTextAlternatives(); [webView synchronouslyLoadHTMLString:@"hello world "]; [webView stringByEvaluatingJavaScript:@"getSelection().setPosition(document.body, 1)"]; auto alternatives = adoptNS([[NSTextAlternatives alloc] initWithPrimaryString:@"hello world" alternativeStrings:@[ @"👋🌎" ]]); [[webView textInputContentView] addTextAlternatives:alternatives.get()]; [webView waitForNextPresentationUpdate]; EXPECT_EQ(1U, [webView dictationAlternativesMarkerCount:@"document.body.childNodes[0]"]); // This should not remove the text alternatives above, since the selection does not intersect with the dictation alternative marker. [[webView textInputContentView] removeEmojiAlternatives]; [webView waitForNextPresentationUpdate]; EXPECT_EQ(1U, [webView dictationAlternativesMarkerCount:@"document.body.childNodes[0]"]); [[webView textInputContentView] moveByOffset:-1]; [webView waitForNextPresentationUpdate]; [[webView textInputContentView] removeEmojiAlternatives]; [webView waitForNextPresentationUpdate]; EXPECT_EQ(0U, [webView dictationAlternativesMarkerCount:@"document.body.childNodes[0]"]); } TEST(TextAlternatives, AddAndRemoveTextAlternativesWithTextAndEmojis) { auto webView = createWebViewForTestingTextAlternatives(); [webView synchronouslyLoadHTMLString:@"hello world"]; [webView stringByEvaluatingJavaScript:@"getSelection().setPosition(document.body, 1)"]; auto alternatives = adoptNS([[NSTextAlternatives alloc] initWithPrimaryString:@"hello world" alternativeStrings:@[ @"👋🌎", @"Hello world" ]]); [[webView textInputContentView] addTextAlternatives:alternatives.get()]; [webView waitForNextPresentationUpdate]; EXPECT_EQ(1U, [webView dictationAlternativesMarkerCount:@"document.body.childNodes[0]"]); // This should only remove one of the two text alternative strings, which leaves the document marker intact. [[webView textInputContentView] removeEmojiAlternatives]; [webView waitForNextPresentationUpdate]; EXPECT_EQ(1U, [webView dictationAlternativesMarkerCount:@"document.body.childNodes[0]"]); } TEST(TextAlternatives, AddTextAlternativesWithSelectedMatch) { auto webView = createWebViewForTestingTextAlternatives(); [webView synchronouslyLoadHTMLString:@"hello world "]; [webView stringByEvaluatingJavaScript:@"getSelection().selectAllChildren(document.body)"]; auto alternatives = adoptNS([[NSTextAlternatives alloc] initWithPrimaryString:@"hello world" alternativeStrings:@[ @"👋🌎" ]]); [[webView textInputContentView] addTextAlternatives:alternatives.get()]; [webView waitForNextPresentationUpdate]; EXPECT_EQ(1U, [webView dictationAlternativesMarkerCount:@"document.body.childNodes[0]"]); } TEST(TextAlternatives, AddTextAlternativesWithoutMatch) { auto webView = createWebViewForTestingTextAlternatives(); [webView synchronouslyLoadHTMLString:@"hello world "]; [webView stringByEvaluatingJavaScript:@"getSelection().setPosition(document.body, 1)"]; auto alternatives = adoptNS([[NSTextAlternatives alloc] initWithPrimaryString:@"goodbye world" alternativeStrings:@[ @"👋🌎" ]]); [[webView textInputContentView] addTextAlternatives:alternatives.get()]; [webView waitForNextPresentationUpdate]; EXPECT_EQ(0U, [webView dictationAlternativesMarkerCount:@"document.body.childNodes[0]"]); } } // namespace TestWebKitAPI #endif // PLATFORM(IOS_FAMILY)