mirror of
https://github.com/Instagram/IGListKit
synced 2026-05-06 06:58:26 +00:00
Summary: It seems the under-the-hood changes made to `UICollectionView` from iOS 16.4 onwards has changed our expectations of how these tests work. When initially testing, it seemed that the new behaviour was that the existing cell in the view would get updated, but any newly inserted cells wouldn't be added to the collection view yet. Thinking this might simply be invalid behaviour when the collection view isn't added to a superview, I added the collection view to a new `UIWindow` instance. When I re-ran the tests again while the view has a superview, all of the views update correctly, and none of them were left in a partial state. I'm not too sure what the original intent of testing the collection view cells for being in a partially updated state was, but I think we need to reconsider that for this new `UICollectionView` behaviour. Differential Revision: D49906268 fbshipit-source-id: 7fdc7ba3a534bd49a8a0684888283d2d1eba5912
231 lines
10 KiB
Objective-C
231 lines
10 KiB
Objective-C
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import <XCTest/XCTest.h>
|
|
|
|
#import <IGListKit/IGListCollectionView.h>
|
|
|
|
#import "IGLayoutTestDataSource.h"
|
|
#import "IGLayoutTestItem.h"
|
|
#import "IGLayoutTestSection.h"
|
|
#import "IGListTestHelpers.h"
|
|
|
|
@interface IGListCollectionViewTests : XCTestCase
|
|
|
|
@property (nonatomic, strong) UIWindow *window;
|
|
@property (nonatomic, strong) IGListCollectionView *collectionView;
|
|
@property (nonatomic, strong) IGLayoutTestDataSource *dataSource;
|
|
|
|
@end
|
|
|
|
@implementation IGListCollectionViewTests
|
|
|
|
- (void)setUp {
|
|
[super setUp];
|
|
const CGRect frame = CGRectMake(0, 0, 100, 100);
|
|
self.window = [[UIWindow alloc] initWithFrame:frame];
|
|
self.dataSource = [IGLayoutTestDataSource new];
|
|
self.collectionView = [[IGListCollectionView alloc] initWithFrame:frame];
|
|
self.collectionView.dataSource = self.dataSource;
|
|
self.collectionView.delegate = self.dataSource;
|
|
[self.window addSubview:self.collectionView];
|
|
[self.dataSource configCollectionView:self.collectionView];
|
|
}
|
|
|
|
#pragma mark - Reload All
|
|
|
|
- (void)test_whenReloadData_thatEntireLayoutUpdates {
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))])
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))])
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 20, 20);
|
|
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 20, 0, 10, 10);
|
|
}
|
|
|
|
#pragma mark - Insert/Delete/Reload/Move
|
|
|
|
- (void)test_whenInsertingSection_thatLayoutUpdates {
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))])
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))])
|
|
];
|
|
[self.collectionView insertSections:[NSIndexSet indexSetWithIndex:1]];
|
|
|
|
// check that section 0 was updated
|
|
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 20, 20);
|
|
// check that section 1 was updated
|
|
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 20, 0, 10, 10);
|
|
}
|
|
|
|
- (void)test_whenDeletingSection_thatLayoutUpdates {
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))])
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
];
|
|
[self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:1]];
|
|
|
|
// check that section 0 wasn't updated
|
|
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 20, 20);
|
|
}
|
|
|
|
- (void)test_whenReloadingSection_thatLayoutUpdates {
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))])
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
];
|
|
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:1]];
|
|
|
|
// check that section 0 was updated
|
|
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 20, 20);
|
|
// check that section 1 was updated
|
|
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 20, 0, 20, 20);
|
|
}
|
|
|
|
- (void)test_whenMoveSection_thatLayoutUpdates {
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(30, 30))])
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(40, 40))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(30, 30))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
];
|
|
[self.collectionView moveSection:1 toSection:2];
|
|
|
|
// check that section 0 was updated
|
|
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 40, 40);
|
|
// check that section 1 was updated
|
|
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 40, 0, 30, 30);
|
|
// check that section 2 was updated
|
|
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 70, 0, 20, 20);
|
|
}
|
|
|
|
- (void)test_whenMoveItem_thatLayoutPartiallyUpdates {
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(30, 30))])
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
NSArray *sections = @[genLayoutTestItem(CGSizeMake(10, 10)), genLayoutTestItem(CGSizeMake(20, 20))];
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(sections),
|
|
genLayoutTestSection(@[]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(20, 20))]),
|
|
];
|
|
|
|
[self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:1]
|
|
toIndexPath:[NSIndexPath indexPathForItem:1 inSection:0]];
|
|
|
|
// check that section 0 wasn't updated
|
|
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 10, 10);
|
|
// check that section 1 was updated
|
|
IGAssertEqualFrame([self cellForSection:0 item:1].frame, 10, 0, 20, 20);
|
|
// check that section 2 was updated
|
|
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 30, 0, 20, 20);
|
|
}
|
|
|
|
#pragma mark - Batch
|
|
|
|
- (void)test_whenInsertDeleteMoveSection_thatLayoutUpdates {
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(1, 1))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(2, 2))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(3, 3))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(4, 4))]),
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(0, 0))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(4, 4))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(3, 3))]),
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(5, 5))]),
|
|
];
|
|
|
|
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
|
|
|
|
[self.collectionView performBatchUpdates:^{
|
|
[self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:1]]; // deleted (2, 2)
|
|
[self.collectionView moveSection:3 toSection:1]; // move (4, 4)
|
|
[self.collectionView insertSections:[NSIndexSet indexSetWithIndex:3]]; // inserted (5, 5)
|
|
} completion:^(BOOL finished) {
|
|
[self.collectionView layoutIfNeeded];
|
|
[expectation fulfill];
|
|
|
|
// check that section 0 was updated
|
|
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 0, 0);
|
|
// check that section 1 was updated
|
|
IGAssertEqualFrame([self cellForSection:1 item:0].frame, 0, 0, 4, 4);
|
|
// check that section 2 was updated
|
|
IGAssertEqualFrame([self cellForSection:2 item:0].frame, 4, 0, 3, 3);
|
|
// check that section 3 was updated
|
|
IGAssertEqualFrame([self cellForSection:3 item:0].frame, 7, 0, 5, 5);
|
|
}];
|
|
|
|
[self waitForExpectationsWithTimeout:30 handler:^(NSError * _Nullable error) {
|
|
XCTAssertNil(error);
|
|
}];
|
|
}
|
|
|
|
- (void)test_whenInsertingNilSection_thatExecutionCompletesCleanly {
|
|
self.dataSource.sections = @[
|
|
genLayoutTestSection(@[genLayoutTestItem(CGSizeMake(10, 10))])
|
|
];
|
|
[self.collectionView reloadData];
|
|
[self.collectionView layoutIfNeeded];
|
|
|
|
[self.collectionView insertSections:[NSIndexSet indexSet]];
|
|
|
|
// check that section 0 wasn't updated
|
|
IGAssertEqualFrame([self cellForSection:0 item:0].frame, 0, 0, 10, 10);
|
|
}
|
|
|
|
#pragma mark - Helpers
|
|
|
|
- (UICollectionViewCell *)cellForSection:(NSInteger)section item:(NSInteger)item {
|
|
return [self.collectionView cellForItemAtIndexPath:genIndexPath(section, item)];
|
|
}
|
|
|
|
@end
|