diff --git a/__tests__/components/waves/memes/submission/MemesArtSubmissionContainer.test.tsx b/__tests__/components/waves/memes/submission/MemesArtSubmissionContainer.test.tsx index f057d50628..4a01c7895e 100644 --- a/__tests__/components/waves/memes/submission/MemesArtSubmissionContainer.test.tsx +++ b/__tests__/components/waves/memes/submission/MemesArtSubmissionContainer.test.tsx @@ -1,29 +1,48 @@ -import { render, act } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; -import MemesArtSubmissionContainer from '@/components/waves/memes/submission/MemesArtSubmissionContainer'; -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'; +import { render, act } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import React from "react"; +import MemesArtSubmissionContainer from "@/components/waves/memes/submission/MemesArtSubmissionContainer"; +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'); -jest.mock('@/components/auth/SeizeConnectContext'); -jest.mock('@/components/waves/memes/submission/layout/ModalLayout', () => ({ children }: any) =>
{children}
); -jest.mock('@/components/waves/memes/submission/steps/AgreementStep', () => (props: any) =>
); +jest.mock("@/components/waves/memes/submission/hooks/useArtworkSubmissionForm"); +jest.mock( + "@/components/waves/memes/submission/hooks/useArtworkSubmissionMutation" +); +jest.mock("@/components/auth/SeizeConnectContext"); +jest.mock( + "@/components/waves/memes/submission/layout/ModalLayout", + () => + ({ children }: any) =>
{children}
+); +jest.mock( + "@/components/waves/memes/submission/steps/AgreementStep", + () => (props: any) =>
+); let artworkProps: any; -jest.mock('@/components/waves/memes/submission/steps/ArtworkStep', () => (props: any) => { - artworkProps = props; return
; -}); +jest.mock( + "@/components/waves/memes/submission/steps/ArtworkStep", + () => (props: any) => { + artworkProps = props; + return
; + } +); -const mockForm = useArtworkSubmissionForm as jest.MockedFunction; -const mockMutation = useArtworkSubmissionMutation as jest.MockedFunction; -const mockSeizeConnect = useSeizeConnectContext as jest.MockedFunction; +const mockForm = useArtworkSubmissionForm as jest.MockedFunction< + typeof useArtworkSubmissionForm +>; +const mockMutation = useArtworkSubmissionMutation as jest.MockedFunction< + typeof useArtworkSubmissionMutation +>; +const mockSeizeConnect = useSeizeConnectContext as jest.MockedFunction< + typeof useSeizeConnectContext +>; -describe('MemesArtSubmissionContainer', () => { - const wave = { id: 'w1', participation: { terms: 't' } } as any; +describe("MemesArtSubmissionContainer", () => { + const wave = { id: "w1", participation: { terms: "t" } } as any; const onClose = jest.fn(); beforeEach(() => { @@ -34,20 +53,20 @@ describe('MemesArtSubmissionContainer', () => { setAgreements: jest.fn(), handleContinueFromTerms: jest.fn(), handleContinueFromArtwork: jest.fn(async () => true), - traits: { title: 't', description: 'd' }, + traits: { title: "t", description: "d" }, setTraits: jest.fn(), updateTraitField: jest.fn(), artworkUploaded: false, - artworkUrl: '', + artworkUrl: "", selectedFile: null, - mediaSource: 'upload', - externalMediaUrl: '', - externalMediaPreviewUrl: '', - externalMediaHashInput: '', - externalMediaProvider: 'ipfs', - externalMediaMimeType: 'text/html', + mediaSource: "upload", + externalMediaUrl: "", + externalMediaPreviewUrl: "", + externalMediaHashInput: "", + externalMediaProvider: "ipfs", + externalMediaMimeType: "text/html", externalMediaError: null, - externalMediaValidationStatus: 'idle', + externalMediaValidationStatus: "idle", isExternalMediaValid: false, operationalData: { airdrop_config: [{ id: "test-initial", address: "", count: 20 }], @@ -61,6 +80,7 @@ describe('MemesArtSubmissionContainer', () => { artist_profile_media: [], artwork_commentary_media: [], preview_image: "", + promo_video: "", }, commentary: "", about_artist: "", @@ -84,37 +104,39 @@ describe('MemesArtSubmissionContainer', () => { formState.handleFileSelect = jest.fn((file: File) => { formState.selectedFile = file; formState.artworkUploaded = true; - formState.artworkUrl = 'object-url'; + formState.artworkUrl = "object-url"; }); - formState.setMediaSource = jest.fn((mode: 'upload' | '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.externalMediaUrl = `${formState.externalMediaProvider === "arweave" ? "https://arweave.net/" : "ipfs://"}${hash}`; formState.externalMediaPreviewUrl = - formState.externalMediaProvider === 'arweave' + formState.externalMediaProvider === "arweave" ? `https://arweave.net/${hash}` : `https://ipfs.io/ipfs/${hash}`; formState.isExternalMediaValid = true; - formState.externalMediaValidationStatus = 'valid'; + formState.externalMediaValidationStatus = "valid"; formState.externalMediaError = null; } else { - formState.externalMediaUrl = ''; - formState.externalMediaPreviewUrl = ''; + formState.externalMediaUrl = ""; + formState.externalMediaPreviewUrl = ""; formState.isExternalMediaValid = false; - formState.externalMediaValidationStatus = 'idle'; + formState.externalMediaValidationStatus = "idle"; formState.externalMediaError = null; } }); - formState.setExternalMediaProvider = jest.fn((provider: 'ipfs' | 'arweave') => { - formState.externalMediaProvider = provider; - formState.setExternalMediaHash(formState.externalMediaHashInput); - }); + formState.setExternalMediaProvider = jest.fn( + (provider: "ipfs" | "arweave") => { + formState.externalMediaProvider = provider; + formState.setExternalMediaHash(formState.externalMediaHashInput); + } + ); formState.setExternalMediaMimeType = jest.fn( (mimeType: InteractiveMediaMimeType) => { @@ -123,15 +145,15 @@ describe('MemesArtSubmissionContainer', () => { ); formState.clearExternalMedia = jest.fn(() => { - formState.externalMediaHashInput = ''; - formState.externalMediaUrl = ''; - formState.externalMediaPreviewUrl = ''; + formState.externalMediaHashInput = ""; + formState.externalMediaUrl = ""; + formState.externalMediaPreviewUrl = ""; formState.isExternalMediaValid = false; - formState.externalMediaValidationStatus = 'idle'; + formState.externalMediaValidationStatus = "idle"; formState.externalMediaError = null; }); - formState.getSubmissionData = () => ({ traits: { title: 't' } }); + formState.getSubmissionData = () => ({ traits: { title: "t" } }); formState.getMediaSelection = jest.fn(() => ({ mediaSource: formState.mediaSource, selectedFile: formState.selectedFile, @@ -145,17 +167,17 @@ describe('MemesArtSubmissionContainer', () => { mockForm.mockReturnValue(formState); mockMutation.mockReturnValue({ - submitArtwork: jest.fn(async () => 'ok'), + submitArtwork: jest.fn(async () => "ok"), uploadProgress: 0, - submissionPhase: 'idle', + submissionPhase: "idle", submissionError: undefined, isSubmitting: false, } as any); mockSeizeConnect.mockReturnValue({ - address: '0x123', + address: "0x123", isSafeWallet: false, - walletName: 'MetaMask', - walletIcon: 'metamask-icon.svg', + walletName: "MetaMask", + walletIcon: "metamask-icon.svg", seizeConnect: jest.fn(), seizeDisconnect: jest.fn(), seizeDisconnectAndLogout: jest.fn(), @@ -166,12 +188,12 @@ describe('MemesArtSubmissionContainer', () => { } as any); }); - it('auto closes on success', () => { + it("auto closes on success", () => { jest.useFakeTimers(); mockMutation.mockReturnValueOnce({ submitArtwork: jest.fn(), uploadProgress: 0, - submissionPhase: 'success', + submissionPhase: "success", submissionError: undefined, isSubmitting: false, } as any); @@ -180,18 +202,18 @@ describe('MemesArtSubmissionContainer', () => { expect(onClose).toHaveBeenCalled(); }); - it('submits artwork when file selected', async () => { + it("submits artwork when file selected", async () => { const user = userEvent.setup(); - const submitArtwork = jest.fn(async () => 'result'); + const submitArtwork = jest.fn(async () => "result"); mockMutation.mockReturnValueOnce({ submitArtwork, uploadProgress: 0, - submissionPhase: 'idle', + submissionPhase: "idle", submissionError: undefined, isSubmitting: false, } as any); render(); - const file = new File(['a'], 'a.png', { type: 'image/png' }); + const file = new File(["a"], "a.png", { type: "image/png" }); await act(async () => { artworkProps.handleFileSelect(file); }); diff --git a/__tests__/components/waves/memes/submission/components/AdditionalMediaUpload.test.tsx b/__tests__/components/waves/memes/submission/components/AdditionalMediaUpload.test.tsx index a15ba7fd17..8f8fb29b39 100644 --- a/__tests__/components/waves/memes/submission/components/AdditionalMediaUpload.test.tsx +++ b/__tests__/components/waves/memes/submission/components/AdditionalMediaUpload.test.tsx @@ -1,6 +1,7 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import AdditionalMediaUpload from "@/components/waves/memes/submission/components/AdditionalMediaUpload"; +import type { MetadataValueLengthStatus } from "@/components/waves/memes/submission/utils/submissionMetadata"; describe("AdditionalMediaUpload", () => { const defaultProps = { @@ -28,7 +29,13 @@ describe("AdditionalMediaUpload", () => { }); it("shows preview section when video submission", () => { - render(); + render( + + ); expect(screen.getByText(/Preview \*/i)).toBeInTheDocument(); expect( screen.getByText(/Video submissions require a preview image/i) @@ -36,20 +43,38 @@ describe("AdditionalMediaUpload", () => { }); it("does not show preview section for regular submissions", () => { - render(); + render( + + ); expect(screen.queryByText(/Preview \*/i)).not.toBeInTheDocument(); }); it("shows promo video section for HTML submissions", () => { - render(); + render( + + ); expect(screen.getByText("Promo Video")).toBeInTheDocument(); expect( - screen.getByText(/For HTML submissions, we recommend providing a promo video/i) + screen.getByText( + /For HTML submissions, we recommend providing a promo video/i + ) ).toBeInTheDocument(); }); it("does not show promo video section for video submissions", () => { - render(); + render( + + ); expect(screen.queryByText("Promo Video")).not.toBeInTheDocument(); }); @@ -70,4 +95,25 @@ describe("AdditionalMediaUpload", () => { expect(onArtworkCommentaryChange).toHaveBeenCalled(); }); + + it("shows metadata warning hint for about artist", () => { + const warningStatus: MetadataValueLengthStatus = { + dataKey: "about_artist", + length: 4700, + maxLength: 5000, + warningThreshold: 4500, + remaining: 300, + isWarning: true, + isError: false, + }; + + render( + + ); + + expect(screen.getByText("4700/5000 characters.")).toBeInTheDocument(); + }); }); diff --git a/__tests__/components/waves/memes/submission/components/AllowlistBatchManager.test.tsx b/__tests__/components/waves/memes/submission/components/AllowlistBatchManager.test.tsx index 4998e35da0..4af5c2e4c1 100644 --- a/__tests__/components/waves/memes/submission/components/AllowlistBatchManager.test.tsx +++ b/__tests__/components/waves/memes/submission/components/AllowlistBatchManager.test.tsx @@ -1,18 +1,21 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import AllowlistBatchManager from "@/components/waves/memes/submission/components/AllowlistBatchManager"; +import type { MetadataValueLengthStatus } from "@/components/waves/memes/submission/utils/submissionMetadata"; describe("AllowlistBatchManager", () => { it("renders with no batches and allows adding one", async () => { const user = userEvent.setup(); const onBatchesChange = jest.fn(); - render(); + render( + + ); expect(screen.getByText(/No allowlist batches added/i)).toBeInTheDocument(); - + const addButton = screen.getByText(/Add Batch/i); await user.click(addButton); - + expect(onBatchesChange).toHaveBeenCalledWith([ expect.objectContaining({ contract: "", token_ids_raw: "" }), ]); @@ -23,7 +26,9 @@ describe("AllowlistBatchManager", () => { { id: "batch-1", contract: "0x1", token_ids_raw: "1-10" }, { id: "batch-2", contract: "0x2", token_ids_raw: "20,21" }, ]; - render(); + render( + + ); expect(screen.getByDisplayValue("0x1")).toBeInTheDocument(); expect(screen.getByDisplayValue("1-10")).toBeInTheDocument(); @@ -35,13 +40,20 @@ describe("AllowlistBatchManager", () => { const user = userEvent.setup(); const onBatchesChange = jest.fn(); const batches = [{ id: "batch-1", contract: "0x1", token_ids_raw: "1" }]; - render(); + render( + + ); const contractInput = screen.getByDisplayValue("0x1"); await user.type(contractInput, "2"); await user.tab(); - expect(onBatchesChange).toHaveBeenCalledWith([{ id: "batch-1", contract: "0x12", token_ids_raw: "1" }]); + expect(onBatchesChange).toHaveBeenCalledWith([ + { id: "batch-1", contract: "0x12", token_ids_raw: "1" }, + ]); }); it("allows removing a batch", async () => { @@ -51,11 +63,40 @@ describe("AllowlistBatchManager", () => { { id: "batch-1", contract: "0x1", token_ids_raw: "1" }, { id: "batch-2", contract: "0x2", token_ids_raw: "2" }, ]; - render(); + render( + + ); const removeButtons = screen.getAllByRole("button", { name: /Remove/i }); await user.click(removeButtons[0]); - expect(onBatchesChange).toHaveBeenCalledWith([{ id: "batch-2", contract: "0x2", token_ids_raw: "2" }]); + expect(onBatchesChange).toHaveBeenCalledWith([ + { id: "batch-2", contract: "0x2", token_ids_raw: "2" }, + ]); + }); + + it("shows allowlist metadata warning when near limit", () => { + const status: MetadataValueLengthStatus = { + dataKey: "allowlist_batches", + length: 4800, + maxLength: 5000, + warningThreshold: 4500, + remaining: 200, + isWarning: true, + isError: false, + }; + + render( + + ); + + expect(screen.getByText("4800/5000 characters.")).toBeInTheDocument(); }); }); diff --git a/__tests__/components/waves/memes/submission/components/PaymentConfig.test.tsx b/__tests__/components/waves/memes/submission/components/PaymentConfig.test.tsx index f9d62065f6..fd8201be24 100644 --- a/__tests__/components/waves/memes/submission/components/PaymentConfig.test.tsx +++ b/__tests__/components/waves/memes/submission/components/PaymentConfig.test.tsx @@ -1,5 +1,6 @@ import { render, screen, fireEvent } from "@testing-library/react"; import PaymentConfig from "@/components/waves/memes/submission/components/PaymentConfig"; +import type { MetadataValueLengthStatus } from "@/components/waves/memes/submission/utils/submissionMetadata"; jest.mock( "@/components/utils/input/ens-address/EnsAddressInput", @@ -115,7 +116,9 @@ describe("PaymentConfig", () => { /> ); - const nameInput = screen.getByPlaceholderText(/enter designated payee name/i); + const nameInput = screen.getByPlaceholderText( + /enter designated payee name/i + ); fireEvent.change(nameInput, { target: { value: "Red Cross" } }); expect(onPaymentInfoChange).toHaveBeenCalledWith({ @@ -162,9 +165,9 @@ describe("PaymentConfig", () => { expect(screen.getByPlaceholderText(/0x.*or ENS/i)).toHaveValue(address); const checkbox = screen.getByRole("checkbox") as HTMLInputElement; expect(checkbox.checked).toBe(true); - expect(screen.getByPlaceholderText(/enter designated payee name/i)).toHaveValue( - "Red Cross" - ); + expect( + screen.getByPlaceholderText(/enter designated payee name/i) + ).toHaveValue("Red Cross"); }); it("clears designated payee name when checkbox is unchecked", () => { @@ -189,4 +192,22 @@ describe("PaymentConfig", () => { designated_payee_name: "", }); }); + + it("shows metadata warning for payment info near limit", () => { + const status: MetadataValueLengthStatus = { + dataKey: "payment_info", + length: 4600, + maxLength: 5000, + warningThreshold: 4500, + remaining: 400, + isWarning: true, + isError: false, + }; + + render( + + ); + + expect(screen.getByText("4600/5000 characters.")).toBeInTheDocument(); + }); }); diff --git a/__tests__/components/waves/memes/submission/hooks/useArtworkSubmissionMutation.test.tsx b/__tests__/components/waves/memes/submission/hooks/useArtworkSubmissionMutation.test.tsx index e0380ba3e1..542244df47 100644 --- a/__tests__/components/waves/memes/submission/hooks/useArtworkSubmissionMutation.test.tsx +++ b/__tests__/components/waves/memes/submission/hooks/useArtworkSubmissionMutation.test.tsx @@ -1,5 +1,8 @@ import { transformToApiRequest } from "@/components/waves/memes/submission/hooks/useArtworkSubmissionMutation"; -import { MemesSubmissionAdditionalInfoKey, OperationalData } from "@/components/waves/memes/submission/types/OperationalData"; +import { + MemesSubmissionAdditionalInfoKey, + OperationalData, +} from "@/components/waves/memes/submission/types/OperationalData"; import { TraitsData } from "@/components/waves/memes/submission/types/TraitsData"; describe("useArtworkSubmissionMutation - transformToApiRequest", () => { @@ -11,8 +14,16 @@ describe("useArtworkSubmissionMutation - transformToApiRequest", () => { const mockOperationalData: OperationalData = { airdrop_config: [ - { id: "test-1", address: "0x1234567890123456789012345678901234567890", count: 15 }, - { id: "test-2", address: "0x0987654321098765432109876543210987654321", count: 5 }, + { + id: "test-1", + address: "0x1234567890123456789012345678901234567890", + count: 15, + }, + { + id: "test-2", + address: "0x0987654321098765432109876543210987654321", + count: 5, + }, ], payment_info: { payment_address: "0x789", @@ -26,6 +37,7 @@ describe("useArtworkSubmissionMutation - transformToApiRequest", () => { artist_profile_media: ["https://example.com/profile.jpg"], artwork_commentary_media: ["https://example.com/commentary.jpg"], preview_image: "", + promo_video: "", }, commentary: "Test Commentary", about_artist: "Test About Artist", @@ -50,14 +62,28 @@ describe("useArtworkSubmissionMutation - transformToApiRequest", () => { expect(metadataMap.get("title")).toBe("Test Artwork"); // Check operational data - expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.AIRDROP_CONFIG)).toBe(JSON.stringify(mockOperationalData.airdrop_config)); - expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.PAYMENT_INFO)).toBe(JSON.stringify(mockOperationalData.payment_info)); - expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.ALLOWLIST_BATCHES)).toBe(JSON.stringify([ - { contract: "0xabc", token_ids: "1-5" } // Stored as raw string - ])); - expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.ADDITIONAL_MEDIA)).toBe(JSON.stringify(mockOperationalData.additional_media)); - expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.COMMENTARY)).toBe("Test Commentary"); - expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.ABOUT_ARTIST)).toBe("Test About Artist"); + expect( + metadataMap.get(MemesSubmissionAdditionalInfoKey.AIRDROP_CONFIG) + ).toBe(JSON.stringify(mockOperationalData.airdrop_config)); + expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.PAYMENT_INFO)).toBe( + JSON.stringify(mockOperationalData.payment_info) + ); + expect( + metadataMap.get(MemesSubmissionAdditionalInfoKey.ALLOWLIST_BATCHES) + ).toBe( + JSON.stringify([ + { contract: "0xabc", token_ids: "1-5" }, // Stored as raw string + ]) + ); + expect( + metadataMap.get(MemesSubmissionAdditionalInfoKey.ADDITIONAL_MEDIA) + ).toBe(JSON.stringify(mockOperationalData.additional_media)); + expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.COMMENTARY)).toBe( + "Test Commentary" + ); + expect(metadataMap.get(MemesSubmissionAdditionalInfoKey.ABOUT_ARTIST)).toBe( + "Test About Artist" + ); }); it("should not include operational fields if not provided", () => { @@ -74,11 +100,23 @@ describe("useArtworkSubmissionMutation - transformToApiRequest", () => { result.metadata.map((m) => [m.data_key, m.data_value]) ); - expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.AIRDROP_CONFIG)).toBe(false); - expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.PAYMENT_INFO)).toBe(false); - expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.ALLOWLIST_BATCHES)).toBe(false); - expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.ADDITIONAL_MEDIA)).toBe(false); - expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.COMMENTARY)).toBe(false); - expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.ABOUT_ARTIST)).toBe(false); + expect( + metadataMap.has(MemesSubmissionAdditionalInfoKey.AIRDROP_CONFIG) + ).toBe(false); + expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.PAYMENT_INFO)).toBe( + false + ); + expect( + metadataMap.has(MemesSubmissionAdditionalInfoKey.ALLOWLIST_BATCHES) + ).toBe(false); + expect( + metadataMap.has(MemesSubmissionAdditionalInfoKey.ADDITIONAL_MEDIA) + ).toBe(false); + expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.COMMENTARY)).toBe( + false + ); + expect(metadataMap.has(MemesSubmissionAdditionalInfoKey.ABOUT_ARTIST)).toBe( + false + ); }); -}); \ No newline at end of file +}); diff --git a/__tests__/components/waves/memes/submission/steps/AdditionalInfoStep.test.tsx b/__tests__/components/waves/memes/submission/steps/AdditionalInfoStep.test.tsx new file mode 100644 index 0000000000..6d12c451ef --- /dev/null +++ b/__tests__/components/waves/memes/submission/steps/AdditionalInfoStep.test.tsx @@ -0,0 +1,58 @@ +import { render, screen } from "@testing-library/react"; +import AdditionalInfoStep from "@/components/waves/memes/submission/steps/AdditionalInfoStep"; +import type { TraitsData } from "@/components/waves/memes/submission/types/TraitsData"; + +describe("AdditionalInfoStep", () => { + const baseTraits = { + title: "Title", + description: "Description", + } as TraitsData; + + const baseProps = { + traits: baseTraits, + airdropEntries: [ + { + id: "a1", + address: "0x1234567890123456789012345678901234567890", + count: 20, + }, + ], + onAirdropEntriesChange: jest.fn(), + paymentInfo: { + payment_address: "0x1234567890123456789012345678901234567890", + has_designated_payee: false, + designated_payee_name: "", + }, + onPaymentInfoChange: jest.fn(), + allowlistBatches: [], + supportingMedia: [], + artworkCommentary: "commentary", + aboutArtist: "about", + previewImage: "", + promoVideo: "", + requiresPreviewImage: false, + requiresPromoVideoOption: false, + previewRequiredMediaType: null, + onBatchesChange: jest.fn(), + onSupportingMediaChange: jest.fn(), + onPreviewImageChange: jest.fn(), + onPromoVideoChange: jest.fn(), + onArtworkCommentaryChange: jest.fn(), + onAboutArtistChange: jest.fn(), + onBack: jest.fn(), + onPreview: jest.fn(), + onSubmit: jest.fn(), + isSubmitting: false, + }; + + it("disables preview and submit when metadata exceeds 5000 chars", () => { + render( + + ); + + expect(screen.getByRole("button", { name: "Preview" })).toBeDisabled(); + expect( + screen.getByRole("button", { name: "Submit Artwork" }) + ).toBeDisabled(); + }); +}); diff --git a/components/waves/memes/submission/MemesArtSubmissionContainer.tsx b/components/waves/memes/submission/MemesArtSubmissionContainer.tsx index f713bd4a30..cfecf82926 100644 --- a/components/waves/memes/submission/MemesArtSubmissionContainer.tsx +++ b/components/waves/memes/submission/MemesArtSubmissionContainer.tsx @@ -266,6 +266,7 @@ const MemesArtSubmissionContainer: FC = ({ /> ) : ( void; readonly onArtworkCommentaryChange: (commentary: string) => void; readonly onAboutArtistChange: (aboutArtist: string) => void; + readonly artworkCommentaryLengthStatus?: + | MetadataValueLengthStatus + | undefined; + readonly aboutArtistLengthStatus?: MetadataValueLengthStatus | undefined; + readonly additionalMediaLengthStatus?: MetadataValueLengthStatus | undefined; readonly errors?: { supportingMedia?: string; previewImage?: string; @@ -46,6 +53,9 @@ const AdditionalMediaUpload: FC = ({ onPromoVideoChange, onArtworkCommentaryChange, onAboutArtistChange, + artworkCommentaryLengthStatus, + aboutArtistLengthStatus, + additionalMediaLengthStatus, errors, }) => { const mediaInputRef = useRef(null); @@ -239,7 +249,9 @@ const AdditionalMediaUpload: FC = ({
{description && ( -

{description}

+

+ {description} +

)} {upload.items.length > 0 && ( @@ -291,42 +303,49 @@ const AdditionalMediaUpload: FC = ({ errors?.supportingMedia, "image/*,video/*" )} +
- -