Skip to content

Commit c9b6077

Browse files
committed
Finish test coverage
1 parent 7dc9808 commit c9b6077

File tree

4 files changed

+91
-30
lines changed

4 files changed

+91
-30
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#### Браузерное расширение для загрузки манги | v1.0.1
44

55
[![Test Extension](https://github.com/ivanvit100/DownloadLib/actions/workflows/test.yaml/badge.svg)](https://github.com/ivanvit/DownloadLib/actions/workflows/test.yaml)
6-
![Code Coverage](https://img.shields.io/badge/Coverage-93.75%25-brightgreen)
6+
![Code Coverage](https://img.shields.io/badge/Coverage-100%25-brightgreen)
77

88
**DownloadLib** — расширение для браузера, позволяющее скачивать мангу с порталов [*MangaLib*](https://mangalib.me/) и [*RanobeLib*](https://ranobelib.me/) в форматах *FB2*, *EPUB* и *PDF*. Поддерживает автоматическую обработку изображений и текста, а также гибкие настройки скорости загрузки.
99

background/Background.js

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ function detectServiceByReferer(details) {
4848
return 'mangalib';
4949
if (details.url.includes('ranobelib.me'))
5050
return 'ranobelib';
51+
return null;
5152
}
5253

5354
return null;
@@ -94,7 +95,7 @@ if (isFirefox && browserAPI && browserAPI.webRequest) {
9495
if (existing) existing.value = value;
9596
else headers.push({ name, value });
9697
}
97-
}
98+
} else console.warn(`[Background] No headers found for service ${serviceName} (isImage: ${isImage})`);
9899
}
99100

100101
return { requestHeaders: headers };
@@ -114,9 +115,7 @@ if (isChrome && browserAPI && browserAPI.webRequest) {
114115
if (!isFromExtension(details)) return;
115116

116117
const serviceName = detectServiceByReferer(details);
117-
if (serviceName) {
118-
await rateLimiter.trackRequest(serviceName);
119-
}
118+
serviceName && await rateLimiter.trackRequest(serviceName);
120119
},
121120
{ urls: ['<all_urls>'] },
122121
['requestHeaders']
@@ -132,14 +131,10 @@ if (browserAPI && browserAPI.runtime && browserAPI.runtime.onMessage) {
132131
rateLimiter.setLimit(message.limit);
133132
sendResponse({ ok: true });
134133
return true;
135-
}
136-
137-
if (message.action === 'getRateLimiterStats') {
134+
} else if (message.action === 'getRateLimiterStats') {
138135
sendResponse({ ok: true, stats: rateLimiter.getStats() });
139136
return true;
140-
}
141-
142-
if (message.action === 'fetchImage') {
137+
} else if (message.action === 'fetchImage') {
143138
(async () => {
144139
try {
145140
const url = message.url;
@@ -187,9 +182,7 @@ if (browserAPI && browserAPI.runtime && browserAPI.runtime.onMessage) {
187182
}
188183
})();
189184
return true;
190-
}
191-
192-
if (message.action === 'fetchWithRateLimit') {
185+
} else if (message.action === 'fetchWithRateLimit') {
193186
(async () => {
194187
try {
195188
const url = message.url;
@@ -222,9 +215,7 @@ if (browserAPI && browserAPI.runtime && browserAPI.runtime.onMessage) {
222215
}
223216
})();
224217
return true;
225-
}
226-
227-
if (message.action === 'takeOverDownload') {
218+
} else if (message.action === 'takeOverDownload') {
228219
(async () => {
229220
try {
230221
const result = await backgroundDownload.takeOverDownload({
@@ -246,30 +237,22 @@ if (browserAPI && browserAPI.runtime && browserAPI.runtime.onMessage) {
246237
}
247238
})();
248239
return true;
249-
}
250-
251-
if (message.action === 'getActiveDownloads') {
240+
} else if (message.action === 'getActiveDownloads') {
252241
sendResponse({ ok: true, downloads: backgroundDownload.getActiveDownloads() });
253242
return true;
254-
}
255-
256-
if (message.action === 'pauseBackgroundDownload') {
243+
} else if (message.action === 'pauseBackgroundDownload') {
257244
backgroundDownload.pause(message.downloadId);
258245
sendResponse({ ok: true });
259246
return true;
260-
}
261-
262-
if (message.action === 'resumeBackgroundDownload') {
247+
} else if (message.action === 'resumeBackgroundDownload') {
263248
backgroundDownload.resume(message.downloadId);
264249
sendResponse({ ok: true });
265250
return true;
266-
}
267-
268-
if (message.action === 'stopBackgroundDownload') {
251+
} else if (message.action === 'stopBackgroundDownload') {
269252
backgroundDownload.stop(message.downloadId);
270253
sendResponse({ ok: true });
271254
return true;
272-
}
255+
} else return false;
273256
});
274257

275258
console.log('[Background] Message listener installed');

background/BackgroundDownload.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,5 @@ const backgroundDownload = new BackgroundDownload();
218218

219219
console.log('[BackgroundDownload] Loaded');
220220

221+
/* istanbul ignore next */
221222
if (typeof module !== 'undefined') module.exports = { BackgroundDownload, backgroundDownload };

tests/background/Background.test.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,41 @@ describe('Background', () => {
291291
});
292292
expect(result.requestHeaders).toEqual(headers);
293293
});
294+
295+
it('Falls back to empty array when requestHeaders is undefined', async () => {
296+
const result = await capturedBeforeSendHeadersCb({
297+
tabId: -1,
298+
frameId: 0,
299+
url: 'https://example.com/page',
300+
requestHeaders: undefined,
301+
});
302+
expect(mockTrackRequest).not.toHaveBeenCalled();
303+
expect(result).toEqual({ requestHeaders: [] });
304+
});
305+
306+
it('Returns null for image request from unknown cdn without matching service url', async () => {
307+
await capturedBeforeSendHeadersCb({
308+
tabId: -1,
309+
frameId: 0,
310+
url: 'https://cdn.example.com/uploads/image.jpg',
311+
requestHeaders: [],
312+
});
313+
expect(mockTrackRequest).not.toHaveBeenCalled();
314+
});
315+
316+
it('Warns when no headers found for service config without targetHeaders', async () => {
317+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
318+
globalThis.mangalibConfig = { headers: null, imageHeaders: null };
319+
await loadModule();
320+
await capturedBeforeSendHeadersCb({
321+
tabId: -1,
322+
frameId: 0,
323+
url: 'https://api.mangalib.me/data',
324+
requestHeaders: [{ name: 'Referer', value: 'https://mangalib.me/' }],
325+
});
326+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('No headers found for service mangalib'));
327+
warnSpy.mockRestore();
328+
});
294329
});
295330

