cleanup: wip 3.1

mostly misc cleanups
This commit is contained in:
Zephyr Lykos 2024-02-24 23:01:32 +08:00
parent af2c13a8b4
commit 9524a234cf
No known key found for this signature in database
GPG Key ID: D3E9D31E2F77F04D
99 changed files with 6631 additions and 6055 deletions

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
type AlertType = 'success' | 'info' | 'warning' | 'danger';

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
type Properties = {
readonly title?: string;

View File

@ -1,5 +1,6 @@
/** @jsxImportSource @emotion/react */
import React, {useState, useEffect} from 'react';
import type React from 'react';
import {useState, useEffect} from 'react';
import Autosuggest from 'react-autosuggest';
import {css} from '@emotion/react';
import {emit} from '@/scripts/event';

View File

@ -94,7 +94,7 @@ const Modal: React.FC<ModalOptions & Properties> = properties => {
$(reference.current!).modal('hide');
// The "hidden.bs.modal" event can't be trigged automatically when testing.
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') {
$(reference.current!).trigger('hidden.bs.modal');
}
@ -104,7 +104,6 @@ const Modal: React.FC<ModalOptions & Properties> = properties => {
properties.onDismiss?.();
$(reference.current!).modal('hide');
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') {
$(reference.current!).trigger('hidden.bs.modal');
}

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import ModalContent, {type Props as ContentProperties} from './ModalContent';
import ModalInput, {
type

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
export type Props = {
readonly text?: string;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
export type Props = {
readonly flexFooter?: boolean;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
export type Props = {
readonly title?: string;

View File

@ -1,4 +1,4 @@
import React, {type HTMLAttributes} from 'react';
import type React, {type HTMLAttributes} from 'react';
export type Props = {
readonly inputType?: string;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import PaginationItem from './PaginationItem';
import {t} from '@/scripts/i18n';

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
type Properties = {
readonly disabled?: boolean;

View File

@ -1,5 +1,6 @@
/** @jsxImportSource @emotion/react */
import React, {useState, useEffect} from 'react';
import type React from 'react';
import {useState, useEffect} from 'react';
import {css} from '@emotion/react';
export type ToastType = 'success' | 'info' | 'warning' | 'error';

View File

@ -1,5 +1,6 @@
/** @jsxImportSource @emotion/react */
import React, {useState, useEffect, useRef} from 'react';
import type React from 'react';
import {useState, useEffect, useRef} from 'react';
import {useMeasure} from 'react-use';
import {css} from '@emotion/react';
import styled from '@emotion/styled';

View File

@ -1,7 +1,6 @@
import type {Stdio} from 'blessing-skin-shell';
import * as event from '../event';
/* istanbul ignore next */
export function hackStdin() {
if (process.env.NODE_ENV === 'test') {
return process.stdin;
@ -24,7 +23,6 @@ export function hackStdin() {
} as NodeJS.ReadStream & {_off(): void};
}
/* istanbul ignore next */
export function hackStdout(stdio: Stdio) {
return {
write(message: string) {

View File

@ -1,6 +1,6 @@
export function getExtraData(): Record<string, any> {
const jsonElement = document.querySelector('#blessing-extra');
/* istanbul ignore next */
if (jsonElement) {
return JSON.parse(jsonElement.textContent ?? '{}');
}

View File

@ -14,7 +14,6 @@ export function scrollHander() {
}
}
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'test') {
const {transparent_navbar} = getExtraData() as {
transparent_navbar: boolean;

View File

@ -8,7 +8,6 @@ export function t(key: string, parameters: Record<string, string> = Object.creat
let result = '';
for (const segment of segments) {
/* istanbul ignore next */
const middle = temporary?.[segment];
if (!middle) {
return key;

View File

@ -18,5 +18,5 @@ export async function logout() {
}
const button = document.querySelector('#logout-button');
/* istanbul ignore next */
button?.addEventListener('click', logout);

View File

@ -3,7 +3,6 @@ import {Toast} from './toast';
export const toast = new Toast();
/* istanbul ignore next */
if (process.env.NODE_ENV === 'test') {
afterEach(() => {
toast.clear();

View File

@ -1,6 +1,5 @@
import {loadSkinToCanvas} from 'skinview-utils';
/* istanbul ignore next */
function checkPixel(
context: CanvasRenderingContext2D,
x: number,
@ -15,7 +14,6 @@ function checkPixel(
);
}
/* istanbul ignore next */
export async function isAlex(texture: string): Promise<boolean> {
return new Promise(resolve => {
const image = new Image();

View File

@ -54,7 +54,7 @@ export function ToastContainer() {
))}
</>
);
};
}
export class Toast {
private readonly container: HTMLDivElement;

View File

@ -38,7 +38,7 @@ export function registerNavbarPicker(
const navbar = document.querySelector<HTMLElement>('.wrapper > nav');
const picker = document.querySelector<HTMLDivElement>('#navbar-color-picker');
/* istanbul ignore next */
if (navbar && picker) {
registerNavbarPicker(navbar, picker, blessing.extra.navbar as string || 'white');
}
@ -73,7 +73,7 @@ const darkPicker = document.querySelector<HTMLDivElement>(
const lightPicker = document.querySelector<HTMLDivElement>(
'#sidebar-light-picker',
);
/* istanbul ignore next */
if (sidebar && darkPicker && lightPicker) {
registerSidebarPicker(
sidebar,

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import clsx from 'clsx';
import {Box} from './styles';
import {t} from '@/scripts/i18n';

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import {t} from '@/scripts/i18n';
import type {Player} from '@/scripts/types';
import ButtonEdit from '@/components/ButtonEdit';

View File

@ -1,5 +1,4 @@
import React, {useState, useEffect, useLayoutEffect} from 'react';
;
import {useImmer} from 'use-immer';
import Header from '../UsersManagement/Header';
import Card from './Card';
@ -272,6 +271,6 @@ function PlayersManagement() {
/>
</div>
);
};
}
export default PlayersManagement;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import styled from '@emotion/styled';
import clsx from 'clsx';
import type {Plugin} from './types';

View File

@ -1,5 +1,4 @@
import React, {useState, useEffect} from 'react';
;
import {useImmer} from 'use-immer';
import InfoBox from './InfoBox';
import type {Plugin} from './types';
@ -243,6 +242,6 @@ function PluginsManagement() {
</div>
</div>
);
};
}
export default PluginsManagement;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import type {Plugin} from './types';
import {t} from '@/scripts/i18n';

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import styled from '@emotion/styled';
import {type Report, Status} from './types';
import {t} from '@/scripts/i18n';

View File

@ -1,5 +1,4 @@
import React, {useState, useEffect} from 'react';
;
import {useImmer} from 'use-immer';
import type {Report, Status} from './types';
import ImageBox from './ImageBox';
@ -150,6 +149,6 @@ function ReportsManagement() {
</div>
</div>
);
};
}
export default ReportsManagement;

View File

@ -1,5 +1,5 @@
import styled from '@emotion/styled';
import React from 'react';
import type React from 'react';
import type {Line} from './types';
import {t} from '@/scripts/i18n';

View File

@ -1,5 +1,4 @@
import React, {useState, useEffect} from 'react';
;
import {useImmer} from 'use-immer';
import type {Line} from './types';
import Row from './Row';
@ -116,6 +115,6 @@ function Translations() {
</div>
</>
);
};
}
export default Translations;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import clsx from 'clsx';
import {Box, Icon, InfoTable} from './styles';
import {

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import {
humanizePermission,
verificationStatusText,

View File

@ -1,5 +1,4 @@
import React, {useState, useEffect, useLayoutEffect} from 'react';
;
import {useImmer} from 'use-immer';
import Header from './Header';
import Card from './Card';
@ -364,6 +363,6 @@ function UsersManagement() {
</div>
</div>
);
};
}
export default UsersManagement;

View File

@ -1,6 +1,5 @@
import React, {useState, useEffect} from 'react';
import {createPortal} from 'react-dom';
;
import Skeleton from 'react-loading-skeleton';
import addClosetItem from './addClosetItem';
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra';
@ -493,6 +492,6 @@ function Show() {
/>
</>
);
};
}
export default Show;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
type Properties = {
readonly active?: boolean;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import Button from './Button';
import type {Filter} from './types';
import {humanizeType} from './utils';

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import styled from '@emotion/styled';
import type {LibraryItem} from './types';
import {humanizeType} from './utils';

View File

@ -1,5 +1,4 @@
import React, {useState, useEffect} from 'react';
;
import addClosetItem from '../Show/addClosetItem';
import FilterSelector from './FilterSelector';
import Button from './Button';
@ -299,6 +298,6 @@ function SkinLibrary() {
</section>
</div>
);
};
}
export default SkinLibrary;

View File

@ -1,6 +1,5 @@
import React, {useState} from 'react';
import ReactDOM from 'react-dom';
;
import {t} from '@/scripts/i18n';
import useBlessingExtra from '@/scripts/hooks/useBlessingExtra';
import useEmitMounted from '@/scripts/hooks/useEmitMounted';
@ -255,6 +254,6 @@ function Upload() {
)}
</>
);
};
}
export default Upload;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import setAsAvatar from './setAsAvatar';
import {Card, DropdownButton} from './styles';
import {t} from '@/scripts/i18n';

View File

@ -49,7 +49,7 @@ function Closet() {
useEffect(() => {
const element = containerReference.current;
/* istanbul ignore next */
if (element) {
const {width} = element.getBoundingClientRect();
if (width >= 500) {

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import type {App} from './types';
import {t} from '@/scripts/i18n';
import ButtonEdit from '@/components/ButtonEdit';

View File

@ -1,5 +1,4 @@
import React, {useState, useEffect} from 'react';
;
import Row from './Row';
import ModalCreate from './ModalCreate';
import type {App} from './types';
@ -162,6 +161,6 @@ function OAuth() {
/>
</>
);
};
}
export default OAuth;

View File

@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import styled from '@emotion/styled';
import {t} from '@/scripts/i18n';

View File

@ -1,5 +1,4 @@
import React, {useState, useEffect} from 'react';
;
import Row from './Row';
import LoadingRow from './LoadingRow';
import Previewer from './Previewer';
@ -251,6 +250,6 @@ function Players() {
/>
</>
);
};
}
export default Players;

View File

@ -40,6 +40,6 @@ function EmailVerification() {
</p>
</div>
);
};
}
export default EmailVerification;

View File

@ -79,6 +79,6 @@ function NotificationsList() {
</div>
</>
);
};
}
export default NotificationsList;

View File

@ -1,66 +1,66 @@
import { expect, vi, it } from 'vitest';
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import Reaptcha from 'reaptcha'
import { t } from '@/scripts/i18n'
import Captcha from '@/components/Captcha'
import {expect, vi, it} from 'vitest';
import React from 'react';
import {render, fireEvent} from '@testing-library/react';
import Reaptcha from 'reaptcha';
import {t} from '@/scripts/i18n';
import Captcha from '@/components/Captcha';
describe('picture captcha', () => {
it('retrieve value', async () => {
const ref = React.createRef<Captcha>()
const { getByPlaceholderText } = render(<Captcha ref={ref} />)
it('retrieve value', async () => {
const reference = React.createRef<Captcha>();
const {getByPlaceholderText} = render(<Captcha ref={reference}/>);
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: { value: 'abc' },
})
expect(await ref.current?.execute()).toBe('abc')
})
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: {value: 'abc'},
});
expect(await reference.current?.execute()).toBe('abc');
});
it('refresh on click', () => {
const spy = vi.spyOn(Date, 'now')
it('refresh on click', () => {
const spy = vi.spyOn(Date, 'now');
const ref = React.createRef<Captcha>()
const { getByAltText } = render(<Captcha ref={ref} />)
const reference = React.createRef<Captcha>();
const {getByAltText} = render(<Captcha ref={reference}/>);
fireEvent.click(getByAltText(t('auth.captcha')))
expect(spy).toHaveBeenCalled()
})
fireEvent.click(getByAltText(t('auth.captcha')));
expect(spy).toHaveBeenCalled();
});
it('refresh programatically', () => {
const spy = vi.spyOn(Date, 'now')
it('refresh programatically', () => {
const spy = vi.spyOn(Date, 'now');
const ref = React.createRef<Captcha>()
render(<Captcha ref={ref} />)
const reference = React.createRef<Captcha>();
render(<Captcha ref={reference}/>);
ref.current?.reset()
expect(spy).toHaveBeenCalled()
})
})
reference.current?.reset();
expect(spy).toHaveBeenCalled();
});
});
describe('recaptcha', () => {
beforeEach(() => {
window.blessing.extra = { recaptcha: 'sitekey', invisible: false }
})
beforeEach(() => {
window.blessing.extra = {recaptcha: 'sitekey', invisible: false};
});
it('retrieve value', async () => {
window.blessing.extra.invisible = true
const spy = vi.spyOn(Reaptcha.prototype, 'execute')
it('retrieve value', async () => {
window.blessing.extra.invisible = true;
const spy = vi.spyOn(Reaptcha.prototype, 'execute');
const ref = React.createRef<Captcha>()
render(<Captcha ref={ref} />)
const reference = React.createRef<Captcha>();
render(<Captcha ref={reference}/>);
const value = await ref.current?.execute()
expect(spy).toHaveBeenCalled()
expect(value).toBe('token')
})
const value = await reference.current?.execute();
expect(spy).toHaveBeenCalled();
expect(value).toBe('token');
});
it('refresh programatically', () => {
const spy = vi.spyOn(Reaptcha.prototype, 'reset')
it('refresh programatically', () => {
const spy = vi.spyOn(Reaptcha.prototype, 'reset');
const ref = React.createRef<Captcha>()
render(<Captcha ref={ref} />)
const reference = React.createRef<Captcha>();
render(<Captcha ref={reference}/>);
ref.current?.reset()
expect(spy).toHaveBeenCalled()
})
})
reference.current?.reset();
expect(spy).toHaveBeenCalled();
});
});

View File

@ -1,22 +1,26 @@
import { expect, vi, test } from 'vitest';
import { render, fireEvent, waitFor } from '@testing-library/react'
import * as fetch from '@/scripts/net'
import DarkModeButton from '@/components/DarkModeButton'
import {expect, vi, test} from 'vitest';
import {render, fireEvent, waitFor} from '@testing-library/react';
import * as fetch from '@/scripts/net';
import DarkModeButton from '@/components/DarkModeButton';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
test('click to toggle', async () => {
const { getByRole } = render(<DarkModeButton initMode={false} />)
const button = getByRole('button')
const {getByRole} = render(<DarkModeButton initMode={false}/>);
const button = getByRole('button');
fireEvent.click(button)
await waitFor(() => expect(fetch.put).toBeCalledWith('/user/dark-mode'))
})
fireEvent.click(button);
await waitFor(() => {
expect(fetch.put).toBeCalledWith('/user/dark-mode');
});
});
test('default is dark', async () => {
const { getByRole } = render(<DarkModeButton initMode={true} />)
const button = getByRole('button')
const {getByRole} = render(<DarkModeButton initMode/>);
const button = getByRole('button');
fireEvent.click(button)
await waitFor(() => expect(fetch.put).toBeCalledWith('/user/dark-mode'))
})
fireEvent.click(button);
await waitFor(() => {
expect(fetch.put).toBeCalledWith('/user/dark-mode');
});
});

View File

@ -1,75 +1,75 @@
import { expect, test } from 'vitest'
import React, { useState } from 'react'
import { render, fireEvent } from '@testing-library/react'
import { on } from '@/scripts/event'
import EmailSuggestion from '@/components/EmailSuggestion'
import {expect, test} from 'vitest';
import React, {useState} from 'react';
import {render, fireEvent} from '@testing-library/react';
import {on} from '@/scripts/event';
import EmailSuggestion from '@/components/EmailSuggestion';
function Wrapper() {
const [email, setEmail] = useState('')
const [email, setEmail] = useState('');
return <EmailSuggestion value={email} onChange={setEmail} />
return <EmailSuggestion value={email} onChange={setEmail}/>;
}
test('basic typing', () => {
const { getByDisplayValue, queryByText } = render(<Wrapper />)
const input = getByDisplayValue('')
const {getByDisplayValue, queryByText} = render(<Wrapper/>);
const input = getByDisplayValue('');
fireEvent.input(input, { target: { value: 'abc' } })
fireEvent.focus(input)
expect(queryByText('abc@qq.com')).toBeInTheDocument()
expect(queryByText('abc@163.com')).toBeInTheDocument()
expect(queryByText('abc@gmail.com')).toBeInTheDocument()
expect(queryByText('abc@hotmail.com')).toBeInTheDocument()
fireEvent.input(input, {target: {value: 'abc'}});
fireEvent.focus(input);
expect(queryByText('abc@qq.com')).toBeInTheDocument();
expect(queryByText('abc@163.com')).toBeInTheDocument();
expect(queryByText('abc@gmail.com')).toBeInTheDocument();
expect(queryByText('abc@hotmail.com')).toBeInTheDocument();
fireEvent.input(input, { target: { value: '' } })
expect(queryByText('abc@qq.com')).not.toBeInTheDocument()
})
fireEvent.input(input, {target: {value: ''}});
expect(queryByText('abc@qq.com')).not.toBeInTheDocument();
});
test('apply suggestion', () => {
const { getByDisplayValue, getByText } = render(<Wrapper />)
const input = getByDisplayValue('')
const {getByDisplayValue, getByText} = render(<Wrapper/>);
const input = getByDisplayValue('');
fireEvent.input(input, { target: { value: 'abc' } })
fireEvent.focus(input)
fireEvent.click(getByText('abc@hotmail.com'))
expect(input).toHaveValue('abc@hotmail.com')
})
fireEvent.input(input, {target: {value: 'abc'}});
fireEvent.focus(input);
fireEvent.click(getByText('abc@hotmail.com'));
expect(input).toHaveValue('abc@hotmail.com');
});
test('do not suggest when `at` is existed', () => {
const { getByDisplayValue, queryByText } = render(<Wrapper />)
const input = getByDisplayValue('')
const {getByDisplayValue, queryByText} = render(<Wrapper/>);
const input = getByDisplayValue('');
fireEvent.input(input, { target: { value: 'abc@outlook.com' } })
fireEvent.focus(input)
expect(queryByText('abc@outlook.com@qq.com')).not.toBeInTheDocument()
expect(queryByText('abc@outlook.com@163.com')).not.toBeInTheDocument()
expect(queryByText('abc@outlook.com@gmail.com')).not.toBeInTheDocument()
expect(queryByText('abc@outlook.com@hotmail.com')).not.toBeInTheDocument()
})
fireEvent.input(input, {target: {value: 'abc@outlook.com'}});
fireEvent.focus(input);
expect(queryByText('abc@outlook.com@qq.com')).not.toBeInTheDocument();
expect(queryByText('abc@outlook.com@163.com')).not.toBeInTheDocument();
expect(queryByText('abc@outlook.com@gmail.com')).not.toBeInTheDocument();
expect(queryByText('abc@outlook.com@hotmail.com')).not.toBeInTheDocument();
});
test('display suggestions when typing with configured domain names', () => {
const { getByDisplayValue, queryByText } = render(<Wrapper />)
const input = getByDisplayValue('')
const {getByDisplayValue, queryByText} = render(<Wrapper/>);
const input = getByDisplayValue('');
fireEvent.input(input, { target: { value: 'abc@hotmail.com' } })
fireEvent.focus(input)
expect(queryByText('abc@qq.com')).toBeInTheDocument()
expect(queryByText('abc@163.com')).toBeInTheDocument()
expect(queryByText('abc@gmail.com')).toBeInTheDocument()
expect(queryByText('abc@hotmail.com')).toBeInTheDocument()
})
fireEvent.input(input, {target: {value: 'abc@hotmail.com'}});
fireEvent.focus(input);
expect(queryByText('abc@qq.com')).toBeInTheDocument();
expect(queryByText('abc@163.com')).toBeInTheDocument();
expect(queryByText('abc@gmail.com')).toBeInTheDocument();
expect(queryByText('abc@hotmail.com')).toBeInTheDocument();
});
test('events', () => {
const off = on('emailDomainsSuggestion', (names: Set<string>) => {
names.add('outlook.com')
})
const off = on('emailDomainsSuggestion', (names: Set<string>) => {
names.add('outlook.com');
});
const { getByDisplayValue, queryByText } = render(<Wrapper />)
const input = getByDisplayValue('')
const {getByDisplayValue, queryByText} = render(<Wrapper/>);
const input = getByDisplayValue('');
fireEvent.input(input, { target: { value: 'abc' } })
fireEvent.focus(input)
expect(queryByText('abc@outlook.com')).toBeInTheDocument()
fireEvent.input(input, {target: {value: 'abc'}});
fireEvent.focus(input);
expect(queryByText('abc@outlook.com')).toBeInTheDocument();
off()
})
off();
});

View File

@ -1,39 +1,39 @@
import { expect, test } from 'vitest'
import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import FileInput from '@/components/FileInput'
import {expect, test} from 'vitest';
import {render, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import FileInput from '@/components/FileInput';
test('click to select file', () => {
const { getAllByText } = render(
<FileInput
file={null}
onChange={() => {
/* */
}}
/>,
)
const {getAllByText} = render(
<FileInput
file={null}
onChange={() => {
/* */
}}
/>,
);
fireEvent.click(getAllByText(t('skinlib.upload.select-file'))[1]!)
})
fireEvent.click(getAllByText(t('skinlib.upload.select-file'))[1]);
});
test('display file name', () => {
const file = new File([], 'f.txt')
const { queryByText } = render(
<FileInput
file={file}
onChange={() => {
/* */
}}
/>,
)
expect(queryByText('f.txt')).toBeInTheDocument()
})
const file = new File([], 'f.txt');
const {queryByText} = render(
<FileInput
file={file}
onChange={() => {
/* */
}}
/>,
);
expect(queryByText('f.txt')).toBeInTheDocument();
});
test('input file', () => {
const mock = vi.fn()
const mock = vi.fn();
const { getByLabelText } = render(<FileInput file={null} onChange={mock} />)
fireEvent.change(getByLabelText(t('skinlib.upload.select-file')))
const {getByLabelText} = render(<FileInput file={null} onChange={mock}/>);
fireEvent.change(getByLabelText(t('skinlib.upload.select-file')));
expect(mock).toBeCalled()
})
expect(mock).toBeCalled();
});

View File

@ -1,289 +1,291 @@
import { expect, test, vi, it } from 'vitest'
import { render, fireEvent, act } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import $ from 'jquery'
import Modal from '@/components/Modal'
import {
expect, test, vi, it,
} from 'vitest';
import {render, fireEvent, act} from '@testing-library/react';
import $ from 'jquery';
import {t} from '@/scripts/i18n';
import Modal from '@/components/Modal';
test('hidden by default', () => {
const { queryByRole } = render(<Modal />)
expect(queryByRole('dialog')).toBeNull()
})
const {queryByRole} = render(<Modal/>);
expect(queryByRole('dialog')).toBeNull();
});
test('receive id', () => {
const { getByRole } = render(<Modal id="kumiko" show />)
expect(getByRole('dialog')).toHaveAttribute('id', 'kumiko')
})
const {getByRole} = render(<Modal show id='kumiko'/>);
expect(getByRole('dialog')).toHaveAttribute('id', 'kumiko');
});
test('centered dialog', () => {
const { getByRole } = render(<Modal center show />)
expect(getByRole('document')).toHaveClass('modal-dialog-centered')
})
const {getByRole} = render(<Modal center show/>);
expect(getByRole('document')).toHaveClass('modal-dialog-centered');
});
test('background color', () => {
const { container } = render(<Modal type="primary" show />)
expect(container.querySelector('.modal-content')).toHaveClass('bg-primary')
})
const {container} = render(<Modal show type='primary'/>);
expect(container.querySelector('.modal-content')).toHaveClass('bg-primary');
});
test('jQuery events', () => {
const { getByText } = render(<Modal mode="confirm" show />)
act(() => {
vi.runAllTimers()
$('.modal').trigger('hidden.bs.modal')
})
const {getByText} = render(<Modal show mode='confirm'/>);
act(() => {
vi.runAllTimers();
$('.modal').trigger('hidden.bs.modal');
});
fireEvent.click(getByText(t('general.cancel')))
act(() => {
vi.runAllTimers()
$('.modal').trigger('hidden.bs.modal')
})
})
fireEvent.click(getByText(t('general.cancel')));
act(() => {
vi.runAllTimers();
$('.modal').trigger('hidden.bs.modal');
});
});
describe('modal header', () => {
it('modal title', () => {
const { queryByText } = render(<Modal title="Tips" show />)
expect(queryByText('Tips')).toBeInTheDocument()
})
it('modal title', () => {
const {queryByText} = render(<Modal show title='Tips'/>);
expect(queryByText('Tips')).toBeInTheDocument();
});
it('hide modal header', () => {
const { queryByText } = render(
<Modal title="Tips" showHeader={false} show />,
)
expect(queryByText('Tips')).not.toBeInTheDocument()
})
})
it('hide modal header', () => {
const {queryByText} = render(
<Modal show title='Tips' showHeader={false}/>,
);
expect(queryByText('Tips')).not.toBeInTheDocument();
});
});
describe('modal body', () => {
it('custom children', () => {
const { queryByText } = render(<Modal show>body</Modal>)
expect(queryByText('body')).toBeInTheDocument()
})
it('custom children', () => {
const {queryByText} = render(<Modal show>body</Modal>);
expect(queryByText('body')).toBeInTheDocument();
});
it('text with linebreaks', () => {
const { queryByText } = render(<Modal text={'L1\nL2'} show />)
expect(queryByText('L1')).toBeInTheDocument()
expect(queryByText('L2')).toBeInTheDocument()
})
it('text with linebreaks', () => {
const {queryByText} = render(<Modal show text={'L1\nL2'}/>);
expect(queryByText('L1')).toBeInTheDocument();
expect(queryByText('L2')).toBeInTheDocument();
});
it('dangerous HTML', () => {
const { getByText } = render(
<Modal dangerousHTML="<h1 class='h1'>ab</h1>" show />,
)
expect(getByText('ab')).toHaveClass('h1')
})
it('dangerous HTML', () => {
const {getByText} = render(
<Modal show dangerousHTML="<h1 class='h1'>ab</h1>"/>,
);
expect(getByText('ab')).toHaveClass('h1');
});
describe('input control', () => {
it('set default value', () => {
const { queryByDisplayValue } = render(
<Modal mode="prompt" input="val" show />,
)
expect(queryByDisplayValue('val')).toBeInTheDocument()
})
describe('input control', () => {
it('set default value', () => {
const {queryByDisplayValue} = render(
<Modal show mode='prompt' input='val'/>,
);
expect(queryByDisplayValue('val')).toBeInTheDocument();
});
it('placeholder', () => {
const { queryByPlaceholderText } = render(
<Modal mode="prompt" placeholder="hint" show />,
)
expect(queryByPlaceholderText('hint')).toBeInTheDocument()
})
it('placeholder', () => {
const {queryByPlaceholderText} = render(
<Modal show mode='prompt' placeholder='hint'/>,
);
expect(queryByPlaceholderText('hint')).toBeInTheDocument();
});
it('input control type', () => {
const { getByPlaceholderText } = render(
<Modal
mode="prompt"
placeholder="password"
inputType="password"
show
/>,
)
expect(getByPlaceholderText('password')).toHaveAttribute(
'type',
'password',
)
})
})
})
it('input control type', () => {
const {getByPlaceholderText} = render(
<Modal
show
mode='prompt'
placeholder='password'
inputType='password'
/>,
);
expect(getByPlaceholderText('password')).toHaveAttribute(
'type',
'password',
);
});
});
});
describe('modal footer', () => {
it('custom footer content', () => {
const { queryByText } = render(<Modal footer={<div>footer</div>} show />)
expect(queryByText('footer')).toBeInTheDocument()
expect(queryByText(t('general.confirm'))).not.toBeInTheDocument()
})
it('custom footer content', () => {
const {queryByText} = render(<Modal show footer={<div>footer</div>}/>);
expect(queryByText('footer')).toBeInTheDocument();
expect(queryByText(t('general.confirm'))).not.toBeInTheDocument();
});
it('flex footer', () => {
const { getByText } = render(<Modal footer="footer" flexFooter show />)
expect(getByText('footer')).toHaveClass('d-flex', 'justify-content-between')
})
it('flex footer', () => {
const {getByText} = render(<Modal flexFooter show footer='footer'/>);
expect(getByText('footer')).toHaveClass('d-flex', 'justify-content-between');
});
it('custom ok button', () => {
const { getByText } = render(
<Modal okButtonType="primary" okButtonText="kumiko" show />,
)
expect(getByText('kumiko')).toHaveClass('btn-primary')
})
it('custom ok button', () => {
const {getByText} = render(
<Modal show okButtonType='primary' okButtonText='kumiko'/>,
);
expect(getByText('kumiko')).toHaveClass('btn-primary');
});
it('custom cancel button', () => {
const { getByText } = render(
<Modal cancelButtonType="success" cancelButtonText="reina" show />,
)
expect(getByText('reina')).toHaveClass('btn-success')
})
})
it('custom cancel button', () => {
const {getByText} = render(
<Modal show cancelButtonType='success' cancelButtonText='reina'/>,
);
expect(getByText('reina')).toHaveClass('btn-success');
});
});
describe('"alert" mode', () => {
it('buttons', () => {
const resolve = vi.fn()
const { getByText, queryByText } = render(
<Modal mode="alert" onConfirm={resolve} show />,
)
fireEvent.click(getByText(t('general.confirm')))
expect(resolve).toBeCalledWith({ value: '' })
expect(queryByText(t('general.cancel'))).toBeNull()
})
it('buttons', () => {
const resolve = vi.fn();
const {getByText, queryByText} = render(
<Modal show mode='alert' onConfirm={resolve}/>,
);
fireEvent.click(getByText(t('general.confirm')));
expect(resolve).toBeCalledWith({value: ''});
expect(queryByText(t('general.cancel'))).toBeNull();
});
it('confirm callback is optional', () => {
const { getByText } = render(<Modal mode="alert" show />)
fireEvent.click(getByText(t('general.confirm')))
})
})
it('confirm callback is optional', () => {
const {getByText} = render(<Modal show mode='alert'/>);
fireEvent.click(getByText(t('general.confirm')));
});
});
describe('"confirm" mode', () => {
it('default mode is "confirm"', () => {
const { queryByText } = render(<Modal show />)
expect(queryByText(t('general.confirm'))).toBeInTheDocument()
expect(queryByText(t('general.cancel'))).toBeInTheDocument()
})
it('default mode is "confirm"', () => {
const {queryByText} = render(<Modal show/>);
expect(queryByText(t('general.confirm'))).toBeInTheDocument();
expect(queryByText(t('general.cancel'))).toBeInTheDocument();
});
it('"confirm" button', () => {
const resolve = vi.fn()
const reject = vi.fn()
const { getByText } = render(
<Modal mode="prompt" onConfirm={resolve} onDismiss={reject} show />,
)
fireEvent.click(getByText(t('general.confirm')))
expect(resolve).toBeCalledWith({ value: '' })
expect(reject).not.toBeCalled()
})
it('"confirm" button', () => {
const resolve = vi.fn();
const reject = vi.fn();
const {getByText} = render(
<Modal show mode='prompt' onConfirm={resolve} onDismiss={reject}/>,
);
fireEvent.click(getByText(t('general.confirm')));
expect(resolve).toBeCalledWith({value: ''});
expect(reject).not.toBeCalled();
});
it('"cancel" button', () => {
const resolve = vi.fn()
const reject = vi.fn()
const { getByText } = render(
<Modal mode="prompt" onConfirm={resolve} onDismiss={reject} show />,
)
fireEvent.click(getByText(t('general.cancel')))
expect(resolve).not.toBeCalled()
expect(reject).toBeCalled()
})
})
it('"cancel" button', () => {
const resolve = vi.fn();
const reject = vi.fn();
const {getByText} = render(
<Modal show mode='prompt' onConfirm={resolve} onDismiss={reject}/>,
);
fireEvent.click(getByText(t('general.cancel')));
expect(resolve).not.toBeCalled();
expect(reject).toBeCalled();
});
});
describe('"prompt" mode', () => {
it('retrieve input value', () => {
const resolve = vi.fn()
const reject = vi.fn()
const { getByPlaceholderText, getByText } = render(
<Modal
mode="prompt"
placeholder="hint"
onConfirm={resolve}
onDismiss={reject}
show
/>,
)
fireEvent.change(getByPlaceholderText('hint'), {
target: { value: 'my' },
})
fireEvent.click(getByText(t('general.confirm')))
expect(resolve).toBeCalledWith({ value: 'my' })
expect(reject).not.toBeCalled()
})
it('retrieve input value', () => {
const resolve = vi.fn();
const reject = vi.fn();
const {getByPlaceholderText, getByText} = render(
<Modal
show
mode='prompt'
placeholder='hint'
onConfirm={resolve}
onDismiss={reject}
/>,
);
fireEvent.change(getByPlaceholderText('hint'), {
target: {value: 'my'},
});
fireEvent.click(getByText(t('general.confirm')));
expect(resolve).toBeCalledWith({value: 'my'});
expect(reject).not.toBeCalled();
});
it('cancel dialog', () => {
const resolve = vi.fn()
const reject = vi.fn()
const { getByText } = render(
<Modal mode="prompt" onConfirm={resolve} onDismiss={reject} show />,
)
fireEvent.click(getByText(t('general.cancel')))
expect(resolve).not.toBeCalled()
expect(reject).toBeCalled()
})
it('cancel dialog', () => {
const resolve = vi.fn();
const reject = vi.fn();
const {getByText} = render(
<Modal show mode='prompt' onConfirm={resolve} onDismiss={reject}/>,
);
fireEvent.click(getByText(t('general.cancel')));
expect(resolve).not.toBeCalled();
expect(reject).toBeCalled();
});
it('radio inputs', () => {
const choices = [
{ text: 'A', value: 'a' },
{ text: 'B', value: 'b' },
]
const resolve = vi.fn()
const { getByText, getByLabelText } = render(
<Modal
mode="prompt"
inputType="radios"
choices={choices}
onConfirm={resolve}
show
/>,
)
fireEvent.click(getByLabelText('B'))
fireEvent.click(getByText(t('general.confirm')))
expect(resolve).toBeCalledWith({ value: 'b' })
})
it('radio inputs', () => {
const choices = [
{text: 'A', value: 'a'},
{text: 'B', value: 'b'},
];
const resolve = vi.fn();
const {getByText, getByLabelText} = render(
<Modal
show
mode='prompt'
inputType='radios'
choices={choices}
onConfirm={resolve}
/>,
);
fireEvent.click(getByLabelText('B'));
fireEvent.click(getByText(t('general.confirm')));
expect(resolve).toBeCalledWith({value: 'b'});
});
it('validate input', () => {
const resolve = vi.fn()
const reject = vi.fn()
const validator = vi.fn().mockReturnValue(true)
const { getByText } = render(
<Modal
mode="prompt"
input="val"
validator={validator}
onConfirm={resolve}
onDismiss={reject}
show
/>,
)
fireEvent.click(getByText(t('general.confirm')))
expect(resolve).toBeCalledWith({ value: 'val' })
expect(reject).not.toBeCalled()
})
it('validate input', () => {
const resolve = vi.fn();
const reject = vi.fn();
const validator = vi.fn().mockReturnValue(true);
const {getByText} = render(
<Modal
show
mode='prompt'
input='val'
validator={validator}
onConfirm={resolve}
onDismiss={reject}
/>,
);
fireEvent.click(getByText(t('general.confirm')));
expect(resolve).toBeCalledWith({value: 'val'});
expect(reject).not.toBeCalled();
});
it('report validator message', () => {
const message = 'Invalid input.'
const resolve = vi.fn()
const reject = vi.fn()
const validator = vi.fn().mockReturnValue(message)
const { getByText, queryByText } = render(
<Modal
mode="prompt"
input="val"
validator={validator}
onConfirm={resolve}
onDismiss={reject}
show
/>,
)
expect(queryByText(message)).not.toBeInTheDocument()
it('report validator message', () => {
const message = 'Invalid input.';
const resolve = vi.fn();
const reject = vi.fn();
const validator = vi.fn().mockReturnValue(message);
const {getByText, queryByText} = render(
<Modal
show
mode='prompt'
input='val'
validator={validator}
onConfirm={resolve}
onDismiss={reject}
/>,
);
expect(queryByText(message)).not.toBeInTheDocument();
fireEvent.click(getByText(t('general.confirm')))
expect(queryByText(message)).toBeInTheDocument()
expect(resolve).not.toBeCalled()
expect(reject).not.toBeCalled()
})
})
fireEvent.click(getByText(t('general.confirm')));
expect(queryByText(message)).toBeInTheDocument();
expect(resolve).not.toBeCalled();
expect(reject).not.toBeCalled();
});
});
describe('"onClose" event', () => {
it('button confirm', () => {
const mock = vi.fn()
const { getByText } = render(<Modal show mode="confirm" onClose={mock} />)
fireEvent.click(getByText(t('general.confirm')))
expect(mock).toBeCalled()
})
it('button confirm', () => {
const mock = vi.fn();
const {getByText} = render(<Modal show mode='confirm' onClose={mock}/>);
fireEvent.click(getByText(t('general.confirm')));
expect(mock).toBeCalled();
});
it('button cancel', () => {
const mock = vi.fn()
const { getByText } = render(<Modal show mode="confirm" onClose={mock} />)
fireEvent.click(getByText(t('general.cancel')))
expect(mock).toBeCalled()
})
})
it('button cancel', () => {
const mock = vi.fn();
const {getByText} = render(<Modal show mode='confirm' onClose={mock}/>);
fireEvent.click(getByText(t('general.cancel')));
expect(mock).toBeCalled();
});
});

