/ tests / capture / backfill-screenshots.test.js
backfill-screenshots.test.js
  1  /**
  2   * Unit Tests for Backfill Screenshots Utility
  3   */
  4  
  5  import { describe, it, mock, beforeEach } from 'node:test';
  6  import assert from 'node:assert';
  7  import {
  8    findSitesWithMissingScreenshots,
  9    updateSiteScreenshots,
 10  } from '../../src/utils/backfill-screenshots.js';
 11  
 12  describe('Backfill Screenshots Module', () => {
 13    let mockDb;
 14  
 15    beforeEach(() => {
 16      // Reset mock database before each test
 17      mockDb = {
 18        prepare: mock.fn(),
 19      };
 20    });
 21  
 22    describe('findSitesWithMissingScreenshots', () => {
 23      it('should find sites with missing desktop screenshots', () => {
 24        const mockSites = [
 25          {
 26            id: 1,
 27            domain: 'example.com',
 28            landing_page_url: 'https://example.com',
 29            keyword: 'plumber sydney',
 30            missing_desktop_above: 1,
 31            missing_desktop_below: 0,
 32            missing_mobile_above: 0,
 33            missing_desktop_above_uncropped: 0,
 34            missing_desktop_below_uncropped: 0,
 35            missing_mobile_above_uncropped: 0,
 36          },
 37        ];
 38  
 39        const mockStmt = {
 40          all: mock.fn(() => mockSites),
 41        };
 42  
 43        mockDb.prepare.mock.mockImplementation(() => mockStmt);
 44  
 45        const result = findSitesWithMissingScreenshots(mockDb, 100);
 46  
 47        assert.strictEqual(result, mockSites);
 48        assert.strictEqual(mockDb.prepare.mock.callCount(), 1);
 49        assert.strictEqual(mockStmt.all.mock.callCount(), 1);
 50        assert.deepStrictEqual(mockStmt.all.mock.calls[0].arguments, [100]);
 51      });
 52  
 53      it('should find sites with missing mobile screenshots', () => {
 54        const mockSites = [
 55          {
 56            id: 2,
 57            domain: 'test.com',
 58            landing_page_url: 'https://test.com',
 59            keyword: 'electrician melbourne',
 60            missing_desktop_above: 0,
 61            missing_desktop_below: 0,
 62            missing_mobile_above: 1,
 63            missing_desktop_above_uncropped: 0,
 64            missing_desktop_below_uncropped: 0,
 65            missing_mobile_above_uncropped: 0,
 66          },
 67        ];
 68  
 69        const mockStmt = {
 70          all: mock.fn(() => mockSites),
 71        };
 72  
 73        mockDb.prepare.mock.mockImplementation(() => mockStmt);
 74  
 75        const result = findSitesWithMissingScreenshots(mockDb, 50);
 76  
 77        assert.strictEqual(result.length, 1);
 78        assert.strictEqual(result[0].missing_mobile_above, 1);
 79        assert.strictEqual(mockStmt.all.mock.calls[0].arguments[0], 50);
 80      });
 81  
 82      it('should find sites with missing uncropped screenshots', () => {
 83        const mockSites = [
 84          {
 85            id: 3,
 86            domain: 'uncropped-missing.com',
 87            landing_page_url: 'https://uncropped-missing.com',
 88            keyword: 'roofing perth',
 89            missing_desktop_above: 0,
 90            missing_desktop_below: 0,
 91            missing_mobile_above: 0,
 92            missing_desktop_above_uncropped: 1,
 93            missing_desktop_below_uncropped: 1,
 94            missing_mobile_above_uncropped: 1,
 95          },
 96        ];
 97  
 98        const mockStmt = {
 99          all: mock.fn(() => mockSites),
100        };
101  
102        mockDb.prepare.mock.mockImplementation(() => mockStmt);
103  
104        const result = findSitesWithMissingScreenshots(mockDb, 100);
105  
106        assert.strictEqual(result.length, 1);
107        assert.strictEqual(result[0].missing_desktop_above_uncropped, 1);
108        assert.strictEqual(result[0].missing_desktop_below_uncropped, 1);
109        assert.strictEqual(result[0].missing_mobile_above_uncropped, 1);
110      });
111  
112      it('should return empty array when no sites have missing screenshots', () => {
113        const mockStmt = {
114          all: mock.fn(() => []),
115        };
116  
117        mockDb.prepare.mock.mockImplementation(() => mockStmt);
118  
119        const result = findSitesWithMissingScreenshots(mockDb, 100);
120  
121        assert.strictEqual(result.length, 0);
122      });
123  
124      it('should respect the limit parameter', () => {
125        const mockStmt = {
126          all: mock.fn(() => []),
127        };
128  
129        mockDb.prepare.mock.mockImplementation(() => mockStmt);
130  
131        findSitesWithMissingScreenshots(mockDb, 25);
132  
133        assert.strictEqual(mockStmt.all.mock.calls[0].arguments[0], 25);
134      });
135    });
136  
137    describe('updateSiteScreenshots', () => {
138      it('should update all screenshot fields', () => {
139        const mockStmt = {
140          run: mock.fn(),
141        };
142  
143        mockDb.prepare.mock.mockImplementation(() => mockStmt);
144  
145        const screenshots = {
146          desktop_above: Buffer.from('desktop_above_data'),
147          desktop_below: Buffer.from('desktop_below_data'),
148          mobile_above: Buffer.from('mobile_above_data'),
149        };
150  
151        const screenshotsUncropped = {
152          desktop_above: Buffer.from('desktop_above_uncropped_data'),
153          desktop_below: Buffer.from('desktop_below_uncropped_data'),
154          mobile_above: Buffer.from('mobile_above_uncropped_data'),
155        };
156  
157        updateSiteScreenshots(mockDb, 1, screenshots, screenshotsUncropped);
158  
159        assert.strictEqual(mockDb.prepare.mock.callCount(), 1);
160        assert.strictEqual(mockStmt.run.mock.callCount(), 1);
161  
162        const runArgs = mockStmt.run.mock.calls[0].arguments;
163        assert.strictEqual(runArgs[0], screenshots.desktop_above);
164        assert.strictEqual(runArgs[1], screenshots.desktop_below);
165        assert.strictEqual(runArgs[2], screenshots.mobile_above);
166        assert.strictEqual(runArgs[3], screenshotsUncropped.desktop_above);
167        assert.strictEqual(runArgs[4], screenshotsUncropped.desktop_below);
168        assert.strictEqual(runArgs[5], screenshotsUncropped.mobile_above);
169        assert.strictEqual(runArgs[6], 1); // site ID
170      });
171  
172      it('should handle null screenshots gracefully', () => {
173        const mockStmt = {
174          run: mock.fn(),
175        };
176  
177        mockDb.prepare.mock.mockImplementation(() => mockStmt);
178  
179        const screenshots = {
180          desktop_above: null,
181          desktop_below: Buffer.from('desktop_below_data'),
182          mobile_above: null,
183        };
184  
185        const screenshotsUncropped = {
186          desktop_above: null,
187          desktop_below: Buffer.from('desktop_below_uncropped_data'),
188          mobile_above: null,
189        };
190  
191        updateSiteScreenshots(mockDb, 5, screenshots, screenshotsUncropped);
192  
193        const runArgs = mockStmt.run.mock.calls[0].arguments;
194        assert.strictEqual(runArgs[0], null);
195        assert.strictEqual(runArgs[1], screenshots.desktop_below);
196        assert.strictEqual(runArgs[2], null);
197        assert.strictEqual(runArgs[3], null);
198        assert.strictEqual(runArgs[4], screenshotsUncropped.desktop_below);
199        assert.strictEqual(runArgs[5], null);
200        assert.strictEqual(runArgs[6], 5);
201      });
202  
203      it('should update the correct site by ID', () => {
204        const mockStmt = {
205          run: mock.fn(),
206        };
207  
208        mockDb.prepare.mock.mockImplementation(() => mockStmt);
209  
210        const screenshots = {
211          desktop_above: Buffer.from('data'),
212          desktop_below: Buffer.from('data'),
213          mobile_above: Buffer.from('data'),
214        };
215  
216        const screenshotsUncropped = {
217          desktop_above: Buffer.from('data'),
218          desktop_below: Buffer.from('data'),
219          mobile_above: Buffer.from('data'),
220        };
221  
222        updateSiteScreenshots(mockDb, 42, screenshots, screenshotsUncropped);
223  
224        const runArgs = mockStmt.run.mock.calls[0].arguments;
225        assert.strictEqual(runArgs[6], 42);
226      });
227    });
228  });