test: working test with TypeScript + vite (using vitest)

This commit is contained in:
鲁树人
2023-05-17 01:46:20 +01:00
parent 863a4e4f89
commit 0db84813ad
19 changed files with 687 additions and 75 deletions

View File

@@ -1,5 +1,4 @@
import {
Avatar,
Box,
Button,
Card,
@@ -7,6 +6,7 @@ import {
Center,
Grid,
GridItem,
Image,
Link,
Text,
VStack,
@@ -16,6 +16,7 @@ import {
import { DecryptedAudioFile, ProcessState, deleteFile } from './fileListingSlice';
import { useRef } from 'react';
import { useAppDispatch } from '~/hooks';
import coverFallback from '~/assets/no-cover.svg';
interface FileRowProps {
id: string;
@@ -25,6 +26,7 @@ interface FileRowProps {
export function FileRow({ id, file }: FileRowProps) {
const dispatch = useAppDispatch();
const isDecrypted = file.state === ProcessState.COMPLETE;
const metadata = file.metadata;
const nameWithoutExt = file.fileName.replace(/\.[a-z\d]{3,6}$/, '');
const decryptedName = nameWithoutExt + '.' + file.ext;
@@ -48,7 +50,7 @@ export function FileRow({ id, file }: FileRowProps) {
};
return (
<Card w="full">
<Card w="full" data-testid="file-row">
<CardBody>
<Grid
templateAreas={{
@@ -75,21 +77,33 @@ export function FileRow({ id, file }: FileRowProps) {
>
<GridItem area="cover">
<Center w="160px" h="160px" m="auto">
{file.metadata.cover && <Avatar size="sm" name="专辑封面" src={file.metadata.cover} />}
{!file.metadata.cover && <Text></Text>}
{metadata && (
<Image
objectFit="cover"
src={metadata.cover}
alt={`"${metadata.album}" 的专辑封面`}
fallbackSrc={coverFallback}
/>
)}
</Center>
</GridItem>
<GridItem area="title">
<Box w="full" as="h4" fontWeight="semibold" mt="1" textAlign={{ base: 'center', md: 'left' }}>
{file.metadata.name || nameWithoutExt}
<span data-testid="audio-meta-song-name">{metadata?.name ?? nameWithoutExt}</span>
</Box>
</GridItem>
<GridItem area="meta">
{isDecrypted && (
{isDecrypted && metadata && (
<Box>
<Text>: {file.metadata.album}</Text>
<Text>: {file.metadata.artist}</Text>
<Text>: {file.metadata.albumArtist}</Text>
<Text>
: <span data-testid="audio-meta-album-name">{metadata.album}</span>
</Text>
<Text>
: <span data-testid="audio-meta-song-artist">{metadata.artist}</span>
</Text>
<Text>
: <span data-testid="audio-meta-album-artist">{metadata.albumArtist}</span>
</Text>
</Box>
)}
</GridItem>

View File

@@ -0,0 +1,18 @@
import { FileListing } from '../FileListing';
import { renderWithProviders, screen } from '~/test-utils/test-helper';
import { ListingMode } from '../fileListingSlice';
import { dummyFiles } from './__fixture__/file-list';
test('should be able to render a list of 3 items', () => {
renderWithProviders(<FileListing />, {
preloadedState: {
fileListing: {
displayMode: ListingMode.LIST,
files: dummyFiles,
},
},
});
expect(screen.getAllByTestId('file-row')).toHaveLength(3);
expect(screen.getByText('Für Alice')).toBeInTheDocument();
});

View File

@@ -0,0 +1,24 @@
import { renderWithProviders, screen } from '~/test-utils/test-helper';
import { untouchedFile } from './__fixture__/file-list';
import { FileRow } from '../FileRow';
import { completedFile } from './__fixture__/file-list';
test('should render no metadata when unavailable', () => {
renderWithProviders(<FileRow id="file://ready" file={untouchedFile} />);
expect(screen.getAllByTestId('file-row')).toHaveLength(1);
expect(screen.getByTestId('audio-meta-song-name')).toHaveTextContent('ready');
expect(screen.queryByTestId('audio-meta-album-name')).toBeFalsy();
expect(screen.queryByTestId('audio-meta-song-artist')).toBeFalsy();
expect(screen.queryByTestId('audio-meta-album-artist')).toBeFalsy();
});
test('should render metadata when file has been processed', () => {
renderWithProviders(<FileRow id="file://done" file={completedFile} />);
expect(screen.getAllByTestId('file-row')).toHaveLength(1);
expect(screen.getByTestId('audio-meta-song-name')).toHaveTextContent('Für Alice');
expect(screen.getByTestId('audio-meta-album-name')).toHaveTextContent("NOW That's What I Call Cryptography 2023");
expect(screen.getByTestId('audio-meta-song-artist')).toHaveTextContent('Jixun');
expect(screen.getByTestId('audio-meta-album-artist')).toHaveTextContent('Cipher Lovers');
});

View File

@@ -0,0 +1,43 @@
import { DecryptedAudioFile, ProcessState } from '../../fileListingSlice';
export const untouchedFile: DecryptedAudioFile = {
fileName: 'ready.bin',
raw: 'blob://localhost/file-a',
decrypted: '',
ext: '',
state: ProcessState.UNTOUCHED,
errorMessage: null,
metadata: null,
};
export const completedFile: DecryptedAudioFile = {
fileName: 'hello-b.bin',
raw: 'blob://localhost/file-b',
decrypted: 'blob://localhost/file-b-decrypted',
ext: 'flac',
state: ProcessState.COMPLETE,
errorMessage: null,
metadata: {
name: 'Für Alice',
artist: 'Jixun',
albumArtist: 'Cipher Lovers',
album: "NOW That's What I Call Cryptography 2023",
cover: '',
},
};
export const fileWithError: DecryptedAudioFile = {
fileName: 'hello-c.bin',
raw: 'blob://localhost/file-c',
decrypted: 'blob://localhost/file-c-decrypted',
ext: 'flac',
state: ProcessState.ERROR,
errorMessage: 'Could not decrypt blah blah',
metadata: null,
};
export const dummyFiles: Record<string, DecryptedAudioFile> = {
'file://untouched': untouchedFile,
'file://completed': completedFile,
'file://error': fileWithError,
};

View File

@@ -31,7 +31,7 @@ export interface DecryptedAudioFile {
decrypted: string; // blob uri
state: ProcessState;
errorMessage: null | string;
metadata: AudioMetadata;
metadata: null | AudioMetadata;
}
export interface FileListingState {
@@ -69,13 +69,7 @@ export const fileListingSlice = createSlice({
ext: '',
state: ProcessState.UNTOUCHED,
errorMessage: null,
metadata: {
name: '',
artist: '',
album: '',
albumArtist: '',
cover: '',
},
metadata: null,
};
},
setDecryptedContent: (state, { payload }: PayloadAction<{ id: string; decryptedBlobURI: string }>) => {