Fix URL scheme UI tests for YouTube deep links and content loading

Route HTTPS YouTube URLs through yattee://open?url= scheme since simctl
can't trigger Universal Links. Improve wait strategies: use player
expansion check for video tests, tree length threshold for channel/
playlist content loading. Add retry logic to cleanup_after_video.
This commit is contained in:
Arkadiusz Fal
2026-02-10 06:21:10 +01:00
parent cae1226cfe
commit 288113d177

View File

@@ -1,5 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'cgi'
require_relative '../spec_helper' require_relative '../spec_helper'
RSpec.describe 'URL Schemes', :smoke do RSpec.describe 'URL Schemes', :smoke do
@@ -231,7 +232,7 @@ RSpec.describe 'URL Schemes with Backend', :url_backend do
end end
end end
# Open a URL and dismiss the iOS "Open in Yattee?" system confirmation dialog # Open a yattee:// URL and dismiss the iOS "Open in Yattee?" system confirmation dialog
def open_url(url) def open_url(url)
UITest::Simulator.open_url(@udid, url) UITest::Simulator.open_url(@udid, url)
sleep 0.8 sleep 0.8
@@ -253,6 +254,13 @@ RSpec.describe 'URL Schemes with Backend', :url_backend do
end end
end end
# Wrap an HTTPS URL in yattee://open?url= scheme so simctl routes it to the app
# instead of Safari. This tests the app's YouTube URL parsing via URLRouter.
def open_youtube_url(url)
encoded = CGI.escape(url)
open_url("yattee://open?url=#{encoded}")
end
# Navigate back to Home tab # Navigate back to Home tab
def navigate_to_home def navigate_to_home
5.times do 5.times do
@@ -288,25 +296,21 @@ RSpec.describe 'URL Schemes with Backend', :url_backend do
end end
end end
# Wait for any content to load (not an empty state) # Wait for content to load (channel/playlist views with actual data)
def wait_for_content_loaded(timeout: 20) def wait_for_content_loaded(timeout: 20)
start_time = Time.now start_time = Time.now
loop do loop do
# Content loaded if we see video titles, channel names, etc.
# Check that we're not just on an empty/loading screen
tree = @axe.describe_ui tree = @axe.describe_ui
tree_str = tree.to_s tree_str = tree.to_s
# Look for signs of loaded content (not just nav titles) # A loaded channel/playlist view has a large tree (video thumbnails, titles, etc.)
has_content = tree_str.include?('AXImage') || # Skeleton/loading views are much smaller (< 2000 chars)
tree_str.include?('AXStaticText') && tree_str.length > 2000 return true if tree_str.length > 2000
return true if has_content
if Time.now - start_time > timeout if Time.now - start_time > timeout
@axe.screenshot('debug-content-load-timeout') @axe.screenshot('debug-content-load-timeout')
raise "Content did not load after #{timeout} seconds" raise "Content did not load after #{timeout} seconds (tree length: #{tree_str.length})"
end end
sleep 1 sleep 1
@@ -315,10 +319,25 @@ RSpec.describe 'URL Schemes with Backend', :url_backend do
# Close player if open, then navigate home # Close player if open, then navigate home
def cleanup_after_video def cleanup_after_video
# Try closing expanded player
if @player.player_expanded? if @player.player_expanded?
@player.close_player @player.close_player
sleep 0.5 sleep 1
# Verify it actually closed, retry if needed
if @player.player_expanded?
@player.close_player
sleep 1
end end
end
# Dismiss any remaining sheets/modals (e.g. video info overlays)
begin
@axe.swipe(start_x: 200, start_y: 200, end_x: 200, end_y: 800, duration: 0.3)
sleep 0.5
rescue UITest::Axe::AxeError
# Ignore if swipe fails
end
navigate_to_home navigate_to_home
end end
@@ -329,63 +348,55 @@ RSpec.describe 'URL Schemes with Backend', :url_backend do
it 'opens video via yattee://video/{id}' do it 'opens video via yattee://video/{id}' do
open_url('yattee://video/dQw4w9WgXcQ') open_url('yattee://video/dQw4w9WgXcQ')
sleep 3 @player.wait_for_player_expanded(timeout: 20)
wait_for_content_loaded
@axe.screenshot('url-scheme-video') @axe.screenshot('url-scheme-video')
end end
it 'opens channel via yattee://channel/{id}' do it 'opens channel via yattee://channel/{id}' do
open_url('yattee://channel/UC_x5XG1OV2P6uZZ5FSM9Ttw') open_url('yattee://channel/UC_x5XG1OV2P6uZZ5FSM9Ttw')
sleep 3 wait_for_content_loaded(timeout: 20)
wait_for_content_loaded
@axe.screenshot('url-scheme-channel') @axe.screenshot('url-scheme-channel')
end end
it 'opens playlist via yattee://playlist/{id}' do it 'opens playlist via yattee://playlist/{id}' do
open_url('yattee://playlist/PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf') open_url('yattee://playlist/PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf')
sleep 3 wait_for_content_loaded(timeout: 20)
wait_for_content_loaded
@axe.screenshot('url-scheme-playlist') @axe.screenshot('url-scheme-playlist')
end end
end end
describe 'YouTube URL parsing' do describe 'YouTube URL parsing via yattee://open?url=' do
after(:each) do after(:each) do
cleanup_after_video cleanup_after_video
end end
it 'opens video via youtube.com/watch URL' do it 'parses youtube.com/watch URL and opens video' do
open_url('https://www.youtube.com/watch?v=dQw4w9WgXcQ') open_youtube_url('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
sleep 3 @player.wait_for_player_expanded(timeout: 20)
wait_for_content_loaded
@axe.screenshot('url-scheme-youtube-watch') @axe.screenshot('url-scheme-youtube-watch')
end end
it 'opens video via youtu.be short URL' do it 'parses youtu.be short URL and opens video' do
open_url('https://youtu.be/dQw4w9WgXcQ') open_youtube_url('https://youtu.be/dQw4w9WgXcQ')
sleep 3 @player.wait_for_player_expanded(timeout: 20)
wait_for_content_loaded
@axe.screenshot('url-scheme-youtube-short') @axe.screenshot('url-scheme-youtube-short')
end end
it 'opens video via youtube.com/shorts URL' do it 'parses youtube.com/shorts URL and opens video' do
open_url('https://www.youtube.com/shorts/dQw4w9WgXcQ') open_youtube_url('https://www.youtube.com/shorts/dQw4w9WgXcQ')
sleep 3 @player.wait_for_player_expanded(timeout: 20)
wait_for_content_loaded
@axe.screenshot('url-scheme-youtube-shorts') @axe.screenshot('url-scheme-youtube-shorts')
end end
it 'opens playlist via youtube.com/playlist URL' do it 'parses youtube.com/playlist URL and opens playlist' do
open_url('https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf') open_youtube_url('https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf')
sleep 3 wait_for_content_loaded(timeout: 20)
wait_for_content_loaded
@axe.screenshot('url-scheme-youtube-playlist') @axe.screenshot('url-scheme-youtube-playlist')
end end
it 'opens channel via youtube.com/@handle URL' do it 'parses youtube.com/@handle URL and opens channel' do
open_url('https://www.youtube.com/@Google') open_youtube_url('https://www.youtube.com/@Google')
sleep 3 wait_for_content_loaded(timeout: 20)
wait_for_content_loaded
@axe.screenshot('url-scheme-youtube-handle') @axe.screenshot('url-scheme-youtube-handle')
end end
end end