This commit is contained in:
Moon.eth
2026-07-29 19:37:17 +09:00
parent 4eb785b6ad
commit 8f0d47b850
10 changed files with 614 additions and 22 deletions
+58 -1
View File
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { ApiClient } from './client'
import { updateProfileFields } from './endpoints'
import { postStatus, updateProfileFields, votePoll } from './endpoints'
afterEach(() => {
vi.unstubAllGlobals()
@@ -38,3 +38,60 @@ describe('updateProfileFields', () => {
)
})
})
describe('poll endpoints', () => {
it('submits selected poll option indexes as JSON', async () => {
const fetchMock = vi.fn(async (_url: string, init?: RequestInit) => {
expect(init?.method).toBe('POST')
expect(JSON.parse(String(init?.body))).toEqual({ choices: [0, 2] })
return new Response(
JSON.stringify({
id: 'poll-1',
expired: false,
multiple: true,
votes_count: 2,
options: [],
emojis: [],
voted: true,
own_votes: [0, 2],
}),
{ status: 200, headers: { 'Content-Type': 'application/json' } },
)
})
vi.stubGlobal('fetch', fetchMock)
await votePoll(new ApiClient('example.test', 'token'), 'poll/one', [0, 2])
expect(fetchMock).toHaveBeenCalledWith(
'https://example.test/api/v1/polls/poll%2Fone/votes',
expect.any(Object),
)
})
it('includes a standard Mastodon/Pleroma poll in a new status', async () => {
const fetchMock = vi.fn(async (_url: string, init?: RequestInit) => {
expect(JSON.parse(String(init?.body))).toMatchObject({
status: 'Pick a snack',
poll: {
options: ['Cake', 'Fruit'],
expires_in: 3600,
multiple: false,
},
})
return new Response(JSON.stringify({ id: 'status-1' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
})
})
vi.stubGlobal('fetch', fetchMock)
await postStatus(new ApiClient('example.test', 'token'), {
status: 'Pick a snack',
poll: {
options: ['Cake', 'Fruit'],
expires_in: 3600,
multiple: false,
},
})
})
})
+11
View File
@@ -15,6 +15,7 @@ import type {
InstanceInfo,
MediaAttachment,
Notification,
Poll,
Relationship,
SearchResults,
Status,
@@ -229,6 +230,11 @@ export interface ComposeOptions {
sensitive?: boolean
media_ids?: string[]
language?: string
poll?: {
options: string[]
expires_in: number
multiple: boolean
}
}
export function postStatus(api: ApiClient, options: ComposeOptions): Promise<Status> {
@@ -242,6 +248,7 @@ export function postStatus(api: ApiClient, options: ComposeOptions): Promise<Sta
if (options.sensitive) body.sensitive = true
if (options.media_ids?.length) body.media_ids = options.media_ids
if (options.language) body.language = options.language
if (options.poll) body.poll = options.poll
return api.post<Status>('/api/v1/statuses', body)
}
@@ -259,6 +266,10 @@ export function reblogStatus(api: ApiClient, id: string, on: boolean): Promise<S
return api.post<Status>(`/api/v1/statuses/${encodeURIComponent(id)}/${action}`)
}
export function votePoll(api: ApiClient, id: string, choices: number[]): Promise<Poll> {
return api.post<Poll>(`/api/v1/polls/${encodeURIComponent(id)}/votes`, { choices })
}
export async function uploadMedia(api: ApiClient, file: File, description?: string): Promise<MediaAttachment> {
const form = new FormData()
form.set('file', file)
+6
View File
@@ -266,6 +266,12 @@ export interface InstanceInfo {
max_characters?: number
max_media_attachments?: number
}
polls?: {
max_options?: number
max_characters_per_option?: number
min_expiration?: number
max_expiration?: number
}
accounts?: {
max_profile_fields?: number
/** Pleroma v2 names. */