Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
55 changes: 41 additions & 14 deletions __tests__/components/waves/memes/MemesArtSubmissionFile.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import MemesArtSubmissionFile from '@/components/waves/memes/MemesArtSubmissionFile';
import { AuthContext } from '@/components/auth/Auth';
import type { MemesArtSubmissionFileProps } from '@/components/waves/memes/file-upload/reducers/types';
import type { InteractiveMediaMimeType } from '@/components/waves/memes/submission/constants/media';

// Mock framer-motion to avoid AbortSignal compatibility issues
jest.mock('framer-motion', () => {
Expand Down Expand Up @@ -152,6 +154,37 @@ describe('MemesArtSubmissionFile', () => {
const mockSetToast = jest.fn();
const mockSetArtworkUploaded = jest.fn();
const mockHandleFileSelect = jest.fn();
const mockSetMediaSource = jest.fn();
const mockOnExternalHashChange = jest.fn();
const mockOnExternalProviderChange = jest.fn();
const mockOnExternalMimeTypeChange =
jest.fn<(value: InteractiveMediaMimeType) => void>();
const mockOnClearExternalMedia = jest.fn();

const baseProps: MemesArtSubmissionFileProps = {
artworkUploaded: false,
artworkUrl: 'url',
setArtworkUploaded: mockSetArtworkUploaded,
handleFileSelect: mockHandleFileSelect,
mediaSource: 'upload',
setMediaSource: mockSetMediaSource,
externalHash: '',
externalProvider: 'ipfs',
externalConstructedUrl: '',
externalPreviewUrl: '',
externalMimeType: 'text/html',
externalError: null,
isExternalMediaValid: false,
onExternalHashChange: mockOnExternalHashChange,
onExternalProviderChange: mockOnExternalProviderChange,
onExternalMimeTypeChange: mockOnExternalMimeTypeChange,
onClearExternalMedia: mockOnClearExternalMedia,
};

const renderComponent = (
overrideProps: Partial<MemesArtSubmissionFileProps> = {}
) =>
render(<MemesArtSubmissionFile {...baseProps} {...overrideProps} />);

beforeEach(() => {
jest.clearAllMocks();
Expand All @@ -162,19 +195,17 @@ describe('MemesArtSubmissionFile', () => {
mockProcessFile.mockClear();
mockHandleRetry.mockClear();
mockHandleRemoveFile.mockClear();
mockSetMediaSource.mockClear();
mockOnExternalHashChange.mockClear();
mockOnExternalProviderChange.mockClear();
mockOnExternalMimeTypeChange.mockClear();
mockOnClearExternalMedia.mockClear();
});

describe('Error Handling - Fail Fast', () => {
it('renders with default AuthContext when provider is missing', () => {
// Component should render with default context values when no provider is present
const { container } = render(
<MemesArtSubmissionFile
artworkUploaded={false}
artworkUrl="url"
setArtworkUploaded={mockSetArtworkUploaded}
handleFileSelect={mockHandleFileSelect}
/>
);
const { container } = renderComponent();

// Should render the main container without errors
expect(container.firstChild).toBeInTheDocument();
Expand All @@ -188,6 +219,7 @@ describe('MemesArtSubmissionFile', () => {
const { container } = render(
<AuthContext.Provider value={{ setToast: mockSetToast } as any}>
<MemesArtSubmissionFile
{...baseProps}
artworkUploaded={null as any}
artworkUrl={undefined as any}
setArtworkUploaded={mockSetArtworkUploaded}
Expand All @@ -207,12 +239,7 @@ describe('MemesArtSubmissionFile', () => {
it('shows warning when browser unsupported and calls setToast', async () => {
render(
<AuthContext.Provider value={{ setToast: mockSetToast } as any}>
<MemesArtSubmissionFile
artworkUploaded={false}
artworkUrl="url"
setArtworkUploaded={mockSetArtworkUploaded}
handleFileSelect={mockHandleFileSelect}
/>
<MemesArtSubmissionFile {...baseProps} />
</AuthContext.Provider>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SubmissionStep } from '@/components/waves/memes/submission/types/Steps'
import { useArtworkSubmissionForm } from '@/components/waves/memes/submission/hooks/useArtworkSubmissionForm';
import { useArtworkSubmissionMutation } from '@/components/waves/memes/submission/hooks/useArtworkSubmissionMutation';
import { useSeizeConnectContext } from '@/components/auth/SeizeConnectContext';
import type { InteractiveMediaMimeType } from '@/components/waves/memes/submission/constants/media';

jest.mock('@/components/waves/memes/submission/hooks/useArtworkSubmissionForm');
jest.mock('@/components/waves/memes/submission/hooks/useArtworkSubmissionMutation');
Expand All @@ -27,7 +28,7 @@ describe('MemesArtSubmissionContainer', () => {

beforeEach(() => {
artworkProps = undefined;
mockForm.mockReturnValue({
const formState: any = {
currentStep: SubmissionStep.ARTWORK,
agreements: false,
setAgreements: jest.fn(),
Expand All @@ -37,10 +38,84 @@ describe('MemesArtSubmissionContainer', () => {
updateTraitField: jest.fn(),
artworkUploaded: false,
artworkUrl: '',
setArtworkUploaded: jest.fn(),
handleFileSelect: jest.fn(),
getSubmissionData: () => ({ traits: { title: 't' } }),
} as any);
selectedFile: null,
mediaSource: 'upload',
externalMediaUrl: '',
externalMediaPreviewUrl: '',
externalMediaHashInput: '',
externalMediaProvider: 'ipfs',
externalMediaMimeType: 'text/html',
externalMediaError: null,
isExternalMediaValid: false,
};

formState.setArtworkUploaded = jest.fn((value: boolean) => {
formState.artworkUploaded = value;
if (!value) {
formState.selectedFile = null;
}
});

formState.handleFileSelect = jest.fn((file: File) => {
formState.selectedFile = file;
formState.artworkUploaded = true;
formState.artworkUrl = 'object-url';
});

formState.setMediaSource = jest.fn((mode: 'upload' | 'url') => {
formState.mediaSource = mode;
});

formState.setExternalMediaHash = jest.fn((hash: string) => {
formState.externalMediaHashInput = hash;
if (hash) {
formState.externalMediaUrl = `${formState.externalMediaProvider === 'arweave' ? 'https://arweave.net/' : 'ipfs://'}${hash}`;
formState.externalMediaPreviewUrl =
formState.externalMediaProvider === 'arweave'
? formState.externalMediaUrl
: `https://gateway.pinata.cloud/ipfs/${hash}`;
formState.isExternalMediaValid = true;
formState.externalMediaError = null;
} else {
formState.externalMediaUrl = '';
formState.externalMediaPreviewUrl = '';
formState.isExternalMediaValid = false;
formState.externalMediaError = null;
}
});

formState.setExternalMediaProvider = jest.fn((provider: 'ipfs' | 'arweave') => {
formState.externalMediaProvider = provider;
formState.setExternalMediaHash(formState.externalMediaHashInput);
});

formState.setExternalMediaMimeType = jest.fn(
(mimeType: InteractiveMediaMimeType) => {
formState.externalMediaMimeType = mimeType;
}
);

formState.clearExternalMedia = jest.fn(() => {
formState.externalMediaHashInput = '';
formState.externalMediaUrl = '';
formState.externalMediaPreviewUrl = '';
formState.isExternalMediaValid = false;
formState.externalMediaError = null;
});

formState.getSubmissionData = () => ({ traits: { title: 't' } });
formState.getMediaSelection = jest.fn(() => ({
mediaSource: formState.mediaSource,
selectedFile: formState.selectedFile,
externalUrl: formState.externalMediaUrl,
externalPreviewUrl: formState.externalMediaPreviewUrl,
externalProvider: formState.externalMediaProvider,
externalHash: formState.externalMediaHashInput,
externalMimeType: formState.externalMediaMimeType,
isExternalValid: formState.isExternalMediaValid,
}));

mockForm.mockReturnValue(formState);
mockMutation.mockReturnValue({
submitArtwork: jest.fn(async () => 'ok'),
uploadProgress: 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import React, { ComponentProps } from 'react';
import { render, screen } from '@testing-library/react';
import ArtworkStep from '@/components/waves/memes/submission/steps/ArtworkStep';
import { TraitsData } from '@/components/waves/memes/submission/types/TraitsData';
import type { InteractiveMediaMimeType } from '@/components/waves/memes/submission/constants/media';

jest.mock('@/components/waves/memes/MemesArtSubmissionFile', () => () => <div data-testid="file" />);
jest.mock('@/components/waves/memes/submission/details/ArtworkDetails', () => (props: any) => (
Expand Down Expand Up @@ -67,20 +68,36 @@ function createTraits(): TraitsData {
};
}

const createProps = (
override: Partial<ComponentProps<typeof ArtworkStep>> = {}
) => ({
traits: createTraits(),
artworkUploaded: false,
artworkUrl: '',
setArtworkUploaded: () => {},
handleFileSelect: () => {},
mediaSource: 'upload' as const,
setMediaSource: () => {},
externalHash: '',
externalProvider: 'ipfs',
externalConstructedUrl: '',
externalPreviewUrl: '',
externalMimeType: 'text/html' as InteractiveMediaMimeType,
externalError: null as string | null,
isExternalMediaValid: false,
onExternalHashChange: () => {},
onExternalProviderChange: () => {},
onExternalMimeTypeChange: (_value: InteractiveMediaMimeType) => {},
onClearExternalMedia: () => {},
onSubmit: () => {},
updateTraitField: () => {},
setTraits: () => {},
...override,
});

describe('ArtworkStep', () => {
it('shows upload tooltip when artwork missing', () => {
render(
<ArtworkStep
traits={createTraits()}
artworkUploaded={false}
artworkUrl=""
setArtworkUploaded={() => {}}
handleFileSelect={() => {}}
onSubmit={() => {}}
updateTraitField={() => {}}
setTraits={() => {}}
/>
);
render(<ArtworkStep {...createProps()} />);
expect(screen.getByTestId('submit')).toBeDisabled();
expect(screen.getByTestId('submit').getAttribute('title')).toMatch('Please upload artwork');
});
Expand Down Expand Up @@ -108,14 +125,7 @@ describe('ArtworkStep', () => {
traits.boost = 'bo';
render(
<ArtworkStep
traits={traits}
artworkUploaded={true}
artworkUrl="url"
setArtworkUploaded={() => {}}
handleFileSelect={() => {}}
onSubmit={() => {}}
updateTraitField={() => {}}
setTraits={() => {}}
{...createProps({ traits, artworkUploaded: true, artworkUrl: 'url' })}
/>
);
expect(screen.getByTestId('submit')).not.toBeDisabled();
Expand All @@ -127,14 +137,12 @@ describe('ArtworkStep', () => {
const onSubmit = jest.fn();
render(
<ArtworkStep
traits={{ ...traits, title: 't', description: 'd' }}
artworkUploaded={true}
artworkUrl="u"
setArtworkUploaded={() => {}}
handleFileSelect={() => {}}
onSubmit={onSubmit}
updateTraitField={() => {}}
setTraits={() => {}}
{...createProps({
traits: { ...traits, title: 't', description: 'd' },
artworkUploaded: true,
artworkUrl: 'u',
onSubmit,
})}
/>
);
screen.getByTestId('submit').click();
Expand All @@ -148,16 +156,13 @@ describe('ArtworkStep', () => {
const onCancel = jest.fn();
render(
<ArtworkStep
traits={traits}
artworkUploaded={true}
artworkUrl="url"
setArtworkUploaded={() => {}}
handleFileSelect={() => {}}
onSubmit={() => {}}
onCancel={onCancel}
updateTraitField={() => {}}
setTraits={() => {}}
submissionPhase="uploading"
{...createProps({
traits,
artworkUploaded: true,
artworkUrl: 'url',
onCancel,
submissionPhase: 'uploading',
})}
/>
);
const btn = screen.getByRole('button', { name: /cancel/i });
Expand Down
Loading