mirror of
https://github.com/yattee/yattee.git
synced 2026-02-19 17:29:45 +00:00
163 lines
5.6 KiB
Markdown
163 lines
5.6 KiB
Markdown
# Yattee Development Notes
|
|
|
|
## Testing Instances
|
|
|
|
- **Invidious**: `https://invidious.home.arekf.net/` - Use this instance for testing API calls
|
|
- **Yattee Server**: `https://main.s.yattee.stream` - Local self-hosted Yattee server for backend testing
|
|
|
|
## Related Projects
|
|
|
|
### Yattee Server
|
|
|
|
Location: `~/Developer/yattee-server`
|
|
|
|
A self-hosted API server powered by yt-dlp that provides an Invidious-compatible API for YouTube content. Used as an alternative backend when Invidious/Piped instances are blocked or unavailable.
|
|
|
|
**Key features:**
|
|
- Invidious-compatible API endpoints (`/api/v1/videos`, `/api/v1/channels`, `/api/v1/search`, etc.)
|
|
- Uses yt-dlp with deno for YouTube JS challenge solving
|
|
- Returns direct YouTube CDN stream URLs
|
|
- Optional backing Invidious instance for trending, popular, and search suggestions
|
|
|
|
**API endpoints:**
|
|
- `GET /api/v1/videos/{video_id}` - Video metadata and streams
|
|
- `GET /api/v1/channels/{channel_id}` - Channel info
|
|
- `GET /api/v1/channels/{channel_id}/videos` - Channel videos
|
|
- `GET /api/v1/search?q={query}` - Search
|
|
- `GET /api/v1/playlists/{playlist_id}` - Playlist info
|
|
|
|
**Limitations:**
|
|
- No comments support
|
|
- Stream URLs expire after a few hours
|
|
- Trending/popular/suggestions require backing Invidious instance
|
|
- scheme name to build is Yattee. use generic platform build instead of specific sim/device id
|
|
|
|
## UI Testing with AXe
|
|
|
|
The project uses a Ruby/RSpec-based UI testing framework with [AXe](https://github.com/cameroncooke/AXe) for simulator automation and visual regression testing.
|
|
|
|
### Running UI Tests
|
|
|
|
```bash
|
|
# Install dependencies (first time)
|
|
bundle install
|
|
|
|
# Run all UI tests
|
|
./bin/ui-test
|
|
|
|
# Skip build (faster iteration)
|
|
./bin/ui-test --skip-build
|
|
|
|
# Keep simulator running after tests
|
|
./bin/ui-test --keep-simulator
|
|
|
|
# Generate new baseline screenshots
|
|
./bin/ui-test --generate-baseline
|
|
|
|
# Run on a different device
|
|
./bin/ui-test --device "iPad Pro 13-inch (M5)"
|
|
```
|
|
|
|
### Creating Tests for New Features
|
|
|
|
When implementing a new feature, create a UI test to verify it works:
|
|
|
|
1. **Create a new spec file** in `spec/ui/smoke/`:
|
|
```ruby
|
|
# spec/ui/smoke/my_feature_spec.rb
|
|
require_relative '../spec_helper'
|
|
|
|
RSpec.describe 'My New Feature', :smoke do
|
|
before(:all) do
|
|
@udid = UITest::Simulator.boot(UITest::Config.device)
|
|
UITest::App.build(device: UITest::Config.device, skip: UITest::Config.skip_build?)
|
|
UITest::App.install(udid: @udid)
|
|
UITest::App.launch(udid: @udid)
|
|
sleep UITest::Config.app_launch_wait
|
|
@axe = UITest::Axe.new(@udid)
|
|
end
|
|
|
|
after(:all) do
|
|
UITest::App.terminate(udid: @udid, silent: true) if @udid
|
|
UITest::Simulator.shutdown(@udid) if @udid && !UITest::Config.keep_simulator?
|
|
end
|
|
|
|
it 'displays the new feature element' do
|
|
# Navigate to the feature if needed
|
|
@axe.tap_label('Settings')
|
|
sleep 1
|
|
|
|
# Check for expected elements
|
|
expect(@axe).to have_text('My New Feature')
|
|
end
|
|
|
|
it 'matches baseline screenshot', :visual do
|
|
screenshot = @axe.screenshot('my-feature-screen')
|
|
expect(screenshot).to match_baseline
|
|
end
|
|
end
|
|
```
|
|
|
|
2. **Available AXe actions:**
|
|
```ruby
|
|
@axe.tap_label('Button Text') # Tap by accessibility label
|
|
@axe.tap_id('accessibilityId') # Tap by accessibility identifier
|
|
@axe.tap_coordinates(x: 100, y: 200)
|
|
@axe.swipe(start_x: 200, start_y: 400, end_x: 200, end_y: 100)
|
|
@axe.gesture('scroll-down') # Presets: scroll-up, scroll-down, scroll-left, scroll-right
|
|
@axe.type('search text') # Type text
|
|
@axe.home_button # Press home
|
|
@axe.screenshot('name') # Take screenshot
|
|
```
|
|
|
|
3. **Available matchers:**
|
|
```ruby
|
|
expect(@axe).to have_element('AXUniqueId') # Check by accessibility identifier
|
|
expect(@axe).to have_text('Visible Text') # Check by accessibility label
|
|
expect(screenshot_path).to match_baseline # Visual comparison (2% threshold)
|
|
```
|
|
|
|
4. **Run with baseline generation:**
|
|
```bash
|
|
./bin/ui-test --generate-baseline --keep-simulator
|
|
```
|
|
|
|
5. **Inspect accessibility tree** to find element identifiers:
|
|
```bash
|
|
# Boot simulator and launch app first, then:
|
|
axe describe-ui --udid <SIMULATOR_UDID>
|
|
```
|
|
|
|
### Directory Structure
|
|
|
|
```
|
|
spec/
|
|
├── ui/
|
|
│ ├── spec_helper.rb # RSpec configuration
|
|
│ ├── support/
|
|
│ │ ├── config.rb # Test configuration
|
|
│ │ ├── simulator.rb # Simulator management
|
|
│ │ ├── app.rb # App build/install/launch
|
|
│ │ ├── axe.rb # AXe CLI wrapper
|
|
│ │ ├── axe_matchers.rb # Custom RSpec matchers
|
|
│ │ └── screenshot_comparison.rb
|
|
│ └── smoke/
|
|
│ └── app_launch_spec.rb # Example test
|
|
└── ui_snapshots/
|
|
├── baseline/ # Reference screenshots (by device/iOS version)
|
|
│ └── iPhone_17_Pro/
|
|
│ └── iOS_26_2/
|
|
│ └── app-launch-library.png
|
|
├── current/ # Current test run screenshots
|
|
├── diff/ # Visual diff images
|
|
└── false_positives.yml # Mark expected differences
|
|
```
|
|
|
|
### Tips
|
|
|
|
- Use `have_text` matcher for most checks - it's more reliable than `have_element` since iOS doesn't always expose accessibility identifiers
|
|
- Add `sleep 1` after navigation actions to let UI settle
|
|
- Use `--keep-simulator` during development to speed up iteration
|
|
- Check `spec/ui_snapshots/diff/` for visual diff images when tests fail
|
|
- Add entries to `false_positives.yml` for screenshots with expected dynamic content
|