View File

@ -1,153 +1,155 @@
import { expect, test, it, jest } from 'vitest'
import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import Pagination from '@/components/Pagination'
import {
expect, test, it, jest,
} from 'vitest';
import {render, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import Pagination from '@/components/Pagination';
test('hide when total pages is invalid', () => {
const { queryByText } = render(
<Pagination page={1} totalPages={0} onChange={() => {}} />,
)
expect(queryByText(t('vendor.datatable.prev'))).not.toBeInTheDocument()
expect(queryByText(t('vendor.datatable.next'))).not.toBeInTheDocument()
})
const {queryByText} = render(
<Pagination page={1} totalPages={0} onChange={() => {}}/>,
);
expect(queryByText(t('vendor.datatable.prev'))).not.toBeInTheDocument();
expect(queryByText(t('vendor.datatable.next'))).not.toBeInTheDocument();
});
describe('previous page', () => {
it('enabled', () => {
const mock = vi.fn(() => {})
const { getByText } = render(
<Pagination page={3} totalPages={5} onChange={mock} />,
)
fireEvent.click(getByText(t('vendor.datatable.prev')))
expect(mock).toBeCalledWith(2)
})
it('enabled', () => {
const mock = vi.fn(() => {});
const {getByText} = render(
<Pagination page={3} totalPages={5} onChange={mock}/>,
);
fireEvent.click(getByText(t('vendor.datatable.prev')));
expect(mock).toBeCalledWith(2);
});
it('disabled', () => {
const mock = vi.fn(() => {})
const { getByText } = render(
<Pagination page={1} totalPages={5} onChange={mock} />,
)
fireEvent.click(getByText(t('vendor.datatable.prev')))
expect(mock).not.toBeCalled()
})
})
it('disabled', () => {
const mock = vi.fn(() => {});
const {getByText} = render(
<Pagination page={1} totalPages={5} onChange={mock}/>,
);
fireEvent.click(getByText(t('vendor.datatable.prev')));
expect(mock).not.toBeCalled();
});
});
describe('next page', () => {
it('enabled', () => {
const mock = vi.fn(() => {})
const { getByText } = render(
<Pagination page={3} totalPages={5} onChange={mock} />,
)
fireEvent.click(getByText(t('vendor.datatable.next')))
expect(mock).toBeCalledWith(4)
})
it('enabled', () => {
const mock = vi.fn(() => {});
const {getByText} = render(
<Pagination page={3} totalPages={5} onChange={mock}/>,
);
fireEvent.click(getByText(t('vendor.datatable.next')));
expect(mock).toBeCalledWith(4);
});
it('disabled', () => {
const mock = vi.fn(() => {})
const { getByText } = render(
<Pagination page={5} totalPages={5} onChange={mock} />,
)
fireEvent.click(getByText(t('vendor.datatable.next')))
expect(mock).not.toBeCalled()
})
})
it('disabled', () => {
const mock = vi.fn(() => {});
const {getByText} = render(
<Pagination page={5} totalPages={5} onChange={mock}/>,
);
fireEvent.click(getByText(t('vendor.datatable.next')));
expect(mock).not.toBeCalled();
});
});
describe('middle pages', () => {
it('pages count less than 8', () => {
const mock = vi.fn(() => {})
const { getByText } = render(
<Pagination page={1} totalPages={7} onChange={mock} />,
)
it('pages count less than 8', () => {
const mock = vi.fn(() => {});
const {getByText} = render(
<Pagination page={1} totalPages={7} onChange={mock}/>,
);
fireEvent.click(getByText('1'))
expect(mock).toBeCalledWith(1)
fireEvent.click(getByText('1'));
expect(mock).toBeCalledWith(1);
fireEvent.click(getByText('2'))
expect(mock).toBeCalledWith(2)
fireEvent.click(getByText('2'));
expect(mock).toBeCalledWith(2);
fireEvent.click(getByText('3'))
expect(mock).toBeCalledWith(3)
fireEvent.click(getByText('3'));
expect(mock).toBeCalledWith(3);
fireEvent.click(getByText('4'))
expect(mock).toBeCalledWith(4)
fireEvent.click(getByText('4'));
expect(mock).toBeCalledWith(4);
fireEvent.click(getByText('5'))
expect(mock).toBeCalledWith(5)
fireEvent.click(getByText('5'));
expect(mock).toBeCalledWith(5);
fireEvent.click(getByText('6'))
expect(mock).toBeCalledWith(6)
fireEvent.click(getByText('6'));
expect(mock).toBeCalledWith(6);
fireEvent.click(getByText('7'))
expect(mock).toBeCalledWith(7)
})
fireEvent.click(getByText('7'));
expect(mock).toBeCalledWith(7);
});
describe('pages count greater than or equals to 8', () => {
it('left edge', () => {
const mock = vi.fn(() => {})
const { getByText, queryByText } = render(
<Pagination page={2} totalPages={10} onChange={mock} />,
)
describe('pages count greater than or equals to 8', () => {
it('left edge', () => {
const mock = vi.fn(() => {});
const {getByText, queryByText} = render(
<Pagination page={2} totalPages={10} onChange={mock}/>,
);
fireEvent.click(getByText('1'))
expect(mock).toBeCalledWith(1)
expect(queryByText('1')).toBeInTheDocument()
expect(queryByText('2')).toBeInTheDocument()
expect(queryByText('3')).toBeInTheDocument()
expect(queryByText('...')).toBeInTheDocument()
expect(queryByText('10')).toBeInTheDocument()
fireEvent.click(getByText('1'));
expect(mock).toBeCalledWith(1);
expect(queryByText('1')).toBeInTheDocument();
expect(queryByText('2')).toBeInTheDocument();
expect(queryByText('3')).toBeInTheDocument();
expect(queryByText('...')).toBeInTheDocument();
expect(queryByText('10')).toBeInTheDocument();
fireEvent.click(getByText('2'))
expect(mock).toBeCalledWith(2)
expect(queryByText('1')).toBeInTheDocument()
expect(queryByText('2')).toBeInTheDocument()
expect(queryByText('3')).toBeInTheDocument()
expect(queryByText('...')).toBeInTheDocument()
expect(queryByText('10')).toBeInTheDocument()
})
fireEvent.click(getByText('2'));
expect(mock).toBeCalledWith(2);
expect(queryByText('1')).toBeInTheDocument();
expect(queryByText('2')).toBeInTheDocument();
expect(queryByText('3')).toBeInTheDocument();
expect(queryByText('...')).toBeInTheDocument();
expect(queryByText('10')).toBeInTheDocument();
});
it('right edge', () => {
const mock = vi.fn(() => {})
const { getByText, queryByText } = render(
<Pagination page={9} totalPages={10} onChange={mock} />,
)
it('right edge', () => {
const mock = vi.fn(() => {});
const {getByText, queryByText} = render(
<Pagination page={9} totalPages={10} onChange={mock}/>,
);
fireEvent.click(getByText('10'))
expect(mock).toBeCalledWith(10)
expect(queryByText('1')).toBeInTheDocument()
expect(queryByText('...')).toBeInTheDocument()
expect(queryByText('8')).toBeInTheDocument()
expect(queryByText('9')).toBeInTheDocument()
expect(queryByText('10')).toBeInTheDocument()
fireEvent.click(getByText('10'));
expect(mock).toBeCalledWith(10);
expect(queryByText('1')).toBeInTheDocument();
expect(queryByText('...')).toBeInTheDocument();
expect(queryByText('8')).toBeInTheDocument();
expect(queryByText('9')).toBeInTheDocument();
expect(queryByText('10')).toBeInTheDocument();
fireEvent.click(getByText('9'))
expect(mock).toBeCalledWith(9)
expect(queryByText('1')).toBeInTheDocument()
expect(queryByText('...')).toBeInTheDocument()
expect(queryByText('8')).toBeInTheDocument()
expect(queryByText('9')).toBeInTheDocument()
expect(queryByText('10')).toBeInTheDocument()
})
fireEvent.click(getByText('9'));
expect(mock).toBeCalledWith(9);
expect(queryByText('1')).toBeInTheDocument();
expect(queryByText('...')).toBeInTheDocument();
expect(queryByText('8')).toBeInTheDocument();
expect(queryByText('9')).toBeInTheDocument();
expect(queryByText('10')).toBeInTheDocument();
});
it('middle', () => {
const mock = vi.fn(() => {})
const { getByText, queryByText, queryAllByText } = render(
<Pagination page={4} totalPages={10} onChange={mock} />,
)
it('middle', () => {
const mock = vi.fn(() => {});
const {getByText, queryByText, queryAllByText} = render(
<Pagination page={4} totalPages={10} onChange={mock}/>,
);
expect(queryByText('1')).toBeInTheDocument()
expect(queryAllByText('...')).toHaveLength(2)
expect(queryByText('3')).toBeInTheDocument()
expect(queryByText('4')).toBeInTheDocument()
expect(queryByText('5')).toBeInTheDocument()
expect(queryByText('10')).toBeInTheDocument()
expect(queryByText('1')).toBeInTheDocument();
expect(queryAllByText('...')).toHaveLength(2);
expect(queryByText('3')).toBeInTheDocument();
expect(queryByText('4')).toBeInTheDocument();
expect(queryByText('5')).toBeInTheDocument();
expect(queryByText('10')).toBeInTheDocument();
fireEvent.click(getByText('5'))
expect(mock).toBeCalledWith(5)
fireEvent.click(getByText('5'));
expect(mock).toBeCalledWith(5);
fireEvent.click(getByText('1'))
expect(mock).toBeCalledWith(1)
fireEvent.click(getByText('1'));
expect(mock).toBeCalledWith(1);
fireEvent.click(getByText('10'))
expect(mock).toBeCalledWith(10)
})
})
})
fireEvent.click(getByText('10'));
expect(mock).toBeCalledWith(10);
});
});
});

View File

@ -1,115 +1,115 @@
import { expect, test, it } from 'vitest'
import { render, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import Viewer, { PICTURES_COUNT } from '@/components/Viewer'
import {expect, test, it} from 'vitest';
import {render, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import Viewer, {PICTURES_COUNT} from '@/components/Viewer';
test('custom footer', () => {
const { queryByText } = render(<Viewer isAlex={false}>footer</Viewer>)
expect(queryByText('footer')).toBeInTheDocument()
})
const {queryByText} = render(<Viewer isAlex={false}>footer</Viewer>);
expect(queryByText('footer')).toBeInTheDocument();
});
describe('indicator', () => {
it('hidden by default', () => {
const { queryByText } = render(<Viewer skin="skin" isAlex={false} />)
expect(queryByText(t('general.skin'))).not.toBeInTheDocument()
})
it('hidden by default', () => {
const {queryByText} = render(<Viewer skin='skin' isAlex={false}/>);
expect(queryByText(t('general.skin'))).not.toBeInTheDocument();
});
it('nothing', () => {
const { queryByText } = render(<Viewer isAlex={true} showIndicator />)
expect(queryByText(t('general.skin'))).not.toBeInTheDocument()
expect(queryByText(t('general.cape'))).not.toBeInTheDocument()
})
it('nothing', () => {
const {queryByText} = render(<Viewer showIndicator isAlex/>);
expect(queryByText(t('general.skin'))).not.toBeInTheDocument();
expect(queryByText(t('general.cape'))).not.toBeInTheDocument();
});
it('skin only', () => {
const { queryByText } = render(
<Viewer skin="skin" isAlex={false} showIndicator />,
)
expect(queryByText(t('general.skin'))).toBeInTheDocument()
expect(queryByText(t('general.cape'))).not.toBeInTheDocument()
})
it('skin only', () => {
const {queryByText} = render(
<Viewer showIndicator skin='skin' isAlex={false}/>,
);
expect(queryByText(t('general.skin'))).toBeInTheDocument();
expect(queryByText(t('general.cape'))).not.toBeInTheDocument();
});
it('cape only', () => {
const { queryByText } = render(
<Viewer cape="cape" isAlex={false} showIndicator />,
)
expect(queryByText(t('general.skin'))).not.toBeInTheDocument()
expect(queryByText(t('general.cape'))).toBeInTheDocument()
})
it('cape only', () => {
const {queryByText} = render(
<Viewer showIndicator cape='cape' isAlex={false}/>,
);
expect(queryByText(t('general.skin'))).not.toBeInTheDocument();
expect(queryByText(t('general.cape'))).toBeInTheDocument();
});
it('skin and cape', () => {
const { queryByText } = render(
<Viewer skin="skin" cape="cape" isAlex={false} showIndicator />,
)
expect(
queryByText(`${t('general.skin')} & ${t('general.cape')}`),
).toBeInTheDocument()
expect(queryByText(t('general.skin'))).not.toBeInTheDocument()
expect(queryByText(t('general.cape'))).not.toBeInTheDocument()
})
})
it('skin and cape', () => {
const {queryByText} = render(
<Viewer showIndicator skin='skin' cape='cape' isAlex={false}/>,
);
expect(
queryByText(`${t('general.skin')} & ${t('general.cape')}`),
).toBeInTheDocument();
expect(queryByText(t('general.skin'))).not.toBeInTheDocument();
expect(queryByText(t('general.cape'))).not.toBeInTheDocument();
});
});
describe('actions', () => {
it('toggle animation', () => {
const component = <Viewer isAlex={false} />
const { getByTitle } = render(component)
fireEvent.click(getByTitle(`${t('general.switchAnimation')}`)) // should start running
fireEvent.click(getByTitle(`${t('general.switchAnimation')}`)) // should start flying
fireEvent.click(getByTitle(`${t('general.switchAnimation')}`)) // should be idle
fireEvent.click(getByTitle(`${t('general.switchAnimation')}`)) // should start walking
})
it('toggle animation', () => {
const component = <Viewer isAlex={false}/>;
const {getByTitle} = render(component);
fireEvent.click(getByTitle(`${t('general.switchAnimation')}`)); // Should start running
fireEvent.click(getByTitle(`${t('general.switchAnimation')}`)); // Should start flying
fireEvent.click(getByTitle(`${t('general.switchAnimation')}`)); // Should be idle
fireEvent.click(getByTitle(`${t('general.switchAnimation')}`)); // Should start walking
});
it('toggle rotation', () => {
const { getByTitle } = render(<Viewer isAlex={false} />)
fireEvent.click(getByTitle(t('general.rotation'))) // should stop rotation
fireEvent.click(getByTitle(t('general.rotation'))) // should start rotation
})
it('toggle rotation', () => {
const {getByTitle} = render(<Viewer isAlex={false}/>);
fireEvent.click(getByTitle(t('general.rotation'))); // Should stop rotation
fireEvent.click(getByTitle(t('general.rotation'))); // Should start rotation
});
it('toggle pause', () => {
const { getByTitle } = render(<Viewer isAlex={false} />)
const icon = getByTitle(t('general.pauseAnimation'))
fireEvent.click(icon)
expect(icon).toHaveClass('fa-play')
})
})
it('toggle pause', () => {
const {getByTitle} = render(<Viewer isAlex={false}/>);
const icon = getByTitle(t('general.pauseAnimation'));
fireEvent.click(icon);
expect(icon).toHaveClass('fa-play');
});
});
describe('background', () => {
it('white', () => {
const { getByTitle } = render(<Viewer isAlex={false} />)
fireEvent.click(getByTitle(t('colors.white')))
})
it('white', () => {
const {getByTitle} = render(<Viewer isAlex={false}/>);
fireEvent.click(getByTitle(t('colors.white')));
});
it('black', () => {
const { getByTitle } = render(<Viewer isAlex={false} />)
fireEvent.click(getByTitle(t('colors.black')))
})
it('black', () => {
const {getByTitle} = render(<Viewer isAlex={false}/>);
fireEvent.click(getByTitle(t('colors.black')));
});
it('white', () => {
const { getByTitle } = render(<Viewer isAlex={false} />)
fireEvent.click(getByTitle(t('colors.gray')))
})
it('white', () => {
const {getByTitle} = render(<Viewer isAlex={false}/>);
fireEvent.click(getByTitle(t('colors.gray')));
});
it('previous picture', () => {
const { getByTitle } = render(<Viewer isAlex={false} />)
fireEvent.click(getByTitle(t('colors.prev')))
fireEvent.click(getByTitle(t('colors.prev')))
})
it('previous picture', () => {
const {getByTitle} = render(<Viewer isAlex={false}/>);
fireEvent.click(getByTitle(t('colors.prev')));
fireEvent.click(getByTitle(t('colors.prev')));
});
it('next picture', () => {
const { getByTitle } = render(<Viewer isAlex={false} />)
it('next picture', () => {
const {getByTitle} = render(<Viewer isAlex={false}/>);
fireEvent.click(getByTitle(t('colors.next')))
fireEvent.click(getByTitle(t('colors.next')))
fireEvent.click(getByTitle(t('colors.next')));
fireEvent.click(getByTitle(t('colors.next')));
Array.from({ length: PICTURES_COUNT - 1 }).forEach(() => {
fireEvent.click(getByTitle(t('colors.next')))
})
})
Array.from({length: PICTURES_COUNT - 1}).forEach(() => {
fireEvent.click(getByTitle(t('colors.next')));
});
});
it('default for dark mode', () => {
document.body.classList.add('dark-mode')
it('default for dark mode', () => {
document.body.classList.add('dark-mode');
render(<Viewer isAlex={false} />)
render(<Viewer isAlex={false}/>);
document.body.classList.remove('dark-mode')
})
})
document.body.classList.remove('dark-mode');
});
});

View File

@ -1,70 +1,70 @@
import * as fetch from '@/scripts/net'
import apt from '@/scripts/cli/AptCommand'
import { Stdio } from './stdio'
import {Stdio} from './stdio';
import * as fetch from '@/scripts/net';
import apt from '@/scripts/cli/AptCommand';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
describe('install plugin', () => {
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const stdio = new Stdio();
await apt(stdio, ['install', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
})
expect(stdio.getStdout()).toInclude('ok')
})
await apt(stdio, ['install', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
});
expect(stdio.getStdout()).toInclude('ok');
});
it('failed with reasons', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: { reason: ['unresolved'] },
})
const stdio = new Stdio()
it('failed with reasons', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: {reason: ['unresolved']},
});
const stdio = new Stdio();
await apt(stdio, ['install', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
})
expect(stdio.getStdout()).toInclude('failed')
expect(stdio.getStdout()).toInclude('- unresolved')
})
await apt(stdio, ['install', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
});
expect(stdio.getStdout()).toInclude('failed');
expect(stdio.getStdout()).toInclude('- unresolved');
});
it('use `upgrade` command', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
it('use `upgrade` command', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const stdio = new Stdio();
await apt(stdio, ['upgrade', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
})
expect(stdio.getStdout()).toInclude('ok')
})
})
await apt(stdio, ['upgrade', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
});
expect(stdio.getStdout()).toInclude('ok');
});
});
describe('remove plugin', () => {
beforeAll(() => vi.useRealTimers())
beforeAll(() => vi.useRealTimers());
it('cancelled', async () => {
const stdio = new Stdio()
it('cancelled', async () => {
const stdio = new Stdio();
setTimeout(() => process.stdin.emit('keypress', 'n', 'n'), 0)
await apt(stdio, ['remove', 'test'])
expect(fetch.post).not.toBeCalled()
})
setTimeout(() => process.stdin.emit('keypress', 'n', 'n'), 0);
await apt(stdio, ['remove', 'test']);
expect(fetch.post).not.toBeCalled();
});
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const stdio = new Stdio();
setTimeout(() => process.stdin.emit('keypress', 'y', 'y'), 0)
await apt(stdio, ['remove', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'test',
})
expect(stdio.getStdout()).toInclude('ok')
})
})
setTimeout(() => process.stdin.emit('keypress', 'y', 'y'), 0);
await apt(stdio, ['remove', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'test',
});
expect(stdio.getStdout()).toInclude('ok');
});
});

View File

@ -1,61 +1,61 @@
import * as fetch from '@/scripts/net'
import runCommand from '@/scripts/cli/ClosetCommand'
import { Stdio } from './stdio'
import {Stdio} from './stdio';
import * as fetch from '@/scripts/net';
import runCommand from '@/scripts/cli/ClosetCommand';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
describe('add texture', () => {
it('succeeded', async () => {
fetch.post.mockResolvedValue({
code: 0,
data: { user: { nickname: 'kumiko' }, texture: { name: 'eupho' } },
})
it('succeeded', async () => {
fetch.post.mockResolvedValue({
code: 0,
data: {user: {nickname: 'kumiko'}, texture: {name: 'eupho'}},
});
const stdio = new Stdio()
await runCommand(stdio, ['add', '1', '2'])
const stdio = new Stdio();
await runCommand(stdio, ['add', '1', '2']);
const stdout = stdio.getStdout()
expect(stdout).toInclude('kumiko')
expect(stdout).toInclude('eupho')
expect(fetch.post).toBeCalledWith('/admin/closet/1', { tid: '2' })
})
const stdout = stdio.getStdout();
expect(stdout).toInclude('kumiko');
expect(stdout).toInclude('eupho');
expect(fetch.post).toBeCalledWith('/admin/closet/1', {tid: '2'});
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 1 })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 1});
const stdio = new Stdio()
await runCommand(stdio, ['add', '1', '2'])
const stdio = new Stdio();
await runCommand(stdio, ['add', '1', '2']);
const stdout = stdio.getStdout()
expect(stdout).toInclude('Error occurred.')
expect(fetch.post).toBeCalledWith('/admin/closet/1', { tid: '2' })
})
})
const stdout = stdio.getStdout();
expect(stdout).toInclude('Error occurred.');
expect(fetch.post).toBeCalledWith('/admin/closet/1', {tid: '2'});
});
});
describe('remove texture', () => {
it('succeeded', async () => {
fetch.del.mockResolvedValue({
code: 0,
data: { user: { nickname: 'kumiko' }, texture: { name: 'eupho' } },
})
it('succeeded', async () => {
fetch.del.mockResolvedValue({
code: 0,
data: {user: {nickname: 'kumiko'}, texture: {name: 'eupho'}},
});
const stdio = new Stdio()
await runCommand(stdio, ['remove', '1', '2'])
const stdio = new Stdio();
await runCommand(stdio, ['remove', '1', '2']);
const stdout = stdio.getStdout()
expect(stdout).toInclude('kumiko')
expect(stdout).toInclude('eupho')
expect(fetch.del).toBeCalledWith('/admin/closet/1', { tid: '2' })
})
const stdout = stdio.getStdout();
expect(stdout).toInclude('kumiko');
expect(stdout).toInclude('eupho');
expect(fetch.del).toBeCalledWith('/admin/closet/1', {tid: '2'});
});
it('failed', async () => {
fetch.del.mockResolvedValue({ code: 1 })
it('failed', async () => {
fetch.del.mockResolvedValue({code: 1});
const stdio = new Stdio()
await runCommand(stdio, ['remove', '1', '2'])
const stdio = new Stdio();
await runCommand(stdio, ['remove', '1', '2']);
const stdout = stdio.getStdout()
expect(stdout).toInclude('Error occurred.')
expect(fetch.del).toBeCalledWith('/admin/closet/1', { tid: '2' })
})
})
const stdout = stdio.getStdout();
expect(stdout).toInclude('Error occurred.');
expect(fetch.del).toBeCalledWith('/admin/closet/1', {tid: '2'});
});
});

View File

@ -1,70 +1,70 @@
import * as fetch from '@/scripts/net'
import dnf from '@/scripts/cli/DnfCommand'
import { Stdio } from './stdio'
import {Stdio} from './stdio';
import * as fetch from '@/scripts/net';
import dnf from '@/scripts/cli/DnfCommand';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
describe('install plugin', () => {
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const stdio = new Stdio();
await dnf(stdio, ['install', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
})
expect(stdio.getStdout()).toInclude('ok')
})
await dnf(stdio, ['install', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
});
expect(stdio.getStdout()).toInclude('ok');
});
it('failed with reasons', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: { reason: ['unresolved'] },
})
const stdio = new Stdio()
it('failed with reasons', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: {reason: ['unresolved']},
});
const stdio = new Stdio();
await dnf(stdio, ['install', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
})
expect(stdio.getStdout()).toInclude('failed')
expect(stdio.getStdout()).toInclude('- unresolved')
})
await dnf(stdio, ['install', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
});
expect(stdio.getStdout()).toInclude('failed');
expect(stdio.getStdout()).toInclude('- unresolved');
});
it('use `upgrade` command', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
it('use `upgrade` command', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const stdio = new Stdio();
await dnf(stdio, ['upgrade', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
})
expect(stdio.getStdout()).toInclude('ok')
})
})
await dnf(stdio, ['upgrade', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
});
expect(stdio.getStdout()).toInclude('ok');
});
});
describe('remove plugin', () => {
beforeAll(() => vi.useRealTimers())
beforeAll(() => vi.useRealTimers());
it('cancelled', async () => {
const stdio = new Stdio()
it('cancelled', async () => {
const stdio = new Stdio();
setTimeout(() => process.stdin.emit('keypress', 'n', 'n'), 0)
await dnf(stdio, ['remove', 'test'])
expect(fetch.post).not.toBeCalled()
})
setTimeout(() => process.stdin.emit('keypress', 'n', 'n'), 0);
await dnf(stdio, ['remove', 'test']);
expect(fetch.post).not.toBeCalled();
});
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const stdio = new Stdio();
setTimeout(() => process.stdin.emit('keypress', 'y', 'y'), 0)
await dnf(stdio, ['remove', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'test',
})
expect(stdio.getStdout()).toInclude('ok')
})
})
setTimeout(() => process.stdin.emit('keypress', 'y', 'y'), 0);
await dnf(stdio, ['remove', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'test',
});
expect(stdio.getStdout()).toInclude('ok');
});
});

