| /* |
| * Copyright (C) 2017 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" |
| |
| #import "DataInteractionSimulator.h" |
| #import "PlatformUtilities.h" |
| #import "TestWKWebView.h" |
| #import "WKWebViewConfigurationExtras.h" |
| #import <WebKit/WKPreferencesRefPrivate.h> |
| #import <WebKit/WKWebViewPrivate.h> |
| #import <WebKit/WebKit.h> |
| #import <WebKit/WebKitPrivate.h> |
| #import <wtf/RetainPtr.h> |
| |
| #if PLATFORM(IOS) |
| #import <MobileCoreServices/MobileCoreServices.h> |
| #endif |
| |
| #define USES_MODERN_ATTRIBUTED_STRING_CONVERSION ((PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)) |
| |
| #if WK_API_ENABLED && !PLATFORM(WATCHOS) && !PLATFORM(TVOS) |
| |
| @interface AttachmentUpdateObserver : NSObject <WKUIDelegatePrivate> |
| @property (nonatomic, readonly) NSArray *inserted; |
| @property (nonatomic, readonly) NSArray *removed; |
| @end |
| |
| @implementation AttachmentUpdateObserver { |
| RetainPtr<NSMutableArray<_WKAttachment *>> _inserted; |
| RetainPtr<NSMutableArray<_WKAttachment *>> _removed; |
| RetainPtr<NSMutableDictionary<NSString *, NSString *>> _identifierToSourceMap; |
| } |
| |
| - (instancetype)init |
| { |
| if (self = [super init]) { |
| _inserted = adoptNS([[NSMutableArray alloc] init]); |
| _removed = adoptNS([[NSMutableArray alloc] init]); |
| _identifierToSourceMap = adoptNS([[NSMutableDictionary alloc] init]); |
| } |
| return self; |
| } |
| |
| - (NSArray<_WKAttachment *> *)inserted |
| { |
| return _inserted.get(); |
| } |
| |
| - (NSArray<_WKAttachment *> *)removed |
| { |
| return _removed.get(); |
| } |
| |
| - (NSString *)sourceForIdentifier:(NSString *)identifier |
| { |
| return [_identifierToSourceMap objectForKey:identifier]; |
| } |
| |
| - (void)_webView:(WKWebView *)webView didInsertAttachment:(_WKAttachment *)attachment withSource:(NSString *)source |
| { |
| [_inserted addObject:attachment]; |
| if (source) |
| [_identifierToSourceMap setObject:source forKey:attachment.uniqueIdentifier]; |
| } |
| |
| - (void)_webView:(WKWebView *)webView didRemoveAttachment:(_WKAttachment *)attachment |
| { |
| [_removed addObject:attachment]; |
| } |
| |
| @end |
| |
| namespace TestWebKitAPI { |
| |
| class ObserveAttachmentUpdatesForScope { |
| public: |
| ObserveAttachmentUpdatesForScope(TestWKWebView *webView) |
| : m_webView(webView) |
| { |
| m_previousDelegate = webView.UIDelegate; |
| m_observer = adoptNS([[AttachmentUpdateObserver alloc] init]); |
| webView.UIDelegate = m_observer.get(); |
| } |
| |
| ~ObserveAttachmentUpdatesForScope() |
| { |
| [m_webView setUIDelegate:m_previousDelegate.get()]; |
| } |
| |
| AttachmentUpdateObserver *observer() const { return m_observer.get(); } |
| |
| void expectAttachmentUpdates(NSArray<_WKAttachment *> *removed, NSArray<_WKAttachment *> *inserted) |
| { |
| BOOL removedAttachmentsMatch = [observer().removed isEqual:removed]; |
| if (!removedAttachmentsMatch) |
| NSLog(@"Expected removed attachments: %@ to match %@.", observer().removed, removed); |
| EXPECT_TRUE(removedAttachmentsMatch); |
| |
| BOOL insertedAttachmentsMatch = [observer().inserted isEqual:inserted]; |
| if (!insertedAttachmentsMatch) |
| NSLog(@"Expected inserted attachments: %@ to match %@.", observer().inserted, inserted); |
| EXPECT_TRUE(insertedAttachmentsMatch); |
| } |
| |
| void expectSourceForIdentifier(NSString *expectedSource, NSString *identifier) |
| { |
| NSString *observedSource = [observer() sourceForIdentifier:identifier]; |
| BOOL success = observedSource == expectedSource || [observedSource isEqualToString:expectedSource]; |
| EXPECT_TRUE(success); |
| if (!success) |
| NSLog(@"Expected source: %@ but observed: %@", expectedSource, observedSource); |
| } |
| |
| private: |
| RetainPtr<AttachmentUpdateObserver> m_observer; |
| RetainPtr<TestWKWebView> m_webView; |
| RetainPtr<id> m_previousDelegate; |
| }; |
| |
| } |
| |
| @interface TestWKWebView (AttachmentTesting) |
| @end |
| |
| static RetainPtr<TestWKWebView> webViewForTestingAttachments(CGSize webViewSize, WKWebViewConfiguration *configuration) |
| { |
| configuration._attachmentElementEnabled = YES; |
| WKPreferencesSetCustomPasteboardDataEnabled((WKPreferencesRef)[configuration preferences], YES); |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, webViewSize.width, webViewSize.height) configuration:configuration]); |
| [webView synchronouslyLoadHTMLString:@"<meta name='viewport' content='width=device-width, initial-scale=1'><script>focus = () => document.body.focus()</script><body onload=focus() contenteditable></body>"]; |
| |
| return webView; |
| } |
| |
| static RetainPtr<TestWKWebView> webViewForTestingAttachments(CGSize webViewSize) |
| { |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| return webViewForTestingAttachments(webViewSize, configuration.get()); |
| } |
| |
| static RetainPtr<TestWKWebView> webViewForTestingAttachments() |
| { |
| return webViewForTestingAttachments(CGSizeMake(500, 500)); |
| } |
| |
| static NSData *testZIPData() |
| { |
| NSURL *zipFileURL = [[NSBundle mainBundle] URLForResource:@"compressed-files" withExtension:@"zip" subdirectory:@"TestWebKitAPI.resources"]; |
| return [NSData dataWithContentsOfURL:zipFileURL]; |
| } |
| |
| static NSData *testHTMLData() |
| { |
| return [@"<a href='#'>This is some HTML data</a>" dataUsingEncoding:NSUTF8StringEncoding]; |
| } |
| |
| static NSURL *testImageFileURL() |
| { |
| return [[NSBundle mainBundle] URLForResource:@"icon" withExtension:@"png" subdirectory:@"TestWebKitAPI.resources"]; |
| } |
| |
| static NSData *testImageData() |
| { |
| return [NSData dataWithContentsOfURL:testImageFileURL()]; |
| } |
| |
| static NSData *testVideoData() |
| { |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"mp4" subdirectory:@"TestWebKitAPI.resources"]; |
| return [NSData dataWithContentsOfURL:url]; |
| } |
| |
| static NSURL *testPDFFileURL() |
| { |
| return [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"pdf" subdirectory:@"TestWebKitAPI.resources"]; |
| } |
| |
| static NSData *testPDFData() |
| { |
| return [NSData dataWithContentsOfURL:testPDFFileURL()]; |
| } |
| |
| static _WKAttachmentDisplayOptions *displayOptionsWithMode(_WKAttachmentDisplayMode mode) |
| { |
| _WKAttachmentDisplayOptions *options = [[[_WKAttachmentDisplayOptions alloc] init] autorelease]; |
| options.mode = mode; |
| return options; |
| } |
| |
| @implementation TestWKWebView (AttachmentTesting) |
| |
| - (NSArray<NSString *> *)tagsInBody |
| { |
| return [self objectByEvaluatingJavaScript:@"Array.from(document.body.getElementsByTagName('*')).map(e => e.tagName)"]; |
| } |
| |
| - (void)expectElementTagsInOrder:(NSArray<NSString *> *)tagNames |
| { |
| auto remainingTags = adoptNS([tagNames mutableCopy]); |
| NSArray<NSString *> *tagsInBody = self.tagsInBody; |
| for (NSString *tag in tagsInBody.reverseObjectEnumerator) { |
| if ([tag isEqualToString:[remainingTags lastObject]]) |
| [remainingTags removeLastObject]; |
| if (![remainingTags count]) |
| break; |
| } |
| EXPECT_EQ([remainingTags count], 0U); |
| if ([remainingTags count]) |
| NSLog(@"Expected to find ordered tags: %@ in: %@", tagNames, tagsInBody); |
| } |
| |
| - (void)expectElementTag:(NSString *)tagName toComeBefore:(NSString *)otherTagName |
| { |
| [self expectElementTagsInOrder:@[tagName, otherTagName]]; |
| } |
| |
| - (BOOL)_synchronouslyExecuteEditCommand:(NSString *)command argument:(NSString *)argument |
| { |
| __block bool done = false; |
| __block bool success; |
| [self _executeEditCommand:command argument:argument completion:^(BOOL completionSuccess) { |
| done = true; |
| success = completionSuccess; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| return success; |
| } |
| |
| - (_WKAttachment *)synchronouslyInsertAttachmentWithFilename:(NSString *)filename contentType:(NSString *)contentType data:(NSData *)data options:(_WKAttachmentDisplayOptions *)options |
| { |
| __block bool done = false; |
| RetainPtr<_WKAttachment> attachment = [self _insertAttachmentWithFilename:filename contentType:contentType data:data options:options completion:^(BOOL) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| return attachment.autorelease(); |
| } |
| |
| - (CGSize)attachmentElementSize |
| { |
| __block CGSize size; |
| __block bool doneEvaluatingScript = false; |
| [self evaluateJavaScript:@"r = document.querySelector('attachment').getBoundingClientRect(); [r.width, r.height]" completionHandler:^(NSArray<NSNumber *> *sizeResult, NSError *) { |
| size = CGSizeMake(sizeResult.firstObject.floatValue, sizeResult.lastObject.floatValue); |
| doneEvaluatingScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&doneEvaluatingScript); |
| return size; |
| } |
| |
| - (void)waitForAttachmentElementSizeToBecome:(CGSize)expectedSize |
| { |
| while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]) { |
| if (CGSizeEqualToSize(self.attachmentElementSize, expectedSize)) |
| break; |
| } |
| } |
| |
| - (BOOL)hasAttribute:(NSString *)attributeName forQuerySelector:(NSString *)querySelector |
| { |
| return [self stringByEvaluatingJavaScript:[NSString stringWithFormat:@"document.querySelector('%@').hasAttribute('%@')", querySelector, attributeName]].boolValue; |
| } |
| |
| - (NSString *)valueOfAttribute:(NSString *)attributeName forQuerySelector:(NSString *)querySelector |
| { |
| return [self stringByEvaluatingJavaScript:[NSString stringWithFormat:@"document.querySelector('%@').getAttribute('%@')", querySelector, attributeName]]; |
| } |
| |
| - (void)expectUpdatesAfterCommand:(NSString *)command withArgument:(NSString *)argument expectedRemovals:(NSArray<_WKAttachment *> *)removed expectedInsertions:(NSArray<_WKAttachment *> *)inserted |
| { |
| TestWebKitAPI::ObserveAttachmentUpdatesForScope observer(self); |
| EXPECT_TRUE([self _synchronouslyExecuteEditCommand:command argument:argument]); |
| observer.expectAttachmentUpdates(removed, inserted); |
| } |
| |
| @end |
| |
| @implementation NSData (AttachmentTesting) |
| |
| - (NSString *)shortDescription |
| { |
| return [NSString stringWithFormat:@"<%tu bytes>", self.length]; |
| } |
| |
| @end |
| |
| @implementation _WKAttachment (AttachmentTesting) |
| |
| - (void)synchronouslySetDisplayOptions:(_WKAttachmentDisplayOptions *)options error:(NSError **)error |
| { |
| __block RetainPtr<NSError> resultError; |
| __block bool done = false; |
| [self setDisplayOptions:options completion:^(NSError *error) { |
| resultError = error; |
| done = true; |
| }]; |
| |
| TestWebKitAPI::Util::run(&done); |
| |
| if (error) |
| *error = resultError.autorelease(); |
| } |
| |
| - (_WKAttachmentInfo *)synchronouslyRequestInfo:(NSError **)error |
| { |
| __block RetainPtr<_WKAttachmentInfo> result; |
| __block RetainPtr<NSError> resultError; |
| __block bool done = false; |
| [self requestInfo:^(_WKAttachmentInfo *info, NSError *error) { |
| result = info; |
| resultError = error; |
| done = true; |
| }]; |
| |
| TestWebKitAPI::Util::run(&done); |
| |
| if (error) |
| *error = resultError.autorelease(); |
| |
| return result.autorelease(); |
| } |
| |
| - (NSData *)synchronouslyRequestData:(NSError **)error |
| { |
| return [self synchronouslyRequestInfo:error].data; |
| } |
| |
| - (void)synchronouslySetData:(NSData *)data newContentType:(NSString *)newContentType newFilename:(NSString *)newFilename error:(NSError **)error |
| { |
| __block RetainPtr<NSError> resultError; |
| __block bool done = false; |
| [self setData:data newContentType:newContentType newFilename:newFilename completion:^(NSError *error) { |
| resultError = error; |
| done = true; |
| }]; |
| |
| TestWebKitAPI::Util::run(&done); |
| |
| if (error) |
| *error = resultError.autorelease(); |
| } |
| |
| - (void)expectRequestedDataToBe:(NSData *)expectedData |
| { |
| NSError *requestError = nil; |
| _WKAttachmentInfo *info = [self synchronouslyRequestInfo:&requestError]; |
| |
| BOOL observedDataIsEqualToExpectedData = [info.data isEqualToData:expectedData] || info.data == expectedData; |
| EXPECT_TRUE(observedDataIsEqualToExpectedData); |
| if (!observedDataIsEqualToExpectedData) { |
| NSLog(@"Expected data: %@ but observed: %@ for %@", [expectedData shortDescription], [info.data shortDescription], self); |
| NSLog(@"Observed error: %@ while reading data for %@", requestError, self); |
| } |
| } |
| |
| @end |
| |
| #pragma mark - Platform testing helper functions |
| |
| #if PLATFORM(IOS) |
| |
| typedef void(^ItemProviderDataLoadHandler)(NSData *, NSError *); |
| |
| @implementation NSItemProvider (AttachmentTesting) |
| |
| - (void)registerData:(NSData *)data type:(NSString *)type |
| { |
| [self registerDataRepresentationForTypeIdentifier:type visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[protectedData = retainPtr(data)] (ItemProviderDataLoadHandler completionHandler) -> NSProgress * { |
| completionHandler(protectedData.get(), nil); |
| return nil; |
| }]; |
| } |
| |
| - (void)expectType:(NSString *)type withData:(NSData *)expectedData |
| { |
| BOOL containsType = [self.registeredTypeIdentifiers containsObject:type]; |
| EXPECT_TRUE(containsType); |
| if (!containsType) { |
| NSLog(@"Expected: %@ to contain %@", self, type); |
| return; |
| } |
| |
| __block bool done = false; |
| [self loadDataRepresentationForTypeIdentifier:type completionHandler:^(NSData *observedData, NSError *error) { |
| EXPECT_TRUE([observedData isEqualToData:expectedData]); |
| if (![observedData isEqualToData:expectedData]) |
| NSLog(@"Expected data: <%tu bytes> to be equal to data: <%tu bytes>", observedData.length, expectedData.length); |
| EXPECT_TRUE(!error); |
| if (error) |
| NSLog(@"Encountered error when loading data: %@", error); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| @end |
| |
| #endif // PLATFORM(IOS) |
| |
| void platformCopyRichTextWithMultipleAttachments() |
| { |
| auto image = adoptNS([[NSTextAttachment alloc] initWithData:testImageData() ofType:(NSString *)kUTTypePNG]); |
| auto pdf = adoptNS([[NSTextAttachment alloc] initWithData:testPDFData() ofType:(NSString *)kUTTypePDF]); |
| auto zip = adoptNS([[NSTextAttachment alloc] initWithData:testZIPData() ofType:(NSString *)kUTTypeZipArchive]); |
| |
| auto richText = adoptNS([[NSMutableAttributedString alloc] init]); |
| [richText appendAttributedString:[NSAttributedString attributedStringWithAttachment:image.get()]]; |
| [richText appendAttributedString:[NSAttributedString attributedStringWithAttachment:pdf.get()]]; |
| [richText appendAttributedString:[NSAttributedString attributedStringWithAttachment:zip.get()]]; |
| |
| #if PLATFORM(MAC) |
| NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; |
| [pasteboard clearContents]; |
| [pasteboard writeObjects:@[ richText.get() ]]; |
| #elif PLATFORM(IOS) |
| auto item = adoptNS([[NSItemProvider alloc] init]); |
| [item registerObject:richText.get() visibility:NSItemProviderRepresentationVisibilityAll]; |
| [UIPasteboard generalPasteboard].itemProviders = @[ item.get() ]; |
| #endif |
| } |
| |
| void platformCopyRichTextWithImage() |
| { |
| auto richText = adoptNS([[NSMutableAttributedString alloc] init]); |
| auto image = adoptNS([[NSTextAttachment alloc] initWithData:testImageData() ofType:(NSString *)kUTTypePNG]); |
| |
| [richText appendAttributedString:[[[NSAttributedString alloc] initWithString:@"Lorem ipsum "] autorelease]]; |
| [richText appendAttributedString:[NSAttributedString attributedStringWithAttachment:image.get()]]; |
| [richText appendAttributedString:[[[NSAttributedString alloc] initWithString:@" dolor sit amet."] autorelease]]; |
| |
| #if PLATFORM(MAC) |
| NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; |
| [pasteboard clearContents]; |
| [pasteboard writeObjects:@[ richText.get() ]]; |
| #elif PLATFORM(IOS) |
| auto item = adoptNS([[NSItemProvider alloc] init]); |
| [item registerObject:richText.get() visibility:NSItemProviderRepresentationVisibilityAll]; |
| [UIPasteboard generalPasteboard].itemProviders = @[ item.get() ]; |
| #endif |
| } |
| |
| void platformCopyPNG() |
| { |
| #if PLATFORM(MAC) |
| NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; |
| [pasteboard declareTypes:@[NSPasteboardTypePNG] owner:nil]; |
| [pasteboard setData:testImageData() forType:NSPasteboardTypePNG]; |
| #elif PLATFORM(IOS) |
| UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; |
| auto item = adoptNS([[UIItemProvider alloc] init]); |
| [item setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment]; |
| [item registerData:testImageData() type:(NSString *)kUTTypePNG]; |
| pasteboard.itemProviders = @[ item.get() ]; |
| #endif |
| } |
| |
| #if PLATFORM(MAC) |
| typedef NSImage PlatformImage; |
| #else |
| typedef UIImage PlatformImage; |
| #endif |
| |
| PlatformImage *platformImageWithData(NSData *data) |
| { |
| #if PLATFORM(MAC) |
| return [[[NSImage alloc] initWithData:data] autorelease]; |
| #else |
| return [UIImage imageWithData:data]; |
| #endif |
| } |
| |
| namespace TestWebKitAPI { |
| |
| #pragma mark - Platform-agnostic tests |
| |
| TEST(WKAttachmentTests, AttachmentElementInsertion) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> firstAttachment; |
| RetainPtr<_WKAttachment> secondAttachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| // Use the given content type for the attachment element's type. |
| firstAttachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo" contentType:@"text/html" data:testHTMLData() options:nil]; |
| EXPECT_WK_STREQ(@"foo", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"text/html", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"38 bytes", [webView valueOfAttribute:@"subtitle" forQuerySelector:@"attachment"]); |
| observer.expectAttachmentUpdates(@[ ], @[ firstAttachment.get() ]); |
| } |
| |
| _WKAttachmentInfo *info = [firstAttachment synchronouslyRequestInfo:nil]; |
| EXPECT_TRUE([info.data isEqualToData:testHTMLData()]); |
| EXPECT_TRUE([info.contentType isEqualToString:@"text/html"]); |
| EXPECT_TRUE([info.name isEqualToString:@"foo"]); |
| EXPECT_EQ(info.filePath.length, 0U); |
| |
| { |
| ObserveAttachmentUpdatesForScope scope(webView.get()); |
| // Since no content type is explicitly specified, compute it from the file extension. |
| [webView _executeEditCommand:@"DeleteBackward" argument:nil completion:nil]; |
| secondAttachment = [webView synchronouslyInsertAttachmentWithFilename:@"bar.png" contentType:nil data:testImageData() options:nil]; |
| EXPECT_WK_STREQ(@"bar.png", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"image/png", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"37 KB", [webView valueOfAttribute:@"subtitle" forQuerySelector:@"attachment"]); |
| scope.expectAttachmentUpdates(@[ firstAttachment.get() ], @[ secondAttachment.get() ]); |
| } |
| |
| [firstAttachment expectRequestedDataToBe:nil]; |
| [secondAttachment expectRequestedDataToBe:testImageData()]; |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentbloburl" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentpath" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentid" forQuerySelector:@"attachment"]); |
| } |
| |
| TEST(WKAttachmentTests, AttachmentUpdatesWhenInsertingAndDeletingNewline) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo.txt" contentType:@"text/plain" data:testHTMLData() options:nil]; |
| observer.expectAttachmentUpdates(@[ ], @[attachment.get()]); |
| } |
| [webView expectUpdatesAfterCommand:@"InsertParagraph" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView stringByEvaluatingJavaScript:@"getSelection().collapse(document.body)"]; |
| [webView expectUpdatesAfterCommand:@"InsertParagraph" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| |
| [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| |
| _WKAttachmentInfo *info = [attachment synchronouslyRequestInfo:nil]; |
| EXPECT_TRUE([info.data isEqualToData:testHTMLData()]); |
| EXPECT_TRUE([info.contentType isEqualToString:@"text/plain"]); |
| EXPECT_TRUE([info.name isEqualToString:@"foo.txt"]); |
| EXPECT_EQ(info.filePath.length, 0U); |
| |
| [webView expectUpdatesAfterCommand:@"DeleteForward" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| [attachment expectRequestedDataToBe:nil]; |
| } |
| |
| TEST(WKAttachmentTests, AttachmentUpdatesWhenUndoingAndRedoing) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<NSData> htmlData = testHTMLData(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo.txt" contentType:@"text/plain" data:testHTMLData() options:nil]; |
| observer.expectAttachmentUpdates(@[ ], @[attachment.get()]); |
| } |
| [webView expectUpdatesAfterCommand:@"Undo" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| [attachment expectRequestedDataToBe:nil]; |
| |
| [webView expectUpdatesAfterCommand:@"Redo" withArgument:nil expectedRemovals:@[] expectedInsertions:@[attachment.get()]]; |
| [attachment expectRequestedDataToBe:htmlData.get()]; |
| |
| [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| [attachment expectRequestedDataToBe:nil]; |
| |
| [webView expectUpdatesAfterCommand:@"Undo" withArgument:nil expectedRemovals:@[] expectedInsertions:@[attachment.get()]]; |
| [attachment expectRequestedDataToBe:htmlData.get()]; |
| |
| [webView expectUpdatesAfterCommand:@"Redo" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| [attachment expectRequestedDataToBe:nil]; |
| } |
| |
| TEST(WKAttachmentTests, AttachmentUpdatesWhenChangingFontStyles) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> attachment; |
| [webView _synchronouslyExecuteEditCommand:@"InsertText" argument:@"Hello"]; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo.txt" contentType:@"text/plain" data:testHTMLData() options:nil]; |
| observer.expectAttachmentUpdates(@[ ], @[attachment.get()]); |
| } |
| [webView expectUpdatesAfterCommand:@"InsertText" withArgument:@"World" expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| [webView expectUpdatesAfterCommand:@"ToggleBold" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView expectUpdatesAfterCommand:@"ToggleItalic" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView expectUpdatesAfterCommand:@"ToggleUnderline" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [attachment expectRequestedDataToBe:testHTMLData()]; |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentbloburl" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentpath" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentid" forQuerySelector:@"attachment"]); |
| |
| // Inserting text should delete the current selection, removing the attachment in the process. |
| [webView expectUpdatesAfterCommand:@"InsertText" withArgument:@"foo" expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| [attachment expectRequestedDataToBe:nil]; |
| } |
| |
| TEST(WKAttachmentTests, AttachmentUpdatesWhenInsertingLists) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo.txt" contentType:@"text/plain" data:testHTMLData() options:nil]; |
| observer.expectAttachmentUpdates(@[ ], @[attachment.get()]); |
| } |
| [webView expectUpdatesAfterCommand:@"InsertOrderedList" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| // This edit command behaves more like a "toggle", and will actually break us out of the list we just inserted. |
| [webView expectUpdatesAfterCommand:@"InsertOrderedList" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView expectUpdatesAfterCommand:@"InsertUnorderedList" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView expectUpdatesAfterCommand:@"InsertUnorderedList" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [attachment expectRequestedDataToBe:testHTMLData()]; |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentbloburl" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentpath" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentid" forQuerySelector:@"attachment"]); |
| } |
| |
| TEST(WKAttachmentTests, AttachmentUpdatesWhenInsertingRichMarkup) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"InsertHTML" argument:@"<div><strong><attachment src='cid:123-4567' title='a'></attachment></strong></div>"]; |
| attachment = observer.observer().inserted[0]; |
| observer.expectAttachmentUpdates(@[ ], @[attachment.get()]); |
| observer.expectSourceForIdentifier(@"cid:123-4567", [attachment uniqueIdentifier]); |
| } |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentbloburl" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentpath" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentid" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ([attachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').uniqueIdentifier"]); |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').remove()"]; |
| [webView waitForNextPresentationUpdate]; |
| observer.expectAttachmentUpdates(@[attachment.get()], @[ ]); |
| } |
| [attachment expectRequestedDataToBe:nil]; |
| } |
| |
| TEST(WKAttachmentTests, AttachmentUpdatesWhenCuttingAndPasting) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo.txt" contentType:@"text/plain" data:testHTMLData() options:nil]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| [attachment expectRequestedDataToBe:testHTMLData()]; |
| EXPECT_WK_STREQ([attachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').uniqueIdentifier"]); |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Cut" argument:nil]; |
| observer.expectAttachmentUpdates(@[attachment.get()], @[]); |
| } |
| [attachment expectRequestedDataToBe:nil]; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| [attachment expectRequestedDataToBe:testHTMLData()]; |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentbloburl" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentpath" forQuerySelector:@"attachment"]); |
| EXPECT_FALSE([webView hasAttribute:@"webkitattachmentid" forQuerySelector:@"attachment"]); |
| } |
| |
| TEST(WKAttachmentTests, AttachmentDataForEmptyFile) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"empty.txt" contentType:@"text/plain" data:[NSData data] options:nil]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| [attachment expectRequestedDataToBe:[NSData data]]; |
| EXPECT_WK_STREQ([attachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').uniqueIdentifier"]); |
| { |
| ObserveAttachmentUpdatesForScope scope(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| scope.expectAttachmentUpdates(@[attachment.get()], @[]); |
| } |
| [attachment expectRequestedDataToBe:nil]; |
| } |
| |
| TEST(WKAttachmentTests, InsertedImageSizeIsClampedByMaxWidth) |
| { |
| auto webView = webViewForTestingAttachments(CGSizeMake(100, 100)); |
| RetainPtr<NSData> imageData = testImageData(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"icon.png" contentType:@"image/png" data:imageData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]; |
| [attachment expectRequestedDataToBe:imageData.get()]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(84, 67)]; |
| } |
| |
| TEST(WKAttachmentTests, MultipleSimultaneousAttachmentDataRequests) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<NSData> htmlData = testHTMLData(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo.txt" contentType:@"text/plain" data:htmlData.get() options:nil]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| __block RetainPtr<NSData> dataForFirstRequest; |
| __block RetainPtr<NSData> dataForSecondRequest; |
| __block bool done = false; |
| [attachment requestInfo:^(_WKAttachmentInfo *info, NSError *error) { |
| EXPECT_TRUE(!error); |
| dataForFirstRequest = info.data; |
| }]; |
| [attachment requestInfo:^(_WKAttachmentInfo *info, NSError *error) { |
| EXPECT_TRUE(!error); |
| dataForSecondRequest = info.data; |
| done = true; |
| }]; |
| |
| Util::run(&done); |
| |
| EXPECT_TRUE([dataForFirstRequest isEqualToData:htmlData.get()]); |
| EXPECT_TRUE([dataForSecondRequest isEqualToData:htmlData.get()]); |
| } |
| |
| TEST(WKAttachmentTests, InPlaceImageAttachmentToggleDisplayMode) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<NSData> imageData = testImageData(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"icon.png" contentType:@"image/png" data:imageData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeAsIcon)]; |
| [attachment expectRequestedDataToBe:imageData.get()]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| CGSize iconAttachmentSize = [webView attachmentElementSize]; |
| |
| [attachment synchronouslySetDisplayOptions:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace) error:nil]; |
| [attachment expectRequestedDataToBe:imageData.get()]; |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(215, 174)]; |
| |
| [attachment synchronouslySetDisplayOptions:displayOptionsWithMode(_WKAttachmentDisplayModeAsIcon) error:nil]; |
| [attachment expectRequestedDataToBe:imageData.get()]; |
| [webView waitForAttachmentElementSizeToBecome:iconAttachmentSize]; |
| |
| [attachment synchronouslySetDisplayOptions:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace) error:nil]; |
| [attachment expectRequestedDataToBe:imageData.get()]; |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(215, 174)]; |
| } |
| |
| TEST(WKAttachmentTests, InPlaceImageAttachmentParagraphInsertion) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<NSData> imageData = testImageData(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"icon.png" contentType:@"image/png" data:imageData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| [webView expectUpdatesAfterCommand:@"InsertParagraph" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView stringByEvaluatingJavaScript:@"getSelection().collapse(document.body)"]; |
| [webView expectUpdatesAfterCommand:@"InsertParagraph" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| |
| [attachment expectRequestedDataToBe:imageData.get()]; |
| EXPECT_WK_STREQ([attachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').uniqueIdentifier"]); |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(215, 174)]; |
| |
| [webView expectUpdatesAfterCommand:@"DeleteForward" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| } |
| |
| TEST(WKAttachmentTests, InPlaceVideoAttachmentInsertionWithinList) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<NSData> videoData = testVideoData(); |
| RetainPtr<_WKAttachment> attachment; |
| |
| [webView _synchronouslyExecuteEditCommand:@"InsertOrderedList" argument:nil]; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"test.mp4" contentType:@"video/mp4" data:videoData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(320, 240)]; |
| |
| [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| [webView expectUpdatesAfterCommand:@"Undo" withArgument:nil expectedRemovals:@[] expectedInsertions:@[attachment.get()]]; |
| [webView expectUpdatesAfterCommand:@"InsertOrderedList" withArgument:nil expectedRemovals:@[] expectedInsertions:@[]]; |
| |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(320, 240)]; |
| [attachment expectRequestedDataToBe:videoData.get()]; |
| } |
| |
| TEST(WKAttachmentTests, InPlacePDFAttachmentCutAndPaste) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<NSData> pdfData = testPDFData(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"test.pdf" contentType:@"application/pdf" data:pdfData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(130, 29)]; |
| } |
| |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| [webView expectUpdatesAfterCommand:@"Cut" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| |
| [webView expectUpdatesAfterCommand:@"Paste" withArgument:nil expectedRemovals:@[] expectedInsertions:@[attachment.get()]]; |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(130, 29)]; |
| [attachment expectRequestedDataToBe:pdfData.get()]; |
| } |
| |
| TEST(WKAttachmentTests, ChangeAttachmentDataAndFileInformation) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| RetainPtr<NSData> pdfData = testPDFData(); |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"test.pdf" contentType:@"application/pdf" data:pdfData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeAsIcon)]; |
| [attachment expectRequestedDataToBe:pdfData.get()]; |
| EXPECT_WK_STREQ(@"test.pdf", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"application/pdf", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| { |
| RetainPtr<NSData> imageData = testImageData(); |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [attachment synchronouslySetData:imageData.get() newContentType:@"image/png" newFilename:@"icon.png" error:nil]; |
| [attachment expectRequestedDataToBe:imageData.get()]; |
| EXPECT_WK_STREQ(@"icon.png", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"image/png", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| observer.expectAttachmentUpdates(@[], @[]); |
| } |
| { |
| RetainPtr<NSData> textData = testHTMLData(); |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [attachment synchronouslySetDisplayOptions:displayOptionsWithMode(_WKAttachmentDisplayModeAsIcon) error:nil]; |
| // The new content type should be inferred from the file name. |
| [attachment synchronouslySetData:textData.get() newContentType:nil newFilename:@"foo.txt" error:nil]; |
| [attachment expectRequestedDataToBe:textData.get()]; |
| EXPECT_WK_STREQ(@"foo.txt", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"text/plain", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| observer.expectAttachmentUpdates(@[], @[]); |
| } |
| { |
| RetainPtr<NSData> secondTextData = [@"Hello world" dataUsingEncoding:NSUTF8StringEncoding]; |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| // Both the previous file name and type should be inferred. |
| [attachment synchronouslySetData:secondTextData.get() newContentType:nil newFilename:nil error:nil]; |
| [attachment expectRequestedDataToBe:secondTextData.get()]; |
| EXPECT_WK_STREQ(@"foo.txt", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"text/plain", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| observer.expectAttachmentUpdates(@[], @[]); |
| } |
| [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| } |
| |
| TEST(WKAttachmentTests, ChangeAttachmentDataUpdatesWithInPlaceDisplay) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| RetainPtr<NSData> pdfData = testPDFData(); |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"test.pdf" contentType:@"application/pdf" data:pdfData.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]; |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(130, 29)]; |
| [attachment expectRequestedDataToBe:pdfData.get()]; |
| EXPECT_WK_STREQ(@"test.pdf", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"application/pdf", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| { |
| RetainPtr<NSData> videoData = testVideoData(); |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [attachment synchronouslySetData:videoData.get() newContentType:@"video/mp4" newFilename:@"test.mp4" error:nil]; |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(320, 240)]; |
| [attachment expectRequestedDataToBe:videoData.get()]; |
| EXPECT_WK_STREQ(@"test.mp4", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"video/mp4", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| observer.expectAttachmentUpdates(@[], @[]); |
| } |
| { |
| RetainPtr<NSData> imageData = testImageData(); |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [attachment synchronouslySetData:imageData.get() newContentType:@"image/png" newFilename:@"icon.png" error:nil]; |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(215, 174)]; |
| [attachment expectRequestedDataToBe:imageData.get()]; |
| EXPECT_WK_STREQ(@"icon.png", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ(@"image/png", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| observer.expectAttachmentUpdates(@[], @[]); |
| } |
| [webView expectUpdatesAfterCommand:@"DeleteBackward" withArgument:nil expectedRemovals:@[attachment.get()] expectedInsertions:@[]]; |
| } |
| |
| TEST(WKAttachmentTests, InsertPastedImageAsAttachment) |
| { |
| platformCopyPNG(); |
| |
| RetainPtr<_WKAttachment> attachment; |
| auto webView = webViewForTestingAttachments(); |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| EXPECT_EQ(1U, observer.observer().inserted.count); |
| attachment = observer.observer().inserted[0]; |
| } |
| |
| auto size = platformImageWithData([attachment synchronouslyRequestData:nil]).size; |
| EXPECT_EQ(215., size.width); |
| EXPECT_EQ(174., size.height); |
| EXPECT_WK_STREQ([attachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').uniqueIdentifier"]); |
| |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| observer.expectAttachmentUpdates(@[attachment.get()], @[]); |
| } |
| } |
| |
| TEST(WKAttachmentTests, InsertPastedAttributedStringContainingImage) |
| { |
| platformCopyRichTextWithImage(); |
| |
| RetainPtr<_WKAttachment> attachment; |
| auto webView = webViewForTestingAttachments(); |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| EXPECT_EQ(0U, observer.observer().removed.count); |
| EXPECT_EQ(1U, observer.observer().inserted.count); |
| attachment = observer.observer().inserted[0]; |
| } |
| |
| [attachment expectRequestedDataToBe:testImageData()]; |
| EXPECT_WK_STREQ("Lorem ipsum dolor sit amet.", [webView stringByEvaluatingJavaScript:@"document.body.textContent"]); |
| EXPECT_WK_STREQ("image/png", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ([attachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelector('attachment').uniqueIdentifier"]); |
| |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| observer.expectAttachmentUpdates(@[attachment.get()], @[]); |
| } |
| } |
| |
| TEST(WKAttachmentTests, InsertPastedAttributedStringContainingMultipleAttachments) |
| { |
| platformCopyRichTextWithMultipleAttachments(); |
| |
| RetainPtr<_WKAttachment> imageAttachment; |
| RetainPtr<_WKAttachment> zipAttachment; |
| RetainPtr<_WKAttachment> pdfAttachment; |
| auto webView = webViewForTestingAttachments(); |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| EXPECT_EQ(0U, observer.observer().removed.count); |
| EXPECT_EQ(3U, observer.observer().inserted.count); |
| for (_WKAttachment *attachment in observer.observer().inserted) { |
| NSData *data = [attachment synchronouslyRequestData:nil]; |
| if ([data isEqualToData:testZIPData()]) |
| zipAttachment = attachment; |
| else if ([data isEqualToData:testPDFData()]) |
| pdfAttachment = attachment; |
| else if ([data isEqualToData:testImageData()]) |
| imageAttachment = attachment; |
| } |
| } |
| |
| EXPECT_TRUE(zipAttachment && imageAttachment && pdfAttachment); |
| EXPECT_EQ(3, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment').length"].integerValue); |
| EXPECT_WK_STREQ("image/png", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]); |
| EXPECT_WK_STREQ("application/pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]); |
| |
| NSString *zipAttachmentType = [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[2].getAttribute('type')"]; |
| #if USES_MODERN_ATTRIBUTED_STRING_CONVERSION |
| EXPECT_WK_STREQ("application/zip", zipAttachmentType); |
| #else |
| EXPECT_WK_STREQ("application/octet-stream", zipAttachmentType); |
| #endif |
| |
| EXPECT_WK_STREQ([imageAttachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].uniqueIdentifier"]); |
| EXPECT_WK_STREQ([pdfAttachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].uniqueIdentifier"]); |
| EXPECT_WK_STREQ([zipAttachment uniqueIdentifier], [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[2].uniqueIdentifier"]); |
| |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| NSArray<_WKAttachment *> *removedAttachments = [observer.observer() removed]; |
| EXPECT_EQ(3U, removedAttachments.count); |
| EXPECT_TRUE([removedAttachments containsObject:zipAttachment.get()]); |
| EXPECT_TRUE([removedAttachments containsObject:imageAttachment.get()]); |
| EXPECT_TRUE([removedAttachments containsObject:pdfAttachment.get()]); |
| } |
| } |
| |
| TEST(WKAttachmentTests, DoNotInsertDataURLImagesAsAttachments) |
| { |
| auto webContentSourceView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]); |
| [webContentSourceView synchronouslyLoadTestPageNamed:@"apple-data-url"]; |
| [webContentSourceView selectAll:nil]; |
| [webContentSourceView _synchronouslyExecuteEditCommand:@"Copy" argument:nil]; |
| |
| auto webView = webViewForTestingAttachments(); |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| EXPECT_EQ(0U, observer.observer().inserted.count); |
| } |
| |
| EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"Boolean(document.querySelector('attachment'))"].boolValue); |
| EXPECT_EQ(1990, [webView stringByEvaluatingJavaScript:@"document.querySelector('img').src.length"].integerValue); |
| EXPECT_WK_STREQ("This is an apple", [webView stringByEvaluatingJavaScript:@"document.body.textContent"]); |
| } |
| |
| TEST(WKAttachmentTests, InsertAndRemoveDuplicateAttachment) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<NSData> data = testHTMLData(); |
| RetainPtr<_WKAttachment> originalAttachment; |
| RetainPtr<_WKAttachment> pastedAttachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| originalAttachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo.txt" contentType:@"text/plain" data:data.get() options:nil]; |
| EXPECT_EQ(0U, observer.observer().removed.count); |
| observer.expectAttachmentUpdates(@[], @[originalAttachment.get()]); |
| } |
| [webView selectAll:nil]; |
| [webView _executeEditCommand:@"Copy" argument:nil completion:nil]; |
| [webView evaluateJavaScript:@"getSelection().collapseToEnd()" completionHandler:nil]; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| EXPECT_EQ(0U, observer.observer().removed.count); |
| EXPECT_EQ(1U, observer.observer().inserted.count); |
| pastedAttachment = observer.observer().inserted.firstObject; |
| EXPECT_FALSE([pastedAttachment isEqual:originalAttachment.get()]); |
| } |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| observer.expectAttachmentUpdates(@[pastedAttachment.get()], @[]); |
| [originalAttachment expectRequestedDataToBe:data.get()]; |
| } |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| observer.expectAttachmentUpdates(@[originalAttachment.get()], @[]); |
| } |
| } |
| |
| TEST(WKAttachmentTests, InsertDuplicateAttachmentAndUpdateData) |
| { |
| auto webView = webViewForTestingAttachments(); |
| RetainPtr<NSData> originalData = testHTMLData(); |
| RetainPtr<_WKAttachment> originalAttachment; |
| RetainPtr<_WKAttachment> pastedAttachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| originalAttachment = [webView synchronouslyInsertAttachmentWithFilename:@"foo.txt" contentType:@"text/plain" data:originalData.get() options:nil]; |
| EXPECT_EQ(0U, observer.observer().removed.count); |
| observer.expectAttachmentUpdates(@[], @[originalAttachment.get()]); |
| } |
| [webView selectAll:nil]; |
| [webView _executeEditCommand:@"Copy" argument:nil completion:nil]; |
| [webView evaluateJavaScript:@"getSelection().collapseToEnd()" completionHandler:nil]; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| EXPECT_EQ(0U, observer.observer().removed.count); |
| EXPECT_EQ(1U, observer.observer().inserted.count); |
| pastedAttachment = observer.observer().inserted.firstObject; |
| EXPECT_FALSE([pastedAttachment isEqual:originalAttachment.get()]); |
| } |
| auto updatedData = retainPtr([@"HELLO WORLD" dataUsingEncoding:NSUTF8StringEncoding]); |
| [originalAttachment synchronouslySetData:updatedData.get() newContentType:nil newFilename:nil error:nil]; |
| [originalAttachment expectRequestedDataToBe:updatedData.get()]; |
| [pastedAttachment expectRequestedDataToBe:originalData.get()]; |
| } |
| |
| TEST(WKAttachmentTests, InjectedBundleReplaceURLsWhenPastingAttributedString) |
| { |
| platformCopyRichTextWithMultipleAttachments(); |
| |
| auto configuration = retainPtr([WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"]); |
| [[configuration processPool] _setObject:@{ @"image/png" : @"cid:foo-bar" } forBundleParameter:@"MIMETypeToReplacementURLMap"]; |
| auto webView = webViewForTestingAttachments(CGSizeMake(500, 500), configuration.get()); |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| EXPECT_EQ(2U, observer.observer().inserted.count); |
| } |
| [webView expectElementTagsInOrder:@[ @"IMG", @"ATTACHMENT", @"ATTACHMENT" ]]; |
| EXPECT_WK_STREQ("cid:foo-bar", [webView valueOfAttribute:@"src" forQuerySelector:@"img"]); |
| } |
| |
| TEST(WKAttachmentTests, InjectedBundleReplaceURLWhenPastingImage) |
| { |
| platformCopyPNG(); |
| |
| NSString *replacementURL = @"cid:foo-bar"; |
| auto configuration = retainPtr([WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"]); |
| [[configuration processPool] _setObject:@{ @"image/tiff" : replacementURL, @"image/png" : replacementURL } forBundleParameter:@"MIMETypeToReplacementURLMap"]; |
| auto webView = webViewForTestingAttachments(CGSizeMake(500, 500), configuration.get()); |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| EXPECT_EQ(0U, observer.observer().inserted.count); |
| } |
| EXPECT_WK_STREQ("cid:foo-bar", [webView valueOfAttribute:@"src" forQuerySelector:@"img"]); |
| } |
| |
| #pragma mark - Platform-specific tests |
| |
| #if PLATFORM(MAC) |
| |
| TEST(WKAttachmentTestsMac, InsertPastedFileURLsAsAttachments) |
| { |
| NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; |
| [pasteboard clearContents]; |
| [pasteboard declareTypes:@[NSFilenamesPboardType] owner:nil]; |
| [pasteboard setPropertyList:@[testPDFFileURL().path, testImageFileURL().path] forType:NSFilenamesPboardType]; |
| |
| RetainPtr<NSArray<_WKAttachment *>> insertedAttachments; |
| auto webView = webViewForTestingAttachments(); |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil]; |
| insertedAttachments = [observer.observer() inserted]; |
| EXPECT_EQ(2U, [insertedAttachments count]); |
| } |
| |
| NSArray<NSData *> *expectedAttachmentData = @[ testPDFData(), testImageData() ]; |
| EXPECT_TRUE([expectedAttachmentData containsObject:[[insertedAttachments firstObject] synchronouslyRequestData:nil]]); |
| EXPECT_TRUE([expectedAttachmentData containsObject:[[insertedAttachments lastObject] synchronouslyRequestData:nil]]); |
| EXPECT_WK_STREQ("application/pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]); |
| EXPECT_WK_STREQ("test.pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('title')"]); |
| EXPECT_WK_STREQ("image/png", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]); |
| EXPECT_WK_STREQ("icon.png", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('title')"]); |
| |
| for (_WKAttachment *attachment in insertedAttachments.get()) { |
| _WKAttachmentInfo *info = [attachment synchronouslyRequestInfo:nil]; |
| EXPECT_GT(info.filePath.length, 0U); |
| } |
| |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| NSArray<_WKAttachment *> *removedAttachments = [observer.observer() removed]; |
| EXPECT_EQ(2U, removedAttachments.count); |
| EXPECT_TRUE([removedAttachments containsObject:[insertedAttachments firstObject]]); |
| EXPECT_TRUE([removedAttachments.lastObject isEqual:[insertedAttachments lastObject]]); |
| } |
| } |
| |
| #endif // PLATFORM(MAC) |
| |
| #if PLATFORM(IOS) |
| |
| TEST(WKAttachmentTestsIOS, InsertDroppedImageAsAttachment) |
| { |
| auto webView = webViewForTestingAttachments(); |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| auto item = adoptNS([[NSItemProvider alloc] init]); |
| [item registerData:testImageData() type:(NSString *)kUTTypePNG]; |
| [draggingSimulator setExternalItemProviders:@[ item.get() ]]; |
| [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)]; |
| |
| EXPECT_EQ(1U, [draggingSimulator insertedAttachments].count); |
| EXPECT_EQ(0U, [draggingSimulator removedAttachments].count); |
| auto attachment = retainPtr([draggingSimulator insertedAttachments].firstObject); |
| [attachment expectRequestedDataToBe:testImageData()]; |
| EXPECT_WK_STREQ("public.png", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| observer.expectAttachmentUpdates(@[attachment.get()], @[]); |
| } |
| } |
| |
| TEST(WKAttachmentTestsIOS, InsertDroppedAttributedStringContainingAttachment) |
| { |
| auto webView = webViewForTestingAttachments(); |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| auto image = adoptNS([[NSTextAttachment alloc] initWithData:testImageData() ofType:(NSString *)kUTTypePNG]); |
| auto item = adoptNS([[NSItemProvider alloc] init]); |
| [item registerObject:[NSAttributedString attributedStringWithAttachment:image.get()] visibility:NSItemProviderRepresentationVisibilityAll]; |
| |
| [draggingSimulator setExternalItemProviders:@[ item.get() ]]; |
| [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)]; |
| |
| EXPECT_EQ(1U, [draggingSimulator insertedAttachments].count); |
| EXPECT_EQ(0U, [draggingSimulator removedAttachments].count); |
| auto attachment = retainPtr([draggingSimulator insertedAttachments].firstObject); |
| |
| auto size = platformImageWithData([attachment synchronouslyRequestData:nil]).size; |
| EXPECT_EQ(215., size.width); |
| EXPECT_EQ(174., size.height); |
| EXPECT_WK_STREQ("image/png", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| [webView _synchronouslyExecuteEditCommand:@"SelectAll" argument:nil]; |
| [webView _synchronouslyExecuteEditCommand:@"DeleteBackward" argument:nil]; |
| observer.expectAttachmentUpdates(@[attachment.get()], @[]); |
| } |
| } |
| |
| TEST(WKAttachmentTestsIOS, InsertDroppedRichAndPlainTextFilesAsAttachments) |
| { |
| // Here, both rich text and plain text are content types that WebKit already understands how to insert in editable |
| // areas in the absence of attachment elements. However, due to the explicitly set attachment presentation style |
| // on the item providers, we should instead treat them as dropped files and insert attachment elements. |
| // This exercises the scenario of dragging rich and plain text files from Files to Mail. |
| auto richTextItem = adoptNS([[NSItemProvider alloc] init]); |
| auto richText = adoptNS([[NSAttributedString alloc] initWithString:@"Hello world" attributes:@{ NSFontAttributeName: [UIFont boldSystemFontOfSize:12] }]); |
| [richTextItem setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment]; |
| [richTextItem registerObject:richText.get() visibility:NSItemProviderRepresentationVisibilityAll]; |
| [richTextItem setSuggestedName:@"hello.rtf"]; |
| |
| auto plainTextItem = adoptNS([[NSItemProvider alloc] init]); |
| [plainTextItem setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment]; |
| [plainTextItem registerObject:@"Hello world" visibility:NSItemProviderRepresentationVisibilityAll]; |
| [plainTextItem setSuggestedName:@"world.txt"]; |
| |
| auto webView = webViewForTestingAttachments(); |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| [draggingSimulator setExternalItemProviders:@[ richTextItem.get(), plainTextItem.get() ]]; |
| [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)]; |
| |
| EXPECT_EQ(2U, [draggingSimulator insertedAttachments].count); |
| EXPECT_EQ(0U, [draggingSimulator removedAttachments].count); |
| |
| for (_WKAttachment *attachment in [draggingSimulator insertedAttachments]) { |
| NSError *error = nil; |
| EXPECT_GT([attachment synchronouslyRequestData:&error].length, 0U); |
| EXPECT_TRUE(!error); |
| if (error) |
| NSLog(@"Error: %@", error); |
| } |
| |
| EXPECT_EQ(2, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment').length"].intValue); |
| EXPECT_WK_STREQ("hello.rtf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('title')"]); |
| EXPECT_WK_STREQ("text/rtf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]); |
| EXPECT_WK_STREQ("world.txt", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('title')"]); |
| EXPECT_WK_STREQ("text/plain", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]); |
| } |
| |
| TEST(WKAttachmentTestsIOS, InsertDroppedZipArchiveAsAttachment) |
| { |
| // Since WebKit doesn't have any default DOM representation for ZIP archives, we should fall back to inserting |
| // attachment elements. This exercises the flow of dragging a ZIP file from an app that doesn't specify a preferred |
| // presentation style (e.g. Notes) into Mail. |
| auto item = adoptNS([[NSItemProvider alloc] init]); |
| NSData *data = testZIPData(); |
| [item registerData:data type:(NSString *)kUTTypeZipArchive]; |
| [item setSuggestedName:@"archive.zip"]; |
| |
| auto webView = webViewForTestingAttachments(); |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| [draggingSimulator setExternalItemProviders:@[ item.get() ]]; |
| [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)]; |
| |
| EXPECT_EQ(1U, [draggingSimulator insertedAttachments].count); |
| EXPECT_EQ(0U, [draggingSimulator removedAttachments].count); |
| [[draggingSimulator insertedAttachments].firstObject expectRequestedDataToBe:data]; |
| EXPECT_EQ(1, [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment').length"].intValue); |
| EXPECT_WK_STREQ("archive.zip", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ("application/zip", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| } |
| |
| TEST(WKAttachmentTestsIOS, InsertDroppedItemProvidersInOrder) |
| { |
| // Tests that item providers are inserted in the order they are specified. In this case, the two inserted attachments |
| // should be separated by a link. |
| auto firstAttachmentItem = adoptNS([[NSItemProvider alloc] init]); |
| [firstAttachmentItem setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment]; |
| [firstAttachmentItem registerObject:@"FIRST" visibility:NSItemProviderRepresentationVisibilityAll]; |
| [firstAttachmentItem setSuggestedName:@"first.txt"]; |
| |
| auto inlineTextItem = adoptNS([[NSItemProvider alloc] init]); |
| auto appleURL = retainPtr([NSURL URLWithString:@"https://www.apple.com/"]); |
| [inlineTextItem registerObject:appleURL.get() visibility:NSItemProviderRepresentationVisibilityAll]; |
| |
| auto secondAttachmentItem = adoptNS([[NSItemProvider alloc] init]); |
| [secondAttachmentItem registerData:testPDFData() type:(NSString *)kUTTypePDF]; |
| [secondAttachmentItem setSuggestedName:@"second.pdf"]; |
| |
| auto webView = webViewForTestingAttachments(); |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| [draggingSimulator setExternalItemProviders:@[ firstAttachmentItem.get(), inlineTextItem.get(), secondAttachmentItem.get() ]]; |
| [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)]; |
| |
| EXPECT_EQ(2U, [draggingSimulator insertedAttachments].count); |
| EXPECT_EQ(0U, [draggingSimulator removedAttachments].count); |
| |
| for (_WKAttachment *attachment in [draggingSimulator insertedAttachments]) { |
| NSError *error = nil; |
| EXPECT_GT([attachment synchronouslyRequestData:&error].length, 0U); |
| EXPECT_TRUE(!error); |
| if (error) |
| NSLog(@"Error: %@", error); |
| } |
| |
| NSArray *observedElementTags = (NSArray *)[webView objectByEvaluatingJavaScript:@"Array.from(document.body.children).map(e => e.tagName)"]; |
| NSArray *expectedElementTags = @[ @"ATTACHMENT", @"A", @"ATTACHMENT" ]; |
| EXPECT_TRUE([observedElementTags isEqualToArray:expectedElementTags]); |
| if (![observedElementTags isEqualToArray:expectedElementTags]) |
| NSLog(@"Observed elements: %@ did not match expectations: %@", observedElementTags, expectedElementTags); |
| |
| EXPECT_WK_STREQ("first.txt", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('title')"]); |
| EXPECT_WK_STREQ("text/plain", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[0].getAttribute('type')"]); |
| EXPECT_WK_STREQ([appleURL absoluteString], [webView valueOfAttribute:@"href" forQuerySelector:@"a"]); |
| EXPECT_WK_STREQ("second.pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('title')"]); |
| EXPECT_WK_STREQ("application/pdf", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('attachment')[1].getAttribute('type')"]); |
| } |
| |
| TEST(WKAttachmentTestsIOS, DragAttachmentInsertedAsFile) |
| { |
| auto item = adoptNS([[NSItemProvider alloc] init]); |
| auto data = retainPtr(testPDFData()); |
| [item registerData:data.get() type:(NSString *)kUTTypePDF]; |
| [item setSuggestedName:@"document.pdf"]; |
| |
| auto webView = webViewForTestingAttachments(); |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| [draggingSimulator setExternalItemProviders:@[ item.get() ]]; |
| [draggingSimulator runFrom:CGPointZero to:CGPointMake(50, 50)]; |
| |
| // First, verify that the attachment was successfully dropped. |
| EXPECT_EQ(1U, [draggingSimulator insertedAttachments].count); |
| _WKAttachment *attachment = [draggingSimulator insertedAttachments].firstObject; |
| [attachment expectRequestedDataToBe:data.get()]; |
| EXPECT_WK_STREQ("document.pdf", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ("application/pdf", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| |
| [webView evaluateJavaScript:@"getSelection().removeAllRanges()" completionHandler:nil]; |
| [draggingSimulator setExternalItemProviders:@[ ]]; |
| [draggingSimulator runFrom:CGPointMake(25, 25) to:CGPointMake(-100, -100)]; |
| |
| // Next, verify that dragging the attachment produces an item provider with a PDF attachment. |
| EXPECT_EQ(1U, [draggingSimulator sourceItemProviders].count); |
| NSItemProvider *itemProvider = [draggingSimulator sourceItemProviders].firstObject; |
| EXPECT_EQ(UIPreferredPresentationStyleAttachment, itemProvider.preferredPresentationStyle); |
| [itemProvider expectType:(NSString *)kUTTypePDF withData:data.get()]; |
| EXPECT_WK_STREQ("document.pdf", [itemProvider suggestedName]); |
| [draggingSimulator endDataTransfer]; |
| } |
| |
| TEST(WKAttachmentTestsIOS, DragAttachmentInsertedAsData) |
| { |
| auto webView = webViewForTestingAttachments(); |
| auto data = retainPtr(testPDFData()); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"document.pdf" contentType:@"application/pdf" data:data.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeAsIcon)]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| |
| // First, verify that the attachment was successfully inserted from raw data. |
| [attachment expectRequestedDataToBe:data.get()]; |
| EXPECT_WK_STREQ("document.pdf", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ("application/pdf", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| |
| [webView evaluateJavaScript:@"getSelection().removeAllRanges()" completionHandler:nil]; |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| [draggingSimulator runFrom:CGPointMake(25, 25) to:CGPointMake(-100, -100)]; |
| |
| // Next, verify that dragging the attachment produces an item provider with a PDF attachment. |
| EXPECT_EQ(1U, [draggingSimulator sourceItemProviders].count); |
| NSItemProvider *itemProvider = [draggingSimulator sourceItemProviders].firstObject; |
| EXPECT_EQ(UIPreferredPresentationStyleAttachment, itemProvider.preferredPresentationStyle); |
| [itemProvider expectType:(NSString *)kUTTypePDF withData:data.get()]; |
| EXPECT_WK_STREQ("document.pdf", [itemProvider suggestedName]); |
| [draggingSimulator endDataTransfer]; |
| } |
| |
| TEST(WKAttachmentTestsIOS, DragInPlaceVideoAttachmentElement) |
| { |
| auto webView = webViewForTestingAttachments(); |
| auto data = retainPtr(testVideoData()); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"video.mp4" contentType:@"video/mp4" data:data.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(320, 240)]; |
| [attachment expectRequestedDataToBe:data.get()]; |
| EXPECT_WK_STREQ("video.mp4", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ("video/mp4", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| |
| [webView evaluateJavaScript:@"getSelection().removeAllRanges()" completionHandler:nil]; |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| [draggingSimulator runFrom:CGPointMake(25, 25) to:CGPointMake(-100, -100)]; |
| |
| EXPECT_EQ(1U, [draggingSimulator sourceItemProviders].count); |
| NSItemProvider *itemProvider = [draggingSimulator sourceItemProviders].firstObject; |
| EXPECT_EQ(UIPreferredPresentationStyleAttachment, itemProvider.preferredPresentationStyle); |
| [itemProvider expectType:(NSString *)kUTTypeMPEG4 withData:data.get()]; |
| EXPECT_WK_STREQ("video.mp4", [itemProvider suggestedName]); |
| [draggingSimulator endDataTransfer]; |
| } |
| |
| TEST(WKAttachmentTestsIOS, MoveAttachmentElementAsIconByDragging) |
| { |
| auto webView = webViewForTestingAttachments(); |
| auto data = retainPtr(testPDFData()); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"document.pdf" contentType:@"application/pdf" data:data.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeAsIcon)]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| |
| [webView _executeEditCommand:@"InsertParagraph" argument:nil completion:nil]; |
| [webView _executeEditCommand:@"InsertHTML" argument:@"<strong>text</strong>" completion:nil]; |
| [webView _synchronouslyExecuteEditCommand:@"InsertParagraph" argument:nil]; |
| [webView expectElementTag:@"ATTACHMENT" toComeBefore:@"STRONG"]; |
| |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| [draggingSimulator runFrom:CGPointMake(25, 25) to:CGPointMake(25, 425)]; |
| |
| attachment = [[draggingSimulator insertedAttachments] firstObject]; |
| [attachment expectRequestedDataToBe:data.get()]; |
| EXPECT_WK_STREQ("document.pdf", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ("application/pdf", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| |
| [webView expectElementTag:@"STRONG" toComeBefore:@"ATTACHMENT"]; |
| [draggingSimulator endDataTransfer]; |
| } |
| |
| TEST(WKAttachmentTestsIOS, MoveInPlaceAttachmentElementByDragging) |
| { |
| auto webView = webViewForTestingAttachments(); |
| auto data = retainPtr(testImageData()); |
| RetainPtr<_WKAttachment> attachment; |
| { |
| ObserveAttachmentUpdatesForScope observer(webView.get()); |
| attachment = [webView synchronouslyInsertAttachmentWithFilename:@"icon.png" contentType:@"image/png" data:data.get() options:displayOptionsWithMode(_WKAttachmentDisplayModeInPlace)]; |
| observer.expectAttachmentUpdates(@[], @[attachment.get()]); |
| } |
| |
| [webView waitForAttachmentElementSizeToBecome:CGSizeMake(215, 174)]; |
| [webView _executeEditCommand:@"InsertParagraph" argument:nil completion:nil]; |
| [webView _executeEditCommand:@"InsertHTML" argument:@"<strong>text</strong>" completion:nil]; |
| [webView _synchronouslyExecuteEditCommand:@"InsertParagraph" argument:nil]; |
| [webView expectElementTag:@"ATTACHMENT" toComeBefore:@"STRONG"]; |
| |
| auto draggingSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]); |
| [draggingSimulator runFrom:CGPointMake(25, 25) to:CGPointMake(25, 425)]; |
| |
| attachment = [[draggingSimulator insertedAttachments] firstObject]; |
| [attachment expectRequestedDataToBe:data.get()]; |
| EXPECT_WK_STREQ("icon.png", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment"]); |
| EXPECT_WK_STREQ("image/png", [webView valueOfAttribute:@"type" forQuerySelector:@"attachment"]); |
| |
| [webView expectElementTag:@"STRONG" toComeBefore:@"ATTACHMENT"]; |
| [draggingSimulator endDataTransfer]; |
| } |
| |
| #endif // PLATFORM(IOS) |
| |
| } // namespace TestWebKitAPI |
| |
| #endif // WK_API_ENABLED && !PLATFORM(WATCHOS) && !PLATFORM(TVOS) |