/**
* @vitest-environment happy-dom
*/
import React from 'react';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { act, render } from '@testing-library/react';
import { LoadingIndicator } from '../../../components/common/LoadingIndicator.js';
import { Window } from 'happy-dom';
const advanceTimersBy = async (ms: number) => {
await act(async () => {
await vi.advanceTimersByTimeAsync(ms);
});
};
beforeEach(() => {
vi.useFakeTimers();
const window = new Window();
globalThis.window = window as any;
globalThis.document = window.document as any;
});
afterEach(() => {
vi.clearAllTimers();
vi.useRealTimers();
});
describe('LoadingIndicator', () => {
const getSpinnerText = (container: HTMLElement) => {
return container.querySelector('ink-text')?.textContent ?? '';
};
const getMessageText = (container: HTMLElement) => {
const texts = container.querySelectorAll('ink-text');
return texts.length > 1 ? texts[1]?.textContent ?? '' : '';
};
it('does not render before the delay elapses', async () => {
const { container } = render(
);
expect(container.textContent).toBe('');
await advanceTimersBy(20);
expect(container.textContent).toBe('');
});
it('renders after the delay elapses', async () => {
const { container } = render(
);
await advanceTimersBy(30);
expect(getMessageText(container)).toContain('読み込み中');
});
it('stops rendering when loading becomes false', async () => {
const { container, rerender } = render(
);
await advanceTimersBy(10);
expect(getMessageText(container)).toContain('読み込み中');
await act(async () => {
rerender();
await vi.advanceTimersByTimeAsync(0);
});
expect(container.textContent).toBe('');
});
it('cycles through spinner frames over time', async () => {
const customFrames = ['.', '..', '...'];
const { container } = render(
);
await advanceTimersBy(0);
const firstFrame = getSpinnerText(container);
await advanceTimersBy(5);
const secondFrame = getSpinnerText(container);
await advanceTimersBy(5);
const thirdFrame = getSpinnerText(container);
expect(secondFrame).not.toEqual(firstFrame);
expect(thirdFrame).not.toEqual(secondFrame);
expect(customFrames).toContain(firstFrame ?? '');
expect(customFrames).toContain(secondFrame ?? '');
expect(customFrames).toContain(thirdFrame ?? '');
expect(getMessageText(container)).toContain('読み込み中');
});
it('keeps rendering even when only a single frame is provided', async () => {
const { container } = render(
);
await advanceTimersBy(0);
expect(getSpinnerText(container)).toBe('*');
await advanceTimersBy(30);
expect(getSpinnerText(container)).toBe('*');
expect(getMessageText(container)).toContain('読み込み中');
});
});