| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- /**
- * Copyright (c) 2015-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- */
- #import <XCTest/XCTest.h>
- #import "FBIntegrationTestCase.h"
- #import "XCUIElement.h"
- #import "XCUIDevice.h"
- #import "XCUIApplication+FBTouchAction.h"
- #import "FBTestMacros.h"
- #import "XCUIDevice+FBRotation.h"
- #import "FBRunLoopSpinner.h"
- #import "FBXCodeCompatibility.h"
- @interface FBW3CTouchActionsIntegrationTestsPart1 : FBIntegrationTestCase
- @end
- @interface FBW3CTouchActionsIntegrationTestsPart2 : FBIntegrationTestCase
- @property (nonatomic) XCUIElement *pickerWheel;
- @end
- @implementation FBW3CTouchActionsIntegrationTestsPart1
- - (void)verifyGesture:(NSArray<NSDictionary<NSString *, id> *> *)gesture orientation:(UIDeviceOrientation)orientation
- {
- [[XCUIDevice sharedDevice] fb_setDeviceInterfaceOrientation:orientation];
- NSError *error;
- XCTAssertTrue([self.testedApplication fb_performW3CActions:gesture elementCache:nil error:&error]);
- FBAssertWaitTillBecomesTrue(self.testedApplication.alerts.count > 0);
- }
- - (void)setUp
- {
- [super setUp];
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- [self launchApplication];
- [self goToAlertsPage];
- });
- [self clearAlert];
- }
- - (void)tearDown
- {
- [self clearAlert];
- [self resetOrientation];
- [super tearDown];
- }
- - (void)testErroneousGestures
- {
- NSArray<NSArray<NSDictionary<NSString *, id> *> *> *invalidGestures =
- @[
- // Empty chain
- @[],
-
- // Chain element without 'actions' key
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- },
- ],
-
- // Chain element without type
- @[@{
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @100, @"y": @100},
- ],
- },
- ],
-
- // Chain element without id
- @[@{
- @"type": @"pointer",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @100, @"y": @100},
- ],
- },
- ],
-
- // Chain element with empty id
- @[@{
- @"type": @"pointer",
- @"id": @"",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @100, @"y": @100},
- ],
- },
- ],
-
- // Chain element with unsupported type
- @[@{
- @"type": @"key",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @100, @"y": @100},
- ],
- },
- ],
-
- // Chain element with unsupported pointerType (default)
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @100, @"y": @100},
- ],
- },
- ],
-
- // Chain element with unsupported pointerType (non-default)
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"pen"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @100, @"y": @100},
- ],
- },
- ],
-
- // Chain element without action item type
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"duration": @0, @"x": @1, @"y": @1},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerUp"},
- ],
- },
- ],
- // Chain element with singe up action
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerUp"},
- ],
- },
- ],
-
- // Chain element containing action item without y coordinate
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @1},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerUp"},
- ],
- },
- ],
-
- // Chain element containing action item with an unknown type
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMoved", @"duration": @0, @"x": @1, @"y": @1},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerUp"},
- ],
- },
- ],
-
- // Chain element where action items start with an incorrect item
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerMove", @"duration": @0, @"x": @1, @"y": @1},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerUp"},
- ],
- },
- ],
-
- // Chain element where pointerMove action item does not contain coordinates
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerUp"},
- ],
- },
- ],
-
- // Chain element where pointerMove action item cannot use coordinates of the previous item
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"origin": @"pointer"},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerUp"},
- ],
- },
- ],
-
- // Chain element where action items contains negative duration
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @1, @"y": @1},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @-100},
- @{@"type": @"pointerUp"},
- ],
- },
- ],
-
- // Chain element where action items start with an incorrect one, because the correct one is canceled
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @1, @"y": @1},
- @{@"type": @"pointerCancel"},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @-100},
- @{@"type": @"pointerUp"},
- ],
- },
- ],
-
- ];
-
- for (NSArray<NSDictionary<NSString *, id> *> *invalidGesture in invalidGestures) {
- NSError *error;
- XCTAssertFalse([self.testedApplication fb_performW3CActions:invalidGesture elementCache:nil error:&error]);
- XCTAssertNotNil(error);
- }
- }
- - (void)testNothingDoesWithoutError
- {
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[],
- },
- ];
- NSError *error;
- XCTAssertTrue([self.testedApplication fb_performW3CActions:gesture elementCache:nil error:&error]);
- XCTAssertNil(error);
- }
- - (void)testTap
- {
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"origin": self.testedApplication.buttons[FBShowAlertButtonName], @"x": @0, @"y": @0},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerUp"},
- ],
- },
- ];
- [self verifyGesture:gesture orientation:UIDeviceOrientationPortrait];
- }
- - (void)testDoubleTap
- {
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"origin": self.testedApplication.buttons[FBShowAlertButtonName]},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @50},
- @{@"type": @"pointerUp"},
- @{@"type": @"pause", @"duration": @200},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @50},
- @{@"type": @"pointerUp"},
- ],
- },
- ];
- [self verifyGesture:gesture orientation:UIDeviceOrientationLandscapeLeft];
- }
- - (void)testLongPressWithCombinedPause
- {
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"origin": self.testedApplication.buttons[FBShowAlertButtonName], @"x": @5, @"y": @5},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @200},
- @{@"type": @"pause", @"duration": @200},
- @{@"type": @"pause", @"duration": @100},
- @{@"type": @"pointerUp"},
- ],
- },
- ];
- [self verifyGesture:gesture orientation:UIDeviceOrientationLandscapeRight];
- }
- - (void)testLongPress
- {
- if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
- XCTSkip(@"Failed on Azure Pipeline. Local run succeeded.");
- }
- UIDeviceOrientation orientation = UIDeviceOrientationLandscapeLeft;
- [[XCUIDevice sharedDevice] fb_setDeviceInterfaceOrientation:orientation];
- CGRect elementFrame = self.testedApplication.buttons[FBShowAlertButtonName].frame;
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @(elementFrame.origin.x + 1), @"y": @(elementFrame.origin.y + 1)},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @500},
- @{@"type": @"pointerUp"},
- ],
- },
- ];
- [self verifyGesture:gesture orientation:orientation];
- }
- - (void)testForceTap
- {
- if (![XCUIDevice.sharedDevice supportsPressureInteraction]) {
- return;
- }
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"origin": self.testedApplication.buttons[FBShowAlertButtonName]},
- @{@"type": @"pointerDown"},
- @{@"type": @"pause", @"duration": @500},
- @{@"type": @"pointerDown", @"pressure": @1.0},
- @{@"type": @"pause", @"duration": @50},
- @{@"type": @"pointerDown", @"pressure": @1.0},
- @{@"type": @"pause", @"duration": @50},
- @{@"type": @"pointerUp"},
- ],
- },
- ];
- [self verifyGesture:gesture orientation:UIDeviceOrientationLandscapeLeft];
- }
- @end
- @implementation FBW3CTouchActionsIntegrationTestsPart2
- - (void)setUp
- {
- [super setUp];
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- [self launchApplication];
- [self goToAttributesPage];
- });
- self.pickerWheel = self.testedApplication.pickerWheels.allElementsBoundByIndex.firstObject;
- }
- - (void)tearDown
- {
- [self resetOrientation];
- [super tearDown];
- }
- - (void)verifyPickerWheelPositionChangeWithGesture:(NSArray<NSDictionary<NSString *, id> *> *)gesture
- {
- NSString *previousValue = self.pickerWheel.value;
- NSError *error;
- XCTAssertTrue([self.testedApplication fb_performW3CActions:gesture elementCache:nil error:&error]);
- XCTAssertNil(error);
- XCTAssertTrue([[[[FBRunLoopSpinner new]
- timeout:2.0]
- timeoutErrorMessage:@"Picker wheel value has not been changed after 2 seconds timeout"]
- spinUntilTrue:^BOOL{
- return ![[self.pickerWheel fb_standardSnapshot].value isEqualToString:previousValue];
- }
- error:&error]);
- XCTAssertNil(error);
- }
- - (void)testSwipePickerWheelWithElementCoordinates
- {
- CGRect pickerFrame = self.pickerWheel.frame;
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"origin": self.pickerWheel, @"x": @0, @"y":@0},
- @{@"type": @"pointerDown"},
- @{@"type": @"pointerMove", @"duration": @500, @"origin": self.pickerWheel, @"x": @0, @"y": @(pickerFrame.size.height / 2)},
- @{@"type": @"pointerUp"},
- ],
- },
- ];
- [self verifyPickerWheelPositionChangeWithGesture:gesture];
- }
- - (void)testSwipePickerWheelWithRelativeCoordinates
- {
- CGRect pickerFrame = self.pickerWheel.frame;
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @250, @"origin": self.pickerWheel, @"x": @0, @"y": @0},
- @{@"type": @"pointerDown"},
- @{@"type": @"pointerMove", @"duration": @500, @"origin": @"pointer", @"x": @0, @"y": @(-pickerFrame.size.height / 2)},
- @{@"type": @"pointerUp"},
- ],
- },
- ];
- [self verifyPickerWheelPositionChangeWithGesture:gesture];
- }
- - (void)testSwipePickerWheelWithAbsoluteCoordinates
- {
- CGRect pickerFrame = self.pickerWheel.frame;
- NSArray<NSDictionary<NSString *, id> *> *gesture =
- @[@{
- @"type": @"pointer",
- @"id": @"finger1",
- @"parameters": @{@"pointerType": @"touch"},
- @"actions": @[
- @{@"type": @"pointerMove", @"duration": @0, @"x": @(pickerFrame.origin.x + pickerFrame.size.width / 2), @"y": @(pickerFrame.origin.y + pickerFrame.size.height / 2)},
- @{@"type": @"pointerDown"},
- @{@"type": @"pointerMove", @"duration": @500, @"origin": @"pointer", @"x": @0, @"y": @(pickerFrame.size.height / 2)},
- @{@"type": @"pointerUp"},
- ],
- },
- ];
- [self verifyPickerWheelPositionChangeWithGesture:gesture];
- }
- @end
|