mirror of
https://github.com/movie-web/providers.git
synced 2025-09-13 18:13:25 +00:00
add basic categories to tests
This commit is contained in:
39
src/__test__/standard/fetchers/body.test.ts
Normal file
39
src/__test__/standard/fetchers/body.test.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { serializeBody } from "@/fetchers/body";
|
||||
import FormData from "form-data";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
describe("serializeBody()", () => {
|
||||
it('should work with standard text', () => {
|
||||
expect(serializeBody("hello world")).toEqual({
|
||||
headers: {},
|
||||
body: "hello world"
|
||||
})
|
||||
})
|
||||
|
||||
it('should work with objects', () => {
|
||||
expect(serializeBody({ hello: "world", a: 42 })).toEqual({
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({ hello: "world", a: 42 })
|
||||
})
|
||||
})
|
||||
|
||||
it('should work x-www-form-urlencoded', () => {
|
||||
const obj = new URLSearchParams()
|
||||
obj.set("a", "b");
|
||||
expect(serializeBody(obj)).toEqual({
|
||||
headers: {},
|
||||
body: obj
|
||||
})
|
||||
})
|
||||
|
||||
it('should work multipart/form-data', () => {
|
||||
const obj = new FormData()
|
||||
obj.append("a", "b");
|
||||
expect(serializeBody(obj)).toEqual({
|
||||
headers: {},
|
||||
body: obj
|
||||
})
|
||||
})
|
||||
})
|
48
src/__test__/standard/fetchers/common.test.ts
Normal file
48
src/__test__/standard/fetchers/common.test.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { makeFullUrl } from "@/fetchers/common";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
describe("makeFullUrl()", () => {
|
||||
it('should pass normal url if no options', () => {
|
||||
expect(makeFullUrl('https://example.com/hello/world')).toEqual("https://example.com/hello/world")
|
||||
expect(makeFullUrl('https://example.com/hello/world?a=b')).toEqual("https://example.com/hello/world?a=b")
|
||||
expect(makeFullUrl('https://example.com/hello/world?a=b#hello')).toEqual("https://example.com/hello/world?a=b#hello")
|
||||
expect(makeFullUrl('https://example.com/hello/world#hello')).toEqual("https://example.com/hello/world#hello")
|
||||
})
|
||||
|
||||
it('should append baseurl correctly', () => {
|
||||
const correctResult = "https://example.com/hello/world";
|
||||
expect(makeFullUrl(correctResult, { baseUrl: '' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('/hello/world', { baseUrl: 'https://example.com' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('/hello/world', { baseUrl: 'https://example.com/' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('hello/world', { baseUrl: 'https://example.com/' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('hello/world', { baseUrl: 'https://example.com' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('/world', { baseUrl: 'https://example.com/hello' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('/world', { baseUrl: 'https://example.com/hello/' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('world', { baseUrl: 'https://example.com/hello/' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('world', { baseUrl: 'https://example.com/hello' })).toEqual(correctResult)
|
||||
expect(makeFullUrl('world?a=b', { baseUrl: 'https://example.com/hello' })).toEqual("https://example.com/hello/world?a=b")
|
||||
})
|
||||
|
||||
it('should throw with invalid baseurl combinations', () => {
|
||||
expect(() => makeFullUrl('example.com/hello/world', { baseUrl: '' })).toThrowError()
|
||||
expect(() => makeFullUrl('/hello/world', { baseUrl: 'example.com' })).toThrowError()
|
||||
expect(() => makeFullUrl('/hello/world', { baseUrl: 'tcp://example.com' })).toThrowError()
|
||||
expect(() => makeFullUrl('/hello/world', { baseUrl: 'tcp://example.com' })).toThrowError()
|
||||
})
|
||||
|
||||
it('should add/merge query parameters', () => {
|
||||
expect(makeFullUrl('https://example.com/hello/world', { query: { a: 'b' } })).toEqual("https://example.com/hello/world?a=b")
|
||||
expect(makeFullUrl('https://example.com/hello/world/', { query: { a: 'b' } })).toEqual("https://example.com/hello/world/?a=b")
|
||||
expect(makeFullUrl('https://example.com', { query: { a: 'b' } })).toEqual("https://example.com/?a=b")
|
||||
expect(makeFullUrl('https://example.com/', { query: { a: 'b' } })).toEqual("https://example.com/?a=b")
|
||||
|
||||
expect(makeFullUrl('https://example.com/hello/world?c=d', { query: { a: 'b' } })).toEqual("https://example.com/hello/world?c=d&a=b")
|
||||
expect(makeFullUrl('https://example.com/hello/world?c=d', { query: {} })).toEqual("https://example.com/hello/world?c=d")
|
||||
expect(makeFullUrl('https://example.com/hello/world?c=d')).toEqual("https://example.com/hello/world?c=d")
|
||||
expect(makeFullUrl('https://example.com/hello/world?c=d', {})).toEqual("https://example.com/hello/world?c=d")
|
||||
})
|
||||
|
||||
it('should work with a mix of multiple options', () => {
|
||||
expect(makeFullUrl('/hello/world?c=d', { baseUrl: 'https://example.com/', query: { a: 'b' } })).toEqual("https://example.com/hello/world?c=d&a=b")
|
||||
})
|
||||
})
|
138
src/__test__/standard/fetchers/simpleProxy.test.ts
Normal file
138
src/__test__/standard/fetchers/simpleProxy.test.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import { makeSimpleProxyFetcher } from "@/fetchers/simpleProxy";
|
||||
import { DefaultedFetcherOptions, FetcherOptions } from "@/fetchers/types";
|
||||
import { Headers } from "node-fetch";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe("makeSimpleProxyFetcher()", () => {
|
||||
const fetch = vi.fn();
|
||||
const fetcher = makeSimpleProxyFetcher("https://example.com/proxy", fetch);
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
function setResult(type: "text" | "json", value: any) {
|
||||
if (type === 'text') return fetch.mockResolvedValueOnce({
|
||||
headers: new Headers({
|
||||
"content-type": "text/plain",
|
||||
}),
|
||||
status: 204,
|
||||
url: "test123",
|
||||
text() {
|
||||
return Promise.resolve(value);
|
||||
},
|
||||
});
|
||||
if (type === 'json') return fetch.mockResolvedValueOnce({
|
||||
headers: new Headers({
|
||||
"content-type": "application/json",
|
||||
}),
|
||||
status: 204,
|
||||
url: "test123",
|
||||
json() {
|
||||
return Promise.resolve(value);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function expectFetchCall(ops: { inputUrl: string, input: DefaultedFetcherOptions, outputUrl?: string, output: any, outputBody: any }) {
|
||||
const prom = fetcher(ops.inputUrl, ops.input);
|
||||
expect((async () => (await prom).body)()).resolves.toEqual(ops.outputBody);
|
||||
expect((async () => (await prom).headers.entries())()).resolves.toEqual((new Headers()).entries());
|
||||
expect((async () => (await prom).statusCode)()).resolves.toEqual(204);
|
||||
expect((async () => (await prom).finalUrl)()).resolves.toEqual("test123");
|
||||
expect(fetch).toBeCalledWith(ops.outputUrl ?? ops.inputUrl, ops.output);
|
||||
vi.clearAllMocks();
|
||||
}
|
||||
|
||||
it('should pass options through', () => {
|
||||
setResult("text", "hello world");
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com",
|
||||
input: {
|
||||
method: "GET",
|
||||
query: {},
|
||||
readHeaders: [],
|
||||
headers: {
|
||||
"X-Hello": "world",
|
||||
},
|
||||
},
|
||||
outputUrl: `https://example.com/proxy?destination=${encodeURIComponent('https://google.com/')}`,
|
||||
output: {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-Hello": "world",
|
||||
},
|
||||
},
|
||||
outputBody: "hello world"
|
||||
})
|
||||
setResult("text", "hello world");
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com",
|
||||
input: {
|
||||
method: "GET",
|
||||
headers: {},
|
||||
readHeaders: [],
|
||||
query: {
|
||||
"a": 'b',
|
||||
}
|
||||
},
|
||||
outputUrl: `https://example.com/proxy?destination=${encodeURIComponent('https://google.com/?a=b')}`,
|
||||
output: {
|
||||
method: "GET",
|
||||
headers: {},
|
||||
},
|
||||
outputBody: "hello world"
|
||||
})
|
||||
setResult("text", "hello world");
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com",
|
||||
input: {
|
||||
method: "GET",
|
||||
query: {},
|
||||
readHeaders: [],
|
||||
headers: {},
|
||||
},
|
||||
outputUrl: `https://example.com/proxy?destination=${encodeURIComponent('https://google.com/')}`,
|
||||
output: {
|
||||
method: "GET",
|
||||
headers: {},
|
||||
},
|
||||
outputBody: "hello world"
|
||||
})
|
||||
});
|
||||
|
||||
it('should parse response correctly', () => {
|
||||
setResult("text", "hello world");
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com/",
|
||||
input: {
|
||||
method: "POST",
|
||||
query: {},
|
||||
readHeaders: [],
|
||||
headers: {},
|
||||
},
|
||||
outputUrl: `https://example.com/proxy?destination=${encodeURIComponent('https://google.com/')}`,
|
||||
output: {
|
||||
method: "POST",
|
||||
headers: {},
|
||||
},
|
||||
outputBody: "hello world"
|
||||
})
|
||||
setResult("json", { hello: 42 });
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com/",
|
||||
input: {
|
||||
method: "POST",
|
||||
query: {},
|
||||
readHeaders: [],
|
||||
headers: {},
|
||||
},
|
||||
outputUrl: `https://example.com/proxy?destination=${encodeURIComponent('https://google.com/')}`,
|
||||
output: {
|
||||
method: "POST",
|
||||
headers: {},
|
||||
},
|
||||
outputBody: { hello: 42 }
|
||||
})
|
||||
});
|
||||
});
|
139
src/__test__/standard/fetchers/standard.test.ts
Normal file
139
src/__test__/standard/fetchers/standard.test.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { makeStandardFetcher } from "@/fetchers/standardFetch";
|
||||
import { DefaultedFetcherOptions } from "@/fetchers/types";
|
||||
import { Headers } from "node-fetch";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe("makeStandardFetcher()", () => {
|
||||
const fetch = vi.fn();
|
||||
const fetcher = makeStandardFetcher(fetch);
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
function setResult(type: "text" | "json", value: any) {
|
||||
if (type === 'text') return fetch.mockResolvedValueOnce({
|
||||
headers: new Headers({
|
||||
"content-type": "text/plain",
|
||||
}),
|
||||
status: 204,
|
||||
url: "test123",
|
||||
text() {
|
||||
return Promise.resolve(value);
|
||||
},
|
||||
});
|
||||
if (type === 'json') return fetch.mockResolvedValueOnce({
|
||||
headers: new Headers({
|
||||
"content-type": "application/json",
|
||||
}),
|
||||
status: 204,
|
||||
url: "test123",
|
||||
json() {
|
||||
return Promise.resolve(value);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function expectFetchCall(ops: { inputUrl: string, input: DefaultedFetcherOptions, outputUrl?: string, output: any, outputBody: any }) {
|
||||
const prom = fetcher(ops.inputUrl, ops.input);
|
||||
expect((async () => (await prom).body)()).resolves.toEqual(ops.outputBody);
|
||||
expect((async () => (await prom).headers.entries())()).resolves.toEqual((new Headers()).entries());
|
||||
expect((async () => (await prom).statusCode)()).resolves.toEqual(204);
|
||||
expect((async () => (await prom).finalUrl)()).resolves.toEqual("test123");
|
||||
expect(fetch).toBeCalledWith(ops.outputUrl ?? ops.inputUrl, ops.output);
|
||||
vi.clearAllMocks();
|
||||
}
|
||||
|
||||
it('should pass options through', () => {
|
||||
setResult("text", "hello world");
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com",
|
||||
input: {
|
||||
method: "GET",
|
||||
query: {},
|
||||
readHeaders: [],
|
||||
headers: {
|
||||
"X-Hello": "world",
|
||||
},
|
||||
},
|
||||
outputUrl: "https://google.com/",
|
||||
output: {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-Hello": "world",
|
||||
},
|
||||
body: undefined,
|
||||
},
|
||||
outputBody: "hello world"
|
||||
})
|
||||
setResult("text", "hello world");
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com",
|
||||
input: {
|
||||
method: "GET",
|
||||
headers: {},
|
||||
readHeaders: [],
|
||||
query: {
|
||||
"a": 'b',
|
||||
}
|
||||
},
|
||||
outputUrl: "https://google.com/?a=b",
|
||||
output: {
|
||||
method: "GET",
|
||||
headers: {},
|
||||
},
|
||||
outputBody: "hello world"
|
||||
})
|
||||
setResult("text", "hello world");
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com",
|
||||
input: {
|
||||
query: {},
|
||||
headers: {},
|
||||
readHeaders: [],
|
||||
method: "GET"
|
||||
},
|
||||
outputUrl: "https://google.com/",
|
||||
output: {
|
||||
method: "GET",
|
||||
headers: {},
|
||||
},
|
||||
outputBody: "hello world"
|
||||
})
|
||||
});
|
||||
|
||||
it('should parse response correctly', () => {
|
||||
setResult("text", "hello world");
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com/",
|
||||
input: {
|
||||
query: {},
|
||||
headers: {},
|
||||
readHeaders: [],
|
||||
method: "POST"
|
||||
},
|
||||
outputUrl: "https://google.com/",
|
||||
output: {
|
||||
method: "POST",
|
||||
headers: {},
|
||||
},
|
||||
outputBody: "hello world"
|
||||
})
|
||||
setResult("json", { hello: 42 });
|
||||
expectFetchCall({
|
||||
inputUrl: "https://google.com/",
|
||||
input: {
|
||||
query: {},
|
||||
headers: {},
|
||||
readHeaders: [],
|
||||
method: "POST"
|
||||
},
|
||||
outputUrl: "https://google.com/",
|
||||
output: {
|
||||
method: "POST",
|
||||
headers: {},
|
||||
},
|
||||
outputBody: { hello: 42 }
|
||||
})
|
||||
});
|
||||
});
|
135
src/__test__/standard/providerTests.ts
Normal file
135
src/__test__/standard/providerTests.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { vi } from 'vitest';
|
||||
|
||||
import { gatherAllEmbeds, gatherAllSources } from '@/providers/all';
|
||||
import { makeEmbed, makeSourcerer } from '@/providers/base';
|
||||
|
||||
export function makeProviderMocks() {
|
||||
const embedsMock = vi.fn<Parameters<typeof gatherAllEmbeds>, ReturnType<typeof gatherAllEmbeds>>();
|
||||
const sourcesMock = vi.fn<Parameters<typeof gatherAllSources>, ReturnType<typeof gatherAllSources>>();
|
||||
return {
|
||||
gatherAllEmbeds: embedsMock,
|
||||
gatherAllSources: sourcesMock,
|
||||
};
|
||||
}
|
||||
|
||||
const sourceA = makeSourcerer({
|
||||
id: 'a',
|
||||
name: 'A',
|
||||
rank: 1,
|
||||
disabled: false,
|
||||
flags: [],
|
||||
});
|
||||
const sourceB = makeSourcerer({
|
||||
id: 'b',
|
||||
name: 'B',
|
||||
rank: 2,
|
||||
disabled: false,
|
||||
flags: [],
|
||||
});
|
||||
const sourceCDisabled = makeSourcerer({
|
||||
id: 'c',
|
||||
name: 'C',
|
||||
rank: 3,
|
||||
disabled: true,
|
||||
flags: [],
|
||||
});
|
||||
const sourceAHigherRank = makeSourcerer({
|
||||
id: 'a',
|
||||
name: 'A',
|
||||
rank: 100,
|
||||
disabled: false,
|
||||
flags: [],
|
||||
});
|
||||
const sourceGSameRankAsA = makeSourcerer({
|
||||
id: 'g',
|
||||
name: 'G',
|
||||
rank: 1,
|
||||
disabled: false,
|
||||
flags: [],
|
||||
});
|
||||
const fullSourceYMovie = makeSourcerer({
|
||||
id: 'y',
|
||||
name: 'Y',
|
||||
rank: 105,
|
||||
scrapeMovie: vi.fn(),
|
||||
flags: [],
|
||||
});
|
||||
const fullSourceYShow = makeSourcerer({
|
||||
id: 'y',
|
||||
name: 'Y',
|
||||
rank: 105,
|
||||
scrapeShow: vi.fn(),
|
||||
flags: [],
|
||||
});
|
||||
const fullSourceZBoth = makeSourcerer({
|
||||
id: 'z',
|
||||
name: 'Z',
|
||||
rank: 106,
|
||||
scrapeMovie: vi.fn(),
|
||||
scrapeShow: vi.fn(),
|
||||
flags: [],
|
||||
});
|
||||
|
||||
const embedD = makeEmbed({
|
||||
id: 'd',
|
||||
rank: 4,
|
||||
disabled: false,
|
||||
} as any);
|
||||
const embedA = makeEmbed({
|
||||
id: 'a',
|
||||
rank: 5,
|
||||
disabled: false,
|
||||
} as any);
|
||||
const embedEDisabled = makeEmbed({
|
||||
id: 'e',
|
||||
rank: 6,
|
||||
disabled: true,
|
||||
} as any);
|
||||
const embedDHigherRank = makeEmbed({
|
||||
id: 'd',
|
||||
rank: 4000,
|
||||
disabled: false,
|
||||
} as any);
|
||||
const embedFSameRankAsA = makeEmbed({
|
||||
id: 'f',
|
||||
rank: 5,
|
||||
disabled: false,
|
||||
} as any);
|
||||
const embedHSameRankAsSourceA = makeEmbed({
|
||||
id: 'h',
|
||||
rank: 1,
|
||||
disabled: false,
|
||||
} as any);
|
||||
const fullEmbedX = makeEmbed({
|
||||
id: 'x',
|
||||
name: 'X',
|
||||
rank: 104,
|
||||
} as any);
|
||||
const fullEmbedZ = makeEmbed({
|
||||
id: 'z',
|
||||
name: 'Z',
|
||||
rank: 109,
|
||||
} as any);
|
||||
|
||||
export const mockSources = {
|
||||
sourceA,
|
||||
sourceB,
|
||||
sourceCDisabled,
|
||||
sourceAHigherRank,
|
||||
sourceGSameRankAsA,
|
||||
fullSourceYMovie,
|
||||
fullSourceYShow,
|
||||
fullSourceZBoth,
|
||||
};
|
||||
|
||||
export const mockEmbeds = {
|
||||
embedA,
|
||||
embedD,
|
||||
embedDHigherRank,
|
||||
embedEDisabled,
|
||||
embedFSameRankAsA,
|
||||
embedHSameRankAsSourceA,
|
||||
fullEmbedX,
|
||||
fullEmbedZ,
|
||||
};
|
91
src/__test__/standard/providers/checks.test.ts
Normal file
91
src/__test__/standard/providers/checks.test.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { mockEmbeds, mockSources } from '../providerTests';
|
||||
import { getBuiltinEmbeds, getBuiltinSources } from '@/entrypoint/providers';
|
||||
import { FeatureMap } from '@/entrypoint/utils/targets';
|
||||
import { getProviders } from '@/providers/get';
|
||||
import { vi, describe, it, expect, afterEach } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('../providerTests')).makeProviderMocks());
|
||||
vi.mock('@/providers/all', () => mocks);
|
||||
|
||||
const features: FeatureMap = {
|
||||
requires: [],
|
||||
disallowed: []
|
||||
}
|
||||
|
||||
describe('getProviders()', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return providers', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(getProviders(features, {
|
||||
embeds: getBuiltinEmbeds(),
|
||||
sources: getBuiltinSources(),
|
||||
})).toEqual({
|
||||
sources: [mockSources.sourceA, mockSources.sourceB],
|
||||
embeds: [mockEmbeds.embedD],
|
||||
});
|
||||
});
|
||||
|
||||
it('should filter out disabled providers', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedEDisabled]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceCDisabled, mockSources.sourceB]);
|
||||
expect(getProviders(features,{
|
||||
embeds: getBuiltinEmbeds(),
|
||||
sources: getBuiltinSources(),
|
||||
})).toEqual({
|
||||
sources: [mockSources.sourceA, mockSources.sourceB],
|
||||
embeds: [mockEmbeds.embedD],
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw on duplicate ids in sources', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceAHigherRank, mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(() => getProviders(features,{
|
||||
embeds: getBuiltinEmbeds(),
|
||||
sources: getBuiltinSources(),
|
||||
})).toThrowError();
|
||||
});
|
||||
|
||||
it('should throw on duplicate ids in embeds', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedDHigherRank, mockEmbeds.embedA]);
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
expect(() => getProviders(features,{
|
||||
embeds: getBuiltinEmbeds(),
|
||||
sources: getBuiltinSources(),
|
||||
})).toThrowError();
|
||||
});
|
||||
|
||||
it('should throw on duplicate ids between sources and embeds', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedA]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(() => getProviders(features,{
|
||||
embeds: getBuiltinEmbeds(),
|
||||
sources: getBuiltinSources(),
|
||||
})).toThrowError();
|
||||
});
|
||||
|
||||
it('should throw on duplicate rank between sources and embeds', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedA]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(() => getProviders(features,{
|
||||
embeds: getBuiltinEmbeds(),
|
||||
sources: getBuiltinSources(),
|
||||
})).toThrowError();
|
||||
});
|
||||
|
||||
it('should not throw with same rank between sources and embeds', () => {
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.embedD, mockEmbeds.embedHSameRankAsSourceA]);
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.sourceA, mockSources.sourceB]);
|
||||
expect(getProviders(features,{
|
||||
embeds: getBuiltinEmbeds(),
|
||||
sources: getBuiltinSources(),
|
||||
})).toEqual({
|
||||
sources: [mockSources.sourceA, mockSources.sourceB],
|
||||
embeds: [mockEmbeds.embedD, mockEmbeds.embedHSameRankAsSourceA],
|
||||
});
|
||||
});
|
||||
});
|
130
src/__test__/standard/runner/list.test.ts
Normal file
130
src/__test__/standard/runner/list.test.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { mockEmbeds, mockSources } from '../providerTests.ts';
|
||||
import { makeProviders } from '@/entrypoint/declare';
|
||||
import { targets } from '@/entrypoint/utils/targets';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('../providerTests.ts')).makeProviderMocks());
|
||||
vi.mock('@/providers/all', () => mocks);
|
||||
|
||||
describe('ProviderControls.listSources()', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return the source with movie type', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceYMovie]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
expect(p.listSources()).toEqual([
|
||||
{
|
||||
type: 'source',
|
||||
id: 'y',
|
||||
rank: mockSources.fullSourceYMovie.rank,
|
||||
name: 'Y',
|
||||
mediaTypes: ['movie'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the source with show type', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceYShow]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
expect(p.listSources()).toEqual([
|
||||
{
|
||||
type: 'source',
|
||||
id: 'y',
|
||||
rank: mockSources.fullSourceYShow.rank,
|
||||
name: 'Y',
|
||||
mediaTypes: ['show'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the source with both types', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceZBoth]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
expect(p.listSources()).toEqual([
|
||||
{
|
||||
type: 'source',
|
||||
id: 'z',
|
||||
rank: mockSources.fullSourceZBoth.rank,
|
||||
name: 'Z',
|
||||
mediaTypes: ['movie', 'show'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the sources in correct order', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceYMovie, mockSources.fullSourceZBoth]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p1 = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
const l1 = p1.listSources();
|
||||
expect(l1.map((v) => v.id).join(',')).toEqual('z,y');
|
||||
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceZBoth, mockSources.fullSourceYMovie]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p2 = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
const l2 = p2.listSources();
|
||||
expect(l2.map((v) => v.id).join(',')).toEqual('z,y');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ProviderControls.getAllEmbedMetaSorted()', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return the correct embed format', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.fullEmbedX]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
expect(p.listEmbeds()).toEqual([
|
||||
{
|
||||
type: 'embed',
|
||||
id: 'x',
|
||||
rank: mockEmbeds.fullEmbedX.rank,
|
||||
name: 'X',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the embeds in correct order', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.fullEmbedX, mockEmbeds.fullEmbedZ]);
|
||||
const p1 = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
const l1 = p1.listEmbeds();
|
||||
expect(l1.map((v) => v.id).join(',')).toEqual('z,x');
|
||||
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.fullEmbedZ, mockEmbeds.fullEmbedX]);
|
||||
const p2 = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
const l2 = p2.listEmbeds();
|
||||
expect(l2.map((v) => v.id).join(',')).toEqual('z,x');
|
||||
});
|
||||
});
|
54
src/__test__/standard/runner/meta.test.ts
Normal file
54
src/__test__/standard/runner/meta.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { mockEmbeds, mockSources } from '../providerTests.ts';
|
||||
import { makeProviders } from '@/entrypoint/declare';
|
||||
import { targets } from '@/entrypoint/utils/targets';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('../providerTests.ts')).makeProviderMocks());
|
||||
vi.mock('@/providers/all', () => mocks);
|
||||
|
||||
describe('ProviderControls.getMetadata()', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return null if not found', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
expect(p.getMetadata(':)')).toEqual(null);
|
||||
});
|
||||
|
||||
it('should return correct source meta', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([mockSources.fullSourceZBoth]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
expect(p.getMetadata(mockSources.fullSourceZBoth.id)).toEqual({
|
||||
type: 'source',
|
||||
id: 'z',
|
||||
name: 'Z',
|
||||
rank: mockSources.fullSourceZBoth.rank,
|
||||
mediaTypes: ['movie', 'show'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should return correct embed meta', () => {
|
||||
mocks.gatherAllSources.mockReturnValue([]);
|
||||
mocks.gatherAllEmbeds.mockReturnValue([mockEmbeds.fullEmbedX]);
|
||||
const p = makeProviders({
|
||||
fetcher: null as any,
|
||||
target: targets.NATIVE,
|
||||
});
|
||||
expect(p.getMetadata(mockEmbeds.fullEmbedX.id)).toEqual({
|
||||
type: 'embed',
|
||||
id: 'x',
|
||||
name: 'X',
|
||||
rank: mockEmbeds.fullEmbedX.rank,
|
||||
});
|
||||
});
|
||||
});
|
77
src/__test__/standard/utils/features.test.ts
Normal file
77
src/__test__/standard/utils/features.test.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { FeatureMap, Flags, flags, flagsAllowedInFeatures } from "@/entrypoint/utils/targets";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
describe('flagsAllowedInFeatures()', () => {
|
||||
function checkFeatures(featureMap: FeatureMap, flags: Flags[], output: boolean) {
|
||||
expect(flagsAllowedInFeatures(featureMap, flags)).toEqual(output);
|
||||
}
|
||||
|
||||
it('should check required correctly', () => {
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: []
|
||||
}, [], true);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: []
|
||||
}, [flags.CORS_ALLOWED], true);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: []
|
||||
}, [], false);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED, flags.IP_LOCKED],
|
||||
disallowed: []
|
||||
}, [flags.CORS_ALLOWED, flags.IP_LOCKED], true);
|
||||
checkFeatures({
|
||||
requires: [flags.IP_LOCKED],
|
||||
disallowed: []
|
||||
}, [flags.CORS_ALLOWED], false);
|
||||
checkFeatures({
|
||||
requires: [flags.IP_LOCKED],
|
||||
disallowed: []
|
||||
}, [], false);
|
||||
});
|
||||
|
||||
it('should check disallowed correctly', () => {
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: []
|
||||
}, [], true);
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: [flags.CORS_ALLOWED]
|
||||
}, [], true);
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: [flags.CORS_ALLOWED]
|
||||
}, [flags.CORS_ALLOWED], false);
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: [flags.CORS_ALLOWED]
|
||||
}, [flags.IP_LOCKED], true);
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: [flags.CORS_ALLOWED, flags.IP_LOCKED]
|
||||
}, [flags.CORS_ALLOWED], false);
|
||||
});
|
||||
|
||||
it('should pass mixed tests', () => {
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [flags.IP_LOCKED]
|
||||
}, [], false);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [flags.IP_LOCKED]
|
||||
}, [flags.CORS_ALLOWED], true);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [flags.IP_LOCKED]
|
||||
}, [flags.IP_LOCKED], false);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [flags.IP_LOCKED]
|
||||
}, [flags.IP_LOCKED, flags.CORS_ALLOWED], false);
|
||||
});
|
||||
});
|
54
src/__test__/standard/utils/list.test.ts
Normal file
54
src/__test__/standard/utils/list.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { reorderOnIdList } from "@/utils/list";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
function list(def: string) {
|
||||
return def.split(",").map(v=>({
|
||||
rank: parseInt(v),
|
||||
id: v,
|
||||
}))
|
||||
}
|
||||
|
||||
function expectListToEqual(l1: ReturnType<typeof list>, l2: ReturnType<typeof list>) {
|
||||
function flatten(l: ReturnType<typeof list>) {
|
||||
return l.map(v=>v.id).join(",");
|
||||
}
|
||||
expect(flatten(l1)).toEqual(flatten(l2));
|
||||
}
|
||||
|
||||
describe('reorderOnIdList()', () => {
|
||||
it('should reorder based on rank', () => {
|
||||
const l = list('2,1,4,3');
|
||||
const sortedList = list('4,3,2,1')
|
||||
expectListToEqual(reorderOnIdList([], l), sortedList);
|
||||
});
|
||||
|
||||
it('should work with empty input', () => {
|
||||
expectListToEqual(reorderOnIdList([], []), []);
|
||||
});
|
||||
|
||||
it('should reorder based on id list', () => {
|
||||
const l = list('4,2,1,3');
|
||||
const sortedList = list('4,3,2,1')
|
||||
expectListToEqual(reorderOnIdList(["4","3","2","1"], l), sortedList);
|
||||
});
|
||||
|
||||
it('should reorder based on id list and rank second', () => {
|
||||
const l = list('4,2,1,3');
|
||||
const sortedList = list('4,3,2,1')
|
||||
expectListToEqual(reorderOnIdList(["4","3"], l), sortedList);
|
||||
});
|
||||
|
||||
it('should work with only one item', () => {
|
||||
const l = list('1');
|
||||
const sortedList = list('1')
|
||||
expectListToEqual(reorderOnIdList(["1"], l), sortedList);
|
||||
expectListToEqual(reorderOnIdList([], l), sortedList);
|
||||
});
|
||||
|
||||
it('should not affect original list', () => {
|
||||
const l = list('4,3,2,1');
|
||||
const unsortedList = list('4,3,2,1')
|
||||
reorderOnIdList([], l);
|
||||
expectListToEqual(l, unsortedList);
|
||||
});
|
||||
});
|
65
src/__test__/standard/utils/valid.test.ts
Normal file
65
src/__test__/standard/utils/valid.test.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { makeStandardFetcher } from "@/fetchers/standardFetch";
|
||||
import { makeProviders } from "@/main/builder";
|
||||
import { targets } from "@/main/targets";
|
||||
import { isValidStream } from "@/utils/valid";
|
||||
import fetch from "node-fetch";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
describe('isValidStream()', () => {
|
||||
it('should pass valid streams', () => {
|
||||
expect(isValidStream({
|
||||
type: "file",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
qualities: {
|
||||
"1080": {
|
||||
type: "mp4",
|
||||
url: "hello-world"
|
||||
}
|
||||
}
|
||||
})).toBe(true);
|
||||
expect(isValidStream({
|
||||
type: "hls",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
playlist: "hello-world"
|
||||
})).toBe(true);
|
||||
});
|
||||
|
||||
it('should detect empty qualities', () => {
|
||||
expect(isValidStream({
|
||||
type: "file",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
qualities: {}
|
||||
})).toBe(false);
|
||||
});
|
||||
|
||||
it('should detect empty stream urls', () => {
|
||||
expect(isValidStream({
|
||||
type: "file",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
qualities: {
|
||||
"1080": {
|
||||
type: "mp4",
|
||||
url: "",
|
||||
}
|
||||
}
|
||||
})).toBe(false);
|
||||
});
|
||||
|
||||
it('should detect emtpy HLS playlists', () => {
|
||||
expect(isValidStream({
|
||||
type: "hls",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
playlist: "",
|
||||
})).toBe(false);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user