support flash

This commit is contained in:
Moon.eth
2026-08-03 15:28:51 +09:00
parent 1b14d94f6a
commit 7d16969f02
16 changed files with 599 additions and 9 deletions
@@ -0,0 +1,64 @@
import { fireEvent, render, waitFor } from '@testing-library/svelte'
import { describe, expect, it, vi } from 'vitest'
import type { MediaAttachment } from '$lib/api/types'
import type { RufflePlayerElement } from '$lib/ruffle'
import FlashAttachment from './FlashAttachment.svelte'
const media: MediaAttachment = {
id: 'flash-1',
type: 'unknown',
url: 'https://media.example.test/movie.swf',
preview_url: null,
description: 'A Flash movie',
meta: { original: { width: 640, height: 480 } },
}
describe('FlashAttachment', () => {
it('stays inert until clicked, loads securely through Ruffle, and can be stopped', async () => {
const load = vi.fn().mockResolvedValue(undefined)
const player = document.createElement('ruffle-player') as RufflePlayerElement
player.config = {}
player.ruffle = () => ({ load })
const createPlayer = vi.fn(() => player)
const loadRuffle = vi.fn().mockResolvedValue({
newest: () => ({ createPlayer }),
})
const view = render(FlashAttachment, { media, loadRuffle })
expect(loadRuffle).not.toHaveBeenCalled()
expect(view.getByText(/arbitrary code/i)).toBeInTheDocument()
await fireEvent.click(view.getByRole('button', { name: /Play Flash attachment/i }))
await waitFor(() => expect(load).toHaveBeenCalled())
expect(createPlayer).toHaveBeenCalledOnce()
expect(player.config).toMatchObject({
allowScriptAccess: false,
allowNetworking: 'internal',
openUrlMode: 'confirm',
})
expect(load).toHaveBeenCalledWith({
url: media.url,
autoplay: 'on',
letterbox: 'on',
allowScriptAccess: false,
allowNetworking: 'internal',
openUrlMode: 'confirm',
})
expect(view.container.querySelector('ruffle-player')).toBeInTheDocument()
await fireEvent.click(view.getByRole('button', { name: 'Stop Flash player' }))
expect(view.container.querySelector('ruffle-player')).not.toBeInTheDocument()
expect(view.getByRole('button', { name: /Play Flash attachment/i })).toBeInTheDocument()
})
it('shows a retry action after the runtime fails', async () => {
const loadRuffle = vi.fn().mockRejectedValue(new Error('no wasm'))
const view = render(FlashAttachment, { media, loadRuffle })
await fireEvent.click(view.getByRole('button', { name: /Play Flash attachment/i }))
expect(
await view.findByRole('button', { name: /could not be loaded.*retry/i }),
).toBeInTheDocument()
})
})