| // Copyright 2018-present the Material Components for iOS authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #import <XCTest/XCTest.h> |
| |
| #import "MDCButton.h" |
| #import "MDCShadowElevations.h" |
| #import "MDCSnackbarManager.h" |
| #import "MDCSnackbarMessage.h" |
| #import "MDCSnackbarMessageView.h" |
| #import "MDCFakeMDCSnackbarManagerDelegate.h" |
| |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wprivate-header" |
| #import "MDCSnackbarManagerInternal.h" |
| #import "MDCSnackbarOverlayView.h" |
| #pragma clang diagnostic pop |
| |
| NS_ASSUME_NONNULL_BEGIN |
| |
| static const int64_t kDispatchTimeWait = (int64_t)((CGFloat)0.2 * NSEC_PER_SEC); |
| |
| @interface MDCSnackbarManagerInternal (Testing) |
| @property(nonatomic) MDCSnackbarMessageView *currentSnackbar; |
| @property(nonatomic) MDCSnackbarOverlayView *overlayView; |
| @property(nonatomic) BOOL isVoiceOverRunningOverride; |
| @end |
| @interface MDCSnackbarManager (Testing) |
| @property(nonnull, nonatomic, strong) MDCSnackbarManagerInternal *internalManager; |
| @end |
| @interface MDCSnackbarMessageView (Testing) |
| @property(nonatomic, strong) UILabel *label; |
| @end |
| |
| /** Fake MDCChipView for unit testing. */ |
| @interface MDCSnackbarMessageViewTestsFakeView : MDCSnackbarMessageView |
| |
| /** Used to set the value of @c traitCollection. */ |
| @property(nonatomic, strong) UITraitCollection *traitCollectionOverride; |
| |
| @end |
| |
| @implementation MDCSnackbarMessageViewTestsFakeView |
| |
| - (UITraitCollection *)traitCollection { |
| return self.traitCollectionOverride ?: [super traitCollection]; |
| } |
| |
| @end |
| |
| @interface MDCSnackbarMessageViewTests : XCTestCase |
| @property(nonatomic, strong, nullable) MDCSnackbarManager *manager; |
| @property(nonatomic, strong, nullable) FakeMDCSnackbarManagerDelegate *delegate; |
| @property(nonatomic, strong, nullable) MDCSnackbarMessage *message; |
| @end |
| |
| @implementation MDCSnackbarMessageViewTests |
| |
| - (void)setUp { |
| [super setUp]; |
| |
| self.manager = [[MDCSnackbarManager alloc] init]; |
| self.delegate = [[FakeMDCSnackbarManagerDelegate alloc] init]; |
| self.manager.delegate = self.delegate; |
| self.message = [MDCSnackbarMessage messageWithText:@"message text"]; |
| } |
| |
| - (void)tearDown { |
| [self.manager dismissAndCallCompletionBlocksWithCategory:nil]; |
| self.message = nil; |
| self.manager.delegate = nil; |
| self.delegate = nil; |
| self.manager = nil; |
| |
| [super tearDown]; |
| } |
| |
| - (void)testMessageDescription { |
| // Given |
| NSString *text = @"the message text"; |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| |
| // When |
| self.message.text = text; |
| self.message.action = action; |
| |
| // Then |
| XCTAssertNotNil(self.message.description); |
| XCTAssertTrue([self.message.description containsString:@"text:"]); |
| XCTAssertTrue([self.message.description containsString:text]); |
| XCTAssertTrue([self.message.description containsString:@"action:"]); |
| XCTAssertTrue([self.message.description containsString:action.title]); |
| XCTAssertTrue([self.message.description containsString:@"viewClass:"]); |
| XCTAssertTrue([self.message.description containsString:@"MDCSnackbarMessageView"]); |
| } |
| |
| - (void)testSettingMessageActionWithNilTitleAsserts { |
| // Given |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| |
| // When/Then |
| XCTAssertThrows(self.message.action = action); |
| } |
| |
| - (void)testSettingMessageActionWithEmptyTitleAsserts { |
| // Given |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @""; |
| |
| // When/Then |
| XCTAssertThrows(self.message.action = action); |
| } |
| |
| - (void)testDescription { |
| // Given |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| |
| // When |
| [self.manager showMessage:self.message]; |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| MDCSnackbarMessageView *messageView = self.delegate.presentedView; |
| XCTAssertNotNil(messageView.description); |
| XCTAssertTrue([messageView.description containsString:@"message:"]); |
| XCTAssertTrue([messageView.description containsString:@"MDCSnackbarMessage"]); |
| } |
| |
| - (void)testDefaultColors { |
| // Given |
| MDCSnackbarMessageView *messageView = [[MDCSnackbarMessageView alloc] init]; |
| |
| // Then |
| XCTAssertEqualObjects(messageView.snackbarMessageViewBackgroundColor, |
| [UIColor colorWithRed:(CGFloat)(0x32 / 255.0) |
| green:(CGFloat)(0x32 / 255.0) |
| blue:(CGFloat)(0x32 / 255.0) |
| alpha:1]); |
| XCTAssertEqualObjects(messageView.snackbarMessageViewShadowColor, UIColor.blackColor); |
| XCTAssertEqualObjects(messageView.messageTextColor, UIColor.whiteColor); |
| } |
| |
| - (void)testDefaultElevation { |
| // Then |
| XCTAssertEqual([[MDCSnackbarMessageView alloc] init].elevation, MDCShadowElevationSnackbar); |
| } |
| |
| - (void)testCustomElevation { |
| // Given |
| CGFloat fakeElevation = 10; |
| MDCSnackbarMessageView *messageView = [[MDCSnackbarMessageView alloc] init]; |
| |
| // When |
| messageView.elevation = fakeElevation; |
| |
| // Then |
| XCTAssertEqual(messageView.elevation, fakeElevation); |
| } |
| |
| - (void)testAccessibilityLabelDefaultIsNil { |
| // When |
| [self.manager showMessage:self.message]; |
| |
| // Then |
| XCTAssertNil(self.delegate.presentedView.label.accessibilityLabel); |
| } |
| |
| - (void)testAccessibilityLabelSetFromSnackbarMessageProperty { |
| // When |
| self.message.accessibilityLabel = @"not message text"; |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertEqualObjects(self.delegate.presentedView.label.accessibilityLabel, |
| self.message.accessibilityLabel); |
| } |
| |
| - (void)testAccessibilityHintDefaultIsNotNil { |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertNotNil(self.delegate.presentedView.label.accessibilityHint); |
| } |
| |
| - (void)testAccessibilityHintSetFromSnackbarMessageProperty { |
| // When |
| self.message.accessibilityHint = @"a hint"; |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertEqualObjects(self.delegate.presentedView.label.accessibilityHint, |
| self.message.accessibilityHint); |
| } |
| |
| - (void)testSnackbarAccessibiltyViewIsModalDefaultsToNoWithActions { |
| // Given |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| self.message.action = action; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertFalse(self.manager.internalManager.overlayView.accessibilityViewIsModal); |
| } |
| |
| - (void)testSnackbarAccessibiltyViewIsModalDefaultsToNoWithNoActions { |
| // Given |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertFalse(self.manager.internalManager.overlayView.accessibilityViewIsModal); |
| } |
| |
| - (void)testSnackbarAccessibilityViewIsModalIsYesWithActions { |
| // Given |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| self.message.action = action; |
| self.manager.shouldEnableAccessibilityViewIsModal = YES; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertTrue(self.manager.internalManager.overlayView.accessibilityViewIsModal); |
| } |
| |
| - (void)testSnackbarAccessibiltyViewIsModalIsNoWithoutActions { |
| // Given |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| self.manager.shouldEnableAccessibilityViewIsModal = YES; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertFalse(self.manager.internalManager.overlayView.accessibilityViewIsModal); |
| } |
| |
| - (void)testSnackbarAccessibilityViewIsModalIsNoWithoutVoiceOverWithLegacyBehavior { |
| // Given |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| self.message.action = action; |
| self.message.usesLegacyDismissalBehavior = YES; |
| self.manager.internalManager.isVoiceOverRunningOverride = NO; |
| self.manager.shouldEnableAccessibilityViewIsModal = YES; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertFalse(self.manager.internalManager.overlayView.accessibilityViewIsModal); |
| } |
| |
| - (void)testSnackbarAccessibiltyViewIsModalWithSnackbarViewOverwriteWithActions { |
| // Given |
| self.delegate.shouldSetSnackbarViewAccessibilityViewIsModal = YES; |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| self.message.action = action; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertTrue(self.manager.internalManager.overlayView.accessibilityViewIsModal); |
| } |
| |
| - (void)testSnackbarAccessibiltyViewIsModalWithSnackbarViewOverwriteWithNoActions { |
| // Given |
| self.delegate.shouldSetSnackbarViewAccessibilityViewIsModal = YES; |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertTrue(self.manager.internalManager.overlayView.accessibilityViewIsModal); |
| } |
| |
| - (void)testSnackbarViewShowWhenShouldShowMessageWhenVoiceOverIsRunningIsYES { |
| // Given |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| self.manager.shouldShowMessageWhenVoiceOverIsRunning = YES; |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| self.message.action = action; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, kDispatchTimeWait); |
| dispatch_after(popTime, dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertNotNil(self.manager.internalManager.currentSnackbar); |
| } |
| |
| - (void)testSnackbarViewNotShowWhenShouldShowMessageWhenVoiceOverIsRunningIsNO { |
| // Given |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| self.manager.shouldShowMessageWhenVoiceOverIsRunning = NO; |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| self.message.action = action; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, kDispatchTimeWait); |
| dispatch_after(popTime, dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertNil(self.manager.internalManager.currentSnackbar); |
| } |
| |
| - (void)testManagerForwardsButtonProperties { |
| // Given |
| self.manager.uppercaseButtonTitle = NO; |
| self.manager.buttonInkColor = UIColor.redColor; |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| self.message.action = action; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| UIButton *actionButton = self.manager.internalManager.currentSnackbar.actionButton; |
| XCTAssertTrue([actionButton isKindOfClass:[MDCButton class]]); |
| MDCButton *button = (MDCButton *)actionButton; |
| XCTAssertFalse(button.uppercaseTitle); |
| XCTAssertEqualObjects(UIColor.redColor, button.inkColor); |
| } |
| |
| - (void)testTraitCollectionDidChangeCalledWhenTraitCollectionChanges { |
| // Given |
| MDCSnackbarMessageView *messageView = [[MDCSnackbarMessageView alloc] init]; |
| XCTestExpectation *expectation = |
| [self expectationWithDescription:@"Called traitCollectionDidChange"]; |
| __block UITraitCollection *passedTraitCollection; |
| __block MDCSnackbarMessageView *passedMessageView; |
| messageView.traitCollectionDidChangeBlock = |
| ^(MDCSnackbarMessageView *_Nonnull inMessageView, |
| UITraitCollection *_Nullable previousTraitCollection) { |
| passedMessageView = inMessageView; |
| passedTraitCollection = previousTraitCollection; |
| [expectation fulfill]; |
| }; |
| |
| // When |
| UITraitCollection *testCollection = [UITraitCollection traitCollectionWithDisplayScale:77]; |
| [messageView traitCollectionDidChange:testCollection]; |
| |
| // Then |
| [self waitForExpectations:@[ expectation ] timeout:1]; |
| XCTAssertEqual(passedTraitCollection, testCollection); |
| XCTAssertEqual(passedMessageView, messageView); |
| } |
| |
| - (void)testCurrentElevationMatchesElevationWhenElevationChanges { |
| // Given |
| MDCSnackbarMessageView *messageView = [[MDCSnackbarMessageView alloc] init]; |
| |
| // When |
| messageView.elevation = 4; |
| |
| // Then |
| XCTAssertEqualWithAccuracy(messageView.mdc_currentElevation, messageView.elevation, 0.001); |
| } |
| |
| - (void)testSettingOverrideBaseElevationReturnsSetValue { |
| // Given |
| MDCSnackbarMessageView *messageView = [[MDCSnackbarMessageView alloc] init]; |
| CGFloat expectedBaseElevation = 99; |
| |
| // When |
| messageView.mdc_overrideBaseElevation = expectedBaseElevation; |
| |
| // Then |
| XCTAssertEqualWithAccuracy(messageView.mdc_overrideBaseElevation, expectedBaseElevation, 0.001); |
| } |
| |
| - (void)testElevationDidChangeBlockCalledWhenElevationChangesValue { |
| // Given |
| MDCSnackbarMessageView *messageView = [[MDCSnackbarMessageView alloc] init]; |
| messageView.elevation = 5; |
| __block BOOL blockCalled = NO; |
| messageView.mdc_elevationDidChangeBlock = ^(id<MDCElevatable> _, CGFloat elevation) { |
| blockCalled = YES; |
| }; |
| |
| // When |
| messageView.elevation = messageView.elevation + 1; |
| |
| // Then |
| XCTAssertTrue(blockCalled); |
| } |
| |
| - (void)testElevationDidChangeBlockNotCalledWhenElevationIsSetWithoutChangingValue { |
| // Given |
| MDCSnackbarMessageView *messageView = [[MDCSnackbarMessageView alloc] init]; |
| messageView.elevation = 5; |
| __block BOOL blockCalled = NO; |
| messageView.mdc_elevationDidChangeBlock = ^(id<MDCElevatable> _, CGFloat elevation) { |
| blockCalled = YES; |
| }; |
| |
| // When |
| messageView.elevation = messageView.elevation; |
| |
| // Then |
| XCTAssertFalse(blockCalled); |
| } |
| |
| - (void)testDefaultValueForOverrideBaseElevationIsNegative { |
| // Given |
| MDCSnackbarMessageView *messageView = [[MDCSnackbarMessageView alloc] init]; |
| |
| // Then |
| XCTAssertLessThan(messageView.mdc_overrideBaseElevation, 0); |
| } |
| |
| - (void)testMessageStaysWhenFocusOnShowIsEnabled { |
| // Given |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| self.message.focusOnShow = YES; |
| self.message.duration = 0.1; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, kDispatchTimeWait); |
| dispatch_after(popTime, dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertFalse(self.manager.internalManager.currentSnackbar.accessibilityElementsHidden); |
| } |
| |
| - (void)testAccessibilityElementsVisibleWhenVoiceOverStatusEnabled { |
| // Given |
| MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init]; |
| action.title = @"Tap Me"; |
| self.message.action = action; |
| |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| // Wait for the snackbar to be displayed. |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| // Wait for the completion block to run after displaying the snackbar. |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| XCTAssertFalse(self.manager.internalManager.currentSnackbar.accessibilityElementsHidden); |
| // When |
| self.manager.internalManager.isVoiceOverRunningOverride = YES; |
| [[NSNotificationCenter defaultCenter] |
| postNotificationName:UIAccessibilityVoiceOverStatusDidChangeNotification |
| object:nil]; |
| |
| // Then |
| XCTAssertFalse(self.manager.internalManager.currentSnackbar.accessibilityElementsHidden); |
| } |
| |
| - (void)testMessageCustomizationUsingWillPresentBlock { |
| // Given |
| __block BOOL blockCalled = NO; |
| self.message.snackbarMessageWillPresentBlock = |
| ^(MDCSnackbarMessage *snackbarMessage, MDCSnackbarMessageView *messageView) { |
| blockCalled = YES; |
| }; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_async(dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertTrue(blockCalled); |
| } |
| |
| - (void)testMessageStaysWhenDurationIsZero { |
| // Given |
| self.message.duration = 0.1; |
| self.message.automaticallyDismisses = NO; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, kDispatchTimeWait); |
| dispatch_after(popTime, dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertNotNil(self.manager.internalManager.currentSnackbar); |
| } |
| |
| - (void)testSnackbarDidDisappearDelegateCalled { |
| // Given |
| const CGFloat kSnackbarDuration = (CGFloat)0.1; |
| self.message.duration = kSnackbarDuration; |
| // When |
| [self.manager showMessage:self.message]; |
| self.delegate.didDisappearExpectation = [self expectationWithDescription:@"didDisappear"]; |
| // Then |
| // Expect 'snackbarDidDisappear' delegate method to be called. |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| } |
| |
| - (void)testSnackbarWillDisappearDelegateCalled { |
| // Given |
| const CGFloat kSnackbarDuration = (CGFloat)0.1; |
| self.message.duration = kSnackbarDuration; |
| // When |
| [self.manager showMessage:self.message]; |
| self.delegate.willDisappearExpectation = [self expectationWithDescription:@"willDisappear"]; |
| // Then |
| // Expect 'snackbarWillDisappear' delegate method to be called. |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| } |
| |
| - (void)testSettingPresentationHostViewOverrideDisplaysSnackbarInCorrectView { |
| // Given |
| UIView *customView = [[UIView alloc] init]; |
| self.message.presentationHostViewOverride = customView; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| XCTestExpectation *expectation = [self expectationWithDescription:@"completed"]; |
| dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, kDispatchTimeWait); |
| dispatch_after(popTime, dispatch_get_main_queue(), ^{ |
| [expectation fulfill]; |
| }); |
| [self waitForExpectationsWithTimeout:3 handler:nil]; |
| |
| // Then |
| XCTAssertTrue([customView.subviews count] > 0); |
| XCTAssertEqual([customView.subviews.firstObject class], [MDCSnackbarOverlayView class]); |
| } |
| |
| /** |
| * This test creates a snackbar with 'shouldDismissOnOverlayTap' enabled, presents it, waits for the |
| * snackbar to appear, and then taps the screen. The snackbar should dismiss at this point. |
| */ |
| - (void)testDismissOnScreenTap { |
| // Given |
| self.message.shouldDismissOnOverlayTap = YES; |
| self.message.duration = 0; |
| self.delegate.didDisappearExpectation = [self expectationWithDescription:@"didDisappear"]; |
| self.delegate.willPresentExpectation = [self expectationWithDescription:@"willPresent"]; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| [self waitForExpectations:@[ self.delegate.willPresentExpectation ] timeout:0.5]; |
| [self.manager.internalManager.overlayView pointInside:CGPointMake(3, 3) withEvent:nil]; |
| |
| // Then |
| [self waitForExpectationsWithTimeout:0.5 handler:nil]; |
| } |
| |
| /** |
| * This test is identical to the one above, but we do *not* tap the screen, and check to make sure |
| * the snackbar has *not* been dismissed. |
| */ |
| - (void)testDismissOnScreenTap_NoTap { |
| // Given |
| self.message.shouldDismissOnOverlayTap = YES; |
| self.message.duration = 0; |
| self.delegate.willPresentExpectation = [self expectationWithDescription:@"willPresent"]; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| [self waitForExpectationsWithTimeout:0.5 handler:nil]; |
| |
| // Then |
| [NSThread sleepForTimeInterval:0.5]; |
| // Unfortunately, there is no way to to assert an expectation has *not* fired after a time |
| // interval. Instead we rely on 'internalManager.currentSnackbar' to be nil iff the snackbar is |
| // dismissed. |
| XCTAssertNotNil(self.manager.internalManager.currentSnackbar); |
| } |
| |
| /** |
| * In a similar vein to the tests above, this test ensures the snackbar does *not* dismiss on tap if |
| * the user doesn't enable shouldDismissOnScreenTap. |
| */ |
| - (void)testNotDismissedOnScreenTap { |
| // Given |
| self.message.duration = 0; |
| self.delegate.willPresentExpectation = [self expectationWithDescription:@"willPresent"]; |
| |
| // When |
| [self.manager showMessage:self.message]; |
| [self waitForExpectationsWithTimeout:0.5 handler:nil]; |
| |
| // Then |
| [NSThread sleepForTimeInterval:0.5]; |
| // Unfortunately, there is no way to to assert an expectation has *not* fired after a time |
| // interval. Instead we rely on 'internalManager.currentSnackbar' to be nil iff the snackbar is |
| // dismissed. |
| XCTAssertNotNil(self.manager.internalManager.currentSnackbar); |
| } |
| |
| - (void)testsnackbarIsPresentingDelegateCalled { |
| // Given |
| self.delegate.willPresentExpectation = [self expectationWithDescription:@"willPresent"]; |
| self.delegate.isPresentingExpectation = [self expectationWithDescription:@"isPresenting"]; |
| // When |
| [self.manager showMessage:self.message]; |
| // Then |
| [self waitForExpectationsWithTimeout:0.2 handler:nil]; |
| } |
| |
| @end |
| |
| NS_ASSUME_NONNULL_END |