Skip to content

test(paywalls): cover video KVO crash fix (#6985)#6988

Closed
facumenzella wants to merge 2 commits into
alex/fix-avfoundation-kvo-crashfrom
facu/paywall-video-kvo-crash-tests
Closed

test(paywalls): cover video KVO crash fix (#6985)#6988
facumenzella wants to merge 2 commits into
alex/fix-avfoundation-kvo-crashfrom
facu/paywall-video-kvo-crash-tests

Conversation

@facumenzella

Copy link
Copy Markdown
Member

Stacked on top of #6987 (targets alex/fix-avfoundation-kvo-crash, not main).

#6987 fixes the looping-video KVO teardown crash but ships without automated coverage, and the core invariant is cheap to pin. This adds structural tests so the fix can't silently regress:

They assert through makeCoordinator(), so they also cover the player-ownership seam #6987 introduced.

Verified locally on iPhone 16 Pro (18.4) via the RevenueCatUITests scheme: 5 tests, 0 failures.

AI session context

AI Context

Metadata

Goal

Add automated coverage for the looping-video crash fix in #6987 so the fix is regression-proof. No production code changed; tests only.

Initial Prompt

Review issue #6985 (looping Paywalls V2 video crashes with NSInternalInconsistencyException), then compare an independently-built fix against the official PR #6987, and push for test coverage on #6987 by drafting the missing tests. (Opened as "check this out https://.../issues/6985".)

Important Follow-up Prompts

Agent Contribution

  • Drafted VideoPlayerViewTests.swift (5 tests) targeting Use AVPlayerLayer for no-controls; fix KVO crash #6987's API (VideoPlayerUIView, VideoPlayerLayerView, PlayerLayerBackedView, Coordinator.player).
  • Checked out alex/fix-avfoundation-kvo-crash, regenerated the Tuist workspace, ran the tests.

Human Decisions

Key Implementation Decisions

  • Decision: assert through makeCoordinator() and check player is AVQueuePlayer / layer backing.
    • Rationale: the dealloc race is not directly unit-testable, but the structural invariant (no AVQueuePlayer to AVPlayerViewController; no-controls uses AVPlayerLayer) is, and it sits on the ownership seam Use AVPlayerLayer for no-controls; fix KVO crash #6987 added.
    • Rejected: a full SwiftUI lifecycle/teardown test (impractical in a unit test, high flakiness).

Files / Symbols Touched

  • Tests/RevenueCatUITests/PaywallsV2/VideoPlayerViewTests.swift
    • Why: new test coverage.
    • Symbols: VideoPlayerUIView, VideoPlayerLayerView, PlayerLayerBackedView, Coordinator.player.
    • Review relevance: confirm the assertions match the intended invariant and the API stays stable.

Dependencies / Config / Migrations

  • None.

Validation

  • Commands run:
    • tuist generate --no-open: success
    • xcodebuild test ... -only-testing:RevenueCatUITests/VideoPlayerViewTests: 5 tests, 0 failures
    • swiftlint lint: clean
  • Manual verification: confirmed each test maps to a pre-fix failure mode (controls path built an AVQueuePlayer; the layer types did not exist).
  • CI: Not captured.

Validation Gaps

  • Tests assert player/looper construction, not the actual AVKit teardown sequence (not unit-testable).
  • Run on a single simulator (iPhone 16 Pro, iOS 18.4); not exercised across the SDK's full OS matrix locally.

Review Focus

  • Are the asserted invariants the ones the maintainer wants pinned long-term?
  • Should the controls+loop manual-seek behavior (non-gapless) get its own coverage/expectation?

Risks / Reviewer Notes

  • Risk: tests couple to internal types (Coordinator.player).
    • Evidence: @testable import makes this intentional and stable; it's the genuine owner of the player.
    • Mitigation: assertions are behavioral (player type / layer class), not implementation trivia.

Non-goals / Out of Scope

Omitted Context

  • Raw transcript, the dropped independent implementation, and exploratory steps were omitted.

alexrepty and others added 2 commits June 12, 2026 17:15
Add PlayerLayerBackedView and VideoPlayerLayerView to render looping/auto-playing videos via AVPlayerLayer for the no-controls path, avoiding AVKit's internal AVPlayerController KVO observers. Update VideoPlayerView to choose between AVPlayerViewController when controls are shown and the new AVPlayerLayer path when hidden. Refactor VideoPlayerUIView to move player lifecycle into its Coordinator, implement manual looping for the AVPlayerViewController path (to avoid AVPlayerLooper-driven KVO issues), disable video frame analysis on iOS 16+, manage/restore audio session category, and deterministically tear down players and observers during dismantle/deinit.
Add structural tests for the looping-video crash fix:
- controls path (AVPlayerViewController) never builds an AVQueuePlayer,
  so an AVPlayerLooper-driven queue player is never handed to AVKit's
  internal AVPlayerController (the #6985 teardown crash)
- no-controls path uses an AVQueuePlayer via AVPlayerLayer, which has no
  AVPlayerController and is safe with AVPlayerLooper
- PlayerLayerBackedView is backed by AVPlayerLayer

Tests go through makeCoordinator(), covering the player-ownership seam.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@RevenueCat-Danger-Bot

RevenueCat-Danger-Bot commented Jun 12, 2026

Copy link
Copy Markdown

❌ Failures

RevenueCat.xcodeproj is out of sync.

The following Swift files were added but are missing from RevenueCat.xcodeproj:
RevenueCatUI/Templates/V2/Components/Video/VideoPlayerLayerUIView.swift
Tests/RevenueCatUITests/PaywallsV2/VideoPlayerViewTests.swift

To fix: open RevenueCat.xcodeproj in Xcode, add/remove the files above in the appropriate target. Check where similar files in the same directory are assigned if you're unsure which target to use.

@RevenueCat-Danger-Bot

RevenueCat-Danger-Bot commented Jun 12, 2026

Copy link
Copy Markdown
1 Error
🚫 Purchases iOS checks failed — see the comment above for details.

Generated by 🚫 Danger

@alexrepty alexrepty force-pushed the alex/fix-avfoundation-kvo-crash branch from 870b3e1 to b4575c1 Compare June 12, 2026 15:50
@facumenzella

Copy link
Copy Markdown
Member Author

Folded these directly into alex/fix-avfoundation-kvo-crash (commit 58ba665) per @alexrepty, so no need to stack. Closing.

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.

3 participants