import { describe, it, expect } from 'vitest' import { loadLib } from './helpers/loadLib.js' const { chipState, chipLabel, panelDefaults, addRequest, renameOffer } = loadLib('chip.js', [ 'chipState', 'chipLabel', 'panelDefaults', 'addRequest', 'renameOffer' ]) const discord = (extra = {}) => ({ platform: 'discord', slug: '111/222', discord: { server_id: '111', channel_id: '222', server_name: 'Studio', channel_name: 'drops', server_url: 'https://discord.com/channels/111', channel_url: 'https://discord.com/channels/111/222' }, ...extra }) describe('chip state and label', () => { it('keeps the one-click wording on creator platforms', () => { expect(chipLabel({ state: 'new', platform: 'patreon' }, 'Patreon')).toBe('+ Add to FabledCurator') expect( chipLabel({ state: 'artist_match', platform: 'patreon', artist: { name: 'Atole' } }, 'Patreon') ).toBe('+ Add Patreon source to Atole') expect(chipLabel({ state: 'source_match', platform: 'patreon' }, 'Patreon')).toBe( '✓ In FabledCurator · Patreon' ) }) it('offers the channel by name on Discord, whatever the suggestion', () => { expect(chipLabel(discord({ state: 'new' }), 'Discord')).toBe('+ Add #drops to FabledCurator') expect(chipLabel(discord({ state: 'artist_match', artist: { name: 'A' } }), 'Discord')).toBe( '+ Add #drops to FabledCurator' ) }) it('says "this channel" when the token could not read the name', () => { const p = discord({ state: 'new' }) p.discord.channel_name = null expect(chipLabel(p, 'Discord')).toBe('+ Add this channel to FabledCurator') }) it('says whose source a Discord channel already is, and when the server covers it', () => { const artist = { name: 'Tamada', slug: 'tamada' } expect(chipLabel(discord({ state: 'source_match', artist, covered_by_server: false }), 'Discord')).toBe( '✓ In FabledCurator · Tamada' ) expect(chipLabel(discord({ state: 'source_match', artist, covered_by_server: true }), 'Discord')).toBe( '✓ Whole server in FabledCurator · Tamada' ) }) it('falls back to the generic add when the probe failed', () => { expect(chipState({ error: 'x' })).toBe('new') expect(chipLabel({ error: 'x' }, '')).toBe('+ Add to FabledCurator') expect(chipState({ state: 'source_match' })).toBe('source-match') }) }) describe('Add panel on Discord', () => { it('opens on the channel with the suggested artist preselected', () => { const d = panelDefaults(discord({ state: 'artist_match', artist: { id: 7, name: 'Tamada' } })) expect(d.scope).toBe('channel') expect(d.artist).toEqual({ id: 7, name: 'Tamada' }) expect(d.artistName).toBe('Tamada') }) it('proposes a new artist named after the server when nothing is suggested', () => { const d = panelDefaults(discord({ state: 'new' })) expect(d.artist).toBe(null) expect(d.artistName).toBe('Studio') }) it('sends a picked artist by id', () => { const choice = panelDefaults(discord({ state: 'artist_match', artist: { id: 7, name: 'Tamada' } })) expect(addRequest(choice)).toEqual({ url: 'https://discord.com/channels/111/222', artistId: 7 }) }) it('sends a typed name once the picked artist has been edited away', () => { const choice = panelDefaults(discord({ state: 'artist_match', artist: { id: 7, name: 'Tamada' } })) choice.artistName = 'Tamada Alt' expect(addRequest(choice)).toEqual({ url: 'https://discord.com/channels/111/222', artistName: 'Tamada Alt' }) }) it('adds the whole server when the operator picks it', () => { const choice = panelDefaults(discord({ state: 'new' })) choice.scope = 'server' expect(addRequest(choice).url).toBe('https://discord.com/channels/111') }) it('has nothing to send without an artist', () => { const choice = panelDefaults(discord({ state: 'new' })) choice.artistName = ' ' expect(addRequest(choice)).toBe(null) }) }) const { squashName, exactArtistMatch, inlineCompletion } = loadLib('chip.js', [ 'squashName', 'exactArtistMatch', 'inlineCompletion' ]) describe('artist matching for the Add panel', () => { const results = [ { id: 1, name: 'TamadaHeijun' }, { id: 2, name: 'Tamago' }, { id: 3, name: 'Sabu Art' } ] it('treats spacing, case and punctuation as the same name', () => { expect(squashName('Tamada Heijun')).toBe('tamadaheijun') expect(squashName('sabu_art!')).toBe('sabuart') expect(squashName('玉田 平順')).toBe('玉田平順') }) it('finds the result that is the query, spacing aside', () => { expect(exactArtistMatch('tamada heijun', results)).toEqual({ id: 1, name: 'TamadaHeijun' }) expect(exactArtistMatch('Tama', results)).toBe(null) expect(exactArtistMatch(' ', results)).toBe(null) }) it('autofills the first name that extends what was typed', () => { expect(inlineCompletion('tamad', results)).toEqual({ id: 1, name: 'TamadaHeijun' }) expect(inlineCompletion('Sab', results).name).toBe('Sabu Art') // Nothing to add once the name is complete, or when nothing extends it. expect(inlineCompletion('Sabu Art', results)).toBe(null) expect(inlineCompletion('heijun', results)).toBe(null) expect(inlineCompletion('', results)).toBe(null) }) }) describe('Add panel on Patreon and SubscribeStar', () => { const PAGE = 'https://www.patreon.com/cw/tamadaheijun' const patreon = (extra = {}) => ({ platform: 'patreon', slug: 'tamadaheijun', ...extra }) it('opens on the Patreon display name as a new artist', () => { const c = panelDefaults(patreon({ state: 'new', display_name: 'Tamada Heijun' }), PAGE) expect(c.scope).toBe('page') expect(c.artistName).toBe('Tamada Heijun') expect(addRequest(c)).toEqual({ url: PAGE, artistName: 'Tamada Heijun' }) }) it('leaves an untouched URL handle to the server to resolve', () => { const c = panelDefaults(patreon({ state: 'new' }), PAGE) expect(c.artistName).toBe('tamadaheijun') expect(addRequest(c)).toEqual({ url: PAGE }) c.artistName = 'Someone Else' expect(addRequest(c)).toEqual({ url: PAGE, artistName: 'Someone Else' }) }) it('offers the Patreon name when joining an artist known by another name', () => { const c = panelDefaults(patreon({ state: 'new', display_name: 'Tamada Heijun' }), PAGE) c.artist = { id: 4, name: 'tamada' } c.artistName = 'tamada' expect(renameOffer(c)).toEqual({ from: 'tamada', to: 'Tamada Heijun' }) expect(addRequest(c)).toEqual({ url: PAGE, artistId: 4, usePlatformName: true }) c.adoptPlatformName = false expect(addRequest(c)).toEqual({ url: PAGE, artistId: 4 }) }) it('offers no rename when the names agree or the name was not read', () => { const same = panelDefaults(patreon({ state: 'new', display_name: 'Tamada Heijun' }), PAGE) same.artist = { id: 4, name: 'Tamada Heijun' } expect(renameOffer(same)).toBe(null) const unread = panelDefaults(patreon({ state: 'new' }), PAGE) unread.artist = { id: 4, name: 'tamada' } expect(renameOffer(unread)).toBe(null) }) it('never renames from SubscribeStar or Discord — Patreon is the canon', () => { const ss = panelDefaults( { platform: 'subscribestar', slug: 'tamada', state: 'new', display_name: 'SS Tamada' }, 'https://subscribestar.adult/tamada' ) ss.artist = { id: 4, name: 'Tamada Heijun' } ss.artistName = 'Tamada Heijun' expect(renameOffer(ss)).toBe(null) expect(addRequest(ss)).toEqual({ url: 'https://subscribestar.adult/tamada', artistId: 4 }) }) it('preselects the artist the URL already names', () => { const c = panelDefaults(patreon({ state: 'artist_match', artist: { id: 9, name: 'Tamada' } }), PAGE) expect(c.artist).toEqual({ id: 9, name: 'Tamada' }) expect(c.artistName).toBe('Tamada') }) })