mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 15:35:55 +01:00
🧪 Add test for Plex
This commit is contained in:
@@ -37,5 +37,6 @@ module.exports = {
|
||||
max: 3,
|
||||
},
|
||||
],
|
||||
'testing-library/no-node-access': ['error', { allowContainerFirstChild: true }],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -99,7 +99,8 @@
|
||||
"turbo": "^1.7.4",
|
||||
"typescript": "^4.7.4",
|
||||
"video.js": "^8.0.3",
|
||||
"vitest": "^0.29.3"
|
||||
"vitest": "^0.29.3",
|
||||
"vitest-fetch-mock": "^0.2.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.2",
|
||||
|
||||
8
setupVitest.ts
Normal file
8
setupVitest.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
//setupVitest.js or similar file
|
||||
import createFetchMock from 'vitest-fetch-mock';
|
||||
import { vi } from 'vitest';
|
||||
|
||||
const fetchMocker = createFetchMock(vi);
|
||||
|
||||
// sets globalThis.fetch and globalThis.fetchMock to our mocked version
|
||||
fetchMocker.enableMocks();
|
||||
@@ -2,15 +2,51 @@ import { render } from '@testing-library/react';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { AppAvatar } from './AppAvatar';
|
||||
|
||||
describe(AppAvatar.name, () => {
|
||||
it.concurrent('display placeholder when no url', () => {
|
||||
describe('AppAvatar', () => {
|
||||
it('display placeholder when no url', () => {
|
||||
const { container } = render(<AppAvatar iconUrl="" color="blue" />);
|
||||
|
||||
expect(container.firstElementChild).not.toBeNull();
|
||||
expect(container.firstElementChild!.className).contain('mantine-Avatar-root');
|
||||
expect(container.firstChild).toMatchInlineSnapshot(`
|
||||
<div
|
||||
class="mantine-Avatar-root mantine-1rb4n7x"
|
||||
>
|
||||
<div
|
||||
class="mantine-lgdaxf mantine-Avatar-placeholder"
|
||||
>
|
||||
<svg
|
||||
class="mantine-rsrrdl mantine-Avatar-placeholderIcon"
|
||||
fill="none"
|
||||
height="15"
|
||||
viewBox="0 0 15 15"
|
||||
width="15"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M0.877014 7.49988C0.877014 3.84219 3.84216 0.877045 7.49985 0.877045C11.1575 0.877045 14.1227 3.84219 14.1227 7.49988C14.1227 11.1575 11.1575 14.1227 7.49985 14.1227C3.84216 14.1227 0.877014 11.1575 0.877014 7.49988ZM7.49985 1.82704C4.36683 1.82704 1.82701 4.36686 1.82701 7.49988C1.82701 8.97196 2.38774 10.3131 3.30727 11.3213C4.19074 9.94119 5.73818 9.02499 7.50023 9.02499C9.26206 9.02499 10.8093 9.94097 11.6929 11.3208C12.6121 10.3127 13.1727 8.97172 13.1727 7.49988C13.1727 4.36686 10.6328 1.82704 7.49985 1.82704ZM10.9818 11.9787C10.2839 10.7795 8.9857 9.97499 7.50023 9.97499C6.01458 9.97499 4.71624 10.7797 4.01845 11.9791C4.97952 12.7272 6.18765 13.1727 7.49985 13.1727C8.81227 13.1727 10.0206 12.727 10.9818 11.9787ZM5.14999 6.50487C5.14999 5.207 6.20212 4.15487 7.49999 4.15487C8.79786 4.15487 9.84999 5.207 9.84999 6.50487C9.84999 7.80274 8.79786 8.85487 7.49999 8.85487C6.20212 8.85487 5.14999 7.80274 5.14999 6.50487ZM7.49999 5.10487C6.72679 5.10487 6.09999 5.73167 6.09999 6.50487C6.09999 7.27807 6.72679 7.90487 7.49999 7.90487C8.27319 7.90487 8.89999 7.27807 8.89999 6.50487C8.89999 5.73167 8.27319 5.10487 7.49999 5.10487Z"
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
const svgElement = container.querySelector('svg');
|
||||
expect(svgElement).not.toBeNull();
|
||||
expect(svgElement?.getAttribute('fill')).not.toBeNull();
|
||||
it('display placeholder when valid url', () => {
|
||||
const { container } = render(
|
||||
<AppAvatar iconUrl="https://homarr.dev/img/logo.svg" color="red" />
|
||||
);
|
||||
|
||||
expect(container.firstChild).toMatchInlineSnapshot(`
|
||||
<div
|
||||
class="mantine-Avatar-root mantine-11ss4u9"
|
||||
>
|
||||
<img
|
||||
class="mantine-1trwvlz mantine-Avatar-image"
|
||||
src="https://homarr.dev/img/logo.svg"
|
||||
/>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ export const getServerSideTranslations = async (
|
||||
res?: ServerResponse,
|
||||
) => {
|
||||
if (!req || !res) {
|
||||
return await serverSideTranslations(
|
||||
return serverSideTranslations(
|
||||
requestLocale ?? 'en',
|
||||
namespaces
|
||||
);
|
||||
@@ -17,7 +17,7 @@ export const getServerSideTranslations = async (
|
||||
|
||||
const configLocale = getCookie('config-locale', { req, res });
|
||||
|
||||
return await serverSideTranslations(
|
||||
return serverSideTranslations(
|
||||
(configLocale ?? requestLocale ?? 'en') as string,
|
||||
namespaces
|
||||
);
|
||||
|
||||
73
src/tools/server/sdk/plex/plexClient.test.ts
Normal file
73
src/tools/server/sdk/plex/plexClient.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import 'vitest-fetch-mock';
|
||||
import { PlexClient } from './plexClient';
|
||||
|
||||
const mockResponse = `<MediaContainer size="1">
|
||||
<Video addedAt="0000000" art="/library/metadata/2/art/00000000" audienceRating="0.0" audienceRatingImage="niceImage" chapterSource="media" contentRating="TV-PG" duration="6262249" guid="plex://movie/0000000000000000" key="/library/metadata/2" lastViewedAt="0000000" librarySectionID="1" librarySectionKey="/library/sections/1" librarySectionTitle="Movies" originalTitle="00000000000000" originallyAvailableAt="0000-00-00" rating="0.0" ratingImage="ratingimage" ratingKey="2" sessionKey="1" studio="Example Studio" summary="Lorem Ispum dolor sit amet" tagline="Yep" thumb="/library/metadata/2/thumb/0000000" title="A long title" titleSort="A short title" type="movie" updatedAt="000000" viewOffset="0" year="0000">
|
||||
<Media audioProfile="ma" id="2" videoProfile="high" audioChannels="2" audioCodec="aac" bitrate="20231" container="mp4" duration="6262249" height="1080" optimizedForStreaming="1" protocol="dash" videoCodec="h264" videoFrameRate="24p" videoResolution="1080p" width="1920" selected="1">
|
||||
<Part audioProfile="ma" hasThumbnail="1" id="2" videoProfile="high" bitrate="20231" container="mp4" duration="6262249" height="1080" optimizedForStreaming="1" protocol="dash" width="1920" decision="transcode" selected="1">
|
||||
<Stream bitDepth="8" bitrate="19975" chromaLocation="left" chromaSubsampling="4:2:0" codec="h264" codedHeight="1088" codedWidth="1920" default="1" displayTitle="XXXX" extendedDisplayTitle="Yes" frameRate="23.975999832153320" hasScalingMatrix="0" height="1080" id="4" level="41" profile="high" refFrames="4" scanType="progressive" streamType="1" title="Example" width="1920" decision="copy" location="segments-video"/>
|
||||
<Stream bitrate="256" bitrateMode="cbr" channels="2" codec="aac" default="1" displayTitle="Not Existing" extendedDisplayTitle="Yes, really" id="5" language="Yep" languageCode="jpn" languageTag="ch" selected="1" streamType="2" decision="transcode" location="segments-audio"/>
|
||||
</Part>
|
||||
</Media>
|
||||
<Genre count="13" filter="genre=48" id="48" tag="Drama"/>
|
||||
<Genre count="8" filter="genre=104" id="104" tag="Adventure"/>
|
||||
<User id="1" thumb="https://google.com" title="example_usr"/>
|
||||
<Player address="0.0.0.0" device="Windows" machineIdentifier="72483785378573857385" model="bundled" platform="Chrome" platformVersion="111.0" product="Plex Web" profile="Web" state="paused" title="Chrome" version="0.000.0" local="1" relayed="0" secure="1" userID="1"/>
|
||||
<Session id="2894294r2jf2038fj3098jgf3gt" bandwidth="21560" location="lan"/>
|
||||
<TranscodeSession key="/transcode/sessions/example-session" throttled="0" complete="0" progress="0" size="-22" speed="18.600000381469727" error="0" duration="100" remaining="70" context="streaming" sourceVideoCodec="h264" sourceAudioCodec="dca" videoDecision="copy" audioDecision="transcode" protocol="dash" container="mp4" videoCodec="h264" audioCodec="aac" audioChannels="2" width="1920" height="1080" transcodeHwRequested="0" transcodeHwFullPipeline="0" timeStamp="1679349635.2791338" maxOffsetAvailable="104.27" minOffsetAvailable="84.166999816894531"/>
|
||||
</Video>
|
||||
</MediaContainer>`;
|
||||
|
||||
describe('Plex SDK', () => {
|
||||
it('abc', async () => {
|
||||
// arrange
|
||||
const client = new PlexClient('https://plex', 'MY_TOKEN');
|
||||
|
||||
fetchMock.mockResponseOnce(mockResponse);
|
||||
|
||||
// act
|
||||
const response = await client.getSessions();
|
||||
|
||||
// assert
|
||||
expect(fetchMock.requests().length).toBe(1);
|
||||
expect(fetchMock.requests()[0].url).toBe('https://plex/status/sessions?X-Plex-Token=MY_TOKEN');
|
||||
expect(response).not.toBeNull();
|
||||
expect(response.length).toBe(1);
|
||||
expect(response[0].id).toBe('2894294r2jf2038fj3098jgf3gt');
|
||||
expect(response[0].username).toBe('example_usr');
|
||||
expect(response[0].userProfilePicture).toBe('https://google.com');
|
||||
expect(response[0].sessionName).toBe('Plex Web (Chrome)');
|
||||
expect(response[0].currentlyPlaying).toMatchObject({
|
||||
name: 'A long title',
|
||||
type: 'movie',
|
||||
metadata: {
|
||||
video: {
|
||||
bitrate: '20231',
|
||||
height: '1080',
|
||||
videoCodec: 'h264',
|
||||
videoFrameRate: '24p',
|
||||
width: '1920',
|
||||
},
|
||||
audio: { audioChannels: '2', audioCodec: 'aac' },
|
||||
transcoding: {
|
||||
audioChannels: '2',
|
||||
audioCodec: 'aac',
|
||||
audioDecision: 'transcode',
|
||||
container: 'mp4',
|
||||
context: 'streaming',
|
||||
duration: '100',
|
||||
error: false,
|
||||
height: '1080',
|
||||
sourceAudioCodec: 'dca',
|
||||
sourceVideoCodec: 'h264',
|
||||
timeStamp: '1679349635.2791338',
|
||||
transcodeHwRequested: false,
|
||||
videoCodec: 'h264',
|
||||
videoDecision: 'copy',
|
||||
width: '1920',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -12,6 +12,9 @@ export default defineConfig({
|
||||
reporter: ['html'],
|
||||
all: true,
|
||||
exclude: ['.next/', '.yarn/', 'data/']
|
||||
}
|
||||
},
|
||||
setupFiles: [
|
||||
"./setupVitest.ts"
|
||||
]
|
||||
},
|
||||
});
|
||||
|
||||
59
yarn.lock
59
yarn.lock
@@ -3145,6 +3145,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cross-fetch@npm:^3.0.6":
|
||||
version: 3.1.5
|
||||
resolution: "cross-fetch@npm:3.1.5"
|
||||
dependencies:
|
||||
node-fetch: 2.6.7
|
||||
checksum: f6b8c6ee3ef993ace6277fd789c71b6acf1b504fd5f5c7128df4ef2f125a429e29cd62dc8c127523f04a5f2fa4771ed80e3f3d9695617f441425045f505cf3bb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2":
|
||||
version: 7.0.3
|
||||
resolution: "cross-spawn@npm:7.0.3"
|
||||
@@ -4932,6 +4941,7 @@ __metadata:
|
||||
uuid: ^8.3.2
|
||||
video.js: ^8.0.3
|
||||
vitest: ^0.29.3
|
||||
vitest-fetch-mock: ^0.2.2
|
||||
xml-js: ^1.6.11
|
||||
yarn: ^1.22.19
|
||||
zustand: ^4.1.4
|
||||
@@ -6273,6 +6283,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-fetch@npm:2.6.7":
|
||||
version: 2.6.7
|
||||
resolution: "node-fetch@npm:2.6.7"
|
||||
dependencies:
|
||||
whatwg-url: ^5.0.0
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
checksum: 8d816ffd1ee22cab8301c7756ef04f3437f18dace86a1dae22cf81db8ef29c0bf6655f3215cb0cdb22b420b6fe141e64b26905e7f33f9377a7fa59135ea3e10b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-gyp@npm:latest":
|
||||
version: 9.3.1
|
||||
resolution: "node-gyp@npm:9.3.1"
|
||||
@@ -7868,6 +7892,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tr46@npm:~0.0.3":
|
||||
version: 0.0.3
|
||||
resolution: "tr46@npm:0.0.3"
|
||||
checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tsconfig-paths@npm:^3.14.1":
|
||||
version: 3.14.1
|
||||
resolution: "tsconfig-paths@npm:3.14.1"
|
||||
@@ -8304,6 +8335,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vitest-fetch-mock@npm:^0.2.2":
|
||||
version: 0.2.2
|
||||
resolution: "vitest-fetch-mock@npm:0.2.2"
|
||||
dependencies:
|
||||
cross-fetch: ^3.0.6
|
||||
peerDependencies:
|
||||
vitest: ">=0.16.0"
|
||||
checksum: fa160f301171cd45dbf7d782880b6b6063fc74b9dd1965ef9206545e812ca8696e6be76662afbac822c6bf850fbb66cf8fb066af646e0e159f5a87ab25c97a02
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vitest@npm:^0.29.3":
|
||||
version: 0.29.3
|
||||
resolution: "vitest@npm:0.29.3"
|
||||
@@ -8378,6 +8420,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webidl-conversions@npm:^3.0.0":
|
||||
version: 3.0.1
|
||||
resolution: "webidl-conversions@npm:3.0.1"
|
||||
checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webidl-conversions@npm:^7.0.0":
|
||||
version: 7.0.0
|
||||
resolution: "webidl-conversions@npm:7.0.0"
|
||||
@@ -8430,6 +8479,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-url@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "whatwg-url@npm:5.0.0"
|
||||
dependencies:
|
||||
tr46: ~0.0.3
|
||||
webidl-conversions: ^3.0.0
|
||||
checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"which-boxed-primitive@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "which-boxed-primitive@npm:1.0.2"
|
||||
|
||||
Reference in New Issue
Block a user