import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { alertChallengeVerificationFailed, getPublicationPreview, getPublicationType, getVotePreview } from '../challenge-utils'; const alertMock = vi.fn(); const originalAlert = globalThis.alert; const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined); const logSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined); describe('challenge-utils', () => { beforeEach(() => { vi.clearAllMocks(); globalThis.alert = alertMock; }); afterEach(() => { globalThis.alert = originalAlert; }); it('alerts with merged object challenge errors, reason, and resolved board path', () => { alertChallengeVerificationFailed( { challengeErrors: { captcha: 'invalid captcha', ignored: 42, }, challengeSuccess: false, reason: 'try again later', } as never, { communityAddress: 'business-and-finance.bso' }, ); expect(warnSpy).toHaveBeenCalledWith( 'Challenge Verification Failed:', expect.objectContaining({ challengeSuccess: false }), 'Publication:', expect.objectContaining({ communityAddress: 'business-and-finance.bso' }), ); expect(alertMock).toHaveBeenCalledWith('Error from /biz/: invalid captcha try again later'); }); it('alerts with joined array challenge errors and falls back to the raw board address when unmapped', () => { alertChallengeVerificationFailed( { challengeErrors: ['first error', 'second error'], challengeSuccess: false, } as never, { communityAddress: 'unknown-board.eth' }, ); expect(alertMock).toHaveBeenCalledWith('Error from unknown-board.eth: first error second error'); }); it('uses communityAddress when the upgraded publication no longer exposes communityAddress', () => { alertChallengeVerificationFailed( { challengeErrors: ['first error'], challengeSuccess: false, } as never, { communityAddress: 'business-and-finance.bso' }, ); expect(alertMock).toHaveBeenCalledWith('Error from /biz/: first error'); }); it('warns about invalid challenge error payloads and falls back to an unknown error', () => { alertChallengeVerificationFailed( { challengeErrors: 'bad-shape', challengeSuccess: false, } as never, {}, ); expect(warnSpy).toHaveBeenCalledWith('challengeVerification.challengeErrors is not an object or array:', 'bad-shape'); expect(alertMock).toHaveBeenCalledWith('Error from unknown board: unknown error'); }); it('logs successful challenge verification instead of alerting', () => { alertChallengeVerificationFailed({ challengeSuccess: true } as never, { communityAddress: 'business-and-finance.bso' }); expect(logSpy).toHaveBeenCalledWith('Challenge verification succeeded:', expect.objectContaining({ challengeSuccess: true })); expect(alertMock).not.toHaveBeenCalled(); }); it('classifies publication types and vote previews', () => { expect(getPublicationType(undefined)).toBeUndefined(); expect(getPublicationType({ vote: 1 })).toBe('vote'); expect(getPublicationType({ parentCid: 'reply-parent' })).toBe('reply'); expect(getPublicationType({ commentCid: 'comment-cid' })).toBe('edit'); expect(getPublicationType({ title: 'new thread' })).toBe('post'); expect(getVotePreview(undefined)).toBe(''); expect(getVotePreview({ vote: 1 })).toBe(' +1'); expect(getVotePreview({ vote: -1 })).toBe(' -1'); }); it('builds publication previews from title, content, links, and truncation rules', () => { expect(getPublicationPreview(undefined)).toBe(''); expect(getPublicationPreview({ link: 'https://example.com/only-link' })).toBe('https://example.com/only-link'); expect(getPublicationPreview({ title: 'Announcement', content: 'Now live' })).toBe('Announcement: Now live'); expect( getPublicationPreview({ content: 'a'.repeat(80), }), ).toBe(`${'a'.repeat(50)}...`); }); });