Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use PostRepository to fetch pages in the Menu screen #21949

Merged
merged 6 commits into from
Nov 6, 2023

Conversation

crazytonyli
Copy link
Contributor

@crazytonyli crazytonyli commented Nov 2, 2023

Fixes #21947

There are a few issues in the "sync posts" function in PostServices, which I have described in #21814. In this PR, I have replace one usage of the "sync posts" function with the new implementation in PostRepository.

To test: verify #21947 is fixed.

Regression Notes

  1. Potential unintended areas of impact
    None.

  2. What I did to test those areas of impact (or what existing automated tests I relied on)
    Verify Menus screen enters an infinite loop of loading site's pages #21947

  3. What automated tests I added (or what prevented me from doing so)
    Unit tests for successful API responses and cancellation.

PR submission checklist:

  • I have completed the Regression Notes.
  • I have considered adding unit tests for my changes.
  • I have considered adding accessibility improvements for my changes.
  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

UI Changes testing checklist: N/A

@crazytonyli crazytonyli added this to the 23.7 milestone Nov 2, 2023
@crazytonyli crazytonyli requested a review from mokagio November 2, 2023 06:20
@crazytonyli crazytonyli self-assigned this Nov 2, 2023
@wpmobilebot
Copy link
Contributor

wpmobilebot commented Nov 2, 2023

WordPress Alpha📲 You can test the changes from this Pull Request in WordPress Alpha by scanning the QR code below to install the corresponding build.
App NameWordPress Alpha WordPress Alpha
ConfigurationRelease-Alpha
Build Numberpr21949-ed781a5
Version23.6
Bundle IDorg.wordpress.alpha
Commited781a5
App Center BuildWPiOS - One-Offs #7709
Automatticians: You can use our internal self-serve MC tool to give yourself access to App Center if needed.

@wpmobilebot
Copy link
Contributor

wpmobilebot commented Nov 2, 2023

Jetpack Alpha📲 You can test the changes from this Pull Request in Jetpack Alpha by scanning the QR code below to install the corresponding build.
App NameJetpack Alpha Jetpack Alpha
ConfigurationRelease-Alpha
Build Numberpr21949-ed781a5
Version23.6
Bundle IDcom.jetpack.alpha
Commited781a5
App Center Buildjetpack-installable-builds #6724
Automatticians: You can use our internal self-serve MC tool to give yourself access to App Center if needed.

Copy link
Contributor

@mokagio mokagio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm approving to unblock but I haven't had the time to manually test.

To be clear, that's on me. I'll try to come back to this, but wanted to unblock just in case.

Comment on lines -75 to +77
* @brief Generate a list MenuItems from the blog's top-level pages.
* @brief Create a list MenuItems from the given page.
*
* @param blog The blog to use for pages. Cannot be nil.
* @param success The success handler. Can be nil.
* @param failure The failure handler. Can be nil.
* @return A MenuItem instance for the page if it's a top-level page. Otherwise, nil.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick. There docs in the previous method has @params. The new one doesn't. One could see this as a regression.

At the same time, I personally prefer this style of documentation, which I interpret as "only document was is not obvious."

What do you think? Is it worth using this as an example to start a team-wide conversation to define a standard?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"only document was is not obvious."

This is exactly what I was thinking. I don't think those param docs in the original function is really useful.

@@ -9,8 +9,6 @@
#import "WordPress-Swift.h"
@import WordPressKit;

NS_ASSUME_NONNULL_BEGIN
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this removed? I'm guessing because it's not necessary in .m files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. No benefit whatsoever in using it in .m files.

}
failure:failure];
- (MenuItem *)createItemWithPageID:(NSManagedObjectID *)pageObjectID inContext:(NSManagedObjectContext *)context {
Page *page = [context existingObjectWithID:pageObjectID error:nil];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered passing an error object?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That didn't cross my mind. That's a good idea though: turning this Objective-C function to a throwing Swift function.

But unfortunately, after giving it go, I noticed Swift turns the function to createItem() throws -> MenuItem, but I want an optional return value: createItem() throws -> MenuItem?. I think I'll keep it as it is, because returning an non optional MenuItem is a lie.

{
[super viewDidDisappear:animated];

if (self.navigationController == nil && self.fetchAllPagesCancellationHandler != nil) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the code check for the navigationController value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make sure we only cancel the fetching when user taps the Back button. viewDidDisappear is also called when a new view controller is pushed into the stack. In which case, we'd like the pages fetching to continue.

return
}

guard let menusService = self?.menusService else { return }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to suggest moving the check at the start of the Task to exit early. But maybe it's best to check if self is still available after the fetchAllPagesTask completed, in case the ViewController (self) was deallocated in the meantime. Is this the reason for the check being at this point?

cancelled.fulfill()
}

await fulfillment(of: [cancelled], timeout: 0.3)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a neat test 🤩


let pages = try await repository.fetchAllPages(statuses: [.publish], in: blogID).value
XCTAssertEqual(pages.count, 110)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered a test to explicitly check that no more requests are made after an empty or < page size response has been received?

🤔 I guess the fact that await triggers sort of guarantees this, but I don't know... I feel like it would be "nice" to test it explicitly.

Not a must. If I had some time, I'd see if I could change the source code to make these tests pass with more requests, but I don't think I'll get to it any time soon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explicitly check that no more requests are made after an empty or < page size response has been received?

I think that's already covered here. If there are more requests fired, then the fake PostServiceRemote API response would make sure either

  • an extra 100 or 10 page instances are returned to the PostRepository fucntion. Or,
  • a failure is returned.

That means the final total pages should be more than 110 and breaks the assertion or throw an error. Given the test passes, we should(?) be fairly certain that there no unnecessary requests are fired.

I guess that's not entirely true. Because if the fetchAllPages is implemented in a way that removes duplication or swallows error, then the test would still pass when there are unnecessary requests.

I guess we could to add a XCTFail to the error case to be really really sure.

override func getPostsOfType(_ postType: String!, options: [AnyHashable: Any]! = [:], success: (([RemotePost]?) -> Void)!, failure: ((Error?) -> Void)!) {
guard !remotePostsToReturnOnSyncPostsOfType.isEmpty else {
failure(testError())
return
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added another test in ed781a5 to ensure when there is an HTTP API error, the fetchAllPages should throw, which means the error is not swallowed and at the same time ensure no extra requests are fired after an empty or < page size response.

@crazytonyli crazytonyli enabled auto-merge November 6, 2023 02:53
@crazytonyli crazytonyli merged commit ae33467 into trunk Nov 6, 2023
23 checks passed
@crazytonyli crazytonyli deleted the tonyli-use-post-repository-search-in-menu branch November 6, 2023 03:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Menus screen enters an infinite loop of loading site's pages
3 participants