View File

@ -1,66 +1,66 @@
import * as fetch from '@/scripts/net'
import pacman from '@/scripts/cli/PacmanCommand'
import { Stdio } from './stdio'
import {Stdio} from './stdio';
import * as fetch from '@/scripts/net';
import pacman from '@/scripts/cli/PacmanCommand';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
test('no arguments', async () => {
const stdio = new Stdio()
await pacman(stdio, [])
expect(stdio.getStdout()).toInclude('help')
expect(fetch.post).not.toBeCalled()
})
const stdio = new Stdio();
await pacman(stdio, []);
expect(stdio.getStdout()).toInclude('help');
expect(fetch.post).not.toBeCalled();
});
describe('install plugin', () => {
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const stdio = new Stdio();
await pacman(stdio, ['-S', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
})
expect(stdio.getStdout()).toInclude('ok')
})
await pacman(stdio, ['-S', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
});
expect(stdio.getStdout()).toInclude('ok');
});
it('failed with reasons', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: { reason: ['unresolved'] },
})
const stdio = new Stdio()
it('failed with reasons', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: {reason: ['unresolved']},
});
const stdio = new Stdio();
await pacman(stdio, ['-S', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
})
expect(stdio.getStdout()).toInclude('failed')
expect(stdio.getStdout()).toInclude('- unresolved')
})
})
await pacman(stdio, ['-S', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: 'test',
});
expect(stdio.getStdout()).toInclude('failed');
expect(stdio.getStdout()).toInclude('- unresolved');
});
});
describe('remove plugin', () => {
beforeAll(() => vi.useRealTimers())
beforeAll(() => vi.useRealTimers());
it('cancelled', async () => {
const stdio = new Stdio()
it('cancelled', async () => {
const stdio = new Stdio();
setTimeout(() => process.stdin.emit('keypress', 'n', 'n'), 0)
await pacman(stdio, ['-R', 'test'])
expect(fetch.post).not.toBeCalled()
})
setTimeout(() => process.stdin.emit('keypress', 'n', 'n'), 0);
await pacman(stdio, ['-R', 'test']);
expect(fetch.post).not.toBeCalled();
});
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const stdio = new Stdio()
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const stdio = new Stdio();
setTimeout(() => process.stdin.emit('keypress', 'y', 'y'), 0)
await pacman(stdio, ['-R', 'test'])
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'test',
})
expect(stdio.getStdout()).toInclude('ok')
})
})
setTimeout(() => process.stdin.emit('keypress', 'y', 'y'), 0);
await pacman(stdio, ['-R', 'test']);
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'test',
});
expect(stdio.getStdout()).toInclude('ok');
});
});

View File

@ -1,30 +1,30 @@
import * as fetch from '@/scripts/net'
import runCommand from '@/scripts/cli/RmCommand'
import { Stdio } from './stdio'
import {Stdio} from './stdio';
import * as fetch from '@/scripts/net';
import runCommand from '@/scripts/cli/RmCommand';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
test('missing operand', async () => {
const stdio = new Stdio()
await runCommand(stdio, [])
expect(stdio.getStdout()).toInclude('missing operand')
expect(fetch.post).not.toBeCalled()
})
const stdio = new Stdio();
await runCommand(stdio, []);
expect(stdio.getStdout()).toInclude('missing operand');
expect(fetch.post).not.toBeCalled();
});
test('without "rf"', async () => {
const stdio = new Stdio()
await runCommand(stdio, ['/'])
expect(fetch.post).not.toBeCalled()
})
const stdio = new Stdio();
await runCommand(stdio, ['/']);
expect(fetch.post).not.toBeCalled();
});
test('not from root', async () => {
const stdio = new Stdio()
await runCommand(stdio, ['-rf', '.'])
expect(fetch.post).not.toBeCalled()
})
const stdio = new Stdio();
await runCommand(stdio, ['-rf', '.']);
expect(fetch.post).not.toBeCalled();
});
test('send request', async () => {
const stdio = new Stdio()
await runCommand(stdio, ['-rf', '/'])
expect(fetch.post).toBeCalledWith('/admin/resource?clear-cache')
})
const stdio = new Stdio();
await runCommand(stdio, ['-rf', '/']);
expect(fetch.post).toBeCalledWith('/admin/resource?clear-cache');
});

View File

@ -1,16 +1,16 @@
import { Spinner } from '@/scripts/cli/Spinner'
import { Stdio } from './stdio'
import {Stdio} from './stdio';
import {Spinner} from '@/scripts/cli/Spinner';
test('run', async () => {
vi.useRealTimers()
vi.useRealTimers();
const stdio = new Stdio()
const spinner = new Spinner(stdio)
const stdio = new Stdio();
const spinner = new Spinner(stdio);
spinner.start()
spinner.start();
await new Promise((resolve) => setTimeout(resolve, 500))
expect(stdio.getStdout().length).toBeGreaterThan(0)
await new Promise(resolve => setTimeout(resolve, 500));
expect(stdio.getStdout().length).toBeGreaterThan(0);
spinner.stop()
})
spinner.stop();
});

View File

@ -1,24 +1,24 @@
export class Stdio {
private stdout = ''
private stdout = '';
public print(data: string) {
this.stdout += data
}
public print(data: string) {
this.stdout += data;
}
public println(data: string) {
this.stdout += data
this.stdout += '\r\n'
}
public println(data: string) {
this.stdout += data;
this.stdout += '\r\n';
}
public reset() {
//
}
public reset() {
//
}
public free() {
//
}
public free() {
//
}
public getStdout() {
return this.stdout
}
public getStdout() {
return this.stdout;
}
}

View File

@ -1,30 +1,30 @@
import * as emitter from '@/scripts/event'
import * as emitter from '@/scripts/event';
test('add listener and emit event', () => {
const mockA1 = vi.fn()
const mockA2 = vi.fn()
const mockB = vi.fn()
const mockA1 = vi.fn();
const mockA2 = vi.fn();
const mockB = vi.fn();
emitter.on('a', mockA1)
emitter.on('a', mockA2)
emitter.on('b', mockB)
emitter.on('a', mockA1);
emitter.on('a', mockA2);
emitter.on('b', mockB);
emitter.emit('a')
emitter.emit('a');
expect(mockA1).toBeCalledTimes(1)
expect(mockA2).toBeCalledTimes(1)
expect(mockB).not.toBeCalled()
})
expect(mockA1).toBeCalledTimes(1);
expect(mockA2).toBeCalledTimes(1);
expect(mockB).not.toBeCalled();
});
test('not throw for un-existed event', () => {
emitter.emit('c')
})
emitter.emit('c');
});
test('unsubscribe event', () => {
const mock = vi.fn()
const mock = vi.fn();
const off = emitter.on('c', mock)
off()
const off = emitter.on('c', mock);
off();
expect(mock).not.toBeCalled()
})
expect(mock).not.toBeCalled();
});

View File

@ -1,29 +1,29 @@
import { scrollHander } from '@/scripts/homePage'
import {scrollHander} from '@/scripts/homePage';
describe('scroll handler', () => {
beforeAll(() => {
window.blessing.extra = {
transparent_navbar: false,
}
})
beforeAll(() => {
window.blessing.extra = {
transparent_navbar: false,
};
});
it('should be transparent at top', () => {
Object.assign(window, { innerHeight: 900 })
document.body.innerHTML = '<nav class="navbar"></nav>'
scrollHander()
window.dispatchEvent(new Event('scroll'))
expect(
document.querySelector('nav')!.classList.contains('transparent'),
).toBeTrue()
})
it('should be transparent at top', () => {
Object.assign(window, {innerHeight: 900});
document.body.innerHTML = '<nav class="navbar"></nav>';
scrollHander();
window.dispatchEvent(new Event('scroll'));
expect(
document.querySelector('nav')!.classList.contains('transparent'),
).toBeTrue();
});
it('should not be transparent at bottom', () => {
Object.assign(window, { innerHeight: 900, scrollY: 800 })
document.body.innerHTML = '<nav class="navbar transparent"></nav>'
scrollHander()
window.dispatchEvent(new Event('scroll'))
expect(
document.querySelector('nav')!.classList.contains('transparent'),
).toBeFalse()
})
})
it('should not be transparent at bottom', () => {
Object.assign(window, {innerHeight: 900, scrollY: 800});
document.body.innerHTML = '<nav class="navbar transparent"></nav>';
scrollHander();
window.dispatchEvent(new Event('scroll'));
expect(
document.querySelector('nav')!.classList.contains('transparent'),
).toBeFalse();
});
});

View File

@ -1,14 +1,14 @@
import { t } from '@/scripts/i18n'
import {t} from '@/scripts/i18n';
test('mount to global', () => {
expect(window.trans).toBe(t)
})
expect(window.trans).toBe(t);
});
test('translate text', () => {
window.blessing.i18n = { a: { b: { c: 'text', d: 'Hi, :name!' } } }
expect(t('a.b.c')).toBe('text')
expect(t('a.b.d')).toBe('Hi, :name!')
expect(t('a.b.d', { name: 'me' })).toBe('Hi, me!')
expect(t('a.b.e')).toBe('a.b.e')
expect(t('d.e')).toBe('d.e')
})
window.blessing.i18n = {a: {b: {c: 'text', d: 'Hi, :name!'}}};
expect(t('a.b.c')).toBe('text');
expect(t('a.b.d')).toBe('Hi, :name!');
expect(t('a.b.d', {name: 'me'})).toBe('Hi, me!');
expect(t('a.b.e')).toBe('a.b.e');
expect(t('d.e')).toBe('d.e');
});

View File

@ -1,18 +1,18 @@
import { logout } from '@/scripts/logout'
import { post } from '@/scripts/net'
import { showModal } from '@/scripts/notify'
import urls from '@/scripts/urls'
import {logout} from '@/scripts/logout';
import {post} from '@/scripts/net';
import {showModal} from '@/scripts/notify';
import urls from '@/scripts/urls';
vi.mock('@/scripts/net')
vi.mock('@/scripts/notify')
vi.mock('@/scripts/net');
vi.mock('@/scripts/notify');
test('log out', async () => {
showModal.mockRejectedValueOnce(null).mockResolvedValueOnce({ value: '' })
post.mockResolvedValue({ message: '' })
showModal.mockRejectedValueOnce(null).mockResolvedValueOnce({value: ''});
post.mockResolvedValue({message: ''});
await logout()
expect(post).not.toBeCalled()
await logout();
expect(post).not.toBeCalled();
await logout()
expect(post).toBeCalledWith(urls.auth.logout())
})
await logout();
expect(post).toBeCalledWith(urls.auth.logout());
});

View File

@ -1,13 +1,13 @@
import { t } from '@/scripts/i18n'
import { showModal } from '@/scripts/modal'
import {t} from '@/scripts/i18n';
import {showModal} from '@/scripts/modal';
test('show modal', async () => {
Promise.resolve().then(() => {
expect(document.querySelector('.modal-title')!.textContent).toBe(
t('general.tip'),
)
document.querySelector<HTMLButtonElement>('.btn-primary')!.click()
})
const { value } = await showModal()
expect(value).toBe('')
})
Promise.resolve().then(() => {
expect(document.querySelector('.modal-title')!.textContent).toBe(
t('general.tip'),
);
document.querySelector<HTMLButtonElement>('.btn-primary')!.click();
});
const {value} = await showModal();
expect(value).toBe('');
});

View File

@ -1,262 +1,262 @@
import * as net from '@/scripts/net'
import { on } from '@/scripts/event'
import { t } from '@/scripts/i18n'
import { showModal } from '@/scripts/notify'
import * as net from '@/scripts/net';
import {on} from '@/scripts/event';
import {t} from '@/scripts/i18n';
import {showModal} from '@/scripts/notify';
vi.mock('@/scripts/notify')
vi.mock('@/scripts/notify');
test('the GET method', async () => {
const json = vi.fn().mockResolvedValue({})
window.fetch = vi.fn().mockResolvedValue({
ok: true,
json,
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
})
const json = vi.fn().mockResolvedValue({});
window.fetch = vi.fn().mockResolvedValue({
ok: true,
json,
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
});
const stub = vi.fn()
on('beforeFetch', stub)
const stub = vi.fn();
on('beforeFetch', stub);
await net.get('/abc', { a: 'b' })
expect(stub).toBeCalledWith({
method: 'GET',
url: '/abc',
data: { a: 'b' },
})
expect(window.fetch.mock.calls[0][0].url).toBe('/abc?a=b')
expect(json).toBeCalled()
await net.get('/abc', {a: 'b'});
expect(stub).toBeCalledWith({
method: 'GET',
url: '/abc',
data: {a: 'b'},
});
expect(window.fetch.mock.calls[0][0].url).toBe('/abc?a=b');
expect(json).toBeCalled();
await net.get('/abc')
expect(window.fetch.mock.calls[1][0].url).toBe('/abc?')
})
await net.get('/abc');
expect(window.fetch.mock.calls[1][0].url).toBe('/abc?');
});
test('the POST method', async () => {
window.fetch = vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({}),
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
})
window.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({}),
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
});
const meta = document.createElement('meta')
meta.name = 'csrf-token'
meta.content = 'token'
document.head.appendChild(meta)
const meta = document.createElement('meta');
meta.name = 'csrf-token';
meta.content = 'token';
document.head.append(meta);
const stub = vi.fn()
on('beforeFetch', stub)
const stub = vi.fn();
on('beforeFetch', stub);
const formData = new FormData()
await net.post('/abc', formData)
expect(stub).toBeCalledWith({
method: 'POST',
url: '/abc',
data: formData,
})
const formData = new FormData();
await net.post('/abc', formData);
expect(stub).toBeCalledWith({
method: 'POST',
url: '/abc',
data: formData,
});
await net.post('/abc', { a: 'b' })
expect(stub).toBeCalledWith({
method: 'POST',
url: '/abc',
data: { a: 'b' },
})
// eslint-disable-next-line prefer-destructuring
const request = window.fetch.mock.calls[1][0]
expect(request.url).toBe('/abc')
expect(request.method).toBe('POST')
expect(request.body).toBe(JSON.stringify({ a: 'b' }))
expect(request.headers.get('X-CSRF-TOKEN')).toBe('token')
expect(request.headers.get('Content-Type')).toBe('application/json')
await net.post('/abc', {a: 'b'});
expect(stub).toBeCalledWith({
method: 'POST',
url: '/abc',
data: {a: 'b'},
});
await net.post('/abc')
expect(window.fetch.mock.calls[2][0].body).toBeUndefined()
})
const request = window.fetch.mock.calls[1][0];
expect(request.url).toBe('/abc');
expect(request.method).toBe('POST');
expect(request.body).toBe(JSON.stringify({a: 'b'}));
expect(request.headers.get('X-CSRF-TOKEN')).toBe('token');
expect(request.headers.get('Content-Type')).toBe('application/json');
await net.post('/abc');
expect(window.fetch.mock.calls[2][0].body).toBeUndefined();
});
test('the PUT method', () => {
const fetch = vi.fn()
window.fetch = fetch
const fetch = vi.fn();
window.fetch = fetch;
const stub = vi.fn()
on('beforeFetch', stub)
const stub = vi.fn();
on('beforeFetch', stub);
net.put('/abc')
expect(fetch).toBeCalled()
// eslint-disable-next-line prefer-destructuring
const request = fetch.mock.calls[0][0]
expect(request.method).toBe('PUT')
net.put('/abc');
expect(fetch).toBeCalled();
expect(stub).toBeCalledWith({
method: 'PUT',
url: '/abc',
data: undefined,
})
})
const request = fetch.mock.calls[0][0];
expect(request.method).toBe('PUT');
expect(stub).toBeCalledWith({
method: 'PUT',
url: '/abc',
data: undefined,
});
});
test('the DELETE method', () => {
const fetch = vi.fn()
window.fetch = fetch
const fetch = vi.fn();
window.fetch = fetch;
const stub = vi.fn()
on('beforeFetch', stub)
const stub = vi.fn();
on('beforeFetch', stub);
net.del('/abc')
expect(fetch).toBeCalled()
// eslint-disable-next-line prefer-destructuring
const request = fetch.mock.calls[0][0]
expect(request.method).toBe('DELETE')
net.del('/abc');
expect(fetch).toBeCalled();
expect(stub).toBeCalledWith({
method: 'DELETE',
url: '/abc',
data: undefined,
})
})
const request = fetch.mock.calls[0][0];
expect(request.method).toBe('DELETE');
expect(stub).toBeCalledWith({
method: 'DELETE',
url: '/abc',
data: undefined,
});
});
test('low level fetch', async () => {
const json = vi.fn().mockResolvedValue({})
window.fetch = vi.fn()
.mockRejectedValueOnce(new Error('network'))
.mockResolvedValueOnce({
ok: false,
headers: new Map(),
text: () => Promise.resolve('404'),
clone: () => ({}),
})
.mockResolvedValueOnce({
ok: false,
json: () => Promise.resolve({ message: 'error' }),
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
})
.mockResolvedValueOnce({
ok: true,
json,
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
})
.mockResolvedValueOnce({
ok: true,
headers: new Map(),
text: () => Promise.resolve('text'),
clone: () => ({}),
})
const json = vi.fn().mockResolvedValue({});
window.fetch = vi.fn()
.mockRejectedValueOnce(new Error('network'))
.mockResolvedValueOnce({
ok: false,
headers: new Map(),
text: async () => '404',
clone: () => ({}),
})
.mockResolvedValueOnce({
ok: false,
json: async () => ({message: 'error'}),
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
})
.mockResolvedValueOnce({
ok: true,
json,
headers: new Map([['Content-Type', 'application/json']]),
clone: () => ({}),
})
.mockResolvedValueOnce({
ok: true,
headers: new Map(),
text: async () => 'text',
clone: () => ({}),
});
const request: RequestInit = { headers: new Headers() }
const request: RequestInit = {headers: new Headers()};
const stub = vi.fn()
on('fetchError', stub)
const stub = vi.fn();
on('fetchError', stub);
await net.walkFetch(request as Request)
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML: 'network',
type: 'danger',
okButtonType: 'outline-light',
})
expect(stub).toBeCalledWith(expect.any(Error))
await net.walkFetch(request as Request);
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML: 'network',
type: 'danger',
okButtonType: 'outline-light',
});
expect(stub).toBeCalledWith(expect.any(Error));
await net.walkFetch(request as Request)
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML: '404',
type: 'danger',
okButtonType: 'outline-light',
})
expect(stub.mock.calls[1][0]).toHaveProperty('message', '404')
expect(stub.mock.calls[1][0]).toHaveProperty('response')
await net.walkFetch(request as Request);
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML: '404',
type: 'danger',
okButtonType: 'outline-light',
});
expect(stub.mock.calls[1][0]).toHaveProperty('message', '404');
expect(stub.mock.calls[1][0]).toHaveProperty('response');
await net.walkFetch(request as Request)
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML: 'error',
type: 'danger',
okButtonType: 'outline-light',
})
expect(stub.mock.calls[2][0]).toHaveProperty('message', 'error')
expect(stub.mock.calls[2][0]).toHaveProperty('response')
await net.walkFetch(request as Request);
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML: 'error',
type: 'danger',
okButtonType: 'outline-light',
});
expect(stub.mock.calls[2][0]).toHaveProperty('message', 'error');
expect(stub.mock.calls[2][0]).toHaveProperty('response');
await net.walkFetch(request as Request)
expect(json).toBeCalled()
await net.walkFetch(request as Request);
expect(json).toBeCalled();
expect(await net.walkFetch(request as Request)).toBe('text')
})
expect(await net.walkFetch(request as Request)).toBe('text');
});
test('process backend errors', async () => {
window.fetch = vi.fn()
.mockResolvedValueOnce({
status: 422,
headers: new Map([['Content-Type', 'application/json']]),
json() {
return Promise.resolve({
errors: { name: ['required'] },
})
},
clone: () => ({}),
})
.mockResolvedValueOnce({
status: 419,
headers: new Map([['Content-Type', 'application/json']]),
json() {
return Promise.resolve({
message: 'CSRF token mismatched.',
})
},
clone: () => ({}),
})
.mockResolvedValueOnce({
status: 403,
headers: new Map([['Content-Type', 'application/json']]),
json() {
return Promise.resolve({ message: 'forbidden' })
},
clone: () => ({}),
})
.mockResolvedValueOnce({
status: 500,
headers: new Map([['Content-Type', 'application/json']]),
json() {
return Promise.resolve({
message: 'fake exception',
exception: true,
trace: [
{ file: 'k.php', line: 2 },
{ file: 'v.php', line: 3 },
],
})
},
clone: () => ({}),
})
window.fetch = vi.fn()
.mockResolvedValueOnce({
status: 422,
headers: new Map([['Content-Type', 'application/json']]),
async json() {
return {
errors: {name: ['required']},
};
},
clone: () => ({}),
})
.mockResolvedValueOnce({
status: 419,
headers: new Map([['Content-Type', 'application/json']]),
async json() {
return {
message: 'CSRF token mismatched.',
};
},
clone: () => ({}),
})
.mockResolvedValueOnce({
status: 403,
headers: new Map([['Content-Type', 'application/json']]),
async json() {
return {message: 'forbidden'};
},
clone: () => ({}),
})
.mockResolvedValueOnce({
status: 500,
headers: new Map([['Content-Type', 'application/json']]),
async json() {
return {
message: 'fake exception',
exception: true,
trace: [
{file: 'k.php', line: 2},
{file: 'v.php', line: 3},
],
};
},
clone: () => ({}),
});
const result: {
code: number
message: string
} = await net.walkFetch({ headers: new Headers() } as Request)
expect(result.code).toBe(1)
expect(result.message).toBe('required')
const result: {
code: number;
message: string;
} = await net.walkFetch({headers: new Headers()} as Request);
expect(result.code).toBe(1);
expect(result.message).toBe('required');
await net.walkFetch({ headers: new Headers() } as Request)
expect(showModal).toBeCalledWith({
mode: 'alert',
text: t('general.csrf'),
})
await net.walkFetch({headers: new Headers()} as Request);
expect(showModal).toBeCalledWith({
mode: 'alert',
text: t('general.csrf'),
});
await net.walkFetch({ headers: new Headers() } as Request)
expect(showModal).toBeCalledWith({
mode: 'alert',
text: 'forbidden',
type: 'warning',
})
await net.walkFetch({headers: new Headers()} as Request);
expect(showModal).toBeCalledWith({
mode: 'alert',
text: 'forbidden',
type: 'warning',
});
await net.walkFetch({ headers: new Headers() } as Request)
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML:
await net.walkFetch({headers: new Headers()} as Request);
expect(showModal).toBeCalledWith({
mode: 'alert',
title: t('general.fatalError'),
dangerousHTML:
'fake exception<br><details>[1] k.php#L2<br>[2] v.php#L3</details>',
type: 'danger',
okButtonType: 'outline-light',
})
})
type: 'danger',
okButtonType: 'outline-light',
});
});

View File

@ -1,49 +1,49 @@
import { render, fireEvent, screen } from '@testing-library/react'
import { Toast } from '@/scripts/toast'
import {render, fireEvent, screen} from '@testing-library/react';
import {Toast} from '@/scripts/toast';
test('"Toast" class', () => {
const toast = new Toast(render)
const toast = new Toast(render);
toast.success('success')
expect(document.querySelector('.alert-success')!.textContent).toContain(
'success',
)
toast.success('success');
expect(document.querySelector('.alert-success')!.textContent).toContain(
'success',
);
toast.info('info')
expect(document.querySelector('.alert-info')!.textContent).toContain('info')
toast.info('info');
expect(document.querySelector('.alert-info')!.textContent).toContain('info');
toast.warning('warning')
expect(document.querySelector('.alert-warning')!.textContent).toContain(
'warning',
)
toast.warning('warning');
expect(document.querySelector('.alert-warning')!.textContent).toContain(
'warning',
);
toast.error('error')
expect(document.querySelector('.alert-danger')!.textContent).toContain(
'error',
)
toast.error('error');
expect(document.querySelector('.alert-danger')!.textContent).toContain(
'error',
);
vi.runAllTimers()
toast.dispose()
})
vi.runAllTimers();
toast.dispose();
});
test('clear toasts', () => {
const toast = new Toast(render)
const toast = new Toast(render);
toast.success('success')
toast.info('info')
toast.success('success');
toast.info('info');
toast.clear()
expect(document.querySelectorAll('.alert')).toHaveLength(0)
toast.clear();
expect(document.querySelectorAll('.alert')).toHaveLength(0);
toast.dispose()
})
toast.dispose();
});
test('close toast manually', () => {
const toast = new Toast(render)
toast.success('success')
const toast = new Toast(render);
toast.success('success');
fireEvent.click(screen.getByText('×'))
expect(document.querySelectorAll('.alert')).toHaveLength(0)
fireEvent.click(screen.getByText('×'));
expect(document.querySelectorAll('.alert')).toHaveLength(0);
toast.dispose()
})
toast.dispose();
});

View File

@ -1,57 +1,57 @@
import { expect, test } from 'vitest'
import {expect, test} from 'vitest';
import {
registerNavbarPicker,
registerSidebarPicker,
} from '@/views/admin/Customization'
registerNavbarPicker,
registerSidebarPicker,
} from '@/views/admin/Customization';
test('preview navbar color', () => {
const nav = document.createElement('nav')
nav.className = 'navbar-primary navbar-dark'
const picker = document.createElement('div')
picker.innerHTML = `
const nav = document.createElement('nav');
nav.className = 'navbar-primary navbar-dark';
const picker = document.createElement('div');
picker.innerHTML = `
<label><input type="radio" name="navbar" value="cyan"></label>
<label><input type="radio" name="navbar" value="orange"></label>
`
const cyan = picker.querySelector<HTMLInputElement>('[value=cyan]')!
const orange = picker.querySelector<HTMLInputElement>('[value=orange]')!
`;
const cyan = picker.querySelector<HTMLInputElement>('[value=cyan]')!;
const orange = picker.querySelector<HTMLInputElement>('[value=orange]')!;
registerNavbarPicker(nav, picker, 'primary')
cyan.click()
expect(nav.className).toContain('navbar-cyan')
expect(nav.className).toContain('navbar-dark')
expect(nav.className).not.toContain('navbar-light')
orange.click()
expect(nav.className).toContain('navbar-orange')
expect(nav.className).not.toContain('navbar-cyan')
expect(nav.className).toContain('navbar-light')
expect(nav.className).not.toContain('navbar-dark')
})
registerNavbarPicker(nav, picker, 'primary');
cyan.click();
expect(nav.className).toContain('navbar-cyan');
expect(nav.className).toContain('navbar-dark');
expect(nav.className).not.toContain('navbar-light');
orange.click();
expect(nav.className).toContain('navbar-orange');
expect(nav.className).not.toContain('navbar-cyan');
expect(nav.className).toContain('navbar-light');
expect(nav.className).not.toContain('navbar-dark');
});
test('preview sidebar color', () => {
const sidebar = document.createElement('aside')
sidebar.className = 'sidebar-dark-primary'
const sidebar = document.createElement('aside');
sidebar.className = 'sidebar-dark-primary';
const darkPicker = document.createElement('div')
darkPicker.innerHTML = `
<label><input type="radio" name="sidebar" value="dark-cyan"></label>`
const darkCyan = darkPicker.querySelector<HTMLInputElement>(
'[value="dark-cyan"]',
)!
const darkPicker = document.createElement('div');
darkPicker.innerHTML = `
<label><input type="radio" name="sidebar" value="dark-cyan"></label>`;
const darkCyan = darkPicker.querySelector<HTMLInputElement>(
'[value="dark-cyan"]',
)!;
const lightPicker = document.createElement('div')
lightPicker.innerHTML = `
<label><input type="radio" name="sidebar" value="light-cyan"></label>`
const lightCyan = lightPicker.querySelector<HTMLInputElement>(
'[value="light-cyan"]',
)!
const lightPicker = document.createElement('div');
lightPicker.innerHTML = `
<label><input type="radio" name="sidebar" value="light-cyan"></label>`;
const lightCyan = lightPicker.querySelector<HTMLInputElement>(
'[value="light-cyan"]',
)!;
registerSidebarPicker(
sidebar,
{ dark: darkPicker, light: lightPicker },
'dark-primary',
)
darkCyan.click()
expect(sidebar.className).toContain('sidebar-dark-cyan')
lightCyan.click()
expect(sidebar.className).toContain('sidebar-light-cyan')
})
registerSidebarPicker(
sidebar,
{dark: darkPicker, light: lightPicker},
'dark-primary',
);
darkCyan.click();
expect(sidebar.className).toContain('sidebar-dark-cyan');
lightCyan.click();
expect(sidebar.className).toContain('sidebar-light-cyan');
});

View File

