Files
social/server/audience.test.mjs
b272d4701c Tell the truth on Connect, and let an org keep its own accounts and keys (#9)
* Say when a connector catalog is loading, missing, or unconfigured.

The Connect card treated a /v1/provider read that had not answered as
"not in the catalog". Cards now say whether that read is in flight,
failed, the network is absent, or present without app credentials —
and name the connect-plane variables, keeping the publish plane's
names when they differ. The read asks for each social network by id
instead of the unfiltered registry.

Co-authored-by: z <[email protected]>

* Let an organization keep several accounts on one network.

Connect already listed every handle the social API returned, but it
never said which was a person and which was the company. Each account
can now be personal or the network's own business kind — company on X,
a Company Page on LinkedIn, a Page on Facebook, Business on Instagram —
and the composer counts those kinds. The kind is stored on
/v1/settings/social-audiences so it does not share a document with the
Postiz post settings.

Co-authored-by: z <[email protected]>

* Add a Keys page for an organization's own app credentials.

GET and PUT /v1/social/credentials are the contract the connect plane is
growing: the public client id comes back, the secret never does, an
omitted secret is left sealed, and an empty secret clears it. The screen
masks both. A deployment that answers 404 or 501 has not shipped the
route, and Keys stays off the rail until it has.

Co-authored-by: z <[email protected]>

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: z <[email protected]>
2026-10-26 17:56:06 -07:00

73 lines
2.2 KiB
JavaScript

import assert from 'node:assert/strict'
import test from 'node:test'
import {
accountLine,
audienceLabel,
audiencesFor,
readAudiences,
whereLine,
writeAudiences,
} from '../src/audience.ts'
test('each network names personal and its own kind of business account', () => {
assert.deepEqual(
audiencesFor('x').map((choice) => choice.label),
['Personal', 'Company'],
)
assert.deepEqual(
audiencesFor('linkedin').map((choice) => choice.label),
['Personal', 'Company Page'],
)
assert.deepEqual(
audiencesFor('facebook').map((choice) => choice.label),
['Personal', 'Page'],
)
assert.deepEqual(
audiencesFor('instagram').map((choice) => choice.label),
['Personal', 'Business'],
)
assert.equal(audienceLabel('tiktok', 'business'), 'Business')
assert.equal(audienceLabel('x', undefined), '')
})
test('a kind map ignores anything that is not personal or business', () => {
assert.deepEqual(
readAudiences({
accounts: { a: 'personal', b: 'business', c: 'page', d: '', e: 1 },
posts: { keep: true },
}),
{ a: 'personal', b: 'business' },
)
assert.deepEqual(readAudiences(null), {})
assert.deepEqual(readAudiences({ accounts: ['personal'] }), {})
})
test('writing kinds keeps every other settings key', () => {
const next = writeAudiences(
{ posts: { p1: { tone: 'plain' } }, accounts: { old: 'personal' } },
{ acct_x: 'business' },
)
assert.deepEqual(next.posts, { p1: { tone: 'plain' } })
assert.deepEqual(next.accounts, { acct_x: 'business' })
assert.deepEqual(writeAudiences(undefined, { a: 'personal' }).accounts, { a: 'personal' })
})
test('several accounts on one network are counted and their kinds named once', () => {
const audiences = { personal: 'personal', company: 'business', bare: 'personal' }
assert.equal(
whereLine(
'linkedin',
[{ id: 'personal' }, { id: 'company' }, { id: 'bare' }],
audiences,
),
'Where posts go — 3 accounts · Personal, Company Page',
)
assert.equal(accountLine(1, ['Personal']), '1 account · Personal')
assert.equal(accountLine(0, []), '0 accounts')
assert.equal(
whereLine('x', [{ id: 'missing' }], {}),
'Where posts go — 1 account',
)
})