import assert from 'node:assert/strict'
import test from 'node:test'
import { createLinkToken } from './link.ts'
import {
ACCESS_TOKEN_SETUP_URL,
CLIENT_ID_SETUP_URL,
DEFAULT_ACCESS_TOKEN_SECRET,
DEFAULT_CLIENT_ID_SECRET,
DEFAULT_SECRET_SECRET,
PRODUCTION_API_BASE_URL,
SANDBOX_API_BASE_URL,
SANDBOX_API_HOST,
SECRET_SETUP_URL,
accessTokenForPreview,
accessTokenSetupUrl,
clientIdSetupUrl,
getPlaidApiBaseUrl,
mutationPreview,
parseAction,
requireConfirm,
resolveAccessTokenSecretName,
resolveClientIdSecretName,
resolveEnvironment,
resolveSecretSecretName,
secretSetupUrl,
} from './plaid-core.ts'
import { createSandboxPublicToken } from './sandbox.ts'
import { exchangePublicToken } from './item.ts'
test('resolve secret names default and suffix accounts', () => {
assert.equal(resolveClientIdSecretName(), DEFAULT_CLIENT_ID_SECRET)
assert.equal(resolveClientIdSecretName({ account: 'default' }), DEFAULT_CLIENT_ID_SECRET)
assert.equal(resolveClientIdSecretName({ account: 'work' }), 'plaidClientId-work')
assert.equal(resolveSecretSecretName({ account: 'work' }), 'plaidSecret-work')
assert.equal(resolveAccessTokenSecretName({ account: 'work' }), 'plaidAccessToken-work')
assert.equal(resolveClientIdSecretName({ clientIdSecret: 'plaidClientId-live' }), 'plaidClientId-live')
})
test('resolve secret names reject Kent-style aliases and invalid labels', () => {
assert.throws(() => resolveClientIdSecretName({ clientIdSecret: 'PLAID_CLIENT_ID' }), /plaidClientId/)
assert.throws(() => resolveSecretSecretName({ secretSecret: 'plaid_secret' }), /plaidSecret/)
assert.throws(() => resolveAccessTokenSecretName({ accessTokenSecret: 'kentPlaidToken' }), /plaidAccessToken/)
assert.throws(() => resolveClientIdSecretName({ account: 'youtube-brand!' }), /short label/)
})
test('setup URLs stay prefilled for the hosted secrets page', () => {
assert.equal(clientIdSetupUrl(), CLIENT_ID_SETUP_URL)
assert.equal(secretSetupUrl(), SECRET_SETUP_URL)
assert.equal(accessTokenSetupUrl(), ACCESS_TOKEN_SETUP_URL)
assert.match(CLIENT_ID_SETUP_URL, /name=plaidClientId/)
assert.match(SECRET_SETUP_URL, /name=plaidSecret/)
assert.match(CLIENT_ID_SETUP_URL, /allowedHosts=sandbox\.plaid\.com,production\.plaid\.com/)
assert.match(SECRET_SETUP_URL, /PLAID_SECRET/)
assert.match(accessTokenSetupUrl('plaidAccessToken-work'), /name=plaidAccessToken-work/)
assert.match(ACCESS_TOKEN_SETUP_URL, /Not%20a%20bank%20password/)
})
test('environment defaults to sandbox', () => {
assert.equal(resolveEnvironment(), 'sandbox')
assert.equal(getPlaidApiBaseUrl(), SANDBOX_API_BASE_URL)
assert.equal(getPlaidApiBaseUrl({ environment: 'production' }), PRODUCTION_API_BASE_URL)
assert.throws(() => resolveEnvironment({ environment: 'development' as 'sandbox' }), /sandbox/)
})
test('access token preview never emits a resolvable secret placeholder', () => {
assert.equal(accessTokenForPreview(), 'secret:plaidAccessToken')
assert.equal(accessTokenForPreview({ accessToken: 'access-sandbox-example' }), '<access_token>')
assert.doesNotMatch(accessTokenForPreview(), /\{\{secret:/)
})
test('requireConfirm blocks live mutations', () => {
assert.throws(() => requireConfirm({}, 'create link token'), /confirm: true/)
requireConfirm({ confirm: true }, 'create link token')
})
test('mutationPreview defaults to dry-run without confirm', () => {
const preview = mutationPreview(
{},
{
action: 'create link token',
method: 'POST',
path: '/link/token/create',
body: { client_name: 'Kody' },
},
)
assert.deepEqual(preview, {
dryRun: true,
action: 'create link token',
method: 'POST',
path: '/link/token/create',
environment: 'sandbox',
host: SANDBOX_API_HOST,
body: { client_name: 'Kody' },
})
})
test('mutationPreview confirm without dryRun is live (returns null)', () => {
const preview = mutationPreview(
{ confirm: true },
{ action: 'create link token', method: 'POST', path: '/link/token/create' },
)
assert.equal(preview, null)
})
test('parseAction defaults and rejects unknown actions', () => {
assert.equal(parseAction(undefined, ['smoke-test', 'get-item'], 'smoke-test', 'Plaid'), 'smoke-test')
assert.throws(() => parseAction('refund', ['smoke-test'], 'smoke-test', 'Plaid'), /Unknown Plaid action/)
})
test('createLinkToken defaults to a dry-run preview', async () => {
const preview = await createLinkToken({ clientUserId: 'user-1' })
assert.equal('dryRun' in preview && preview.dryRun, true)
if ('dryRun' in preview) {
assert.equal(preview.path, '/link/token/create')
assert.equal(preview.body?.client_name, 'Kody')
}
})
test('createSandboxPublicToken defaults to dry-run and rejects production', async () => {
const preview = await createSandboxPublicToken()
assert.equal('dryRun' in preview && preview.dryRun, true)
await assert.rejects(
() => createSandboxPublicToken({ environment: 'production', confirm: true }),
/Sandbox-only/,
)
})
test('exchangePublicToken dry-run does not require a public token', async () => {
const preview = await exchangePublicToken()
assert.equal('dryRun' in preview && preview.dryRun, true)
})