Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dodostream",
"version": "0.10.0",
"version": "0.10.1",
"license": "GPL-3.0-only",
"main": "expo-router/entry",
"scripts": {
Expand Down
21 changes: 11 additions & 10 deletions src/api/simkl/__tests__/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ describe('simkl client', () => {
);

// Act
await getPinCode('client-123');
await getPinCode();

// Assert
const calledUrl = String(mockFetch.mock.calls[0][0]);
const parsed = new URL(calledUrl);

expect(parsed.pathname).toBe('/oauth/pin');
expect(parsed.searchParams.get('client_id')).toBe('client-123');
expect(parsed.searchParams.get('client_id')).toBe('test-client-id');
expect(parsed.searchParams.get('app-name')).toBe('dodostream');
expect(parsed.searchParams.get('app-version')).toBe('1.0.0');
});
Expand All @@ -58,21 +58,22 @@ describe('simkl client', () => {
);

// Act
await getUserSettings('token-abc', 'client-id');
await getUserSettings('token-abc');

// Assert
const options = mockFetch.mock.calls[0][1] as RequestInit;
const headers = options.headers as Record<string, string>;
expect(headers.Authorization).toBe('Bearer token-abc');
expect(headers['simkl-api-key']).toBe('test-client-id');
});

it('getAllItems includes date_from when provided and omits when not provided', async () => {
// Arrange
mockFetch.mockResolvedValue(mockResponse({ movies: [] }));

// Act
await getAllItems('token-1', 'client-id', 'movies', '2026-01-01T00:00:00.000Z');
await getAllItems('token-1', 'client-id', 'movies');
await getAllItems('token-1', 'movies', '2026-01-01T00:00:00.000Z');
await getAllItems('token-1', 'movies');

// Assert
const firstUrl = new URL(String(mockFetch.mock.calls[0][0]));
Expand All @@ -87,23 +88,23 @@ describe('simkl client', () => {
mockFetch.mockResolvedValue(mockResponse({}));

// Act
await getAllItems('token-1', 'client-id', 'movies');
await getAllItems('token-1', 'client-id', 'anime');
await getAllItems('token-1', 'movies');
await getAllItems('token-1', 'anime');

// Assert
const movieUrl = new URL(String(mockFetch.mock.calls[0][0]));
const animeUrl = new URL(String(mockFetch.mock.calls[1][0]));

expect(movieUrl.searchParams.get('extended')).toBe('full');
expect(animeUrl.searchParams.get('extended')).toBe('full_anime_seasons');
expect(animeUrl.searchParams.get('extended')).toBe('full');
});

it('simklFetch throws on non-ok response via exported function', async () => {
// Arrange
mockFetch.mockResolvedValueOnce({ ok: false, status: 500, json: async () => ({}) });

// Act / Assert
await expect(getUserSettings('bad-token', 'client-id')).rejects.toThrow('Simkl API error 500');
await expect(getUserSettings('bad-token')).rejects.toThrow('Simkl API error 500');
});

it('simklFetch includes User-Agent header', async () => {
Expand All @@ -120,7 +121,7 @@ describe('simkl client', () => {
);

// Act
await getPinCode('client-123');
await getPinCode();

// Assert
const options = mockFetch.mock.calls[0][1] as RequestInit;
Expand Down
16 changes: 8 additions & 8 deletions src/api/simkl/__tests__/id-resolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ describe('resolveSimklIds', () => {
// Act
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { resolveSimklIds } = require('../id-resolver') as typeof import('../id-resolver');
const result = await resolveSimklIds('meta-1', 'movie', 'client-1');
const result = await resolveSimklIds('meta-1', 'movie');

// Assert
expect(result).toEqual(ids);
expect(mockSearchById).toHaveBeenCalledWith('client-1', 'meta-1');
expect(mockSearchById).toHaveBeenCalledWith('meta-1');
});

it('returns null when searchById returns empty array', async () => {
Expand All @@ -32,7 +32,7 @@ describe('resolveSimklIds', () => {
// Act
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { resolveSimklIds } = require('../id-resolver') as typeof import('../id-resolver');
const result = await resolveSimklIds('meta-2', 'series', 'client-1');
const result = await resolveSimklIds('meta-2', 'series');

// Assert
expect(result).toBeNull();
Expand All @@ -46,8 +46,8 @@ describe('resolveSimklIds', () => {
// Act
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { resolveSimklIds } = require('../id-resolver') as typeof import('../id-resolver');
const first = await resolveSimklIds('cached-meta', 'movie', 'client-1');
const second = await resolveSimklIds('cached-meta', 'movie', 'client-1');
const first = await resolveSimklIds('cached-meta', 'movie');
const second = await resolveSimklIds('cached-meta', 'movie');

// Assert
expect(first).toEqual(ids);
Expand All @@ -62,8 +62,8 @@ describe('resolveSimklIds', () => {
// Act
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { resolveSimklIds } = require('../id-resolver') as typeof import('../id-resolver');
const first = await resolveSimklIds('error-meta', 'movie', 'client-1');
const second = await resolveSimklIds('error-meta', 'movie', 'client-1');
const first = await resolveSimklIds('error-meta', 'movie');
const second = await resolveSimklIds('error-meta', 'movie');

// Assert
expect(first).toBeNull();
Expand All @@ -75,7 +75,7 @@ describe('resolveSimklIds', () => {
// Arrange / Act
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { resolveSimklIds } = require('../id-resolver') as typeof import('../id-resolver');
const result = await resolveSimklIds('tt9999999', 'movie', 'client-1');
const result = await resolveSimklIds('tt9999999', 'movie');

// Assert — IMDB IDs are returned directly without a network lookup
expect(result).toEqual({ imdb: 'tt9999999' });
Expand Down
Loading
Loading