@ -1,433 +1,484 @@
import { expect, test, vi, it } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import type { Player } from '@/scripts/types'
import urls from '@/scripts/urls'
import PlayersManagement from '@/views/admin/PlayersManagement'
import {
expect, test, vi, it,
} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {createPaginator} from '../../utils';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import type {Player} from '@/scripts/types';
import urls from '@/scripts/urls';
import PlayersManagement from '@/views/admin/PlayersManagement';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
const fixture: Readonly<Player> = Object.freeze<Player>({
pid: 1,
name: 'kumiko',
uid: 1,
tid_skin: 1,
tid_cape: 2,
last_modified: new Date().toString(),
})
pid: 1,
name: 'kumiko',
uid: 1,
tid_skin: 1,
tid_cape: 2,
last_modified: new Date().toString(),
});
beforeAll(() => {
Object.assign(window, { innerWidth: 500 })
})
Object.assign(window, {innerWidth: 500});
});
afterAll(() => {
Object.assign(window, { innerWidth: 1024 })
})
Object.assign(window, {innerWidth: 1024});
});
test('search players', async () => {
fetch.get.mockResolvedValue(createPaginator([]))
fetch.get.mockResolvedValue(createPaginator([]));
const { getByTitle, getByText } = render(<PlayersManagement />)
await waitFor(() =>
expect(fetch.get).toBeCalledWith(urls.admin.players.list(), {
q: '',
page: 1,
}),
)
const {getByTitle, getByText} = render(<PlayersManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledWith(urls.admin.players.list(), {
q: '',
page: 1,
});
},
);
fireEvent.input(getByTitle(t('vendor.datatable.search')), {
target: { value: 's' },
})
fireEvent.click(getByText(t('vendor.datatable.search')))
await waitFor(() =>
expect(fetch.get).toBeCalledWith(urls.admin.players.list(), {
q: 's',
page: 1,
}),
)
})
fireEvent.input(getByTitle(t('vendor.datatable.search')), {
target: {value: 's'},
});
fireEvent.click(getByText(t('vendor.datatable.search')));
await waitFor(() => {
expect(fetch.get).toBeCalledWith(urls.admin.players.list(), {
q: 's',
page: 1,
});
},
);
});
test('preview textures', async () => {
fetch.get.mockResolvedValue(createPaginator([fixture]))
fetch.get.mockResolvedValue(createPaginator([fixture]));
const { getByText, queryByAltText } = render(<PlayersManagement />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, queryByAltText} = render(<PlayersManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('general.player.previews')))
fireEvent.click(getByText(t('general.player.previews')));
expect(
queryByAltText(`${fixture.name} - ${t('general.skin')}`),
).toHaveAttribute(
'src',
`${blessing.base_url}/preview/${fixture.tid_skin}?png`,
)
expect(
queryByAltText(`${fixture.name} - ${t('general.cape')}`),
).toHaveAttribute(
'src',
`${blessing.base_url}/preview/${fixture.tid_cape}?png`,
)
expect(
queryByAltText(`${fixture.name} - ${t('general.skin')}`),
).toHaveAttribute(
'src',
`${blessing.base_url}/preview/${fixture.tid_skin}?png`,
);
expect(
queryByAltText(`${fixture.name} - ${t('general.cape')}`),
).toHaveAttribute(
'src',
`${blessing.base_url}/preview/${fixture.tid_cape}?png`,
);
fireEvent.click(getByText(t('general.confirm')))
})
fireEvent.click(getByText(t('general.confirm')));
});
describe('update player name', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]));
});
it('empty value', async () => {
const { getByText, getByDisplayValue, queryByText } = render(
<PlayersManagement />,
)
it('empty value', async () => {
const {getByText, getByDisplayValue, queryByText} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changePlayerName')))
fireEvent.input(getByDisplayValue(fixture.name), {
target: { value: '' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changePlayerName')));
fireEvent.input(getByDisplayValue(fixture.name), {
target: {value: ''},
});
fireEvent.click(getByText(t('general.confirm')));
expect(queryByText(t('admin.emptyPlayerName'))).toBeInTheDocument()
expect(fetch.put).not.toBeCalled()
expect(queryByText(t('admin.emptyPlayerName'))).toBeInTheDocument();
expect(fetch.put).not.toBeCalled();
fireEvent.click(getByText(t('general.cancel')))
fireEvent.click(getByText(t('general.cancel')));
expect(queryByText(fixture.name)).toBeInTheDocument()
})
expect(queryByText(fixture.name)).toBeInTheDocument();
});
it('succeeded', async () => {
fetch.put.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.put.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, getByDisplayValue, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, getByDisplayValue, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changePlayerName')))
fireEvent.input(getByDisplayValue(fixture.name), {
target: { value: 'reina' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changePlayerName')));
fireEvent.input(getByDisplayValue(fixture.name), {
target: {value: 'reina'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.put).toBeCalledWith(urls.admin.players.name(fixture.pid), {
player_name: 'reina',
}),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(queryByRole('status')).toHaveClass('alert-success')
expect(queryByText('reina')).toBeInTheDocument()
})
await waitFor(() => {
expect(fetch.put).toBeCalledWith(urls.admin.players.name(fixture.pid), {
player_name: 'reina',
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(queryByRole('status')).toHaveClass('alert-success');
expect(queryByText('reina')).toBeInTheDocument();
});
it('failed', async () => {
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.put.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByDisplayValue, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, getByDisplayValue, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changePlayerName')))
fireEvent.input(getByDisplayValue(fixture.name), {
target: { value: 'reina' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changePlayerName')));
fireEvent.input(getByDisplayValue(fixture.name), {
target: {value: 'reina'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.put).toBeCalledWith(urls.admin.players.name(fixture.pid), {
player_name: 'reina',
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(queryByRole('alert')).toHaveClass('alert-danger')
expect(queryByText(fixture.name)).toBeInTheDocument()
})
})
await waitFor(() => {
expect(fetch.put).toBeCalledWith(urls.admin.players.name(fixture.pid), {
player_name: 'reina',
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(queryByRole('alert')).toHaveClass('alert-danger');
expect(queryByText(fixture.name)).toBeInTheDocument();
});
});
describe('update owner', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]));
});
it('cancelled', async () => {
const { getByText, queryByText } = render(<PlayersManagement />)
it('cancelled', async () => {
const {getByText, queryByText} = render(<PlayersManagement/>);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changeOwner')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changeOwner')));
fireEvent.click(getByText(t('general.cancel')));
expect(fetch.put).not.toBeCalled()
expect(
queryByText(`${t('general.player.owner')}: ${fixture.uid}`),
).toBeInTheDocument()
})
expect(fetch.put).not.toBeCalled();
expect(
queryByText(`${t('general.player.owner')}: ${fixture.uid}`),
).toBeInTheDocument();
});
it('succeeded', async () => {
fetch.put.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.put.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, getByDisplayValue, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, getByDisplayValue, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changeOwner')))
fireEvent.input(getByDisplayValue(fixture.uid.toString()), {
target: { value: '2' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changeOwner')));
fireEvent.input(getByDisplayValue(fixture.uid.toString()), {
target: {value: '2'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.put).toBeCalledWith(urls.admin.players.owner(fixture.pid), {
uid: 2,
}),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(queryByRole('status')).toHaveClass('alert-success')
expect(queryByText(`${t('general.player.owner')}: 2`)).toBeInTheDocument()
})
await waitFor(() => {
expect(fetch.put).toBeCalledWith(urls.admin.players.owner(fixture.pid), {
uid: 2,
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(queryByRole('status')).toHaveClass('alert-success');
expect(queryByText(`${t('general.player.owner')}: 2`)).toBeInTheDocument();
});
it('failed', async () => {
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.put.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByDisplayValue, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, getByDisplayValue, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changeOwner')))
fireEvent.input(getByDisplayValue(fixture.uid.toString()), {
target: { value: '2' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changeOwner')));
fireEvent.input(getByDisplayValue(fixture.uid.toString()), {
target: {value: '2'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.put).toBeCalledWith(urls.admin.players.owner(fixture.pid), {
uid: 2,
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(queryByRole('alert')).toHaveClass('alert-danger')
expect(
queryByText(`${t('general.player.owner')}: ${fixture.uid}`),
).toBeInTheDocument()
})
})
await waitFor(() => {
expect(fetch.put).toBeCalledWith(urls.admin.players.owner(fixture.pid), {
uid: 2,
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(queryByRole('alert')).toHaveClass('alert-danger');
expect(
queryByText(`${t('general.player.owner')}: ${fixture.uid}`),
).toBeInTheDocument();
});
});
describe('update texture', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]));
});
it('cancelled', async () => {
const { getByText } = render(<PlayersManagement />)
it('cancelled', async () => {
const {getByText} = render(<PlayersManagement/>);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changeTexture')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changeTexture')));
fireEvent.click(getByText(t('general.cancel')));
expect(fetch.put).not.toBeCalled()
})
expect(fetch.put).not.toBeCalled();
});
it('skin', async () => {
fetch.put.mockResolvedValue({ code: 0, message: 'ok' })
it('skin', async () => {
fetch.put.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, getByLabelText, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, getByLabelText, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changeTexture')))
fireEvent.input(getByLabelText('TID'), {
target: { value: '2' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changeTexture')));
fireEvent.input(getByLabelText('TID'), {
target: {value: '2'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.put).toBeCalledWith(
urls.admin.players.texture(fixture.pid),
{
type: 'skin',
tid: 2,
},
),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(queryByRole('status')).toHaveClass('alert-success')
})
await waitFor(() => {
expect(fetch.put).toBeCalledWith(
urls.admin.players.texture(fixture.pid),
{
type: 'skin',
tid: 2,
},
);
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(queryByRole('status')).toHaveClass('alert-success');
});
it('cape', async () => {
fetch.put.mockResolvedValue({ code: 0, message: 'ok' })
it('cape', async () => {
fetch.put.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, getByLabelText, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, getByLabelText, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changeTexture')))
fireEvent.click(getByLabelText(t('general.cape')))
fireEvent.input(getByLabelText('TID'), {
target: { value: '2' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changeTexture')));
fireEvent.click(getByLabelText(t('general.cape')));
fireEvent.input(getByLabelText('TID'), {
target: {value: '2'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.put).toBeCalledWith(
urls.admin.players.texture(fixture.pid),
{
type: 'cape',
tid: 2,
},
),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(queryByRole('status')).toHaveClass('alert-success')
})
await waitFor(() => {
expect(fetch.put).toBeCalledWith(
urls.admin.players.texture(fixture.pid),
{
type: 'cape',
tid: 2,
},
);
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(queryByRole('status')).toHaveClass('alert-success');
});
it('failed', async () => {
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.put.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByLabelText, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, getByLabelText, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.changeTexture')))
fireEvent.input(getByLabelText('TID'), {
target: { value: '2' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.changeTexture')));
fireEvent.input(getByLabelText('TID'), {
target: {value: '2'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.put).toBeCalledWith(
urls.admin.players.texture(fixture.pid),
{
type: 'skin',
tid: 2,
},
),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(queryByRole('alert')).toHaveClass('alert-danger')
})
})
await waitFor(() => {
expect(fetch.put).toBeCalledWith(
urls.admin.players.texture(fixture.pid),
{
type: 'skin',
tid: 2,
},
);
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(queryByRole('alert')).toHaveClass('alert-danger');
});
});
describe('delete player', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]));
});
it('cancelled', async () => {
const { getByText, queryByText } = render(<PlayersManagement />)
it('cancelled', async () => {
const {getByText, queryByText} = render(<PlayersManagement/>);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.deletePlayer')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.deletePlayer')));
fireEvent.click(getByText(t('general.cancel')));
expect(fetch.del).not.toBeCalled()
expect(queryByText(fixture.name)).toBeInTheDocument()
})
expect(fetch.del).not.toBeCalled();
expect(queryByText(fixture.name)).toBeInTheDocument();
});
it('succeeded', async () => {
fetch.del.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.del.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.deletePlayer')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.deletePlayer')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.del).toBeCalledWith(urls.admin.players.delete(fixture.pid)),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(queryByRole('status')).toHaveClass('alert-success')
expect(queryByText(fixture.name)).not.toBeInTheDocument()
})
await waitFor(() => {
expect(fetch.del).toBeCalledWith(urls.admin.players.delete(fixture.pid));
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(queryByRole('status')).toHaveClass('alert-success');
expect(queryByText(fixture.name)).not.toBeInTheDocument();
});
it('failed', async () => {
fetch.del.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.del.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, queryByText, queryByRole } = render(
<PlayersManagement />,
)
const {getByText, queryByText, queryByRole} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('admin.deletePlayer')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.deletePlayer')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.del).toBeCalledWith(urls.admin.players.delete(fixture.pid)),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(queryByRole('alert')).toHaveClass('alert-danger')
expect(queryByText(fixture.name)).toBeInTheDocument()
})
})
await waitFor(() => {
expect(fetch.del).toBeCalledWith(urls.admin.players.delete(fixture.pid));
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(queryByRole('alert')).toHaveClass('alert-danger');
expect(queryByText(fixture.name)).toBeInTheDocument();
});
});
describe('table mode', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]));
});
it('large screen', async () => {
Object.assign(window, { innerWidth: 1024 })
it('large screen', async () => {
Object.assign(window, {innerWidth: 1024});
const { queryByText } = render(<PlayersManagement />)
const {queryByText} = render(<PlayersManagement/>);
await waitFor(() => expect(fetch.get).toBeCalled())
expect(queryByText(t('admin.operationsTitle'))).toBeInTheDocument()
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
expect(queryByText(t('admin.operationsTitle'))).toBeInTheDocument();
Object.assign(window, { innerWidth: 500 })
})
Object.assign(window, {innerWidth: 500});
});
it('update player name', async () => {
const { getByText, getByTitle, queryByText } = render(<PlayersManagement />)
it('update player name', async () => {
const {getByText, getByTitle, queryByText} = render(<PlayersManagement/>);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByTitle('Table Mode'))
fireEvent.click(getByTitle(t('admin.changePlayerName')))
expect(queryByText(t('admin.changePlayerNameNotice'))).toBeInTheDocument()
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByTitle('Table Mode'));
fireEvent.click(getByTitle(t('admin.changePlayerName')));
expect(queryByText(t('admin.changePlayerNameNotice'))).toBeInTheDocument();
fireEvent.click(getByText(t('general.cancel')))
})
fireEvent.click(getByText(t('general.cancel')));
});
it('update owner', async () => {
const { getByText, getByTitle, queryByText } = render(<PlayersManagement />)
it('update owner', async () => {
const {getByText, getByTitle, queryByText} = render(<PlayersManagement/>);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByTitle('Table Mode'))
fireEvent.click(getByTitle(t('admin.changeOwner')))
expect(queryByText(t('admin.changePlayerOwner'))).toBeInTheDocument()
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByTitle('Table Mode'));
fireEvent.click(getByTitle(t('admin.changeOwner')));
expect(queryByText(t('admin.changePlayerOwner'))).toBeInTheDocument();
fireEvent.click(getByText(t('general.cancel')))
})
fireEvent.click(getByText(t('general.cancel')));
});
it('update texture', async () => {
const { getByText, getByTitle, queryByPlaceholderText } = render(
<PlayersManagement />,
)
it('update texture', async () => {
const {getByText, getByTitle, queryByPlaceholderText} = render(
<PlayersManagement/>,
);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByTitle('Table Mode'))
fireEvent.click(getByText(t('admin.changeTexture')))
expect(queryByPlaceholderText(t('admin.pidNotice'))).toBeInTheDocument()
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByTitle('Table Mode'));
fireEvent.click(getByText(t('admin.changeTexture')));
expect(queryByPlaceholderText(t('admin.pidNotice'))).toBeInTheDocument();
fireEvent.click(getByText(t('general.cancel')))
})
fireEvent.click(getByText(t('general.cancel')));
});
it('delete player', async () => {
const { getByText, getByTitle, queryByText } = render(<PlayersManagement />)
it('delete player', async () => {
const {getByText, getByTitle, queryByText} = render(<PlayersManagement/>);
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByTitle('Table Mode'))
fireEvent.click(getByText(t('admin.deletePlayer')))
expect(queryByText(t('admin.deletePlayerNotice'))).toBeInTheDocument()
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByTitle('Table Mode'));
fireEvent.click(getByText(t('admin.deletePlayer')));
expect(queryByText(t('admin.deletePlayerNotice'))).toBeInTheDocument();
fireEvent.click(getByText(t('general.cancel')))
})
})
fireEvent.click(getByText(t('general.cancel')));
});
});

View File

@ -1,356 +1,392 @@
import { expect, test, vi, it } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import PluginsManagement from '@/views/admin/PluginsManagement'
import {
expect, test, vi, it,
} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import PluginsManagement from '@/views/admin/PluginsManagement';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
test('show loading indicator', () => {
fetch.get.mockResolvedValue([])
const { queryByTitle } = render(<PluginsManagement />)
expect(queryByTitle('Loading...')).not.toBeNull()
})
fetch.get.mockResolvedValue([]);
const {queryByTitle} = render(<PluginsManagement/>);
expect(queryByTitle('Loading...')).not.toBeNull();
});
test('plugin info box', async () => {
fetch.get.mockResolvedValue([
{
name: 'a',
title: 'My Plugin',
version: '1.0.0',
description: 'desc',
config: true,
readme: true,
icon: {},
enabled: true,
},
{
name: 'b',
title: 'Another Plugin',
version: '0.1.0',
description: '',
config: false,
readme: false,
icon: {},
enabled: false,
},
])
fetch.get.mockResolvedValue([
{
name: 'a',
title: 'My Plugin',
version: '1.0.0',
description: 'desc',
config: true,
readme: true,
icon: {},
enabled: true,
},
{
name: 'b',
title: 'Another Plugin',
version: '0.1.0',
description: '',
config: false,
readme: false,
icon: {},
enabled: false,
},
]);
const { queryByTitle, queryByText } = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {queryByTitle, queryByText} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(queryByTitle(t('admin.configurePlugin'))).not.toBeNull()
expect(queryByTitle(t('admin.pluginReadme'))).not.toBeNull()
expect(queryByText('My Plugin')).not.toBeNull()
expect(queryByText('v1.0.0')).not.toBeNull()
expect(queryByText('desc')).not.toBeNull()
})
expect(queryByTitle(t('admin.configurePlugin'))).not.toBeNull();
expect(queryByTitle(t('admin.pluginReadme'))).not.toBeNull();
expect(queryByText('My Plugin')).not.toBeNull();
expect(queryByText('v1.0.0')).not.toBeNull();
expect(queryByText('desc')).not.toBeNull();
});
describe('enable plugin', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([
{
name: 'a',
icon: {},
enabled: false,
},
])
})
beforeEach(() => {
fetch.get.mockResolvedValue([
{
name: 'a',
icon: {},
enabled: false,
},
]);
});
it('succeeded', async () => {
fetch.get.mockResolvedValue([
{
name: 'a',
icon: {},
enabled: false,
},
])
fetch.post.mockResolvedValue({ code: 0, message: 'success' })
it('succeeded', async () => {
fetch.get.mockResolvedValue([
{
name: 'a',
icon: {},
enabled: false,
},
]);
fetch.post.mockResolvedValue({code: 0, message: 'success'});
const { getByTitle, getByRole, queryByText } = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getByRole, queryByText} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('admin.enablePlugin')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'enable',
name: 'a',
}),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
expect(getByTitle(t('admin.disablePlugin'))).toBeChecked()
})
fireEvent.click(getByTitle(t('admin.enablePlugin')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'enable',
name: 'a',
});
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
expect(getByTitle(t('admin.disablePlugin'))).toBeChecked();
});
it('failed', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'unresolved',
data: { reason: ['abc'] },
})
it('failed', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'unresolved',
data: {reason: ['abc']},
});
const { getByTitle, getByText, queryByText } = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getByText, queryByText} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('admin.enablePlugin')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'enable',
name: 'a',
}),
)
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'enable',
name: 'a',
})
expect(queryByText('unresolved')).toBeInTheDocument()
expect(queryByText('abc')).toBeInTheDocument()
fireEvent.click(getByTitle(t('admin.enablePlugin')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'enable',
name: 'a',
});
},
);
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'enable',
name: 'a',
});
expect(queryByText('unresolved')).toBeInTheDocument();
expect(queryByText('abc')).toBeInTheDocument();
fireEvent.click(getByText(t('general.confirm')))
})
})
fireEvent.click(getByText(t('general.confirm')));
});
});
describe('disable plugin', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([
{
name: 'a',
icon: {},
enabled: true,
},
])
})
beforeEach(() => {
fetch.get.mockResolvedValue([
{
name: 'a',
icon: {},
enabled: true,
},
]);
});
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'success' })
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'success'});
const { getByTitle, getByRole, queryByText } = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getByRole, queryByText} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('admin.disablePlugin')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'disable',
name: 'a',
}),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
expect(getByTitle(t('admin.enablePlugin'))).not.toBeChecked()
})
fireEvent.click(getByTitle(t('admin.disablePlugin')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'disable',
name: 'a',
});
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
expect(getByTitle(t('admin.enablePlugin'))).not.toBeChecked();
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const { getByTitle, getByRole, queryByText } = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getByRole, queryByText} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('admin.disablePlugin')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'disable',
name: 'a',
}),
)
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'disable',
name: 'a',
})
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
})
fireEvent.click(getByTitle(t('admin.disablePlugin')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'disable',
name: 'a',
});
},
);
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'disable',
name: 'a',
});
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
});
describe('delete plugin', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([
{
name: 'a',
title: 'My Plugin',
icon: {},
enabled: false,
},
])
})
beforeEach(() => {
fetch.get.mockResolvedValue([
{
name: 'a',
title: 'My Plugin',
icon: {},
enabled: false,
},
]);
});
it('rejected by user', async () => {
const { getByTitle, getByText } = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('rejected by user', async () => {
const {getByTitle, getByText} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('admin.deletePlugin')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.post).not.toBeCalled())
})
fireEvent.click(getByTitle(t('admin.deletePlugin')));
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.post).not.toBeCalled();
});
});
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'success' })
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'success'});
const { getByTitle, getByText, getByRole, queryByText } = render(
<PluginsManagement />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getByText, getByRole, queryByText} = render(
<PluginsManagement/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('admin.deletePlugin')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'a',
}),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
expect(queryByText('My Plugin')).toBeNull()
})
fireEvent.click(getByTitle(t('admin.deletePlugin')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'a',
});
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
expect(queryByText('My Plugin')).toBeNull();
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const { getByTitle, getByText, getByRole, queryByText } = render(
<PluginsManagement />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getByText, getByRole, queryByText} = render(
<PluginsManagement/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('admin.deletePlugin')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'a',
}),
)
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'a',
})
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
expect(queryByText('My Plugin')).not.toBeNull()
})
})
fireEvent.click(getByTitle(t('admin.deletePlugin')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'a',
});
},
);
expect(fetch.post).toBeCalledWith('/admin/plugins/manage', {
action: 'delete',
name: 'a',
});
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
expect(queryByText('My Plugin')).not.toBeNull();
});
});
describe('upload plugin archive', () => {
it('no selected file', async () => {
fetch.get.mockResolvedValue([])
it('no selected file', async () => {
fetch.get.mockResolvedValue([]);
const { getAllByText } = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getAllByText} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getAllByText(t('general.submit'))[0]!)
expect(fetch.post).not.toBeCalled()
})
fireEvent.click(getAllByText(t('general.submit'))[0]);
expect(fetch.post).not.toBeCalled();
});
it('succeeded', async () => {
fetch.get.mockResolvedValue([])
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.get.mockResolvedValue([]);
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const { getByTitle, getAllByText, getByRole, queryByText } = render(
<PluginsManagement />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getAllByText, getByRole, queryByText} = render(
<PluginsManagement/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
const file = new File([], 'plugin.zip')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.click(getAllByText(t('general.submit'))[0]!)
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(2)
expect(fetch.post).toBeCalledWith(
'/admin/plugins/upload',
expect.any(FormData),
)
})
const formData = fetch.post.mock.calls[0]![1] as FormData
expect(formData.get('file')).toStrictEqual(file)
expect(queryByText('plugin.zip')).not.toBeInTheDocument()
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
})
const file = new File([], 'plugin.zip');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.click(getAllByText(t('general.submit'))[0]);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(2);
expect(fetch.post).toBeCalledWith(
'/admin/plugins/upload',
expect.any(FormData),
);
});
const formData = fetch.post.mock.calls[0]![1] as FormData;
expect(formData.get('file')).toStrictEqual(file);
expect(queryByText('plugin.zip')).not.toBeInTheDocument();
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
});
it('failed', async () => {
fetch.get.mockResolvedValue([])
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.get.mockResolvedValue([]);
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const { getByTitle, getAllByText, getByRole, queryByText } = render(
<PluginsManagement />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getAllByText, getByRole, queryByText} = render(
<PluginsManagement/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
const file = new File([], 'plugin.zip')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.click(getAllByText(t('general.submit'))[0]!)
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1)
expect(fetch.post).toBeCalledWith(
'/admin/plugins/upload',
expect.any(FormData),
)
})
expect(queryByText('plugin.zip')).toBeInTheDocument()
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
})
const file = new File([], 'plugin.zip');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.click(getAllByText(t('general.submit'))[0]);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
expect(fetch.post).toBeCalledWith(
'/admin/plugins/upload',
expect.any(FormData),
);
});
expect(queryByText('plugin.zip')).toBeInTheDocument();
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
});
describe('submit remote URL', () => {
it('succeeded', async () => {
fetch.get.mockResolvedValue([])
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.get.mockResolvedValue([]);
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const {
getByLabelText,
getAllByText,
getByRole,
queryByText,
queryByDisplayValue,
} = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {
getByLabelText,
getAllByText,
getByRole,
queryByText,
queryByDisplayValue,
} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.input(getByLabelText('URL'), {
target: { value: 'https://example.com/a.zip' },
})
fireEvent.click(getAllByText(t('general.submit'))[1]!)
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(2)
expect(fetch.post).toBeCalledWith('/admin/plugins/wget', {
url: 'https://example.com/a.zip',
})
})
expect(
queryByDisplayValue('https://example.com/a.zip'),
).not.toBeInTheDocument()
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
})
fireEvent.input(getByLabelText('URL'), {
target: {value: 'https://example.com/a.zip'},
});
fireEvent.click(getAllByText(t('general.submit'))[1]);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(2);
expect(fetch.post).toBeCalledWith('/admin/plugins/wget', {
url: 'https://example.com/a.zip',
});
});
expect(
queryByDisplayValue('https://example.com/a.zip'),
).not.toBeInTheDocument();
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
});
it('failed', async () => {
fetch.get.mockResolvedValue([])
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.get.mockResolvedValue([]);
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const {
getByLabelText,
getAllByText,
getByRole,
queryByText,
queryByDisplayValue,
} = render(<PluginsManagement />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {
getByLabelText,
getAllByText,
getByRole,
queryByText,
queryByDisplayValue,
} = render(<PluginsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.input(getByLabelText('URL'), {
target: { value: 'https://example.com/a.zip' },
})
fireEvent.click(getAllByText(t('general.submit'))[1]!)
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1)
expect(fetch.post).toBeCalledWith('/admin/plugins/wget', {
url: 'https://example.com/a.zip',
})
})
expect(queryByDisplayValue('https://example.com/a.zip')).toBeInTheDocument()
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
})
fireEvent.input(getByLabelText('URL'), {
target: {value: 'https://example.com/a.zip'},
});
fireEvent.click(getAllByText(t('general.submit'))[1]);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
expect(fetch.post).toBeCalledWith('/admin/plugins/wget', {
url: 'https://example.com/a.zip',
});
});
expect(queryByDisplayValue('https://example.com/a.zip')).toBeInTheDocument();
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
});

View File

@ -1,213 +1,238 @@
import { expect, test, vi, it } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import PluginsMarket from '@/views/admin/PluginsMarket'
import type { Plugin } from '@/views/admin/PluginsMarket/types'
import {
expect, test, vi, it,
} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import PluginsMarket from '@/views/admin/PluginsMarket';
import type {Plugin} from '@/views/admin/PluginsMarket/types';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
const fixture: Readonly<Plugin> = Object.freeze<Readonly<Plugin>>({
name: 'yggdrasil-api',
title: 'Yggdrasil API',
description: 'Auth System',
version: '1.0.0',
author: 'Blessing Skin',
installed: false,
dependencies: {
all: {
'blessing-skin-server': '^5.0.0',
},
unsatisfied: {},
},
})
name: 'yggdrasil-api',
title: 'Yggdrasil API',
description: 'Auth System',
version: '1.0.0',
author: 'Blessing Skin',
installed: false,
dependencies: {
all: {
'blessing-skin-server': '^5.0.0',
},
unsatisfied: {},
},
});
test('search plugins', async () => {
fetch.get.mockResolvedValue([fixture])
fetch.get.mockResolvedValue([fixture]);
const { getByPlaceholderText, queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByPlaceholderText, queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.input(getByPlaceholderText(t('vendor.datatable.search')), {
target: { value: 'test' },
})
expect(queryByText('yggdrasil-api')).not.toBeInTheDocument()
})
fireEvent.input(getByPlaceholderText(t('vendor.datatable.search')), {
target: {value: 'test'},
});
expect(queryByText('yggdrasil-api')).not.toBeInTheDocument();
});
test('install a plugin after first page', async () => {
const plugins = Array.from({ length: 10 }).map(() => {
return { ...fixture, name: `${fixture.name}_${Math.random()}` }
})
plugins.push(fixture)
fetch.get.mockResolvedValue(plugins)
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const plugins = Array.from({length: 10}).map(() => ({...fixture, name: `${fixture.name}_${Math.random()}`}));
plugins.push(fixture);
fetch.get.mockResolvedValue(plugins);
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, queryByText, queryAllByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, queryByText, queryAllByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText('2'))
fireEvent.click(getByText(t('admin.installPlugin')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
}),
)
expect(queryByText(t('admin.installPlugin'))).toBeDisabled()
fireEvent.click(getByText('2'));
fireEvent.click(getByText(t('admin.installPlugin')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
});
},
);
expect(queryByText(t('admin.installPlugin'))).toBeDisabled();
fireEvent.click(getByText('1'))
expect(queryAllByText(t('admin.installPlugin'))[0]).toBeEnabled()
})
fireEvent.click(getByText('1'));
expect(queryAllByText(t('admin.installPlugin'))[0]).toBeEnabled();
});
describe('dependencies', () => {
it('no dependencies', async () => {
fetch.get.mockResolvedValue([
{ ...fixture, dependencies: { all: {}, unsatisfied: {} } },
])
it('no dependencies', async () => {
fetch.get.mockResolvedValue([
{...fixture, dependencies: {all: {}, unsatisfied: {}}},
]);
const { queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
expect(queryByText(t('admin.noDependencies'))).toBeInTheDocument()
})
const {queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
expect(queryByText(t('admin.noDependencies'))).toBeInTheDocument();
});
it('satisfied dependencies', async () => {
fetch.get.mockResolvedValue([fixture])
it('satisfied dependencies', async () => {
fetch.get.mockResolvedValue([fixture]);
const { queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
expect(
queryByText(
`blessing-skin-server: ${fixture.dependencies.all['blessing-skin-server']}`,
),
).toHaveClass('bg-green')
})
const {queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
expect(
queryByText(
`blessing-skin-server: ${fixture.dependencies.all['blessing-skin-server']}`,
),
).toHaveClass('bg-green');
});
it('unsatisfied dependencies', async () => {
fetch.get.mockResolvedValue([
{
...fixture,
dependencies: {
all: { 'blessing-skin-server': '^5.0.0' },
unsatisfied: { 'blessing-skin-server': '4.0.0' },
},
},
])
it('unsatisfied dependencies', async () => {
fetch.get.mockResolvedValue([
{
...fixture,
dependencies: {
all: {'blessing-skin-server': '^5.0.0'},
unsatisfied: {'blessing-skin-server': '4.0.0'},
},
},
]);
const { queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
expect(
queryByText(
`blessing-skin-server: ${fixture.dependencies.all['blessing-skin-server']}`,
),
).toHaveClass('bg-red')
})
})
const {queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
expect(
queryByText(
`blessing-skin-server: ${fixture.dependencies.all['blessing-skin-server']}`,
),
).toHaveClass('bg-red');
});
});
describe('install plugin', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([fixture])
})
beforeEach(() => {
fetch.get.mockResolvedValue([fixture]);
});
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, queryByRole, queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, queryByRole, queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.installPlugin')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
}),
)
expect(queryByText(t('admin.installPlugin'))).toBeDisabled()
expect(queryByText('ok')).toBeInTheDocument()
expect(queryByRole('status')).toHaveClass('alert-success')
})
fireEvent.click(getByText(t('admin.installPlugin')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
});
},
);
expect(queryByText(t('admin.installPlugin'))).toBeDisabled();
expect(queryByText('ok')).toBeInTheDocument();
expect(queryByRole('status')).toHaveClass('alert-success');
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.installPlugin')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(queryByText(t('admin.installPlugin'))).toBeEnabled()
fireEvent.click(getByText(t('admin.installPlugin')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(queryByText(t('admin.installPlugin'))).toBeEnabled();
fireEvent.click(getByText(t('general.confirm')))
})
fireEvent.click(getByText(t('general.confirm')));
});
it('failed with unsatisfied', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: { reason: ['version is too low'] },
})
it('failed with unsatisfied', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: {reason: ['version is too low']},
});
const { getByText, queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.installPlugin')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(queryByText('version is too low')).toBeInTheDocument()
expect(queryByText(t('admin.installPlugin'))).toBeEnabled()
fireEvent.click(getByText(t('admin.installPlugin')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(queryByText('version is too low')).toBeInTheDocument();
expect(queryByText(t('admin.installPlugin'))).toBeEnabled();
fireEvent.click(getByText(t('general.confirm')))
})
})
fireEvent.click(getByText(t('general.confirm')));
});
});
describe('update plugin', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([
{ ...fixture, can_update: true, installed: '0.5.0' },
])
})
beforeEach(() => {
fetch.get.mockResolvedValue([
{...fixture, can_update: true, installed: '0.5.0'},
]);
});
it('cancelled', async () => {
const { getByText, queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('cancelled', async () => {
const {getByText, queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.updatePlugin')))
expect(
queryByText(
t('admin.confirmUpdate', {
plugin: fixture.title,
old: '0.5.0',
new: fixture.version,
}),
),
).toBeInTheDocument()
fireEvent.click(getByText(t('admin.updatePlugin')));
expect(
queryByText(
t('admin.confirmUpdate', {
plugin: fixture.title,
old: '0.5.0',
new: fixture.version,
}),
),
).toBeInTheDocument();
fireEvent.click(getByText(t('general.cancel')))
expect(fetch.post).not.toBeCalled()
})
fireEvent.click(getByText(t('general.cancel')));
expect(fetch.post).not.toBeCalled();
});
it('confirm to update', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
it('confirm to update', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, queryByText } = render(<PluginsMarket />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, queryByText} = render(<PluginsMarket/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('admin.updatePlugin')))
fireEvent.click(getByText(t('general.confirm')))
fireEvent.click(getByText(t('admin.updatePlugin')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
}),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(queryByText(t('admin.updatePlugin'))).not.toBeInTheDocument()
expect(queryByText(t('admin.installPlugin'))).toBeDisabled()
})
})
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/admin/plugins/market/download', {
name: fixture.name,
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(queryByText(t('admin.updatePlugin'))).not.toBeInTheDocument();
expect(queryByText(t('admin.installPlugin'))).toBeDisabled();
});
});

