add basic categories to tests

This commit is contained in:
mrjvs
2024-01-17 17:18:12 +01:00
parent b3212bd327
commit 9798659af8
15 changed files with 71 additions and 45 deletions

View 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
})
})
})

View 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")
})
})

View 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 }
})
});
});

View 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 }
})
});
});

View 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,
};

View 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],
});
});
});

View 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');
});
});

View 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,
});
});
});

View 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);
});
});

View 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);
});
});

View 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);
});
});