Commit Graph
15 Commits
Author SHA1 Message Date
Divarion_D 1e2a0d13c1 test(e2e): give the category poll longer than one heavy cache cycle
`the channel is listed under its category` failed intermittently on the second
poll: the category never showed up in get_live_categories within 200s.

That list is filtered by the line's category_ids, which UserRepository builds
from the `category_map` cache file, and only CacheCronJob's heavy pass writes
it. That pass returns early while its `heavy_cache_built` marker is under 300s
old, and cron:cache runs once a minute, so a category created just after a pass
waits up to ~360s. A 200s budget cannot cover that — the test passed only when
the category happened to land late in a cycle, which is why it looked flaky
rather than broken.

The poll now gets 380s and the test 600s, with the 300s throttle named in the
comment so the budget is not trimmed back without seeing why it is that size.
Nothing in the panel changed; the first poll (get_live_streams, fed by the
light pass) was always passing.

Forcing the rebuild from the test is not an option: ./api?action=regenerate_cache
runs cron:cache_engine, which only reads bouquet_map, and the only way to skip
the throttle is `console.php cron:cache 1` — a shell the HTTP-only harness does
not have.

Verified: the full spec file passes (10/10, 3.5m).
2026-09-22 21:50:52 +03:00
rootandobscuremind 469a8a8d64 test: add bouquet and admin playback coverage 2026-09-18 09:57:17 +00:00
df66b8fc71 test(e2e): player API lists a real channel under its category
The spec now gives the line a bouquet with a (never started) live channel
in its own category and checks get_live_streams / get_live_categories
list it — which caught the icon-less channel crash — plus the
/player_api/<user>/<pass>[/<action>] path form and active_cons.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4P9p5BXijMoGXd31tN6Zp
2026-09-18 09:57:17 +00:00
4295835f84 test(e2e): a line signs in to player_api and every action answers JSON
Creates a bouquet and a line, signs in to player_api.php as an app does
and walks each action; info actions must stay empty for content outside
the line's bouquets, and malformed parameters and a wrong password must
still get JSON. Guards the sign-in TypeError that broke every player.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4P9p5BXijMoGXd31tN6Zp
2026-09-18 09:57:17 +00:00
edcb5bad8e test(e2e): every date field opens its calendar
Covers the expiry pickers on the line, MAG and Enigma2 forms (pick a day,
type a date, never-expire disables it), on their mass-edit pages once the
field is enabled, and the log pages' date range filters.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4P9p5BXijMoGXd31tN6Zp
2026-09-18 09:57:17 +00:00
rootandClaude Opus 5 4357bbdbab test(e2e): cover activation codes, category templates and range reports
The active-codes pages and both category template pages went blank, and
theft detection showed nothing, without any spec noticing:

- templates.spec.ts opens the four activation-code pages and walks a
  category template through the menu's create entry, create, rename and
  system switch, clone and delete; it also fails on icons the generated
  subset lacks (they render as solid squares).
- reports.spec.ts checks theft detection and line IP usage keep the
  chosen range.
- The cleanup teardown sweeps leftover e2e-named templates.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4P9p5BXijMoGXd31tN6Zp
2026-09-17 08:25:01 +00:00
rootandClaude Opus 5 d0458a8eeb test(e2e): drive the admin panel the way an administrator does
The Playwright suite only checked that pages render. It now performs the
administrator's work against a live test panel and asserts the panel's own
data after each step:

- catalogue: a stream category, a bouquet and a reseller package — created,
  renamed / edited, reopened, deleted;
- subscribers: a line with a bouquet (search, edit in the modal, disable /
  enable, ban / unban, delete), a MAG and an Enigma2 device;
- bulk: two lines selected with the header checkbox, disabled and deleted;
- resellers: created with credits, topped up, edited, disabled, deleted;
- block lists: an IP (RFC 5737 address — blocking adds an iptables rule), a
  user agent and an ISP;
- streams: a live stream added with a source and a server, started, running
  with codecs and the Resources column filled in, stopped, renamed, deleted;
- sign-in: a second administrator refused with a wrong password, signing in
  and out — a separate account, because every admin login re-hashes the
  password and ends that account's other sessions.