View File

@ -1,205 +1,227 @@
import { expect, test, vi, it } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { type Texture, TextureType, type User, UserPermission } from '@/scripts/types'
import ReportsManagement from '@/views/admin/ReportsManagement'
import { type Report, Status } from '@/views/admin/ReportsManagement/types'
import {
expect, test, vi, it,
} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {createPaginator} from '../../utils';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import {
type Texture, TextureType, type User, UserPermission,
} from '@/scripts/types';
import ReportsManagement from '@/views/admin/ReportsManagement';
import {type Report, Status} from '@/views/admin/ReportsManagement/types';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
const fixture: Readonly<Report> = Object.freeze<Report>({
id: 1,
tid: 1,
texture: null,
uploader: 1,
texture_uploader: Object.freeze<Readonly<User>>({
uid: 1,
email: 'a@b.c',
nickname: 'abc',
locale: 'en',
score: 1000,
avatar: 0,
permission: UserPermission.Normal,
ip: '::1',
is_dark_mode: false,
last_sign_at: new Date().toString(),
register_at: new Date().toString(),
verified: true,
}),
reporter: 2,
informer: Object.freeze<Readonly<User>>({
uid: 1,
email: 'a@b.c',
nickname: 'abc',
locale: 'en',
score: 1000,
avatar: 0,
permission: UserPermission.Normal,
ip: '::1',
is_dark_mode: false,
last_sign_at: new Date().toString(),
register_at: new Date().toString(),
verified: true,
}),
reason: 'nsfw',
status: Status.Pending,
report_at: new Date().toString(),
})
id: 1,
tid: 1,
texture: null,
uploader: 1,
texture_uploader: Object.freeze<Readonly<User>>({
uid: 1,
email: 'a@b.c',
nickname: 'abc',
locale: 'en',
score: 1000,
avatar: 0,
permission: UserPermission.Normal,
ip: '::1',
is_dark_mode: false,
last_sign_at: new Date().toString(),
register_at: new Date().toString(),
verified: true,
}),
reporter: 2,
informer: Object.freeze<Readonly<User>>({
uid: 1,
email: 'a@b.c',
nickname: 'abc',
locale: 'en',
score: 1000,
avatar: 0,
permission: UserPermission.Normal,
ip: '::1',
is_dark_mode: false,
last_sign_at: new Date().toString(),
register_at: new Date().toString(),
verified: true,
}),
reason: 'nsfw',
status: Status.Pending,
report_at: new Date().toString(),
});
test('search reports', async () => {
fetch.get.mockResolvedValue(createPaginator([]))
fetch.get.mockResolvedValue(createPaginator([]));
const { getByTitle, getByText } = render(<ReportsManagement />)
await waitFor(() =>
expect(fetch.get).toBeCalledWith('/admin/reports/list', {
q: 'status:0 sort:-report_at',
page: 1,
}),
)
const {getByTitle, getByText} = render(<ReportsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalledWith('/admin/reports/list', {
q: 'status:0 sort:-report_at',
page: 1,
});
},
);
fireEvent.input(getByTitle(t('vendor.datatable.search')), {
target: { value: 's' },
})
fireEvent.click(getByText(t('vendor.datatable.search')))
await waitFor(() =>
expect(fetch.get).toBeCalledWith('/admin/reports/list', {
q: 's',
page: 1,
}),
)
})
fireEvent.input(getByTitle(t('vendor.datatable.search')), {
target: {value: 's'},
});
fireEvent.click(getByText(t('vendor.datatable.search')));
await waitFor(() => {
expect(fetch.get).toBeCalledWith('/admin/reports/list', {
q: 's',
page: 1,
});
},
);
});
test('empty reporter or texture uploader', () => {
const report = { ...fixture, texture_uploader: null, informer: null }
fetch.get.mockResolvedValue(createPaginator([report]))
const report = {...fixture, texture_uploader: null, informer: null};
fetch.get.mockResolvedValue(createPaginator([report]));
render(<ReportsManagement />)
})
render(<ReportsManagement/>);
});
test('preview texture', async () => {
const texture: Texture = {
tid: fixture.tid,
name: 'cape',
type: TextureType.Cape,
hash: 'def',
size: 2,
uploader: fixture.uploader,
public: true,
upload_at: new Date().toString(),
likes: 1,
}
fetch.get.mockResolvedValue(createPaginator([{ ...fixture, texture }]))
const texture: Texture = {
tid: fixture.tid,
name: 'cape',
type: TextureType.Cape,
hash: 'def',
size: 2,
uploader: fixture.uploader,
public: true,
upload_at: new Date().toString(),
likes: 1,
};
fetch.get.mockResolvedValue(createPaginator([{...fixture, texture}]));
const { getByAltText } = render(<ReportsManagement />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByAltText} = render(<ReportsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByAltText(fixture.tid.toString()))
})
fireEvent.click(getByAltText(fixture.tid.toString()));
});
describe('proceed report', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixture]));
});
describe('ban uploader', () => {
it('succeeded', async () => {
fetch.put.mockResolvedValue({
code: 0,
message: 'ok',
data: { status: Status.Resolved },
})
describe('ban uploader', () => {
it('succeeded', async () => {
fetch.put.mockResolvedValue({
code: 0,
message: 'ok',
data: {status: Status.Resolved},
});
const { getByText, getByRole, queryByText } = render(
<ReportsManagement />,
)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, getByRole, queryByText} = render(
<ReportsManagement/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('report.ban')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/admin/reports/${fixture.id}`, {
action: 'ban',
}),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toBeInTheDocument()
expect(queryByText(t('report.status.1'))).toBeInTheDocument()
})
fireEvent.click(getByText(t('report.ban')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/admin/reports/${fixture.id}`, {
action: 'ban',
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toBeInTheDocument();
expect(queryByText(t('report.status.1'))).toBeInTheDocument();
});
it('failed', async () => {
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.put.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByRole, queryByText } = render(
<ReportsManagement />,
)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, getByRole, queryByText} = render(
<ReportsManagement/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('report.ban')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/admin/reports/${fixture.id}`, {
action: 'ban',
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toBeInTheDocument()
expect(queryByText(t('report.status.0'))).toBeInTheDocument()
})
})
fireEvent.click(getByText(t('report.ban')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/admin/reports/${fixture.id}`, {
action: 'ban',
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toBeInTheDocument();
expect(queryByText(t('report.status.0'))).toBeInTheDocument();
});
});
describe('delete texture', () => {
it('cancelled', async () => {
const { getByText } = render(<ReportsManagement />)
await waitFor(() => expect(fetch.get).toBeCalled())
describe('delete texture', () => {
it('cancelled', async () => {
const {getByText} = render(<ReportsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('skinlib.show.delete-texture')))
fireEvent.click(getByText(t('general.cancel')))
expect(fetch.put).not.toBeCalled()
})
fireEvent.click(getByText(t('skinlib.show.delete-texture')));
fireEvent.click(getByText(t('general.cancel')));
expect(fetch.put).not.toBeCalled();
});
it('succeeded', async () => {
fetch.put.mockResolvedValue({
code: 0,
message: 'ok',
data: { status: Status.Resolved },
})
it('succeeded', async () => {
fetch.put.mockResolvedValue({
code: 0,
message: 'ok',
data: {status: Status.Resolved},
});
const { getByText, getByRole, queryByText } = render(
<ReportsManagement />,
)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, getByRole, queryByText} = render(
<ReportsManagement/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('skinlib.show.delete-texture')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/admin/reports/${fixture.id}`, {
action: 'delete',
}),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toBeInTheDocument()
expect(queryByText(t('report.status.1'))).toBeInTheDocument()
})
})
fireEvent.click(getByText(t('skinlib.show.delete-texture')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/admin/reports/${fixture.id}`, {
action: 'delete',
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toBeInTheDocument();
expect(queryByText(t('report.status.1'))).toBeInTheDocument();
});
});
it('reject report', async () => {
fetch.put.mockResolvedValue({
code: 0,
message: 'ok',
data: { status: Status.Rejected },
})
it('reject report', async () => {
fetch.put.mockResolvedValue({
code: 0,
message: 'ok',
data: {status: Status.Rejected},
});
const { getByText, getByRole, queryByText } = render(<ReportsManagement />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, getByRole, queryByText} = render(<ReportsManagement/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('report.reject')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/admin/reports/${fixture.id}`, {
action: 'reject',
}),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toBeInTheDocument()
expect(queryByText(t('report.status.2'))).toBeInTheDocument()
})
})
fireEvent.click(getByText(t('report.reject')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/admin/reports/${fixture.id}`, {
action: 'reject',
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toBeInTheDocument();
expect(queryByText(t('report.status.2'))).toBeInTheDocument();
});
});

View File

@ -1,126 +1,147 @@
import { expect, test, vi, it } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import Translations from '@/views/admin/Translations'
import type { Line } from '@/views/admin/Translations/types'
import {
expect, test, vi, it,
} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {createPaginator} from '../../utils';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import Translations from '@/views/admin/Translations';
import type {Line} from '@/views/admin/Translations/types';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
const fixtureLine: Readonly<Line> = Object.freeze<Line>({
id: 1,
group: 'general',
key: 'submit',
text: {
en: 'Submit',
},
})
id: 1,
group: 'general',
key: 'submit',
text: {
en: 'Submit',
},
});
test('empty text', async () => {
const line = { ...fixtureLine, text: { en: '' } }
fetch.get.mockResolvedValue(createPaginator([line]))
const line = {...fixtureLine, text: {en: ''}};
fetch.get.mockResolvedValue(createPaginator([line]));
const { queryByText } = render(<Translations />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
expect(queryByText(t('admin.i18n.empty'))).toBeInTheDocument()
})
const {queryByText} = render(<Translations/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(queryByText(t('admin.i18n.empty'))).toBeInTheDocument();
});
describe('edit line', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixtureLine]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixtureLine]));
});
it('succeeded', async () => {
fetch.put.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.put.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, getByDisplayValue, getByRole, queryByText } = render(
<Translations />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByDisplayValue, getByRole, queryByText} = render(
<Translations/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('admin.i18n.modify')))
fireEvent.input(getByDisplayValue(fixtureLine.text.en!), {
target: { value: 'finish' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/admin/i18n/${fixtureLine.id}`, {
text: 'finish',
}),
)
expect(queryByText('finish')).toBeInTheDocument()
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
})
fireEvent.click(getByText(t('admin.i18n.modify')));
fireEvent.input(getByDisplayValue(fixtureLine.text.en), {
target: {value: 'finish'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/admin/i18n/${fixtureLine.id}`, {
text: 'finish',
});
},
);
expect(queryByText('finish')).toBeInTheDocument();
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
});
it('failed', async () => {
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.put.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByDisplayValue, getByRole, queryByText } = render(
<Translations />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByDisplayValue, getByRole, queryByText} = render(
<Translations/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('admin.i18n.modify')))
fireEvent.input(getByDisplayValue(fixtureLine.text.en!), {
target: { value: 'finish' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/admin/i18n/${fixtureLine.id}`, {
text: 'finish',
}),
)
expect(queryByText(fixtureLine.text.en!)).toBeInTheDocument()
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
fireEvent.click(getByText(t('admin.i18n.modify')));
fireEvent.input(getByDisplayValue(fixtureLine.text.en), {
target: {value: 'finish'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/admin/i18n/${fixtureLine.id}`, {
text: 'finish',
});
},
);
expect(queryByText(fixtureLine.text.en)).toBeInTheDocument();
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('cancelled', async () => {
const { getByText, getByDisplayValue, queryByText } = render(
<Translations />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancelled', async () => {
const {getByText, getByDisplayValue, queryByText} = render(
<Translations/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('admin.i18n.modify')))
fireEvent.input(getByDisplayValue(fixtureLine.text.en!), {
target: { value: 'finish' },
})
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.put).not.toBeCalled())
expect(queryByText(fixtureLine.text.en!)).toBeInTheDocument()
})
})
fireEvent.click(getByText(t('admin.i18n.modify')));
fireEvent.input(getByDisplayValue(fixtureLine.text.en), {
target: {value: 'finish'},
});
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.put).not.toBeCalled();
});
expect(queryByText(fixtureLine.text.en)).toBeInTheDocument();
});
});
describe('delete line', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixtureLine]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([fixtureLine]));
});
it('succeeded', async () => {
fetch.del.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.del.mockResolvedValue({code: 0, message: 'ok'});
const { getByText, getByRole, queryByText } = render(<Translations />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByRole, queryByText} = render(<Translations/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('admin.i18n.delete')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.del).toBeCalledWith(`/admin/i18n/${fixtureLine.id}`),
)
expect(queryByText(fixtureLine.text.en!)).not.toBeInTheDocument()
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
})
fireEvent.click(getByText(t('admin.i18n.delete')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalledWith(`/admin/i18n/${fixtureLine.id}`);
},
);
expect(queryByText(fixtureLine.text.en)).not.toBeInTheDocument();
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
});
it('cancelled', async () => {
const { getByText, queryByText } = render(<Translations />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancelled', async () => {
const {getByText, queryByText} = render(<Translations/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('admin.i18n.delete')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.del).not.toBeCalled())
expect(queryByText(fixtureLine.text.en!)).toBeInTheDocument()
})
})
fireEvent.click(getByText(t('admin.i18n.delete')));
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.del).not.toBeCalled();
});
expect(queryByText(fixtureLine.text.en)).toBeInTheDocument();
});
});

View File

@ -1,26 +1,26 @@
import { expect, test, jest } from 'vitest'
import { flushPromises } from '../../utils'
import { showModal } from '@/scripts/notify'
import { post } from '@/scripts/net'
import handler from '@/views/admin/Update'
import {expect, test, jest} from 'vitest';
import {flushPromises} from '../../utils';
import {showModal} from '@/scripts/notify';
import {post} from '@/scripts/net';
import handler from '@/views/admin/Update';
vi.mock('@/scripts/notify')
vi.mock('@/scripts/net')
vi.mock('@/scripts/notify');
vi.mock('@/scripts/net');
test('click button', async () => {
post
.mockResolvedValueOnce({ code: 1, message: 'failed' })
.mockResolvedValue({ code: 0, message: 'ok' })
post
.mockResolvedValueOnce({code: 1, message: 'failed'})
.mockResolvedValue({code: 0, message: 'ok'});
const button = document.createElement('button')
button.addEventListener('click', handler)
const button = document.createElement('button');
button.addEventListener('click', handler);
const event = new MouseEvent('click')
button.dispatchEvent(event)
await flushPromises()
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'failed' })
const event = new MouseEvent('click');
button.dispatchEvent(event);
await flushPromises();
expect(showModal).toBeCalledWith({mode: 'alert', text: 'failed'});
button.dispatchEvent(event)
await flushPromises()
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'ok' })
})
button.dispatchEvent(event);
await flushPromises();
expect(showModal).toBeCalledWith({mode: 'alert', text: 'ok'});
});

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +1,54 @@
import { expect, vi, it } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import urls from '@/scripts/urls'
import Forgot from '@/views/auth/Forgot'
import {expect, vi, it} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import urls from '@/scripts/urls';
import Forgot from '@/views/auth/Forgot';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
describe('submit', () => {
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const { getByPlaceholderText, getByText, queryByText } = render(<Forgot />)
const {getByPlaceholderText, getByText, queryByText} = render(<Forgot/>);
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: { value: 'abc' },
})
fireEvent.click(getByText(t('auth.send')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.forgot(), {
email: 'a@b.c',
captcha: 'abc',
}),
)
expect(queryByText('ok')).toBeInTheDocument()
})
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: {value: 'abc'},
});
fireEvent.click(getByText(t('auth.send')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.forgot(), {
email: 'a@b.c',
captcha: 'abc',
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const { getByPlaceholderText, getByText, queryByText } = render(<Forgot />)
const {getByPlaceholderText, getByText, queryByText} = render(<Forgot/>);
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: { value: 'abc' },
})
fireEvent.click(getByText(t('auth.send')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.forgot(), {
email: 'a@b.c',
captcha: 'abc',
}),
)
expect(queryByText('failed')).toBeInTheDocument()
})
})
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: {value: 'abc'},
});
fireEvent.click(getByText(t('auth.send')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.forgot(), {
email: 'a@b.c',
captcha: 'abc',
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
});
});

View File

@ -1,194 +1,203 @@
import { expect, test, vi, it } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import urls from '@/scripts/urls'
import Login from '@/views/auth/Login'
import {
expect, test, vi, it,
} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import urls from '@/scripts/urls';
import Login from '@/views/auth/Login';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
beforeEach(() => {
window.blessing.extra = { tooManyFails: false }
})
window.blessing.extra = {tooManyFails: false};
});
test('show captcha if too many login fails', () => {
window.blessing.extra = { tooManyFails: true }
const { queryByAltText } = render(<Login />)
expect(queryByAltText(t('auth.captcha'))).toBeInTheDocument()
})
window.blessing.extra = {tooManyFails: true};
const {queryByAltText} = render(<Login/>);
expect(queryByAltText(t('auth.captcha'))).toBeInTheDocument();
});
describe('submit form', () => {
it('succeeded', async () => {
fetch.post.mockResolvedValue({
code: 0,
message: 'ok',
data: { redirectTo: '/user' },
})
it('succeeded', async () => {
fetch.post.mockResolvedValue({
code: 0,
message: 'ok',
data: {redirectTo: '/user'},
});
const { getByPlaceholderText, getByText } = render(<Login />)
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.click(getByText(t('auth.login')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
}),
)
})
const {getByPlaceholderText, getByText} = render(<Login/>);
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.click(getByText(t('auth.login')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
});
},
);
});
it('remember me', async () => {
fetch.post.mockResolvedValue({
code: 0,
message: 'ok',
data: { redirectTo: '/user' },
})
it('remember me', async () => {
fetch.post.mockResolvedValue({
code: 0,
message: 'ok',
data: {redirectTo: '/user'},
});
const { getByPlaceholderText, getByText, getByLabelText } = render(
<Login />,
)
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.click(getByLabelText(t('auth.keep')))
fireEvent.click(getByText(t('auth.login')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: true,
}),
)
})
const {getByPlaceholderText, getByText, getByLabelText} = render(
<Login/>,
);
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.click(getByLabelText(t('auth.keep')));
fireEvent.click(getByText(t('auth.login')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: true,
});
},
);
});
it('failed', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: { login_fails: 1 },
})
it('failed', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: {login_fails: 1},
});
const { getByPlaceholderText, getByText, queryByText } = render(<Login />)
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.click(getByText(t('auth.login')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
}),
)
expect(queryByText('failed')).toBeInTheDocument()
})
const {getByPlaceholderText, getByText, queryByText} = render(<Login/>);
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.click(getByText(t('auth.login')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
});
it('too many fails', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: { login_fails: 4 },
})
it('too many fails', async () => {
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: {login_fails: 4},
});
const { getByPlaceholderText, getByText, queryByText, queryByAltText } =
render(<Login />)
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.click(getByText(t('auth.login')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(queryByText(t('auth.tooManyFails.captcha'))).toBeInTheDocument()
expect(queryByAltText(t('auth.captcha'))).toBeInTheDocument()
const {getByPlaceholderText, getByText, queryByText, queryByAltText}
= render(<Login/>);
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.click(getByText(t('auth.login')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(queryByText(t('auth.tooManyFails.captcha'))).toBeInTheDocument();
expect(queryByAltText(t('auth.captcha'))).toBeInTheDocument();
fireEvent.click(getByText(t('general.confirm')))
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: { value: 'captcha' },
})
fireEvent.click(getByText(t('auth.login')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
captcha: 'captcha',
}),
)
})
fireEvent.click(getByText(t('general.confirm')));
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: {value: 'captcha'},
});
fireEvent.click(getByText(t('auth.login')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
captcha: 'captcha',
});
},
);
});
it('too many fails with normal recaptcha', async () => {
window.blessing.extra.recaptcha = 'sitekey'
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: { login_fails: 4 },
})
it('too many fails with normal recaptcha', async () => {
window.blessing.extra.recaptcha = 'sitekey';
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: {login_fails: 4},
});
const { getByPlaceholderText, getByText, queryByText } = render(<Login />)
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.click(getByText(t('auth.login')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
}),
)
expect(queryByText('failed')).toBeInTheDocument()
})
const {getByPlaceholderText, getByText, queryByText} = render(<Login/>);
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.click(getByText(t('auth.login')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
});
it('too many fails with invisible recaptcha', async () => {
window.blessing.extra.recaptcha = 'sitekey'
window.blessing.extra.invisible = true
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: { login_fails: 4 },
})
it('too many fails with invisible recaptcha', async () => {
window.blessing.extra.recaptcha = 'sitekey';
window.blessing.extra.invisible = true;
fetch.post.mockResolvedValue({
code: 1,
message: 'failed',
data: {login_fails: 4},
});
const { getByPlaceholderText, getByText, queryByText } = render(<Login />)
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.click(getByText(t('auth.login')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(queryByText(t('auth.tooManyFails.recaptcha'))).toBeInTheDocument()
const {getByPlaceholderText, getByText, queryByText} = render(<Login/>);
fireEvent.input(getByPlaceholderText(t('auth.identification')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.click(getByText(t('auth.login')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.login(), {
identification: 'a@b.c',
password: 'password',
keep: false,
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(queryByText(t('auth.tooManyFails.recaptcha'))).toBeInTheDocument();
fireEvent.click(getByText(t('general.confirm')))
})
})
fireEvent.click(getByText(t('general.confirm')));
});
});

View File

@ -1,140 +1,143 @@
import { expect, test, jest } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import urls from '@/scripts/urls'
import Registration from '@/views/auth/Registration'
import {expect, test, jest} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import urls from '@/scripts/urls';
import Registration from '@/views/auth/Registration';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
beforeEach(() => {
window.blessing.extra = { player: false }
})
window.blessing.extra = {player: false};
});
test('confirmation is not matched', () => {
const { getByText, getByPlaceholderText, queryByText } = render(
<Registration />,
)
const {getByText, getByPlaceholderText, queryByText} = render(
<Registration/>,
);
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: { value: 'password1' },
})
fireEvent.input(getByPlaceholderText(t('auth.nickname')), {
target: { value: 't' },
})
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: { value: 'a' },
})
fireEvent.click(getByText(t('auth.register')))
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: {value: 'password1'},
});
fireEvent.input(getByPlaceholderText(t('auth.nickname')), {
target: {value: 't'},
});
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: {value: 'a'},
});
fireEvent.click(getByText(t('auth.register')));
expect(queryByText(t('auth.invalidConfirmPwd'))).toBeInTheDocument()
expect(fetch.post).not.toBeCalled()
})
expect(queryByText(t('auth.invalidConfirmPwd'))).toBeInTheDocument();
expect(fetch.post).not.toBeCalled();
});
test('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const { getByText, getByPlaceholderText, getByRole, queryByText } = render(
<Registration />,
)
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const {getByText, getByPlaceholderText, getByRole, queryByText} = render(
<Registration/>,
);
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.nickname')), {
target: { value: 't' },
})
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: { value: 'a' },
})
fireEvent.click(getByText(t('auth.register')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.register(), {
email: 'a@b.c',
password: 'password',
nickname: 't',
captcha: 'a',
}),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
vi.runAllTimers()
})
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.nickname')), {
target: {value: 't'},
});
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: {value: 'a'},
});
fireEvent.click(getByText(t('auth.register')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.register(), {
email: 'a@b.c',
password: 'password',
nickname: 't',
captcha: 'a',
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
vi.runAllTimers();
});
test('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
const { getByText, getByPlaceholderText, queryByText } = render(
<Registration />,
)
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const {getByText, getByPlaceholderText, queryByText} = render(
<Registration/>,
);
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.nickname')), {
target: { value: 't' },
})
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: { value: 'a' },
})
fireEvent.click(getByText(t('auth.register')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.register(), {
email: 'a@b.c',
password: 'password',
nickname: 't',
captcha: 'a',
}),
)
expect(queryByText('failed')).toBeInTheDocument()
})
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.nickname')), {
target: {value: 't'},
});
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: {value: 'a'},
});
fireEvent.click(getByText(t('auth.register')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.register(), {
email: 'a@b.c',
password: 'password',
nickname: 't',
captcha: 'a',
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
});
test('register with new player', async () => {
window.blessing.extra = { player: true }
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const { getByText, getByPlaceholderText, queryByText } = render(
<Registration />,
)
window.blessing.extra = {player: true};
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const {getByText, getByPlaceholderText, queryByText} = render(
<Registration/>,
);
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: { value: 'a@b.c' },
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.player-name')), {
target: { value: 'player' },
})
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: { value: 'a' },
})
fireEvent.click(getByText(t('auth.register')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.auth.register(), {
email: 'a@b.c',
password: 'password',
player_name: 'player',
captcha: 'a',
}),
)
expect(queryByText('ok')).toBeInTheDocument()
})
fireEvent.input(getByPlaceholderText(t('auth.email')), {
target: {value: 'a@b.c'},
});
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.player-name')), {
target: {value: 'player'},
});
fireEvent.input(getByPlaceholderText(t('auth.captcha')), {
target: {value: 'a'},
});
fireEvent.click(getByText(t('auth.register')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.auth.register(), {
email: 'a@b.c',
password: 'password',
player_name: 'player',
captcha: 'a',
});
},
);
expect(queryByText('ok')).toBeInTheDocument();
});

View File

@ -1,66 +1,68 @@
import { expect, test, jest } from 'vitest'
import { render, waitFor, fireEvent } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import Reset from '@/views/auth/Reset'
import {expect, test, jest} from 'vitest';
import {render, waitFor, fireEvent} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import Reset from '@/views/auth/Reset';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
test('confirmation is not matched', () => {
const { getByText, getByPlaceholderText, queryByText } = render(<Reset />)
const {getByText, getByPlaceholderText, queryByText} = render(<Reset/>);
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: { value: 'password1' },
})
fireEvent.click(getByText(t('auth.reset')))
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: {value: 'password1'},
});
fireEvent.click(getByText(t('auth.reset')));
expect(queryByText(t('auth.invalidConfirmPwd'))).toBeInTheDocument()
expect(fetch.post).not.toBeCalled()
})
expect(queryByText(t('auth.invalidConfirmPwd'))).toBeInTheDocument();
expect(fetch.post).not.toBeCalled();
});
test('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
const { getByText, getByPlaceholderText, getByRole, queryByText } = render(
<Reset />,
)
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
const {getByText, getByPlaceholderText, getByRole, queryByText} = render(
<Reset/>,
);
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: { value: 'password' },
})
fireEvent.click(getByText(t('auth.reset')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(
location.href.replace(blessing.base_url, ''),
{ password: 'password' },
),
)
expect(queryByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
vi.runAllTimers()
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: {value: 'password'},
});
fireEvent.click(getByText(t('auth.reset')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(
location.href.replace(blessing.base_url, ''),
{password: 'password'},
);
},
);
expect(queryByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
vi.runAllTimers();
});
test('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
const { getByText, getByPlaceholderText, queryByText } = render(<Reset />)
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const {getByText, getByPlaceholderText, queryByText} = render(<Reset/>);
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: { value: 'password' },
})
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: { value: 'password' },
})
fireEvent.click(getByText(t('auth.reset')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(
location.href.replace(blessing.base_url, ''),
{ password: 'password' },
),
)
expect(queryByText('failed')).toBeInTheDocument()
})
fireEvent.input(getByPlaceholderText(t('auth.password')), {
target: {value: 'password'},
});
fireEvent.input(getByPlaceholderText(t('auth.repeat-pwd')), {
target: {value: 'password'},
});
fireEvent.click(getByText(t('auth.reset')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(
location.href.replace(blessing.base_url, ''),
{password: 'password'},
);
},
);
expect(queryByText('failed')).toBeInTheDocument();
});

File diff suppressed because it is too large Load Diff

View File

