Files
Greenlens/server/test/tiktok.test.js
2026-07-11 22:04:38 +02:00

101 lines
3.3 KiB
JavaScript

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;
}
});