Records are named `e2e-<run>-…`; a teardown project sweeps whatever a run
leaves behind and nothing else. tools/create-admin.php provisions the
dedicated test administrator on the panel host.

The first runs found three save paths that answered an empty page (fixed in
f7bba5cb, fd13c940, ee2f586a). Against the test panel: 82 passed, 1 skipped
(no series to select).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WDhDajBPziJwjWZcXnh6R
2026-09-16 14:39:39 +00:00
Divarion_D 53efe7071c refactor(admin-ui): rename vuexy identifiers to newui + fix mangled names
Rename the last lowercase "vuexy" identifiers left after the de-brand:
- views {header,footer,menu,vendors,topbar}.vuexy.php -> .newui.php
- functions xc_admin_use_vuexy / xc_vuexy_vendor_* / _xc_vuexy_icon -> *_newui*
- constant XC_VUEXY_PAGES -> XC_NEWUI_PAGES
- E2E spec vuexy-tables.spec.ts -> newui-tables.spec.ts + drop the brand
  name from test/Makefile prose

Also fix two identifiers the earlier brand scrub corrupted (a bare "Vuexy"
in a name became "Bootstrap 5", inserting a space): class
XcVuexyMenuBuilder -> XcNewuiMenuBuilder (was a parse error in the menu view)
and global key xmVuexyVendors -> xmNewuiVendors.

Refs: #148 #178
2026-09-03 19:50:15 +03:00
Divarion_D 34c3edd48e feat(admin-ui): migrate streams (Live Streams) to clean-JSON table
Rebuild the panel's most complex serverSide table on the Bootstrap 5 stack.
handleStreams now emits structured rows (StatusBadge::stream code, live uptime,
convert-to-channel encode %, restart-fails indicator, current server/source,
client count, EPG availability, player-codec compatibility, archive/adaptive/
title-sync flags, codec stream-info) instead of building HTML; the view renders
every cell and the per-row action dropdown client-side via datatables-bs5. The
$rActualStatus computation is preserved verbatim; the data-gathering (grouping,
per-server fails, redis connection counts) is untouched.

Features: category / server / status / codec filters, bulk-select toolbar
(start/stop/restart/kill/delete via action=multi&type=stream), per-row edit +
fingerprint iframe modals, start/stop/restart/purge/delete via action=stream,
player, live-connections link, CSV export. $rOrder gains the control + checkbox
offset. Add streams to the allowlist + E2E suite and the `filter` i18n key.
Verified on canary: 200, correct row shape, renders.

Refs: #148 #178
2026-09-02 20:43:54 +03:00
Divarion_D 1895ce63d0 feat(admin-ui): migrate lines (Lines) to clean-JSON table
Rebuild the panel's largest management table on the Bootstrap 5 stack. handleLines
now emits structured rows (status code, online/trial/restreamer flags, live
connection count, current stream, owner, formatted expiration + last-connection,
notes, ban/enable state, contact) instead of HTML; the view renders every cell
and the per-row action dropdown client-side via datatables-bs5.

Features: reseller (select2-ajax) + status + search filters, bulk-select
toolbar (enable/disable/ban/unban/kill/delete via action=multi&type=line),
per-row edit + fingerprint iframe modals, native Download-Playlist modal
(output_devices) and WhatsApp-renewal modal, kill/ban/unban/enable/disable/
delete via action=line, and CSV export. $rOrder gains the control + checkbox
offset. Add lines to the allowlist + E2E suite (ajax wait widened to 40s for
this heavy handler) and the `all` / `download_playlist` i18n keys.

Refs: #148 #178
2026-09-02 20:10:57 +03:00
Divarion_D 62639aacc6 feat(admin-ui): migrate backups (Backups) to clean-JSON table
Rebuild the Backups page on the Bootstrap 5 stack: the Dropbox / automatic-backup
settings form (native Bootstrap 5 fields + form-switch) posting to
post.php?action=backups, plus the backups list as a clean-JSON table.
handleBackups now emits structured rows (date, filename, size, local flag,
remote state yes/no/error/uploading + error message) and the view renders
status dots, size and restore/delete actions client-side; Create Backup Now
and restore/delete hit ./api?action=backup.