@ -1,443 +1,516 @@
import { expect, test, vi, it, beforeEach } from 'vitest'
import { render, fireEvent, waitFor } from '@testing-library/react'
import { createPaginator } from '../../utils'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { TextureType } from '@/scripts/types'
import urls from '@/scripts/urls'
import SkinLibrary from '@/views/skinlib/SkinLibrary'
import type { LibraryItem } from '@/views/skinlib/SkinLibrary/types'
import {
expect, test, vi, it, beforeEach,
} from 'vitest';
import {render, fireEvent, waitFor} from '@testing-library/react';
import {createPaginator} from '../../utils';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import {TextureType} from '@/scripts/types';
import urls from '@/scripts/urls';
import SkinLibrary from '@/views/skinlib/SkinLibrary';
import type {LibraryItem} from '@/views/skinlib/SkinLibrary/types';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
const fixtureItem: Readonly<LibraryItem> = Object.freeze<LibraryItem>({
tid: 1,
name: 'my skin',
type: TextureType.Steve,
uploader: 1,
nickname: 'me',
public: true,
likes: 70,
})
tid: 1,
name: 'my skin',
type: TextureType.Steve,
uploader: 1,
nickname: 'me',
public: true,
likes: 70,
});
beforeEach(() => {
window.blessing.extra = { currentUid: null }
})
window.blessing.extra = {currentUid: null};
});
test('without authenticated', async () => {
fetch.get.mockResolvedValue(createPaginator([]))
fetch.get.mockResolvedValue(createPaginator([]));
const { queryByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {queryByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
expect(fetch.get).toBeCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('skin')
expect(search.get('sort')).toBe('time')
expect(search.get('page')).toBe('1')
return true
}),
)
expect(fetch.get).not.toBeCalledWith('/user/closet/ids')
expect(queryByText(t('skinlib.seeMyUpload'))).not.toBeInTheDocument()
})
expect(fetch.get).toBeCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('skin');
expect(search.get('sort')).toBe('time');
expect(search.get('page')).toBe('1');
return true;
}),
);
expect(fetch.get).not.toBeCalledWith('/user/closet/ids');
expect(queryByText(t('skinlib.seeMyUpload'))).not.toBeInTheDocument();
});
test('search by keyword', async () => {
fetch.get.mockResolvedValue({ ...createPaginator([]), last_page: 10 })
fetch.get.mockResolvedValue({...createPaginator([]), last_page: 10});
const { getByText, getByTitle, getByPlaceholderText } = render(
<SkinLibrary />,
)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, getByTitle, getByPlaceholderText} = render(
<SkinLibrary/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
// test for resetting page
fireEvent.click(getByText('2'))
// Test for resetting page
fireEvent.click(getByText('2'));
fireEvent.input(getByPlaceholderText(t('vendor.datatable.search')), {
target: { value: 'k' },
})
fireEvent.click(getByTitle(t('vendor.datatable.search')))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('keyword')).toBe('k')
expect(search.get('page')).toBe('1')
return true
}),
),
)
})
fireEvent.input(getByPlaceholderText(t('vendor.datatable.search')), {
target: {value: 'k'},
});
fireEvent.click(getByTitle(t('vendor.datatable.search')));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('keyword')).toBe('k');
expect(search.get('page')).toBe('1');
return true;
}),
);
},
);
});
test('select uploaded by self', async () => {
window.blessing.extra.currentUid = 1
fetch.get.mockResolvedValue({ ...createPaginator([]), last_page: 10 })
window.blessing.extra.currentUid = 1;
fetch.get.mockResolvedValue({...createPaginator([]), last_page: 10});
const { getByText, queryByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, queryByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
// test for resetting page
fireEvent.click(getByText('2'))
// Test for resetting page
fireEvent.click(getByText('2'));
fireEvent.click(getByText(t('skinlib.seeMyUpload')))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('uploader')).toBe('1')
expect(search.get('page')).toBe('1')
return true
}),
),
)
expect(queryByText(t('skinlib.filter.uploader', { uid: 1 })))
})
fireEvent.click(getByText(t('skinlib.seeMyUpload')));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('uploader')).toBe('1');
expect(search.get('page')).toBe('1');
return true;
}),
);
},
);
expect(queryByText(t('skinlib.filter.uploader', {uid: 1})));
});
test('reset query', async () => {
window.blessing.extra.currentUid = 1
fetch.get.mockResolvedValue(createPaginator([]))
window.blessing.extra.currentUid = 1;
fetch.get.mockResolvedValue(createPaginator([]));
const { getByText, getByTitle, getByPlaceholderText, queryByText } = render(
<SkinLibrary />,
)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, getByTitle, getByPlaceholderText, queryByText} = render(
<SkinLibrary/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText('Steve'))
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.input(getByPlaceholderText(t('vendor.datatable.search')), {
target: { value: 'k' },
})
fireEvent.click(getByTitle(t('vendor.datatable.search')))
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('skinlib.seeMyUpload')))
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('skinlib.sort.likes')))
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('skinlib.reset')))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('skin')
expect(search.get('keyword')).toBeNull()
expect(search.get('uploader')).toBeNull()
expect(search.get('sort')).toBe('time')
expect(search.get('page')).toBe('1')
return true
}),
),
)
expect(queryByText(t('skinlib.filter.uploader', { uid: 1 })))
})
fireEvent.click(getByText('Steve'));
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.input(getByPlaceholderText(t('vendor.datatable.search')), {
target: {value: 'k'},
});
fireEvent.click(getByTitle(t('vendor.datatable.search')));
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('skinlib.seeMyUpload')));
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('skinlib.sort.likes')));
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('skinlib.reset')));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('skin');
expect(search.get('keyword')).toBeNull();
expect(search.get('uploader')).toBeNull();
expect(search.get('sort')).toBe('time');
expect(search.get('page')).toBe('1');
return true;
}),
);
},
);
expect(queryByText(t('skinlib.filter.uploader', {uid: 1})));
});
test('browser goes back', async () => {
fetch.get.mockResolvedValue(createPaginator([]))
fetch.get.mockResolvedValue(createPaginator([]));
const { getByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText('Steve'))
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText('Steve'));
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
const state: string = window.history.state
const event = new PopStateEvent('popstate', {
state: state.replace('steve', 'skin'),
})
window.dispatchEvent(event)
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('skin')
return true
}),
),
)
})
const {state} = window.history;
const event = new PopStateEvent('popstate', {
state: state.replace('steve', 'skin'),
});
window.dispatchEvent(event);
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('skin');
return true;
}),
);
},
);
});
test('pagination', async () => {
const response = { ...createPaginator([]), last_page: 2 }
fetch.get.mockResolvedValue(response)
const response = {...createPaginator([]), last_page: 2};
fetch.get.mockResolvedValue(response);
const { getByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText('2'))
fireEvent.click(getByText('2'));
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('page')).toBe('2')
return true
}),
)
})
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('page')).toBe('2');
return true;
}),
);
});
test('library item', async () => {
fetch.get.mockResolvedValue(createPaginator([fixtureItem]))
fetch.get.mockResolvedValue(createPaginator([fixtureItem]));
const { getByText, queryByText, queryAllByText, queryByAltText } = render(
<SkinLibrary />,
)
await waitFor(() => expect(fetch.get).toBeCalled())
const {getByText, queryByText, queryAllByText, queryByAltText} = render(
<SkinLibrary/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
expect(queryAllByText('Steve')).toHaveLength(2)
expect(queryByText(fixtureItem.name)).toBeInTheDocument()
expect(queryByAltText(fixtureItem.name)).toHaveAttribute(
'src',
`/preview/${fixtureItem.tid}?height=150&png`,
)
expect(queryByText(fixtureItem.nickname)).toBeInTheDocument()
expect(queryAllByText('Steve')).toHaveLength(2);
expect(queryByText(fixtureItem.name)).toBeInTheDocument();
expect(queryByAltText(fixtureItem.name)).toHaveAttribute(
'src',
`/preview/${fixtureItem.tid}?height=150&png`,
);
expect(queryByText(fixtureItem.nickname)).toBeInTheDocument();
fireEvent.click(getByText(fixtureItem.nickname))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('uploader')).toBe(fixtureItem.uploader.toString())
return true
}),
),
)
const search = new URLSearchParams(location.search)
expect(search.get('uploader')).toBe(fixtureItem.uploader.toString())
})
fireEvent.click(getByText(fixtureItem.nickname));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('uploader')).toBe(fixtureItem.uploader.toString());
return true;
}),
);
},
);
const search = new URLSearchParams(location.search);
expect(search.get('uploader')).toBe(fixtureItem.uploader.toString());
});
test('private texture', async () => {
const item = { ...fixtureItem, public: false }
fetch.get.mockResolvedValue(createPaginator([item]))
const item = {...fixtureItem, public: false};
fetch.get.mockResolvedValue(createPaginator([item]));
const { queryByTitle } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
const {queryByTitle} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
expect(queryByTitle(t('skinlib.private'))).toBeInTheDocument()
})
expect(queryByTitle(t('skinlib.private'))).toBeInTheDocument();
});
describe('by filter', () => {
beforeEach(() => {
fetch.get.mockResolvedValue({ ...createPaginator([]), last_page: 10 })
})
beforeEach(() => {
fetch.get.mockResolvedValue({...createPaginator([]), last_page: 10});
});
it('skin', async () => {
const { getByText, queryAllByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('skin', async () => {
const {getByText, queryAllByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
// test for resetting page
fireEvent.click(getByText('2'))
// Test for resetting page
fireEvent.click(getByText('2'));
fireEvent.click(getByText('Steve'))
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('general.skin')))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('skin')
expect(search.get('page')).toBe('1')
return true
}),
),
)
expect(queryAllByText(t('general.skin'))).toHaveLength(2)
const search = new URLSearchParams(location.search)
expect(search.get('filter')).toBe('skin')
})
fireEvent.click(getByText('Steve'));
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('general.skin')));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('skin');
expect(search.get('page')).toBe('1');
return true;
}),
);
},
);
expect(queryAllByText(t('general.skin'))).toHaveLength(2);
const search = new URLSearchParams(location.search);
expect(search.get('filter')).toBe('skin');
});
it('steve', async () => {
const { getByText, queryAllByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('steve', async () => {
const {getByText, queryAllByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
// test for resetting page
fireEvent.click(getByText('2'))
// Test for resetting page
fireEvent.click(getByText('2'));
fireEvent.click(getByText('Steve'))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('steve')
expect(search.get('page')).toBe('1')
return true
}),
),
)
expect(queryAllByText('Steve')).toHaveLength(2)
const search = new URLSearchParams(location.search)
expect(search.get('filter')).toBe('steve')
})
fireEvent.click(getByText('Steve'));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('steve');
expect(search.get('page')).toBe('1');
return true;
}),
);
},
);
expect(queryAllByText('Steve')).toHaveLength(2);
const search = new URLSearchParams(location.search);
expect(search.get('filter')).toBe('steve');
});
it('alex', async () => {
const { getByText, queryAllByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('alex', async () => {
const {getByText, queryAllByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
// test for resetting page
fireEvent.click(getByText('2'))
// Test for resetting page
fireEvent.click(getByText('2'));
fireEvent.click(getByText('Alex'))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('alex')
expect(search.get('page')).toBe('1')
return true
}),
),
)
expect(queryAllByText('Alex')).toHaveLength(2)
const search = new URLSearchParams(location.search)
expect(search.get('filter')).toBe('alex')
})
fireEvent.click(getByText('Alex'));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('alex');
expect(search.get('page')).toBe('1');
return true;
}),
);
},
);
expect(queryAllByText('Alex')).toHaveLength(2);
const search = new URLSearchParams(location.search);
expect(search.get('filter')).toBe('alex');
});
it('cape', async () => {
const { getByText, queryAllByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('cape', async () => {
const {getByText, queryAllByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
// test for resetting page
fireEvent.click(getByText('2'))
// Test for resetting page
fireEvent.click(getByText('2'));
fireEvent.click(getByText(t('general.cape')))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('cape')
expect(search.get('page')).toBe('1')
return true
}),
),
)
expect(queryAllByText(t('general.cape'))).toHaveLength(2)
const search = new URLSearchParams(location.search)
expect(search.get('filter')).toBe('cape')
})
})
fireEvent.click(getByText(t('general.cape')));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('filter')).toBe('cape');
expect(search.get('page')).toBe('1');
return true;
}),
);
},
);
expect(queryAllByText(t('general.cape'))).toHaveLength(2);
const search = new URLSearchParams(location.search);
expect(search.get('filter')).toBe('cape');
});
});
describe('sorting', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([]))
})
beforeEach(() => {
fetch.get.mockResolvedValue(createPaginator([]));
});
it('by time', async () => {
const { getByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('by time', async () => {
const {getByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('skinlib.sort.likes')))
await waitFor(() => expect(fetch.get).toBeCalled())
fireEvent.click(getByText(t('skinlib.sort.time')))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('sort')).toBe('time')
return true
}),
),
)
const search = new URLSearchParams(location.search)
expect(search.get('sort')).toBe('time')
})
fireEvent.click(getByText(t('skinlib.sort.likes')));
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('skinlib.sort.time')));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('sort')).toBe('time');
return true;
}),
);
},
);
const search = new URLSearchParams(location.search);
expect(search.get('sort')).toBe('time');
});
it('by likes', async () => {
const { getByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('by likes', async () => {
const {getByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(t('skinlib.sort.likes')))
await waitFor(() =>
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('sort')).toBe('likes')
return true
}),
),
)
const search = new URLSearchParams(location.search)
expect(search.get('sort')).toBe('likes')
})
})
fireEvent.click(getByText(t('skinlib.sort.likes')));
await waitFor(() => {
expect(fetch.get).toHaveBeenLastCalledWith(
urls.skinlib.list(),
expect.toSatisfy((search: URLSearchParams) => {
expect(search.get('sort')).toBe('likes');
return true;
}),
);
},
);
const search = new URLSearchParams(location.search);
expect(search.get('sort')).toBe('likes');
});
});
describe('add to closet', () => {
beforeEach(() => {
fetch.get.mockImplementation((url: string) => {
if (url === urls.skinlib.list()) {
return Promise.resolve(createPaginator([fixtureItem]))
} else {
return Promise.resolve([])
}
})
})
beforeEach(() => {
fetch.get.mockImplementation(async (url: string) => {
if (url === urls.skinlib.list()) {
return createPaginator([fixtureItem]);
}
it('without authenticated', async () => {
const { getByText, queryByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
return [];
});
});
fireEvent.click(getByText(fixtureItem.likes.toString()))
expect(queryByText(t('skinlib.anonymous'))).toBeInTheDocument()
expect(fetch.post).not.toBeCalled()
})
it('without authenticated', async () => {
const {getByText, queryByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
it('succeeded', async () => {
window.blessing.extra.currentUid = 1
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
fireEvent.click(getByText(fixtureItem.likes.toString()));
expect(queryByText(t('skinlib.anonymous'))).toBeInTheDocument();
expect(fetch.post).not.toBeCalled();
});
const { getByText, queryByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('succeeded', async () => {
window.blessing.extra.currentUid = 1;
fetch.post.mockResolvedValue({code: 0, message: 'ok'});
fireEvent.click(getByText(fixtureItem.likes.toString()))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => expect(fetch.post).toBeCalled())
expect(queryByText((fixtureItem.likes + 1).toString())).toBeInTheDocument()
})
const {getByText, queryByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
it('failed', async () => {
window.blessing.extra.currentUid = 1
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
fireEvent.click(getByText(fixtureItem.likes.toString()));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.post).toBeCalled();
});
expect(queryByText((fixtureItem.likes + 1).toString())).toBeInTheDocument();
});
const { getByText, queryByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('failed', async () => {
window.blessing.extra.currentUid = 1;
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
fireEvent.click(getByText(fixtureItem.likes.toString()))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => expect(fetch.post).toBeCalled())
expect(queryByText(fixtureItem.likes.toString())).toBeInTheDocument()
})
})
const {getByText, queryByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(fixtureItem.likes.toString()));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.post).toBeCalled();
});
expect(queryByText(fixtureItem.likes.toString())).toBeInTheDocument();
});
});
describe('remove from closet', () => {
beforeEach(() => {
window.blessing.extra.currentUid = 1
fetch.get.mockImplementation((url: string) => {
if (url === urls.skinlib.list()) {
return Promise.resolve(createPaginator([fixtureItem]))
} else {
return Promise.resolve([fixtureItem.tid])
}
})
})
beforeEach(() => {
window.blessing.extra.currentUid = 1;
fetch.get.mockImplementation(async (url: string) => {
if (url === urls.skinlib.list()) {
return createPaginator([fixtureItem]);
}
it('succeeded', async () => {
fetch.del.mockResolvedValue({ code: 0, message: 'ok' })
return [fixtureItem.tid];
});
});
const { getByText, queryByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('succeeded', async () => {
fetch.del.mockResolvedValue({code: 0, message: 'ok'});
fireEvent.click(getByText(fixtureItem.likes.toString()))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => expect(fetch.del).toBeCalled())
expect(queryByText((fixtureItem.likes - 1).toString())).toBeInTheDocument()
})
const {getByText, queryByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
it('failed', async () => {
fetch.del.mockResolvedValue({ code: 1, message: 'failed' })
fireEvent.click(getByText(fixtureItem.likes.toString()));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalled();
});
expect(queryByText((fixtureItem.likes - 1).toString())).toBeInTheDocument();
});
const { getByText, queryByText } = render(<SkinLibrary />)
await waitFor(() => expect(fetch.get).toBeCalled())
it('failed', async () => {
fetch.del.mockResolvedValue({code: 1, message: 'failed'});
fireEvent.click(getByText(fixtureItem.likes.toString()))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => expect(fetch.del).toBeCalled())
expect(queryByText(fixtureItem.likes.toString())).toBeInTheDocument()
})
})
const {getByText, queryByText} = render(<SkinLibrary/>);
await waitFor(() => {
expect(fetch.get).toBeCalled();
});
fireEvent.click(getByText(fixtureItem.likes.toString()));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalled();
});
expect(queryByText(fixtureItem.likes.toString())).toBeInTheDocument();
});
});

View File

@ -1,271 +1,279 @@
import { expect, test, vi, it, beforeEach, afterEach, describe } from 'vitest'
import { render, fireEvent, waitFor } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { isAlex } from '@/scripts/textureUtils'
import urls from '@/scripts/urls'
import Upload from '@/views/skinlib/Upload'
import {
expect, test, vi, it, beforeEach, afterEach, describe,
} from 'vitest';
import {render, fireEvent, waitFor} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import {isAlex} from '@/scripts/textureUtils';
import urls from '@/scripts/urls';
import Upload from '@/views/skinlib/Upload';
vi.mock('@/scripts/net')
vi.mock('@/scripts/textureUtils')
vi.mock('@/scripts/net');
vi.mock('@/scripts/textureUtils');
beforeEach(() => {
const container = document.createElement('div')
container.id = 'previewer'
document.body.appendChild(container)
const container = document.createElement('div');
container.id = 'previewer';
document.body.append(container);
window.blessing.extra = {
rule: 'rule',
privacyNotice: 'privacy notice',
score: 15,
scorePrivate: 10,
scorePublic: 1,
closetItemCost: 10,
award: 0,
contentPolicy: 'the policy',
}
window.blessing.extra = {
rule: 'rule',
privacyNotice: 'privacy notice',
score: 15,
scorePrivate: 10,
scorePublic: 1,
closetItemCost: 10,
award: 0,
contentPolicy: 'the policy',
};
URL.createObjectURL = vi.fn().mockReturnValue('')
})
URL.createObjectURL = vi.fn().mockReturnValue('');
});
afterEach(() => {
document.querySelector('#previewer')!.remove()
})
document.querySelector('#previewer')!.remove();
});
test('display texture name rule', () => {
const { queryByPlaceholderText } = render(<Upload />)
expect(queryByPlaceholderText('rule')).toBeInTheDocument()
})
const {queryByPlaceholderText} = render(<Upload/>);
expect(queryByPlaceholderText('rule')).toBeInTheDocument();
});
test('content policy', () => {
const { queryByText } = render(<Upload />)
expect(queryByText('the policy')).toBeInTheDocument()
})
const {queryByText} = render(<Upload/>);
expect(queryByText('the policy')).toBeInTheDocument();
});
test('privacy notice', () => {
const { getByLabelText, queryByText } = render(<Upload />)
fireEvent.click(getByLabelText(t('skinlib.upload.set-as-private')))
expect(queryByText('privacy notice')).toBeInTheDocument()
})
const {getByLabelText, queryByText} = render(<Upload/>);
fireEvent.click(getByLabelText(t('skinlib.upload.set-as-private')));
expect(queryByText('privacy notice')).toBeInTheDocument();
});
test('award notice', () => {
Object.assign(window.blessing.extra, { award: 5 })
Object.assign(window.blessing.extra, {award: 5});
const { getByLabelText, queryByText } = render(<Upload />)
expect(
queryByText(t('skinlib.upload.award', { score: 5 })),
).toBeInTheDocument()
const {getByLabelText, queryByText} = render(<Upload/>);
expect(
queryByText(t('skinlib.upload.award', {score: 5})),
).toBeInTheDocument();
fireEvent.click(getByLabelText(t('skinlib.upload.set-as-private')))
expect(
queryByText(t('skinlib.upload.award', { score: 5 })),
).not.toBeInTheDocument()
})
fireEvent.click(getByLabelText(t('skinlib.upload.set-as-private')));
expect(
queryByText(t('skinlib.upload.award', {score: 5})),
).not.toBeInTheDocument();
});
describe('input file', () => {
it('cancelled', () => {
const { getByTitle } = render(<Upload />)
it('cancelled', () => {
const {getByTitle} = render(<Upload/>);
fireEvent.change(getByTitle(t('skinlib.upload.select-file')))
})
fireEvent.change(getByTitle(t('skinlib.upload.select-file')));
});
it('add file', () => {
const { getByTitle, queryByDisplayValue, queryByText } = render(<Upload />)
it('add file', () => {
const {getByTitle, queryByDisplayValue, queryByText} = render(<Upload/>);
const file = new File([], 't.png')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
const file = new File([], 't.png');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
expect(queryByDisplayValue('t')).toBeInTheDocument()
expect(queryByText('t.png')).toBeInTheDocument()
})
expect(queryByDisplayValue('t')).toBeInTheDocument();
expect(queryByText('t.png')).toBeInTheDocument();
});
it('do not overwrite existing name', () => {
const { getByTitle, getByLabelText, queryByDisplayValue, queryByText } =
render(<Upload />)
it('do not overwrite existing name', () => {
const {getByTitle, getByLabelText, queryByDisplayValue, queryByText}
= render(<Upload/>);
fireEvent.input(getByLabelText(t('skinlib.upload.texture-name')), {
target: { value: 'my texture' },
})
fireEvent.input(getByLabelText(t('skinlib.upload.texture-name')), {
target: {value: 'my texture'},
});
const file = new File([], 't.png')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
const file = new File([], 't.png');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
expect(queryByDisplayValue('my texture')).toBeInTheDocument()
expect(queryByText('t.png')).toBeInTheDocument()
})
expect(queryByDisplayValue('my texture')).toBeInTheDocument();
expect(queryByText('t.png')).toBeInTheDocument();
});
it('select skin type automatically', async () => {
isAlex.mockResolvedValue(true)
it('select skin type automatically', async () => {
isAlex.mockResolvedValue(true);
const { getByTitle, findByLabelText } = render(<Upload />)
const {getByTitle, findByLabelText} = render(<Upload/>);
const file = new File([], 't.png')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
const file = new File([], 't.png');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
expect(await findByLabelText('Alex')).toBeChecked()
})
expect(await findByLabelText('Alex')).toBeChecked();
});
it('do not overwrite "cape" type', async () => {
const { getByTitle, getByLabelText, findByLabelText } = render(<Upload />)
it('do not overwrite "cape" type', async () => {
const {getByTitle, getByLabelText, findByLabelText} = render(<Upload/>);
fireEvent.click(getByLabelText(t('general.cape')))
await waitFor(() => {
/* */
})
fireEvent.click(getByLabelText(t('general.cape')));
await waitFor(() => {
/* */
});
const file = new File([], 't.png')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
const file = new File([], 't.png');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
expect(await findByLabelText(t('general.cape'))).toBeChecked()
})
})
expect(await findByLabelText(t('general.cape'))).toBeChecked();
});
});
describe('score cost', () => {
it('public texture', () => {
const { getByTitle, queryByText } = render(<Upload />)
it('public texture', () => {
const {getByTitle, queryByText} = render(<Upload/>);
const file = new File(['content'], 't.png')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
const file = new File(['content'], 't.png');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
expect(
queryByText(t('skinlib.upload.cost', { score: 11 })),
).toBeInTheDocument()
})
expect(
queryByText(t('skinlib.upload.cost', {score: 11})),
).toBeInTheDocument();
});
it('private texture', () => {
const { getByTitle, getByLabelText, queryByText } = render(<Upload />)
it('private texture', () => {
const {getByTitle, getByLabelText, queryByText} = render(<Upload/>);
const file = new File(['content'], 't.png')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.click(getByLabelText(t('skinlib.upload.set-as-private')))
const file = new File(['content'], 't.png');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.click(getByLabelText(t('skinlib.upload.set-as-private')));
expect(
queryByText(t('skinlib.upload.cost', { score: 20 })),
).toBeInTheDocument()
})
})
expect(
queryByText(t('skinlib.upload.cost', {score: 20})),
).toBeInTheDocument();
});
});
describe('upload texture', () => {
it('no file', () => {
const { getByText, getByRole, queryByText } = render(<Upload />)
fireEvent.click(getByText(t('skinlib.upload.button')))
expect(queryByText(t('skinlib.emptyUploadFile'))).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
it('no file', () => {
const {getByText, getByRole, queryByText} = render(<Upload/>);
fireEvent.click(getByText(t('skinlib.upload.button')));
expect(queryByText(t('skinlib.emptyUploadFile'))).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('no name', () => {
const { getByText, getByLabelText, getByTitle, getByRole, queryByText } =
render(<Upload />)
it('no name', () => {
const {getByText, getByLabelText, getByTitle, getByRole, queryByText}
= render(<Upload/>);
const file = new File([], 't.png')
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.input(getByLabelText(t('skinlib.upload.texture-name')), {
target: { value: '' },
})
fireEvent.click(getByText(t('skinlib.upload.button')))
const file = new File([], 't.png');
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.input(getByLabelText(t('skinlib.upload.texture-name')), {
target: {value: ''},
});
fireEvent.click(getByText(t('skinlib.upload.button')));
expect(queryByText(t('skinlib.emptyTextureName'))).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
expect(queryByText(t('skinlib.emptyTextureName'))).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('invalid file type', () => {
const { getByText, getByTitle, getByRole, queryByText } = render(<Upload />)
it('invalid file type', () => {
const {getByText, getByTitle, getByRole, queryByText} = render(<Upload/>);
const file = new File([], 't.png', { type: 'image/jpeg' })
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.click(getByText(t('skinlib.upload.button')))
const file = new File([], 't.png', {type: 'image/jpeg'});
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.click(getByText(t('skinlib.upload.button')));
expect(queryByText(t('skinlib.fileExtError'))).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
expect(queryByText(t('skinlib.fileExtError'))).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('uploading', () => {
fetch.post.mockResolvedValue({ code: 1, message: '' })
it('uploading', () => {
fetch.post.mockResolvedValue({code: 1, message: ''});
const { getByText, getByTitle, queryByText } = render(<Upload />)
const {getByText, getByTitle, queryByText} = render(<Upload/>);
const file = new File([], 't.png', { type: 'image/png' })
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.click(getByText(t('skinlib.upload.button')))
const file = new File([], 't.png', {type: 'image/png'});
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.click(getByText(t('skinlib.upload.button')));
expect(queryByText(t('skinlib.uploading'))).toBeInTheDocument()
expect(fetch.post).toBeCalledWith(
urls.texture.upload(),
expect.any(FormData),
)
expect(queryByText(t('skinlib.uploading'))).toBeInTheDocument();
expect(fetch.post).toBeCalledWith(
urls.texture.upload(),
expect.any(FormData),
);
const formData = fetch.post.mock.calls[0]![1] as FormData
expect(formData.get('name')).toBe('t')
expect(formData.get('type')).toBe('steve')
expect(formData.get('file')).toStrictEqual(file)
expect(formData.get('public')).toBe('1')
})
const formData = fetch.post.mock.calls[0]![1] as FormData;
expect(formData.get('name')).toBe('t');
expect(formData.get('type')).toBe('steve');
expect(formData.get('file')).toStrictEqual(file);
expect(formData.get('public')).toBe('1');
});
it('uploaded successfully', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'ok', tid: 1 })
it('uploaded successfully', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'ok', tid: 1});
const { getByText, getByTitle, getByLabelText } = render(<Upload />)
const {getByText, getByTitle, getByLabelText} = render(<Upload/>);
const file = new File([], 't.png', { type: 'image/png' })
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.click(getByLabelText(t('skinlib.upload.set-as-private')))
fireEvent.click(getByText(t('skinlib.upload.button')))
const file = new File([], 't.png', {type: 'image/png'});
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.click(getByLabelText(t('skinlib.upload.set-as-private')));
fireEvent.click(getByText(t('skinlib.upload.button')));
await waitFor(() => expect(fetch.post).toBeCalled())
const formData = fetch.post.mock.calls[0]![1] as FormData
expect(formData.get('public')).toBe('0')
})
await waitFor(() => {
expect(fetch.post).toBeCalled();
});
const formData = fetch.post.mock.calls[0]![1] as FormData;
expect(formData.get('public')).toBe('0');
});
it('duplicated texture detected', async () => {
fetch.post.mockResolvedValue({ code: 2, message: 'dup', tid: 1 })
it('duplicated texture detected', async () => {
fetch.post.mockResolvedValue({code: 2, message: 'dup', tid: 1});
const { getByText, getByTitle, queryByText } = render(<Upload />)
const {getByText, getByTitle, queryByText} = render(<Upload/>);
const file = new File([], 't.png', { type: 'image/png' })
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.click(getByText(t('skinlib.upload.button')))
const file = new File([], 't.png', {type: 'image/png'});
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.click(getByText(t('skinlib.upload.button')));
await waitFor(() => expect(fetch.post).toBeCalled())
expect(queryByText('dup')).toBeInTheDocument()
await waitFor(() => {
expect(fetch.post).toBeCalled();
});
expect(queryByText('dup')).toBeInTheDocument();
fireEvent.click(getByText(t('user.viewInSkinlib')))
})
fireEvent.click(getByText(t('user.viewInSkinlib')));
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByTitle, getByRole, queryByText } = render(<Upload />)
const {getByText, getByTitle, getByRole, queryByText} = render(<Upload/>);
const file = new File([], 't.png', { type: 'image/png' })
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: { files: [file] },
})
fireEvent.click(getByText(t('skinlib.upload.button')))
const file = new File([], 't.png', {type: 'image/png'});
fireEvent.change(getByTitle(t('skinlib.upload.select-file')), {
target: {files: [file]},
});
fireEvent.click(getByText(t('skinlib.upload.button')));
await waitFor(() => expect(fetch.post).toBeCalled())
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
})
await waitFor(() => {
expect(fetch.post).toBeCalled();
});
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
});

File diff suppressed because it is too large Load Diff

View File

@ -1,173 +1,203 @@
import { expect, vi, it, describe, beforeEach } from 'vitest'
import { render, fireEvent, waitFor } from '@testing-library/react'
import * as fetch from '@/scripts/net'
import { t } from '@/scripts/i18n'
import urls from '@/scripts/urls'
import Dashboard from '@/views/user/Dashboard'
import {
expect, vi, it, describe, beforeEach,
} from 'vitest';
import {render, fireEvent, waitFor} from '@testing-library/react';
import * as fetch from '@/scripts/net';
import {t} from '@/scripts/i18n';
import urls from '@/scripts/urls';
import Dashboard from '@/views/user/Dashboard';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
function scoreInfo(data = {}, user = {}, usage = {}) {
return {
user: { score: 600, lastSignAt: '2018-08-07 16:06:49', ...user },
usage: {
players: 3,
storage: 5,
...usage,
},
rate: {
players: 10,
storage: 1,
},
signAfterZero: false,
signGapTime: '24',
...data,
}
return {
user: {score: 600, lastSignAt: '2018-08-07 16:06:49', ...user},
usage: {
players: 3,
storage: 5,
...usage,
},
rate: {
players: 10,
storage: 1,
},
signAfterZero: false,
signGapTime: '24',
...data,
};
}
describe('info box', () => {
it('players', async () => {
fetch.get.mockResolvedValue(scoreInfo({}, { score: 40 }))
it('players', async () => {
fetch.get.mockResolvedValue(scoreInfo({}, {score: 40}));
const { getByText } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
expect(getByText('3')).toBeInTheDocument()
expect(getByText(/7/)).toBeInTheDocument()
})
const {getByText} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(getByText('3')).toBeInTheDocument();
expect(getByText(/7/)).toBeInTheDocument();
});
describe('storage', () => {
it('in KB', async () => {
fetch.get.mockResolvedValue(
scoreInfo({}, { score: 100 }, { storage: 700 }),
)
describe('storage', () => {
it('in KB', async () => {
fetch.get.mockResolvedValue(
scoreInfo({}, {score: 100}, {storage: 700}),
);
const { getByText } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
expect(getByText('700')).toBeInTheDocument()
expect(getByText(/800/)).toBeInTheDocument()
expect(getByText(/KB/)).toBeInTheDocument()
})
const {getByText} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(getByText('700')).toBeInTheDocument();
expect(getByText(/800/)).toBeInTheDocument();
expect(getByText(/KB/)).toBeInTheDocument();
});
it('in MB', async () => {
fetch.get.mockResolvedValue(
scoreInfo({}, { score: 3072 }, { storage: 4096 }),
)
it('in MB', async () => {
fetch.get.mockResolvedValue(
scoreInfo({}, {score: 3072}, {storage: 4096}),
);
const { getByText } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
expect(getByText('4')).toBeInTheDocument()
expect(getByText(/7/)).toBeInTheDocument()
expect(getByText(/MB/)).toBeInTheDocument()
})
})
})
const {getByText} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(getByText('4')).toBeInTheDocument();
expect(getByText(/7/)).toBeInTheDocument();
expect(getByText(/MB/)).toBeInTheDocument();
});
});
});
describe('sign', () => {
beforeEach(() => {
fetch.get.mockResolvedValue(scoreInfo())
})
beforeEach(() => {
fetch.get.mockResolvedValue(scoreInfo());
});
it('succeeded', async () => {
fetch.post.mockResolvedValue({
code: 0,
message: 'ok',
data: { score: 900 },
})
it('succeeded', async () => {
fetch.post.mockResolvedValue({
code: 0,
message: 'ok',
data: {score: 900},
});
const { getByRole, getByText, queryByText } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByRole, getByText, queryByText} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
const button = getByRole('button')
fireEvent.click(button)
await waitFor(() => expect(fetch.post).toBeCalledWith(urls.user.sign()))
expect(getByText('ok')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
expect(button).toBeDisabled()
expect(queryByText(/905/)).toBeInTheDocument()
})
const button = getByRole('button');
fireEvent.click(button);
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.user.sign());
});
expect(getByText('ok')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
expect(button).toBeDisabled();
expect(queryByText(/905/)).toBeInTheDocument();
});
it('cannot sign', async () => {
fetch.post.mockResolvedValue({ code: 1, message: '' })
it('cannot sign', async () => {
fetch.post.mockResolvedValue({code: 1, message: ''});
const { getByRole, getByText } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByRole, getByText} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByRole('button'))
await waitFor(() => expect(fetch.post).toBeCalledWith(urls.user.sign()))
fireEvent.click(getByRole('button'));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.user.sign());
});
expect(getByText(/2[34]\sh/)).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-warning')
})
expect(getByText(/2[34]\sh/)).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-warning');
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 2, message: 'f' })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 2, message: 'f'});
const { getByRole, getByText } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByRole, getByText} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByRole('button'))
await waitFor(() => expect(fetch.post).toBeCalledWith(urls.user.sign()))
fireEvent.click(getByRole('button'));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.user.sign());
});
expect(getByText('f')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
})
expect(getByText('f')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
});
describe('sign button', () => {
it('should disabled when loading', () => {
fetch.get.mockResolvedValue(scoreInfo())
const { getByRole } = render(<Dashboard />)
expect(getByRole('button')).toBeDisabled()
})
it('should disabled when loading', () => {
fetch.get.mockResolvedValue(scoreInfo());
const {getByRole} = render(<Dashboard/>);
expect(getByRole('button')).toBeDisabled();
});
it('sign is allowed', async () => {
fetch.get.mockResolvedValue(scoreInfo())
const { getByRole } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const button = getByRole('button')
it('sign is allowed', async () => {
fetch.get.mockResolvedValue(scoreInfo());
const {getByRole} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
const button = getByRole('button');
expect(button).toBeEnabled()
expect(button).toHaveTextContent(t('user.sign'))
})
expect(button).toBeEnabled();
expect(button).toHaveTextContent(t('user.sign'));
});
it('sign is allowed if last sign is yesterday', async () => {
fetch.get.mockResolvedValue(scoreInfo({ signAfterZero: true }))
const { getByRole } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
expect(getByRole('button')).toBeEnabled()
})
it('sign is allowed if last sign is yesterday', async () => {
fetch.get.mockResolvedValue(scoreInfo({signAfterZero: true}));
const {getByRole} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(getByRole('button')).toBeEnabled();
});
it('sign is not allowed', async () => {
fetch.get.mockResolvedValue(
scoreInfo({ signAfterZero: true }, { lastSignAt: Date.now() }),
)
const { getByRole } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
expect(getByRole('button')).toBeDisabled()
})
it('sign is not allowed', async () => {
fetch.get.mockResolvedValue(
scoreInfo({signAfterZero: true}, {lastSignAt: Date.now()}),
);
const {getByRole} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(getByRole('button')).toBeDisabled();
});
it('remain in hours', async () => {
vi.useRealTimers()
fetch.get.mockResolvedValue(scoreInfo({}, { lastSignAt: Date.now() }))
it('remain in hours', async () => {
vi.useRealTimers();
fetch.get.mockResolvedValue(scoreInfo({}, {lastSignAt: Date.now()}));
const { getByRole } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const button = getByRole('button')
const {getByRole} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
const button = getByRole('button');
expect(button).toBeDisabled()
expect(button).toHaveTextContent('23 h')
})
expect(button).toBeDisabled();
expect(button).toHaveTextContent('23 h');
});
it('remain in minutes', async () => {
fetch.get.mockResolvedValue(
scoreInfo({}, { lastSignAt: Date.now() - 23.5 * 3600 * 1000 }),
)
it('remain in minutes', async () => {
fetch.get.mockResolvedValue(
scoreInfo({}, {lastSignAt: Date.now() - 23.5 * 3600 * 1000}),
);
const { getByRole } = render(<Dashboard />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const button = getByRole('button')
const {getByRole} = render(<Dashboard/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
const button = getByRole('button');
expect(button).toBeDisabled()
expect(button).toHaveTextContent(/(29|30)\smin/)
})
})
expect(button).toBeDisabled();
expect(button).toHaveTextContent(/(29|30)\smin/);
});
});