296331
describe('Chrome mode', () => {
@@ -643,6 +678,48 @@ describe('Background', () => {
643678
expect(sendResponse).toHaveBeenCalledWith({ ok: true });
644679
expect(result).toBe(true);
645680
});
681+
682+
it('Uses full reader result when split produces no base64 part', async () => {
683+
const blob = new Blob(['img'], { type: 'image/jpeg' });
684+
globalThis.fetch = vi.fn().mockResolvedValue({
685+
ok: true,
686+
blob: vi.fn().mockResolvedValue(blob),
687+
});
688+
globalThis.FileReader = class {
689+
readAsDataURL() {
690+
setTimeout(() => {
691+
this.result = 'no-comma-here';
692+
this.onloadend();
693+
}, 0);
694+
}
695+
};
696+
const sendResponse = vi.fn();
697+
capturedMessageCb({ action: 'fetchImage', url: 'https://img.com/a.jpg' }, {}, sendResponse);
698+
await vi.waitFor(() => expect(sendResponse).toHaveBeenCalled());
699+
expect(sendResponse).toHaveBeenCalledWith(
700+
expect.objectContaining({ ok: true, base64: 'no-comma-here' }),
701+
);
702+
});
703+
704+
it('Uses image/jpeg as fallback when blob type is empty', async () => {
705+
const blob = new Blob(['img'], { type: '' });
706+
globalThis.fetch = vi.fn().mockResolvedValue({
707+
ok: true,
708+
blob: vi.fn().mockResolvedValue(blob),
709+
});
710+
const sendResponse = vi.fn();
711+
capturedMessageCb({ action: 'fetchImage', url: 'https://img.com/a.jpg' }, {}, sendResponse);
712+
await vi.waitFor(() => expect(sendResponse).toHaveBeenCalled());
713+
expect(sendResponse).toHaveBeenCalledWith(
714+
expect.objectContaining({ ok: true, contentType: 'image/jpeg' }),
715+
);
716+
});
717+
718+
it('Returns false for unknown message action', () => {
719+
const sendResponse = vi.fn();
720+
const result = capturedMessageCb({ action: 'unknownAction' }, {}, sendResponse);
721+
expect(result).toBe(false);
722+
});
646723
});
647724

648725
describe('onBeforeRequest ad blocking', () => {

0 commit comments

Comments
 (0)