diff --git a/tests/reproxy/minecraft.test.cjs b/tests/reproxy/minecraft.test.cjs new file mode 100644 index 0000000..1442c86 --- /dev/null +++ b/tests/reproxy/minecraft.test.cjs @@ -0,0 +1,59 @@ +const assert = require('node:assert/strict'); +const { readFileSync } = require('node:fs'); +const { resolve } = require('node:path'); +const { test } = require('node:test'); +const { runInNewContext } = require('node:vm'); + +const root = resolve(__dirname, '../../'); +const source = readFileSync(resolve(root, 'reproxy/web/minecraft/app.js'), 'utf8'); + +async function renderStatus(response, error) { + const elements = Object.fromEntries(['server-status', 'build-status', 'build-download'].map(id => [id, {}])); + const requests = []; + let refresh; + const context = { + document: { getElementById: id => elements[id] }, + AbortSignal, + TextDecoder, + Uint8Array, + atob, + fetch: async (url, options) => { + requests.push({ url, options }); + if (url.endsWith('/readme')) { + return { ok: true, json: async () => ({ encoding: 'base64', content: Buffer.from('Актуальная версия — **1.2.3**: [Скачать 1.2.3](dist/minecraft-lab-neoforge-spike-1.2.3/minecraft-lab-neoforge-spike-1.2.3.mrpack)').toString('base64') }) }; + } + if (error) throw error; + return response; + }, + setInterval: (callback, delay) => { refresh = { callback, delay }; }, + }; + runInNewContext(source, context); + await new Promise(setImmediate); + assert.equal(elements['build-download'].hidden, false); + assert.match(elements['build-download'].href, /1\.2\.3\.mrpack$/); + assert.equal(refresh.delay, 300000); + await refresh.callback(); + assert.equal(requests.filter(request => request.url === '/minecraft/api/status').length, 2); + assert.ok(requests.every(request => request.options.signal instanceof AbortSignal)); + return elements['server-status'].textContent; +} + +for (const [name, data, expected] of [ + ['positive count', { online: true, players: { online: 7 } }, 'Игроков онлайн: 7'], + ['zero count', { online: true, players: { online: 0 } }, 'Игроков онлайн: 0'], + ['offline', { online: false }, 'Сервер недоступен'], + ...[null, {}, { online: true }, { online: true, players: { online: -1 } }, { online: true, players: { online: '2' } }].map(data => ['invalid response ' + JSON.stringify(data), data, 'Не удалось получить онлайн']), +]) { + test(name, async () => assert.equal(await renderStatus({ ok: true, json: async () => data }), expected)); +} + +test('HTTP failure', async () => assert.equal(await renderStatus({ ok: false }), 'Не удалось получить онлайн')); +test('invalid JSON', async () => assert.equal(await renderStatus({ ok: true, json: async () => { throw new SyntaxError(); } }), 'Не удалось получить онлайн')); +test('timeout', async () => assert.equal(await renderStatus(null, new DOMException('Timeout', 'TimeoutError')), 'Не удалось получить онлайн')); +test('network failure', async () => assert.equal(await renderStatus(null, new TypeError('Failed to fetch')), 'Не удалось получить онлайн')); + +test('Telemost link and initial status', () => { + const html = readFileSync(resolve(root, 'reproxy/web/minecraft/index.html'), 'utf8'); + assert.match(html, /href="https:\/\/telemost\.yandex\.ru\/j\/76726739040099\?skip_app=1" target="_blank" rel="noopener noreferrer"/); + assert.match(html, /id="server-status" role="status">Проверяем онлайн…/); +});