View File

@ -1,259 +1,298 @@
import { expect, vi, it, test, describe, beforeEach } from 'vitest'
import { render, fireEvent, waitFor } from '@testing-library/react'
import * as fetch from '@/scripts/net'
import { t } from '@/scripts/i18n'
import OAuth from '@/views/user/OAuth'
import type { App } from '@/views/user/OAuth/types'
import {
expect, vi, it, test, describe, beforeEach,
} from 'vitest';
import {render, fireEvent, waitFor} from '@testing-library/react';
import * as fetch from '@/scripts/net';
import {t} from '@/scripts/i18n';
import OAuth from '@/views/user/OAuth';
import type {App} from '@/views/user/OAuth/types';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
const fixture: Readonly<App> = Object.freeze({
id: 1,
name: 'My App',
redirect: 'http://url.test/',
secret: 'abc',
})
id: 1,
name: 'My App',
redirect: 'http://url.test/',
secret: 'abc',
});
test('loading data', () => {
fetch.get.mockResolvedValue([])
const { queryByTitle } = render(<OAuth />)
expect(queryByTitle('Loading...')).toBeInTheDocument()
})
fetch.get.mockResolvedValue([]);
const {queryByTitle} = render(<OAuth/>);
expect(queryByTitle('Loading...')).toBeInTheDocument();
});
describe('create app', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([])
})
beforeEach(() => {
fetch.get.mockResolvedValue([]);
});
it('succeeded', async () => {
fetch.post.mockResolvedValue(fixture)
const { getByLabelText, getByText, queryByText } = render(<OAuth />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('succeeded', async () => {
fetch.post.mockResolvedValue(fixture);
const {getByLabelText, getByText, queryByText} = render(<OAuth/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.oauth.create')))
fireEvent.input(getByLabelText(t('user.oauth.name')), {
target: { value: 'My App' },
})
fireEvent.input(getByLabelText(t('user.oauth.redirect')), {
target: { value: 'http://url.test/' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/oauth/clients', {
name: 'My App',
redirect: 'http://url.test/',
}),
)
expect(queryByText(fixture.id.toString())).toBeInTheDocument()
expect(queryByText(fixture.name)).toBeInTheDocument()
expect(queryByText(fixture.redirect)).toBeInTheDocument()
expect(queryByText(fixture.secret)).toBeInTheDocument()
})
fireEvent.click(getByText(t('user.oauth.create')));
fireEvent.input(getByLabelText(t('user.oauth.name')), {
target: {value: 'My App'},
});
fireEvent.input(getByLabelText(t('user.oauth.redirect')), {
target: {value: 'http://url.test/'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/oauth/clients', {
name: 'My App',
redirect: 'http://url.test/',
});
},
);
expect(queryByText(fixture.id.toString())).toBeInTheDocument();
expect(queryByText(fixture.name)).toBeInTheDocument();
expect(queryByText(fixture.redirect)).toBeInTheDocument();
expect(queryByText(fixture.secret)).toBeInTheDocument();
});
it('failed', async () => {
fetch.post.mockResolvedValue({ message: 'exception' })
const { getByLabelText, getByText, getByRole, queryByText } = render(
<OAuth />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('failed', async () => {
fetch.post.mockResolvedValue({message: 'exception'});
const {getByLabelText, getByText, getByRole, queryByText} = render(
<OAuth/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.oauth.create')))
fireEvent.input(getByLabelText(t('user.oauth.name')), {
target: { value: 'My App' },
})
fireEvent.input(getByLabelText(t('user.oauth.redirect')), {
target: { value: 'http://url.test/' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/oauth/clients', {
name: 'My App',
redirect: 'http://url.test/',
}),
)
expect(queryByText(fixture.name)).not.toBeInTheDocument()
expect(queryByText(fixture.redirect)).not.toBeInTheDocument()
expect(queryByText('exception')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
fireEvent.click(getByText(t('user.oauth.create')));
fireEvent.input(getByLabelText(t('user.oauth.name')), {
target: {value: 'My App'},
});
fireEvent.input(getByLabelText(t('user.oauth.redirect')), {
target: {value: 'http://url.test/'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/oauth/clients', {
name: 'My App',
redirect: 'http://url.test/',
});
},
);
expect(queryByText(fixture.name)).not.toBeInTheDocument();
expect(queryByText(fixture.redirect)).not.toBeInTheDocument();
expect(queryByText('exception')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('cancel dialog', async () => {
const { getByLabelText, getByText } = render(<OAuth />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancel dialog', async () => {
const {getByLabelText, getByText} = render(<OAuth/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.oauth.create')))
fireEvent.input(getByLabelText(t('user.oauth.name')), {
target: { value: 'My App' },
})
fireEvent.input(getByLabelText(t('user.oauth.redirect')), {
target: { value: 'http://url.test/' },
})
fireEvent.click(getByText(t('general.cancel')))
fireEvent.click(getByText(t('user.oauth.create')));
fireEvent.input(getByLabelText(t('user.oauth.name')), {
target: {value: 'My App'},
});
fireEvent.input(getByLabelText(t('user.oauth.redirect')), {
target: {value: 'http://url.test/'},
});
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => expect(fetch.post).not.toBeCalled())
await waitFor(() => {
expect(fetch.post).not.toBeCalled();
});
fireEvent.click(getByText(t('user.oauth.create')))
expect(getByLabelText(t('user.oauth.name'))).toHaveValue('')
expect(getByLabelText(t('user.oauth.redirect'))).toHaveValue('')
})
})
fireEvent.click(getByText(t('user.oauth.create')));
expect(getByLabelText(t('user.oauth.name'))).toHaveValue('');
expect(getByLabelText(t('user.oauth.redirect'))).toHaveValue('');
});
});
describe('edit app', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([fixture])
})
beforeEach(() => {
fetch.get.mockResolvedValue([fixture]);
});
describe('edit name', () => {
it('succeeded', async () => {
fetch.put.mockResolvedValue({ ...fixture, name: 'new name' })
describe('edit name', () => {
it('succeeded', async () => {
fetch.put.mockResolvedValue({...fixture, name: 'new name'});
const { getByTitle, getByText, getByDisplayValue, queryByText } = render(
<OAuth />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getByText, getByDisplayValue, queryByText} = render(
<OAuth/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.oauth.modifyName')))
fireEvent.input(getByDisplayValue(fixture.name), {
target: { value: 'new name' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/oauth/clients/${fixture.id}`, {
...fixture,
name: 'new name',
}),
)
expect(queryByText('new name')).toBeInTheDocument()
})
fireEvent.click(getByTitle(t('user.oauth.modifyName')));
fireEvent.input(getByDisplayValue(fixture.name), {
target: {value: 'new name'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/oauth/clients/${fixture.id}`, {
...fixture,
name: 'new name',
});
},
);
expect(queryByText('new name')).toBeInTheDocument();
});
it('failed', async () => {
fetch.put.mockResolvedValue({ message: 'exception' })
it('failed', async () => {
fetch.put.mockResolvedValue({message: 'exception'});
const {
getByTitle,
getByText,
getByDisplayValue,
getByRole,
queryByText,
} = render(<OAuth />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {
getByTitle,
getByText,
getByDisplayValue,
getByRole,
queryByText,
} = render(<OAuth/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.oauth.modifyName')))
fireEvent.input(getByDisplayValue(fixture.name), {
target: { value: 'new name' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/oauth/clients/${fixture.id}`, {
...fixture,
name: 'new name',
}),
)
expect(queryByText(fixture.name)).toBeInTheDocument()
expect(queryByText('exception')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
fireEvent.click(getByTitle(t('user.oauth.modifyName')));
fireEvent.input(getByDisplayValue(fixture.name), {
target: {value: 'new name'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/oauth/clients/${fixture.id}`, {
...fixture,
name: 'new name',
});
},
);
expect(queryByText(fixture.name)).toBeInTheDocument();
expect(queryByText('exception')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('cancel dialog', async () => {
const { getByTitle, getByText, queryByText } = render(<OAuth />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancel dialog', async () => {
const {getByTitle, getByText, queryByText} = render(<OAuth/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.oauth.modifyName')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.put).not.toBeCalled())
expect(queryByText(fixture.name)).toBeInTheDocument()
})
})
fireEvent.click(getByTitle(t('user.oauth.modifyName')));
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.put).not.toBeCalled();
});
expect(queryByText(fixture.name)).toBeInTheDocument();
});
});
describe('edit redirect url', () => {
it('succeeded', async () => {
fetch.put.mockResolvedValue({ ...fixture, redirect: 'http://new.test/' })
describe('edit redirect url', () => {
it('succeeded', async () => {
fetch.put.mockResolvedValue({...fixture, redirect: 'http://new.test/'});
const { getByTitle, getByDisplayValue, getByText, queryByText } = render(
<OAuth />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByTitle, getByDisplayValue, getByText, queryByText} = render(
<OAuth/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.oauth.modifyUrl')))
fireEvent.input(getByDisplayValue(fixture.redirect), {
target: { value: 'http://new.test/' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/oauth/clients/${fixture.id}`, {
...fixture,
redirect: 'http://new.test/',
}),
)
expect(queryByText('http://new.test/')).toBeInTheDocument()
})
fireEvent.click(getByTitle(t('user.oauth.modifyUrl')));
fireEvent.input(getByDisplayValue(fixture.redirect), {
target: {value: 'http://new.test/'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/oauth/clients/${fixture.id}`, {
...fixture,
redirect: 'http://new.test/',
});
},
);
expect(queryByText('http://new.test/')).toBeInTheDocument();
});
it('failed', async () => {
fetch.put.mockResolvedValue({ message: 'exception' })
it('failed', async () => {
fetch.put.mockResolvedValue({message: 'exception'});
const {
getByTitle,
getByDisplayValue,
getByText,
getByRole,
queryByText,
} = render(<OAuth />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {
getByTitle,
getByDisplayValue,
getByText,
getByRole,
queryByText,
} = render(<OAuth/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.oauth.modifyUrl')))
fireEvent.input(getByDisplayValue(fixture.redirect), {
target: { value: 'http://new.test/' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(`/oauth/clients/${fixture.id}`, {
...fixture,
redirect: 'http://new.test/',
}),
)
expect(queryByText(fixture.redirect)).toBeInTheDocument()
expect(queryByText('exception')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
fireEvent.click(getByTitle(t('user.oauth.modifyUrl')));
fireEvent.input(getByDisplayValue(fixture.redirect), {
target: {value: 'http://new.test/'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(`/oauth/clients/${fixture.id}`, {
...fixture,
redirect: 'http://new.test/',
});
},
);
expect(queryByText(fixture.redirect)).toBeInTheDocument();
expect(queryByText('exception')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('cancel dialog', async () => {
const { getByTitle, getByText, queryByText } = render(<OAuth />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancel dialog', async () => {
const {getByTitle, getByText, queryByText} = render(<OAuth/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.oauth.modifyUrl')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.put).not.toBeCalled())
expect(queryByText(fixture.redirect)).toBeInTheDocument()
})
})
})
fireEvent.click(getByTitle(t('user.oauth.modifyUrl')));
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.put).not.toBeCalled();
});
expect(queryByText(fixture.redirect)).toBeInTheDocument();
});
});
});
describe('delete app', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([fixture])
})
beforeEach(() => {
fetch.get.mockResolvedValue([fixture]);
});
it('succeeded', async () => {
const { getByText, queryByText } = render(<OAuth />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('succeeded', async () => {
const {getByText, queryByText} = render(<OAuth/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('report.delete')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.del).toBeCalledWith(`/oauth/clients/${fixture.id}`),
)
expect(queryByText(fixture.name)).not.toBeInTheDocument()
expect(queryByText(fixture.redirect)).not.toBeInTheDocument()
})
fireEvent.click(getByText(t('report.delete')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalledWith(`/oauth/clients/${fixture.id}`);
},
);
expect(queryByText(fixture.name)).not.toBeInTheDocument();
expect(queryByText(fixture.redirect)).not.toBeInTheDocument();
});
it('cancel dialog', async () => {
const { getByText, queryByText } = render(<OAuth />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancel dialog', async () => {
const {getByText, queryByText} = render(<OAuth/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('report.delete')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.del).not.toBeCalled())
expect(queryByText(fixture.name)).toBeInTheDocument()
expect(queryByText(fixture.redirect)).toBeInTheDocument()
})
})
fireEvent.click(getByText(t('report.delete')));
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.del).not.toBeCalled();
});
expect(queryByText(fixture.name)).toBeInTheDocument();
expect(queryByText(fixture.redirect)).toBeInTheDocument();
});
});

View File

@ -1,490 +1,560 @@
import { expect, vi, it, test, beforeEach, afterEach, describe } from 'vitest'
import { render, fireEvent, waitFor } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import { type Player, TextureType } from '@/scripts/types'
import urls from '@/scripts/urls'
import Players from '@/views/user/Players'
import {
expect, vi, it, test, beforeEach, afterEach, describe,
} from 'vitest';
import {render, fireEvent, waitFor} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import {type Player, TextureType} from '@/scripts/types';
import urls from '@/scripts/urls';
import Players from '@/views/user/Players';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
const fixture: Readonly<Player> = Object.freeze<Player>({
pid: 1,
name: 'kumiko',
uid: 1,
tid_skin: 1,
tid_cape: 2,
last_modified: new Date().toString(),
})
pid: 1,
name: 'kumiko',
uid: 1,
tid_skin: 1,
tid_cape: 2,
last_modified: new Date().toString(),
});
beforeEach(() => {
const container = document.createElement('div')
container.id = 'previewer'
document.body.appendChild(container)
const container = document.createElement('div');
container.id = 'previewer';
document.body.append(container);
blessing.extra = {
count: 1,
rule: 'please follow the rule',
length: 'greater than 3',
score: 1000,
cost: 50,
}
})
blessing.extra = {
count: 1,
rule: 'please follow the rule',
length: 'greater than 3',
score: 1000,
cost: 50,
};
});
afterEach(() => {
document.querySelector('#previewer')!.remove()
})
document.querySelector('#previewer')!.remove();
});
test('search players', async () => {
const fixture2: Player = {
pid: 2,
name: 'reina',
uid: 2,
tid_skin: 3,
tid_cape: 4,
last_modified: new Date().toString(),
}
fetch.get.mockResolvedValue([fixture, fixture2])
const fixture2: Player = {
pid: 2,
name: 'reina',
uid: 2,
tid_skin: 3,
tid_cape: 4,
last_modified: new Date().toString(),
};
fetch.get.mockResolvedValue([fixture, fixture2]);
const { getByPlaceholderText, queryByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByPlaceholderText, queryByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.input(getByPlaceholderText(t('user.typeToSearch')), {
target: { value: 'k' },
})
fireEvent.input(getByPlaceholderText(t('user.typeToSearch')), {
target: {value: 'k'},
});
expect(queryByText(fixture.name)).toBeInTheDocument()
expect(queryByText(fixture2.name)).not.toBeInTheDocument()
})
expect(queryByText(fixture.name)).toBeInTheDocument();
expect(queryByText(fixture2.name)).not.toBeInTheDocument();
});
describe('select player automatically', () => {
it('only one player', async () => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({ hash: '', type: TextureType.Steve })
.mockResolvedValueOnce({ hash: '', type: TextureType.Cape })
render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('only one player', async () => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({hash: '', type: TextureType.Steve})
.mockResolvedValueOnce({hash: '', type: TextureType.Cape});
render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(fetch.get).toBeCalledWith(`/skinlib/info/${fixture.tid_skin}`)
expect(fetch.get).toBeCalledWith(`/skinlib/info/${fixture.tid_cape}`)
})
expect(fetch.get).toBeCalledWith(`/skinlib/info/${fixture.tid_skin}`);
expect(fetch.get).toBeCalledWith(`/skinlib/info/${fixture.tid_cape}`);
});
it('more players', async () => {
const fixture2: Player = {
pid: 2,
name: 'reina',
uid: 2,
tid_skin: 3,
tid_cape: 4,
last_modified: new Date().toString(),
}
fetch.get.mockResolvedValue([fixture, fixture2])
render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('more players', async () => {
const fixture2: Player = {
pid: 2,
name: 'reina',
uid: 2,
tid_skin: 3,
tid_cape: 4,
last_modified: new Date().toString(),
};
fetch.get.mockResolvedValue([fixture, fixture2]);
render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
expect(fetch.get).not.toBeCalledWith(`/skinlib/info/${fixture.tid_skin}`)
expect(fetch.get).not.toBeCalledWith(`/skinlib/info/${fixture.tid_cape}`)
})
})
expect(fetch.get).not.toBeCalledWith(`/skinlib/info/${fixture.tid_skin}`);
expect(fetch.get).not.toBeCalledWith(`/skinlib/info/${fixture.tid_cape}`);
});
});
describe('2d preview', () => {
it('skin and cape', async () => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({ hash: 'a', type: TextureType.Steve })
.mockResolvedValueOnce({ hash: 'b', type: TextureType.Cape })
it('skin and cape', async () => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({hash: 'a', type: TextureType.Steve})
.mockResolvedValueOnce({hash: 'b', type: TextureType.Cape});
const { getByAltText, getByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByAltText, getByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.switch2dPreview')))
fireEvent.click(getByText(t('user.switch2dPreview')));
expect(getByAltText(t('general.skin'))).toHaveAttribute(
'src',
`${blessing.base_url}/textures/a`,
)
expect(getByAltText(t('general.cape'))).toHaveAttribute(
'src',
`${blessing.base_url}/textures/b`,
)
})
expect(getByAltText(t('general.skin'))).toHaveAttribute(
'src',
`${blessing.base_url}/textures/a`,
);
expect(getByAltText(t('general.cape'))).toHaveAttribute(
'src',
`${blessing.base_url}/textures/b`,
);
});
it('skin only', async () => {
fetch.get
.mockResolvedValueOnce([{ ...fixture, tid_cape: 0 }])
.mockResolvedValueOnce({ hash: 'a', type: TextureType.Steve })
it('skin only', async () => {
fetch.get
.mockResolvedValueOnce([{...fixture, tid_cape: 0}])
.mockResolvedValueOnce({hash: 'a', type: TextureType.Steve});
const { getByAltText, queryByAltText, getByText, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByAltText, queryByAltText, getByText, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.switch2dPreview')))
fireEvent.click(getByText(t('user.switch2dPreview')));
expect(getByAltText(t('general.skin'))).toHaveAttribute(
'src',
`${blessing.base_url}/textures/a`,
)
expect(queryByAltText(t('general.cape'))).not.toBeInTheDocument()
expect(queryByText(t('user.player.texture-empty'))).toBeInTheDocument()
})
expect(getByAltText(t('general.skin'))).toHaveAttribute(
'src',
`${blessing.base_url}/textures/a`,
);
expect(queryByAltText(t('general.cape'))).not.toBeInTheDocument();
expect(queryByText(t('user.player.texture-empty'))).toBeInTheDocument();
});
it('cape only', async () => {
fetch.get
.mockResolvedValueOnce([{ ...fixture, tid_skin: 0 }])
.mockResolvedValueOnce({ hash: 'a', type: TextureType.Cape })
it('cape only', async () => {
fetch.get
.mockResolvedValueOnce([{...fixture, tid_skin: 0}])
.mockResolvedValueOnce({hash: 'a', type: TextureType.Cape});
const { getByAltText, queryByAltText, getByText, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByAltText, queryByAltText, getByText, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.switch2dPreview')))
fireEvent.click(getByText(t('user.switch2dPreview')));
expect(getByAltText(t('general.cape'))).toHaveAttribute(
'src',
`${blessing.base_url}/textures/a`,
)
expect(queryByAltText(t('general.skin'))).not.toBeInTheDocument()
expect(queryByText(t('user.player.texture-empty'))).toBeInTheDocument()
})
})
expect(getByAltText(t('general.cape'))).toHaveAttribute(
'src',
`${blessing.base_url}/textures/a`,
);
expect(queryByAltText(t('general.skin'))).not.toBeInTheDocument();
expect(queryByText(t('user.player.texture-empty'))).toBeInTheDocument();
});
});
describe('create player', () => {
beforeEach(() => {
fetch.get.mockResolvedValue([])
})
beforeEach(() => {
fetch.get.mockResolvedValue([]);
});
it('alert if score is enough', async () => {
const { getByRole, getByText, queryByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('alert if score is enough', async () => {
const {getByRole, getByText, queryByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.add-player')))
fireEvent.click(getByText(t('user.player.add-player')));
expect(
queryByText(`${t('user.cur-score')} ${blessing.extra.score}`),
).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-success')
})
expect(
queryByText(`${t('user.cur-score')} ${blessing.extra.score}`),
).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-success');
});
it('alert if lack of score', async () => {
blessing.extra.score = 0
const { getByRole, getByText, queryByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('alert if lack of score', async () => {
blessing.extra.score = 0;
const {getByRole, getByText, queryByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.add-player')))
fireEvent.click(getByText(t('user.player.add-player')));
expect(
queryByText(`${t('user.cur-score')} ${blessing.extra.score}`),
).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
expect(
queryByText(`${t('user.cur-score')} ${blessing.extra.score}`),
).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'success', data: fixture })
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'success', data: fixture});
const { getByText, getByLabelText, getByRole, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByLabelText, getByRole, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.add-player')))
fireEvent.input(getByLabelText(t('general.player.player-name')), {
target: { value: fixture.name },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.user.player.add(), {
name: fixture.name,
}),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
expect(queryByText(fixture.pid.toString())).toBeInTheDocument()
expect(queryByText(fixture.name)).toBeInTheDocument()
})
fireEvent.click(getByText(t('user.player.add-player')));
fireEvent.input(getByLabelText(t('general.player.player-name')), {
target: {value: fixture.name},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.user.player.add(), {
name: fixture.name,
});
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
expect(queryByText(fixture.pid.toString())).toBeInTheDocument();
expect(queryByText(fixture.name)).toBeInTheDocument();
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByLabelText, getByRole, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByLabelText, getByRole, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.add-player')))
fireEvent.input(getByLabelText(t('general.player.player-name')), {
target: { value: fixture.name },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith(urls.user.player.add(), {
name: fixture.name,
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
expect(queryByText(fixture.name)).not.toBeInTheDocument()
})
fireEvent.click(getByText(t('user.player.add-player')));
fireEvent.input(getByLabelText(t('general.player.player-name')), {
target: {value: fixture.name},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith(urls.user.player.add(), {
name: fixture.name,
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
expect(queryByText(fixture.name)).not.toBeInTheDocument();
});
it('cancelled', async () => {
const { getByText, getByLabelText, queryByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancelled', async () => {
const {getByText, getByLabelText, queryByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.add-player')))
fireEvent.input(getByLabelText(t('general.player.player-name')), {
target: { value: fixture.name },
})
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.post).not.toBeCalled())
expect(queryByText(fixture.name)).not.toBeInTheDocument()
})
fireEvent.click(getByText(t('user.player.add-player')));
fireEvent.input(getByLabelText(t('general.player.player-name')), {
target: {value: fixture.name},
});
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.post).not.toBeCalled();
});
expect(queryByText(fixture.name)).not.toBeInTheDocument();
});
it('clear form on close', async () => {
const { getByText, getByLabelText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('clear form on close', async () => {
const {getByText, getByLabelText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.add-player')))
fireEvent.input(getByLabelText(t('general.player.player-name')), {
target: { value: fixture.name },
})
fireEvent.click(getByText(t('general.cancel')))
fireEvent.click(getByText(t('user.player.add-player')))
fireEvent.click(getByText(t('user.player.add-player')));
fireEvent.input(getByLabelText(t('general.player.player-name')), {
target: {value: fixture.name},
});
fireEvent.click(getByText(t('general.cancel')));
fireEvent.click(getByText(t('user.player.add-player')));
expect(getByLabelText(t('general.player.player-name'))).toHaveValue('')
})
})
expect(getByLabelText(t('general.player.player-name'))).toHaveValue('');
});
});
describe('edit player name', () => {
beforeEach(() => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({ hash: 'a', type: 'skin' })
.mockResolvedValueOnce({ hash: 'b', type: TextureType.Cape })
})
beforeEach(() => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({hash: 'a', type: 'skin'})
.mockResolvedValueOnce({hash: 'b', type: TextureType.Cape});
});
it('succeeded', async () => {
fetch.put.mockResolvedValue({ code: 0, message: 'success' })
it('succeeded', async () => {
fetch.put.mockResolvedValue({code: 0, message: 'success'});
const { getByText, getByTitle, getByDisplayValue, getByRole, queryByText } =
render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByTitle, getByDisplayValue, getByRole, queryByText}
= render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.player.edit-pname')))
fireEvent.input(getByDisplayValue(fixture.name), {
target: { value: 'reina' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(urls.user.player.rename(fixture.pid), {
name: 'reina',
}),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
expect(queryByText('reina')).toBeInTheDocument()
})
fireEvent.click(getByTitle(t('user.player.edit-pname')));
fireEvent.input(getByDisplayValue(fixture.name), {
target: {value: 'reina'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(urls.user.player.rename(fixture.pid), {
name: 'reina',
});
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
expect(queryByText('reina')).toBeInTheDocument();
});
it('empty name', async () => {
const { getByText, getByTitle, getByDisplayValue, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('empty name', async () => {
const {getByText, getByTitle, getByDisplayValue, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.player.edit-pname')))
fireEvent.input(getByDisplayValue(fixture.name), {
target: { value: '' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => expect(fetch.put).not.toBeCalled())
expect(queryByText(t('user.emptyPlayerName'))).toBeInTheDocument()
fireEvent.click(getByTitle(t('user.player.edit-pname')));
fireEvent.input(getByDisplayValue(fixture.name), {
target: {value: ''},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).not.toBeCalled();
});
expect(queryByText(t('user.emptyPlayerName'))).toBeInTheDocument();
fireEvent.click(getByText(t('general.cancel')))
expect(queryByText(fixture.name)).toBeInTheDocument()
})
fireEvent.click(getByText(t('general.cancel')));
expect(queryByText(fixture.name)).toBeInTheDocument();
});
it('failed', async () => {
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.put.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByTitle, getByDisplayValue, getByRole, queryByText } =
render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByTitle, getByDisplayValue, getByRole, queryByText}
= render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByTitle(t('user.player.edit-pname')))
fireEvent.input(getByDisplayValue(fixture.name), {
target: { value: 'reina' },
})
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.put).toBeCalledWith(urls.user.player.rename(fixture.pid), {
name: 'reina',
}),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
expect(queryByText(fixture.name)).toBeInTheDocument()
})
})
fireEvent.click(getByTitle(t('user.player.edit-pname')));
fireEvent.input(getByDisplayValue(fixture.name), {
target: {value: 'reina'},
});
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.put).toBeCalledWith(urls.user.player.rename(fixture.pid), {
name: 'reina',
});
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
expect(queryByText(fixture.name)).toBeInTheDocument();
});
});
describe('reset texture', () => {
beforeEach(() => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({ hash: 'a', type: 'skin' })
.mockResolvedValueOnce({ hash: 'b', type: TextureType.Cape })
})
beforeEach(() => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({hash: 'a', type: 'skin'})
.mockResolvedValueOnce({hash: 'b', type: TextureType.Cape});
});
it('clear skin and cape', async () => {
fetch.del.mockResolvedValue({ code: 0, message: 'success' })
it('clear skin and cape', async () => {
fetch.del.mockResolvedValue({code: 0, message: 'success'});
const { getByText, getByRole, getByLabelText, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByRole, getByLabelText, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-texture')))
fireEvent.click(getByLabelText(t('general.skin')))
fireEvent.click(getByLabelText(t('general.cape')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.del).toBeCalledWith(
`${urls.user.player.clear(fixture.pid)}?skin=true&cape=true`,
),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
})
fireEvent.click(getByText(t('user.player.delete-texture')));
fireEvent.click(getByLabelText(t('general.skin')));
fireEvent.click(getByLabelText(t('general.cape')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalledWith(
`${urls.user.player.clear(fixture.pid)}?skin=true&cape=true`,
);
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
});
it('clear skin', async () => {
fetch.del.mockResolvedValue({ code: 0, message: 'success' })
it('clear skin', async () => {
fetch.del.mockResolvedValue({code: 0, message: 'success'});
const { getByText, getByRole, getByLabelText, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByRole, getByLabelText, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-texture')))
fireEvent.click(getByLabelText(t('general.skin')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.del).toBeCalledWith(
`${urls.user.player.clear(fixture.pid)}?skin=true`,
),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
})
fireEvent.click(getByText(t('user.player.delete-texture')));
fireEvent.click(getByLabelText(t('general.skin')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalledWith(
`${urls.user.player.clear(fixture.pid)}?skin=true`,
);
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
});
it('clear cape', async () => {
fetch.del.mockResolvedValue({ code: 0, message: 'success' })
it('clear cape', async () => {
fetch.del.mockResolvedValue({code: 0, message: 'success'});
const { getByText, getByRole, getByLabelText, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByRole, getByLabelText, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-texture')))
fireEvent.click(getByLabelText(t('general.cape')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.del).toBeCalledWith(
`${urls.user.player.clear(fixture.pid)}?cape=true`,
),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
})
fireEvent.click(getByText(t('user.player.delete-texture')));
fireEvent.click(getByLabelText(t('general.cape')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalledWith(
`${urls.user.player.clear(fixture.pid)}?cape=true`,
);
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
});
it('select nothing', async () => {
const { getByText, getByRole, queryByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('select nothing', async () => {
const {getByText, getByRole, queryByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-texture')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() => expect(fetch.del).not.toBeCalled())
expect(queryByText(t('user.noClearChoice'))).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-warning')
})
fireEvent.click(getByText(t('user.player.delete-texture')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).not.toBeCalled();
});
expect(queryByText(t('user.noClearChoice'))).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-warning');
});
it('failed', async () => {
fetch.del.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.del.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByRole, getByLabelText, queryByText } = render(
<Players />,
)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByRole, getByLabelText, queryByText} = render(
<Players/>,
);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-texture')))
fireEvent.click(getByLabelText(t('general.skin')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.del).toBeCalledWith(
`${urls.user.player.clear(fixture.pid)}?skin=true`,
),
)
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
fireEvent.click(getByText(t('user.player.delete-texture')));
fireEvent.click(getByLabelText(t('general.skin')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalledWith(
`${urls.user.player.clear(fixture.pid)}?skin=true`,
);
},
);
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
it('cancelled', async () => {
const { getByText, getByLabelText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancelled', async () => {
const {getByText, getByLabelText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-texture')))
fireEvent.click(getByLabelText(t('general.skin')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.del).not.toBeCalled())
})
})
fireEvent.click(getByText(t('user.player.delete-texture')));
fireEvent.click(getByLabelText(t('general.skin')));
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.del).not.toBeCalled();
});
});
});
describe('delete player', () => {
beforeEach(() => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({ hash: 'a', type: 'skin' })
.mockResolvedValueOnce({ hash: 'b', type: TextureType.Cape })
})
beforeEach(() => {
fetch.get
.mockResolvedValueOnce([fixture])
.mockResolvedValueOnce({hash: 'a', type: 'skin'})
.mockResolvedValueOnce({hash: 'b', type: TextureType.Cape});
});
it('succeeded', async () => {
fetch.del.mockResolvedValue({ code: 0, message: 'success' })
it('succeeded', async () => {
fetch.del.mockResolvedValue({code: 0, message: 'success'});
const { getByText, getByRole, queryByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByRole, queryByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-player')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.del).toBeCalledWith(urls.user.player.delete(fixture.pid)),
)
expect(getByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
expect(queryByText(fixture.name)).not.toBeInTheDocument()
})
fireEvent.click(getByText(t('user.player.delete-player')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalledWith(urls.user.player.delete(fixture.pid));
},
);
expect(getByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
expect(queryByText(fixture.name)).not.toBeInTheDocument();
});
it('failed', async () => {
fetch.del.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.del.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByRole, queryByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
const {getByText, getByRole, queryByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-player')))
fireEvent.click(getByText(t('general.confirm')))
await waitFor(() =>
expect(fetch.del).toBeCalledWith(urls.user.player.delete(fixture.pid)),
)
expect(getByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
expect(queryByText(fixture.name)).toBeInTheDocument()
})
fireEvent.click(getByText(t('user.player.delete-player')));
fireEvent.click(getByText(t('general.confirm')));
await waitFor(() => {
expect(fetch.del).toBeCalledWith(urls.user.player.delete(fixture.pid));
},
);
expect(getByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
expect(queryByText(fixture.name)).toBeInTheDocument();
});
it('cancelled', async () => {
const { getByText, queryByText } = render(<Players />)
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
it('cancelled', async () => {
const {getByText, queryByText} = render(<Players/>);
await waitFor(() => {
expect(fetch.get).toBeCalledTimes(1);
});
fireEvent.click(getByText(t('user.player.delete-player')))
fireEvent.click(getByText(t('general.cancel')))
await waitFor(() => expect(fetch.del).not.toBeCalled())
expect(queryByText(fixture.name)).toBeInTheDocument()
})
})
fireEvent.click(getByText(t('user.player.delete-player')));
fireEvent.click(getByText(t('general.cancel')));
await waitFor(() => {
expect(fetch.del).not.toBeCalled();
});
expect(queryByText(fixture.name)).toBeInTheDocument();
});
});

View File

@ -1,35 +1,35 @@
import { expect, vi, test } from 'vitest'
import { flushPromises } from '../../../utils'
import { showModal } from '@/scripts/notify'
import { post } from '@/scripts/net'
import handler from '@/views/user/profile/deleteAccount'
import {expect, vi, test} from 'vitest';
import {flushPromises} from '../../../utils';
import {showModal} from '@/scripts/notify';
import {post} from '@/scripts/net';
import handler from '@/views/user/profile/deleteAccount';
vi.mock('@/scripts/notify')
vi.mock('@/scripts/net')
vi.mock('@/scripts/notify');
vi.mock('@/scripts/net');
test('delete account', async () => {
post
.mockResolvedValueOnce({ code: 1, message: 'w' })
.mockResolvedValue({ code: 0, message: 'o' })
post
.mockResolvedValueOnce({code: 1, message: 'w'})
.mockResolvedValue({code: 0, message: 'o'});
const form = document.createElement('form')
form.addEventListener('submit', handler)
const form = document.createElement('form');
form.addEventListener('submit', handler);
const password = document.createElement('input')
password.name = 'password'
password.value = 'abc'
form.appendChild(password)
form.password = password
const password = document.createElement('input');
password.name = 'password';
password.value = 'abc';
form.append(password);
form.password = password;
const event = new Event('submit')
form.dispatchEvent(event)
await flushPromises()
expect(post).toBeCalledWith('/user/profile?action=delete', {
password: 'abc',
})
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'w' })
const event = new Event('submit');
form.dispatchEvent(event);
await flushPromises();
expect(post).toBeCalledWith('/user/profile?action=delete', {
password: 'abc',
});
expect(showModal).toBeCalledWith({mode: 'alert', text: 'w'});
form.dispatchEvent(event)
await flushPromises()
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'o' })
})
form.dispatchEvent(event);
await flushPromises();
expect(showModal).toBeCalledWith({mode: 'alert', text: 'o'});
});

View File

@ -1,42 +1,42 @@
import { expect, vi, test } from 'vitest'
import { flushPromises } from '../../../utils'
import { showModal } from '@/scripts/notify'
import { post } from '@/scripts/net'
import handler from '@/views/user/profile/email'
import {expect, vi, test} from 'vitest';
import {flushPromises} from '../../../utils';
import {showModal} from '@/scripts/notify';
import {post} from '@/scripts/net';
import handler from '@/views/user/profile/email';
vi.mock('@/scripts/notify')
vi.mock('@/scripts/net')
vi.mock('@/scripts/notify');
vi.mock('@/scripts/net');
test('change email', async () => {
post
.mockResolvedValueOnce({ code: 1, message: 'w' })
.mockResolvedValue({ code: 0, message: 'o' })
post
.mockResolvedValueOnce({code: 1, message: 'w'})
.mockResolvedValue({code: 0, message: 'o'});
const form = document.createElement('form')
form.addEventListener('submit', handler)
const form = document.createElement('form');
form.addEventListener('submit', handler);
const email = document.createElement('input')
email.name = 'email'
email.value = 'a@b.c'
form.appendChild(email)
form.email = email
const email = document.createElement('input');
email.name = 'email';
email.value = 'a@b.c';
form.append(email);
form.email = email;
const password = document.createElement('input')
password.name = 'password'
password.value = 'abc'
form.appendChild(password)
form.password = password
const password = document.createElement('input');
password.name = 'password';
password.value = 'abc';
form.append(password);
form.password = password;
const event = new Event('submit')
form.dispatchEvent(event)
await flushPromises()
expect(post).toBeCalledWith('/user/profile?action=email', {
email: 'a@b.c',
password: 'abc',
})
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'w' })
const event = new Event('submit');
form.dispatchEvent(event);
await flushPromises();
expect(post).toBeCalledWith('/user/profile?action=email', {
email: 'a@b.c',
password: 'abc',
});
expect(showModal).toBeCalledWith({mode: 'alert', text: 'w'});
form.dispatchEvent(event)
await flushPromises()
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'o' })
})
form.dispatchEvent(event);
await flushPromises();
expect(showModal).toBeCalledWith({mode: 'alert', text: 'o'});
});

