Ctrl K
ComunidadGuías…

server/src/rules/__tests__/scope.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { describe, it, expect } from 'vitest';
import { ruleScopeMatches } from '../scope';
import type { MediaItem, Rule } from '../../types';

function makeRule(overrides: Partial<Rule> = {}): Rule {
  return {
    id: 1,
    name: 'test rule',
    profile_id: null,
    type: 'custom',
    media_type: 'all',
    library_keys: null,
    conditions: '{"version":2,"root":{"kind":"group","logic":"AND","children":[]}}',
    action: 'delete',
    enabled: true,
    grace_period_days: 7,
    deletion_action: 'unmonitor_and_delete',
    reset_overseerr: false,
    priority: 0,
    created_at: new Date().toISOString(),
    updated_at: new Date().toISOString(),
    ...overrides,
  };
}

function makeItem(overrides: Partial<MediaItem> = {}): MediaItem {
  return {
    id: 1,
    type: 'movie',
    title: 'Test Movie',
    plex_id: 'rk-1',
    sonarr_id: null,
    radarr_id: null,
    tmdb_id: null,
    imdb_id: null,
    tvdb_id: null,
    year: 2020,
    poster_url: null,
    file_path: null,
    file_size: null,
    resolution: null,
    codec: null,
    added_at: null,
    last_watched_at: null,
    play_count: 0,
    watched_by: null,
    status: 'monitored',
    library_key: '1',
    marked_at: null,
    delete_after: null,
    deleted_at: null,
    is_protected: false,
    protection_reason: null,
    genres: null,
    tags: null,
    studio: null,
    audio_codec: null,
    video_codec: null,
    hdr: null,
    bitrate: null,
    runtime_minutes: null,
    season_count: null,
    episode_count: null,
    watched_episode_count: null,
    episode_progress: null,
    series_status: null,
    rating_imdb: null,
    rating_tmdb: null,
    rating_rt: null,
    content_rating: null,
    original_language: null,
    requested_by: null,
    created_at: new Date().toISOString(),
    updated_at: new Date().toISOString(),
    ...overrides,
  };
}

describe('ruleScopeMatches', () => {
  describe('media type scoping (existing behaviour)', () => {
    it('matches any type when media_type is all', () => {
      const rule = makeRule({ media_type: 'all' });
      expect(ruleScopeMatches(rule, makeItem({ type: 'movie' }))).toBe(true);
      expect(ruleScopeMatches(rule, makeItem({ type: 'show' }))).toBe(true);
    });

    it('restricts to the configured media type', () => {
      const rule = makeRule({ media_type: 'movie' });
      expect(ruleScopeMatches(rule, makeItem({ type: 'movie' }))).toBe(true);
      expect(ruleScopeMatches(rule, makeItem({ type: 'show' }))).toBe(false);
    });
  });

  describe('library scoping', () => {
    it('matches every library when library_keys is null', () => {
      const rule = makeRule({ library_keys: null });
      expect(ruleScopeMatches(rule, makeItem({ library_key: '1' }))).toBe(true);
      expect(ruleScopeMatches(rule, makeItem({ library_key: '99' }))).toBe(true);
      expect(ruleScopeMatches(rule, makeItem({ library_key: null }))).toBe(true);
    });

    it('matches every library when library_keys is empty', () => {
      const rule = makeRule({ library_keys: [] });
      expect(ruleScopeMatches(rule, makeItem({ library_key: '7' }))).toBe(true);
    });

    it('matches only items in a targeted library', () => {
      const rule = makeRule({ library_keys: ['2', '5'] });
      expect(ruleScopeMatches(rule, makeItem({ library_key: '2' }))).toBe(true);
      expect(ruleScopeMatches(rule, makeItem({ library_key: '5' }))).toBe(true);
      expect(ruleScopeMatches(rule, makeItem({ library_key: '1' }))).toBe(false);
    });

    it('excludes items with no library_key from library-restricted rules', () => {
      const rule = makeRule({ library_keys: ['1'] });
      expect(ruleScopeMatches(rule, makeItem({ library_key: null }))).toBe(false);
      expect(ruleScopeMatches(rule, makeItem({ library_key: undefined }))).toBe(false);
    });
  });

  describe('combined scoping', () => {
    it('requires both media type and library to match', () => {
      const rule = makeRule({ media_type: 'movie', library_keys: ['3'] });
      expect(ruleScopeMatches(rule, makeItem({ type: 'movie', library_key: '3' }))).toBe(true);
      expect(ruleScopeMatches(rule, makeItem({ type: 'show', library_key: '3' }))).toBe(false);
      expect(ruleScopeMatches(rule, makeItem({ type: 'movie', library_key: '4' }))).toBe(false);
    });
  });
});