fix(test-dispatch): fall back to tracker defaults, surface soft errors

- dispatch_test_notification now resolves tracking_config / template_config
  from the tracker's default_* fields when the per-link override is unset,
  matching what load_link_data does for the real watcher. Previously
  periodic/scheduled/memory tests silently failed with "no template
  defined" whenever the user configured the template config at the
  tracker level instead of on each link (the UI's normal default).
- Distinguish the two missing-template cases in the returned error
  ("no template config linked" vs. "slot missing in linked config").
- Frontend testTrackerTarget now treats {success:false,error:"..."} in a
  2xx body as a failure — previously any 2xx flashed a success snack so
  users never saw the real reason their test didn't deliver.
This commit is contained in:
2026-04-22 01:25:35 +03:00
parent a7a2b4efa4
commit 80c034d2af
2 changed files with 35 additions and 9 deletions
@@ -358,8 +358,19 @@
if (ttTesting[key]) return;
ttTesting = { ...ttTesting, [key]: testType };
try {
await api(`/notification-trackers/${trackerId}/targets/${ttId}/test/${testType}?locale=${getLocale()}`, { method: 'POST' });
snackSuccess(t('snack.targetTestSent'));
// The endpoint returns 200 OK with ``{success: false, error: "..."}``
// on soft failures (missing template slot, no matching assets,
// provider unreachable, etc.), so checking for a thrown exception
// is not enough. Surface ``error`` as a snackError when present.
const res = await api<{ success?: boolean; error?: string; target?: string }>(
`/notification-trackers/${trackerId}/targets/${ttId}/test/${testType}?locale=${getLocale()}`,
{ method: 'POST' },
);
if (res && res.success === false) {
snackError(res.error || t('common.error'));
} else {
snackSuccess(t('snack.targetTestSent'));
}
} catch (err: any) {
snackError(err.message);
} finally {