View File

@ -1,37 +1,37 @@
import { expect, vi, test } from 'vitest'
import { flushPromises } from '../../../utils'
import { showModal } from '@/scripts/notify'
import { post } from '@/scripts/net'
import handler from '@/views/user/profile/nickname'
import {expect, vi, test} from 'vitest';
import {flushPromises} from '../../../utils';
import {showModal} from '@/scripts/notify';
import {post} from '@/scripts/net';
import handler from '@/views/user/profile/nickname';
vi.mock('@/scripts/notify')
vi.mock('@/scripts/net')
vi.mock('@/scripts/notify');
vi.mock('@/scripts/net');
test('change nickname', async () => {
document.body.innerHTML = '<span data-mark="nickname"></span>'
post
.mockResolvedValueOnce({ code: 1, message: 'w' })
.mockResolvedValue({ code: 0, message: 'o' })
document.body.innerHTML = '<span data-mark="nickname"></span>';
post
.mockResolvedValueOnce({code: 1, message: 'w'})
.mockResolvedValue({code: 0, message: 'o'});
const form = document.createElement('form')
form.addEventListener('submit', handler)
const form = document.createElement('form');
form.addEventListener('submit', handler);
const nickname = document.createElement('input')
nickname.name = 'nickname'
nickname.value = 'nickname'
form.appendChild(nickname)
form.nickname = nickname
const nickname = document.createElement('input');
nickname.name = 'nickname';
nickname.value = 'nickname';
form.append(nickname);
form.nickname = nickname;
const event = new Event('submit')
form.dispatchEvent(event)
await flushPromises()
expect(post).toBeCalledWith('/user/profile?action=nickname', {
new_nickname: 'nickname',
})
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'w' })
const event = new Event('submit');
form.dispatchEvent(event);
await flushPromises();
expect(post).toBeCalledWith('/user/profile?action=nickname', {
new_nickname: 'nickname',
});
expect(showModal).toBeCalledWith({mode: 'alert', text: 'w'});
form.dispatchEvent(event)
await flushPromises()
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'o' })
expect(document.querySelector('span')!.textContent).toBe('nickname')
})
form.dispatchEvent(event);
await flushPromises();
expect(showModal).toBeCalledWith({mode: 'alert', text: 'o'});
expect(document.querySelector('span')!.textContent).toBe('nickname');
});

View File

@ -1,55 +1,55 @@
import { expect, vi, test } from 'vitest'
import { flushPromises } from '../../../utils'
import { t } from '@/scripts/i18n'
import { showModal, toast } from '@/scripts/notify'
import { post } from '@/scripts/net'
import handler from '@/views/user/profile/password'
import {expect, vi, test} from 'vitest';
import {flushPromises} from '../../../utils';
import {t} from '@/scripts/i18n';
import {showModal, toast} from '@/scripts/notify';
import {post} from '@/scripts/net';
import handler from '@/views/user/profile/password';
vi.mock('@/scripts/notify')
vi.mock('@/scripts/net')
vi.mock('@/scripts/notify');
vi.mock('@/scripts/net');
test('change password', async () => {
post
.mockResolvedValueOnce({ code: 1, message: 'w' })
.mockResolvedValue({ code: 0, message: 'o' })
post
.mockResolvedValueOnce({code: 1, message: 'w'})
.mockResolvedValue({code: 0, message: 'o'});
const form = document.createElement('form')
form.addEventListener('submit', handler)
const form = document.createElement('form');
form.addEventListener('submit', handler);
const oldPassword = document.createElement('input')
oldPassword.name = 'oldPassword'
oldPassword.value = '1'
form.appendChild(oldPassword)
form.oldPassword = oldPassword
const oldPassword = document.createElement('input');
oldPassword.name = 'oldPassword';
oldPassword.value = '1';
form.append(oldPassword);
form.oldPassword = oldPassword;
const newPassword = document.createElement('input')
newPassword.name = 'newPassword'
newPassword.value = '1'
form.appendChild(newPassword)
form.newPassword = newPassword
const newPassword = document.createElement('input');
newPassword.name = 'newPassword';
newPassword.value = '1';
form.append(newPassword);
form.newPassword = newPassword;
const confirm = document.createElement('input')
confirm.name = 'confirm'
confirm.value = '2'
form.appendChild(confirm)
form.confirm = confirm
const confirm = document.createElement('input');
confirm.name = 'confirm';
confirm.value = '2';
form.append(confirm);
form.confirm = confirm;
const event = new Event('submit')
form.dispatchEvent(event)
await flushPromises()
expect(post).not.toBeCalled()
expect(toast.error).toBeCalledWith(t('auth.invalidConfirmPwd'))
const event = new Event('submit');
form.dispatchEvent(event);
await flushPromises();
expect(post).not.toBeCalled();
expect(toast.error).toBeCalledWith(t('auth.invalidConfirmPwd'));
confirm.value = '1'
form.dispatchEvent(event)
await flushPromises()
expect(post).toBeCalledWith('/user/profile?action=password', {
current_password: '1',
new_password: '1',
})
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'w' })
confirm.value = '1';
form.dispatchEvent(event);
await flushPromises();
expect(post).toBeCalledWith('/user/profile?action=password', {
current_password: '1',
new_password: '1',
});
expect(showModal).toBeCalledWith({mode: 'alert', text: 'w'});
form.dispatchEvent(event)
await flushPromises()
expect(showModal).toBeCalledWith({ mode: 'alert', text: 'o' })
})
form.dispatchEvent(event);
await flushPromises();
expect(showModal).toBeCalledWith({mode: 'alert', text: 'o'});
});

View File

@ -1,21 +1,21 @@
import { expect, vi, test } from 'vitest'
import { showModal, toast } from '@/scripts/notify'
import { post } from '@/scripts/net'
import resetAvatar from '@/views/user/profile/resetAvatar'
import {expect, vi, test} from 'vitest';
import {showModal, toast} from '@/scripts/notify';
import {post} from '@/scripts/net';
import resetAvatar from '@/views/user/profile/resetAvatar';
vi.mock('@/scripts/notify')
vi.mock('@/scripts/net')
vi.mock('@/scripts/notify');
vi.mock('@/scripts/net');
test('reset avatar', async () => {
showModal.mockRejectedValueOnce(null).mockResolvedValue({ value: '' })
post.mockResolvedValue({ message: 'ok' })
document.body.innerHTML = '<img alt="User Image" src="a">'
showModal.mockRejectedValueOnce(null).mockResolvedValue({value: ''});
post.mockResolvedValue({message: 'ok'});
document.body.innerHTML = '<img alt="User Image" src="a">';
await resetAvatar()
expect(post).not.toBeCalled()
await resetAvatar();
expect(post).not.toBeCalled();
await resetAvatar()
expect(post).toBeCalledWith('/user/profile/avatar', { tid: 0 })
expect(toast.success).toBeCalledWith('ok')
expect(document.querySelector('img')!.src).toBe('/avatar/0')
})
await resetAvatar();
expect(post).toBeCalledWith('/user/profile/avatar', {tid: 0});
expect(toast.success).toBeCalledWith('ok');
expect(document.querySelector('img')!.src).toBe('/avatar/0');
});

View File

@ -1,36 +1,40 @@
import { expect, vi, it, describe } from 'vitest'
import { render, fireEvent, waitFor } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import EmailVerification from '@/views/widgets/EmailVerification'
import {
expect, vi, it, describe,
} from 'vitest';
import {render, fireEvent, waitFor} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import EmailVerification from '@/views/widgets/EmailVerification';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
describe('send email', () => {
it('succeeded', async () => {
fetch.post.mockResolvedValue({ code: 0, message: 'success' })
it('succeeded', async () => {
fetch.post.mockResolvedValue({code: 0, message: 'success'});
const { getByText, getByRole, queryByText } = render(<EmailVerification />)
const {getByText, getByRole, queryByText} = render(<EmailVerification/>);
fireEvent.click(getByText(t('user.verification.resend')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/user/email-verification'),
)
expect(queryByText('success')).toBeInTheDocument()
expect(getByRole('status')).toHaveClass('alert-success')
})
fireEvent.click(getByText(t('user.verification.resend')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/user/email-verification');
},
);
expect(queryByText('success')).toBeInTheDocument();
expect(getByRole('status')).toHaveClass('alert-success');
});
it('failed', async () => {
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
it('failed', async () => {
fetch.post.mockResolvedValue({code: 1, message: 'failed'});
const { getByText, getByRole, queryByText } = render(<EmailVerification />)
const {getByText, getByRole, queryByText} = render(<EmailVerification/>);
fireEvent.click(getByText(t('user.verification.resend')))
await waitFor(() =>
expect(fetch.post).toBeCalledWith('/user/email-verification'),
)
expect(fetch.post).toBeCalledWith('/user/email-verification')
expect(queryByText('failed')).toBeInTheDocument()
expect(getByRole('alert')).toHaveClass('alert-danger')
})
})
fireEvent.click(getByText(t('user.verification.resend')));
await waitFor(() => {
expect(fetch.post).toBeCalledWith('/user/email-verification');
},
);
expect(fetch.post).toBeCalledWith('/user/email-verification');
expect(queryByText('failed')).toBeInTheDocument();
expect(getByRole('alert')).toHaveClass('alert-danger');
});
});

View File

@ -1,66 +1,68 @@
import { expect, vi, test } from 'vitest'
import { render, fireEvent, waitFor } from '@testing-library/react'
import { t } from '@/scripts/i18n'
import * as fetch from '@/scripts/net'
import {expect, vi, test} from 'vitest';
import {render, fireEvent, waitFor} from '@testing-library/react';
import {t} from '@/scripts/i18n';
import * as fetch from '@/scripts/net';
import NotificationsList, {
type Notification,
} from '@/views/widgets/NotificationsList'
type Notification,
} from '@/views/widgets/NotificationsList';
vi.mock('@/scripts/net')
vi.mock('@/scripts/net');
beforeEach(() => {
document.body.innerHTML = ''
})
document.body.innerHTML = '';
});
function createContainer(notifications: Notification[]) {
const container = document.createElement('div')
container.dataset.notifications = JSON.stringify(notifications)
container.dataset.t = 'no unread'
document.body.appendChild(container)
const container = document.createElement('div');
container.dataset.notifications = JSON.stringify(notifications);
container.dataset.t = 'no unread';
document.body.append(container);
}
test('should not throw if element does not exist', () => {
render(<NotificationsList />)
})
render(<NotificationsList/>);
});
test('no unread notifications', () => {
createContainer([])
createContainer([]);
const { queryByText } = render(<NotificationsList />)
const {queryByText} = render(<NotificationsList/>);
expect(queryByText('no unread')).toBeInTheDocument()
})
expect(queryByText('no unread')).toBeInTheDocument();
});
test('with unread notifications', () => {
createContainer([{ id: '1', title: 'hi' }])
createContainer([{id: '1', title: 'hi'}]);
const { queryByText } = render(<NotificationsList />)
const {queryByText} = render(<NotificationsList/>);
expect(queryByText('1')).toBeInTheDocument()
expect(queryByText('hi')).toBeInTheDocument()
})
expect(queryByText('1')).toBeInTheDocument();
expect(queryByText('hi')).toBeInTheDocument();
});
test('read notification', async () => {
const time = new Date().toLocaleTimeString()
const fixture = {
title: 'hi - title',
content: 'content here',
time,
}
const time = new Date().toLocaleTimeString();
const fixture = {
title: 'hi - title',
content: 'content here',
time,
};
createContainer([{ id: '1', title: 'hi' }])
fetch.post.mockResolvedValue(fixture)
createContainer([{id: '1', title: 'hi'}]);
fetch.post.mockResolvedValue(fixture);
const { getByText, queryByText } = render(<NotificationsList />)
const {getByText, queryByText} = render(<NotificationsList/>);
fireEvent.click(getByText('hi'))
await waitFor(() => expect(fetch.post).toBeCalled())
fireEvent.click(getByText('hi'));
await waitFor(() => {
expect(fetch.post).toBeCalled();
});
expect(queryByText(fixture.title)).toBeInTheDocument()
expect(queryByText(fixture.content)).toBeInTheDocument()
expect(queryByText(fixture.time)).toBeInTheDocument()
expect(queryByText('no unread')).toBeInTheDocument()
expect(queryByText('1')).not.toBeInTheDocument()
expect(queryByText(fixture.title)).toBeInTheDocument();
expect(queryByText(fixture.content)).toBeInTheDocument();
expect(queryByText(fixture.time)).toBeInTheDocument();
expect(queryByText('no unread')).toBeInTheDocument();
expect(queryByText('1')).not.toBeInTheDocument();
fireEvent.click(getByText(t('general.confirm')))
})
fireEvent.click(getByText(t('general.confirm')));
});

View File

@ -1,71 +0,0 @@
import {promises as fs} from 'node:fs';
import * as path from 'node:path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import type {Compiler} from 'webpack';
class HtmlWebpackEnhancementPlugin {
apply(compiler: Compiler) {
compiler.hooks.assetEmitted.tapPromise(
'HtmlWebpackEnhancementPlugin',
async (name, {source}) => {
if (name.endsWith('.twig')) {
const filePath = path.resolve(
process.cwd(),
'resources',
'views',
'assets',
name,
);
await fs.writeFile(filePath, source.source());
}
},
);
compiler.hooks.compilation.tap(
'HtmlWebpackEnhancementPlugin',
compilation => {
const hooks = HtmlWebpackPlugin.getHooks(compilation);
hooks.alterAssetTags.tap('HtmlWebpackEnhancementPlugin', data => {
data.assetTags.scripts = data.assetTags.scripts.map(tag => {
tag.attributes.crossorigin = 'anonymous';
return tag;
});
data.assetTags.styles = data.assetTags.styles.map(tag => {
tag.attributes.crossorigin = 'anonymous';
return tag;
});
return data;
});
hooks.afterTemplateExecution.tap(
'HtmlWebpackEnhancementPlugin',
data => {
if (
compilation.compiler.options.mode === 'production'
&& data.headTags.length > 0
) {
if (
data.headTags.some(tag => tag.attributes.rel === 'stylesheet')
) {
data.bodyTags = data.headTags.filter(
tag => tag.tagName !== 'script',
);
} else {
data.bodyTags = data.headTags;
}
data.headTags = [];
}
return data;
},
);
},
);
}
}
export default HtmlWebpackEnhancementPlugin;

View File

@ -1,7 +1,6 @@
import {spawnSync} from 'node:child_process';
import * as fs from 'node:fs';
import fs from 'node:fs';
import ts from 'typescript';
import prettier from 'prettier';
type Route = {uri: string; name: string | undefined};
const supportedPrefixes = ['auth.', 'user.', 'skinlib.', 'texture.', 'admin.'];
@ -14,14 +13,13 @@ function parseURI(uri: string): ts.ArrowFunction {
const matches = /{([a-z]+)}/.exec(uri);
if (matches?.[0] && matches?.[1]) {
const parameter = matches[1];
const type
= parameter.endsWith('id')
|| parameter === 'texture'
|| parameter === 'user'
|| parameter === 'player'
|| parameter === 'report'
? ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
const type = parameter.endsWith('id')
|| parameter === 'texture'
|| parameter === 'user'
|| parameter === 'player'
|| parameter === 'report'
? ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
return ts.factory.createArrowFunction(
undefined,
@ -91,11 +89,11 @@ function parseTree(tree: Tree): ts.ObjectLiteralExpression {
const {stdout} = spawnSync(
'php',
['artisan', 'route:list', '--json', '--columns=uri,name'],
{encoding: 'utf-8'},
{encoding: 'utf8'},
);
let routes: Route[] = [];
try {
routes = JSON.parse(stdout);
routes = JSON.parse(stdout) as Route[];
} catch (error) {
console.error(stdout);
throw error;
@ -111,6 +109,7 @@ for (const route of routes
const path = route.name!.split('.');
const {length} = path;
// eslint-disable-next-line unicorn/no-array-reduce
path.reduce((object: TreeObject, p, index) => {
if (index === length - 1) {
object[p] = route.uri;
@ -138,14 +137,7 @@ const sourceFile = ts.createSourceFile(
const printer = ts.createPrinter({
newLine: ts.NewLineKind.LineFeed,
});
const code = await prettier.format(
printer.printNode(ts.EmitHint.Unspecified, ast, sourceFile),
{
parser: 'typescript',
semi: false,
singleQuote: true,
},
);
const code = printer.printNode(ts.EmitHint.Unspecified, ast, sourceFile);
fs.writeFileSync('./resources/assets/src/scripts/urls.ts', code, {
encoding: 'utf-8',
encoding: 'utf8',
});

View File

@ -10,6 +10,7 @@
},
"include": [
"resources/assets/src",
"resources/assets/tests",
"tools",
"vite.config.ts",
"vitest.config.ts"