Add backups to the Bootstrap 5 allowlist and the E2E smoke suite (new noControl
flag for tables without a Responsive control column).

Refs: #148 #178
2026-09-02 19:51:35 +03:00
Divarion_D 0083729df5 feat(admin-ui): migrate radios (Radio Stations) to clean-JSON table
Convert handleRadios to the clean-JSON serverSide pattern and rebuild the
radios view on the Bootstrap 5 datatables-bs5 stack (twin of movies, audio
live-streams): icon column, StatusBadge::stream badges with live uptime for
ONLINE, start/stop/restart/kill + edit-modal + delete row actions via
action=stream, bulk delete (action=multi&type=radio), category/server
filters, and a codec/bitrate/speed stream-info column.

Add the missing `restart` i18n key (guards Translator self-poisoning),
add radios to the Bootstrap 5 allowlist and the E2E MANAGEMENT smoke array.

Refs: #148 #178
2026-09-02 19:40:39 +03:00
Divarion_D 1adc5ae96c feat(admin-ui): migrate movies (VOD) to clean-JSON management table
First stream-class content table on the JSON-first pattern:

- TableController::handleMovies: the transcode status code (StatusBadge::vod),
  category, per-server info (name/url/count/offline), client count and codec
  stream-info are resolved server-side; the render branch now emits a structured
  JSON object instead of positional HTML. Two leading false entries prepended to
  $rOrder for the Bootstrap 5 control + bulk-select columns.
- movies.php rewritten as a Bootstrap 5 datatables-bs5 serverSide table with client-side
  render (cover, title+year+category, server link + "+N" servers + offline flag,
  client count linking to live connections, VOD status badge, TMDB, a codec
  stream-info badge row, player). Checkbox column + select-all + bulk delete
  (action=multi&type=movie); row actions: encode start/stop + edit iframe modal +
  delete (action=movie). Category / server / resolution / video / audio filters.
- movies added to the allowlist + the E2E smoke suite; encode/start_encoding/
  stop_encoding keys added.

Refs: #148 #178
2026-09-02 19:32:14 +03:00
Divarion_D c97ba90d1d test(e2e): smoke suite for the migrated Bootstrap 5 admin tables
Adds tests/e2e/tests/vuexy-tables.spec.ts — a data-driven Playwright suite over
every admin page migrated to the Bootstrap 5 clean-JSON / client-side datatables-bs5
pattern (30 pages: logs, security blocklists, reference lists, management).

For each page it asserts the page renders inside the Bootstrap 5 shell (#layout-menu —
proving the xc_admin_use_vuexy allowlist routed it to the new layout, not legacy
chrome), its Bootstrap 5-specific table id is present, a leading Responsive control
column exists, and — for serverSide tables — the DataTables ./table ajax answers
200. Three interaction checks cover series bulk-select, panel_logs server-side
search, and the users row-action dropdown.

All 34 tests (incl. the auth setup project) pass against the canary.

Refs: #148 #178
2026-09-02 19:20:03 +03:00
Divarion_D f348cf08cc test(e2e): Playwright smoke harness for the Bootstrap 5 admin
Add a browser E2E project under tests/e2e/ that runs against a live panel
(there is no built-in server). Verified green (7/7) against a canary instance.

- playwright.config.ts: loads tests/e2e/.env (dotenv); a `setup` project logs in
  once (auth.setup.ts — form #username/#password/#login_button -> ./login) and
  stores the session, the chromium project reuses it via storageState. baseURL is
  normalized to a trailing slash so relative gotos keep the access-code segment.
- Smoke specs: shell renders (sidebar/navbar, server-stamped data-bs-theme);
  Dashboard group + Home link; six stat tiles + a live ./api?action=stats 200;
  charts + server selector; customizer theme change persists across reload and
  reset (opening the customizer panel) clears it.
- Config via env: XC_E2E_BASE_URL (admin base incl. access code), XC_E2E_USER,
  XC_E2E_PASS (see .env.example / README). Makefile: `make e2e` / `e2e-ui` /
  `e2e-install`. node_modules/.auth/results/.env gitignored; @playwright/test
  pinned ~1.49 (Node 18+).
2026-09-01 20:14:21 +03:00