import test from 'node:test'; import assert from 'node:assert/strict'; import { addProviderCard, providerSavedCard, specFromCardInputs } from '../src/cards.js'; test('addProviderCard has the required inputs and a submit action', () => { const card = addProviderCard({ publicBaseUrl: 'https://status.example.com' }); assert.equal(card.contentType, 'application/vnd.microsoft.card.adaptive'); const ids = card.content.body.filter(b => b.type.startsWith('Input.')).map(b => b.id); assert.deepEqual(ids.sort(), ['key', 'name', 'rssUrl', 'siteUrl', 'sourceType', 'webhookFormat'].sort()); assert.equal(card.content.actions[0].type, 'Action.Submit'); assert.equal(card.content.actions[0].data.action, 'addProvider'); // The URL hint should include the public base. const hint = card.content.body.find(b => b.type === 'TextBlock' && b.text && b.text.includes('Webhook URL')); assert.ok(hint.text.includes('status.example.com')); }); test('addProviderCard falls back to a friendly warning when PUBLIC_BASE_URL is unset', () => { const card = addProviderCard({}); const hint = card.content.body.find(b => b.type === 'TextBlock' && b.text && b.text.includes('PUBLIC_BASE_URL')); assert.ok(hint, 'expected a PUBLIC_BASE_URL hint when the base URL is unset'); }); test('specFromCardInputs builds an RSS-only spec', () => { const { key, spec } = specFromCardInputs({ key: 'acme', name: 'Acme', sourceType: 'rss', rssUrl: 'https://acme.example/rss', }, 'room-123'); assert.equal(key, 'acme'); assert.equal(spec.name, 'Acme'); assert.equal(spec.roomId, 'room-123'); assert.equal(spec.rss.url, 'https://acme.example/rss'); assert.equal(spec.webhook, undefined); }); test('specFromCardInputs builds a webhook-only spec', () => { const { spec } = specFromCardInputs({ key: 'acme', name: 'Acme', sourceType: 'webhook', webhookFormat: 'uptimeKuma', }, 'room-123'); assert.equal(spec.webhook.format, 'uptimeKuma'); assert.equal(spec.rss, undefined); }); test('specFromCardInputs builds a both spec and copies siteUrl', () => { const { spec } = specFromCardInputs({ key: 'acme', name: 'Acme', siteUrl: 'https://status.acme.com', sourceType: 'both', rssUrl: 'https://acme.example/rss', webhookFormat: 'statusPage', }, 'room-123'); assert.equal(spec.rss.url, 'https://acme.example/rss'); assert.equal(spec.webhook.format, 'statusPage'); assert.equal(spec.siteUrl, 'https://status.acme.com'); }); test('specFromCardInputs errors when RSS is selected but no URL was provided', () => { assert.throws(() => specFromCardInputs({ key: 'acme', name: 'Acme', sourceType: 'rss', rssUrl: '' }, 'r'), /RSS URL is required/); }); test('providerSavedCard shows the webhook URL when applicable', () => { const card = providerSavedCard({ key: 'acme', provider: { name: 'Acme', webhook: { format: 'statusPage' } }, publicBaseUrl: 'https://status.example.com/', }); const monospace = card.content.body.find(b => b.fontType === 'Monospace'); assert.equal(monospace.text, 'https://status.example.com/acme'); }); test('providerSavedCard omits webhook block for RSS-only providers', () => { const card = providerSavedCard({ key: 'acme', provider: { name: 'Acme', rss: { url: 'https://a/rss' } }, publicBaseUrl: 'https://x', }); const monospace = card.content.body.find(b => b.fontType === 'Monospace'); assert.equal(monospace, undefined); });