const test = require('node:test'); const assert = require('node:assert/strict'); const { assertExpectedTiktokAccount, refreshTiktokTokens } = require('../lib/tiktok'); test('accepts the configured TikTok account', () => { assert.doesNotThrow(() => assertExpectedTiktokAccount('greenlens-id', 'greenlens-id')); }); test('rejects deployments without an expected GreenLens account', () => { assert.throws( () => assertExpectedTiktokAccount('greenlens-id', ''), (error) => error.code === 'TIKTOK_ACCOUNT_NOT_CONFIGURED' && error.status === 500, ); }); test('rejects a TikTok account that belongs to another brand', () => { assert.throws( () => assertExpectedTiktokAccount('qrmaster-id', 'greenlens-id'), (error) => error.code === 'TIKTOK_ACCOUNT_MISMATCH' && error.status === 409, ); }); test('expired refresh tokens require reconnecting before contacting TikTok', async () => { const row = { account_key: 'greenlens', open_id: 'greenlens-id', access_token: 'expired-access', refresh_token: 'expired-refresh', access_token_expires_at: new Date(Date.now() - 60_000), refresh_token_expires_at: new Date(Date.now() - 1_000), }; const db = { query: async (sql, params) => ({ rows: sql.startsWith('SELECT') && params[0] === 'greenlens' ? [row] : [] }), }; await assert.rejects( refreshTiktokTokens(db, { clientKey: 'client', clientSecret: 'secret' }), (error) => error.code === 'TIKTOK_RECONNECT_REQUIRED' && error.status === 401, ); }); test('concurrent refreshes share one provider request and persist rotated tokens', async () => { let row = { account_key: 'greenlens', open_id: 'greenlens-id', access_token: 'old-access', refresh_token: 'old-refresh', scope: 'video.upload', access_token_expires_at: new Date(Date.now() - 1_000), refresh_token_expires_at: new Date(Date.now() + 60_000), }; const db = { query: async (sql, params) => { if (sql.startsWith('SELECT')) return { rows: params[0] === 'greenlens' ? [row] : [] }; if (sql.startsWith('INSERT')) { row = { ...row, account_key: params[0], open_id: params[1], access_token: params[2], refresh_token: params[3], scope: params[4], access_token_expires_at: params[5], refresh_token_expires_at: params[6], }; } return { rows: [], rowCount: 1 }; }, }; const originalFetch = global.fetch; let providerCalls = 0; global.fetch = async () => { providerCalls += 1; await new Promise((resolve) => setTimeout(resolve, 10)); return { ok: true, json: async () => ({ open_id: 'greenlens-id', access_token: 'new-access', refresh_token: 'rotated-refresh', scope: 'video.upload', expires_in: 86_400, refresh_expires_in: 31_536_000, }), }; }; try { const [first, second] = await Promise.all([ refreshTiktokTokens(db, { clientKey: 'client', clientSecret: 'secret' }), refreshTiktokTokens(db, { clientKey: 'client', clientSecret: 'secret' }), ]); assert.equal(providerCalls, 1); assert.equal(first.access_token, 'new-access'); assert.equal(second.refresh_token, 'rotated-refresh'); } finally { global.fetch = originalFetch; } });