/ tests / utils / sync-unsubscribes.test.js
sync-unsubscribes.test.js
 1  /**
 2   * Tests for src/utils/sync-unsubscribes.js
 3   *
 4   * Tests the pure synchronous exports that query the local DB:
 5   * - isEmailUnsubscribed
 6   * - getUnsubscribeCount
 7   *
 8   * syncUnsubscribes() requires a live Cloudflare Worker endpoint — not tested here.
 9   *
10   * Uses pg-mock pattern since sync-unsubscribes.js imports from db.js.
11   */
12  
13  import { test, describe, before, mock } from 'node:test';
14  import assert from 'node:assert/strict';
15  import Database from 'better-sqlite3';
16  import { createPgMock } from '../helpers/pg-mock.js';
17  
18  const db = new Database(':memory:');
19  db.exec(`
20    CREATE TABLE IF NOT EXISTS unsubscribed_emails (
21      id INTEGER PRIMARY KEY AUTOINCREMENT,
22      email TEXT NOT NULL UNIQUE,
23      created_at TEXT NOT NULL DEFAULT (datetime('now'))
24    );
25  `);
26  
27  mock.module('../../src/utils/db.js', { namedExports: createPgMock(db) });
28  
29  const { isEmailUnsubscribed, getUnsubscribeCount } =
30    await import('../../src/utils/sync-unsubscribes.js');
31  
32  before(() => {
33    db.exec(`INSERT INTO unsubscribed_emails (email) VALUES ('unsubbed@example.com')`);
34    db.exec(`INSERT INTO unsubscribed_emails (email) VALUES ('UPPERCASE@EXAMPLE.COM')`);
35  });
36  
37  // ─── isEmailUnsubscribed ──────────────────────────────────────────────────────
38  
39  describe('isEmailUnsubscribed', () => {
40    test('returns true for a known unsubscribed email', async () => {
41      assert.equal(await isEmailUnsubscribed('unsubbed@example.com'), true);
42    });
43  
44    test('is case-insensitive (COLLATE NOCASE)', async () => {
45      assert.equal(await isEmailUnsubscribed('UNSUBBED@EXAMPLE.COM'), true);
46      assert.equal(await isEmailUnsubscribed('Unsubbed@Example.Com'), true);
47    });
48  
49    test('returns false for an email not in the list', async () => {
50      assert.equal(await isEmailUnsubscribed('other@example.com'), false);
51    });
52  
53    test('returns false for empty string', async () => {
54      assert.equal(await isEmailUnsubscribed(''), false);
55    });
56  
57    test('returns false for null', async () => {
58      assert.equal(await isEmailUnsubscribed(null), false);
59    });
60  });
61  
62  // ─── getUnsubscribeCount ──────────────────────────────────────────────────────
63  
64  describe('getUnsubscribeCount', () => {
65    test('returns the number of unsubscribed emails', async () => {
66      const count = await getUnsubscribeCount();
67      assert.equal(typeof count, 'number');
68      assert.equal(count, 2); // inserted 2 in before()
69    });
70  
71    test('returns 0 when table is empty', async () => {
72      // Temporarily clear the table
73      db.exec('DELETE FROM unsubscribed_emails');
74  
75      const count = await getUnsubscribeCount();
76      assert.equal(count, 0);
77  
78      // Restore
79      db.exec(`INSERT INTO unsubscribed_emails (email) VALUES ('unsubbed@example.com')`);
80      db.exec(`INSERT INTO unsubscribed_emails (email) VALUES ('UPPERCASE@EXAMPLE.COM')`);
81    });
82  });