Public Access
A Steam card in the settings links, verifies or unlinks the Steam account through "Sign in through Steam". After the way back the page shows the outcome and refreshes the session, so Core gets the new Steam ID at once. Registration and settings no longer ask for a typed Steam ID.
115 lines
5.2 KiB
React
115 lines
5.2 KiB
React
// @vitest-environment jsdom
|
|
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
|
import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react';
|
|
import {MemoryRouter} from 'react-router-dom';
|
|
import {toast} from 'sonner';
|
|
import SettingsPage from './SettingsPage.jsx';
|
|
import {PreferencesProvider} from '../context/PreferencesContext.jsx';
|
|
|
|
vi.mock('react-i18next', async () => {
|
|
const mock = await import('../test/i18n-mock.js');
|
|
const i18n = {language: 'de', changeLanguage: vi.fn()};
|
|
return {...mock, useTranslation: () => ({t: mock.useTranslation().t, i18n})};
|
|
});
|
|
vi.mock('sonner', () => ({toast: {success: vi.fn(), error: vi.fn(), info: vi.fn()}}));
|
|
|
|
const STEAM_URL = 'https://steamcommunity.com/openid/login?openid.mode=checkid_setup';
|
|
|
|
const profile = (overrides = {}) => ({
|
|
id: 1, email: 'a@b.de', role: 'USER', displayName: 'Lobo', steamId: '76561198005679788', steamIdVerified: false,
|
|
settings: {useDarkTheme: true, language: 'de', publicProfile: false}, ...overrides,
|
|
});
|
|
|
|
const calls = (method) => fetch.mock.calls.filter(([, init]) => init?.method === method);
|
|
|
|
function renderPage(me, {redirectUrl = STEAM_URL, entry = '/settings'} = {}) {
|
|
globalThis.fetch = vi.fn(async (url, init) => {
|
|
if (init?.method === 'POST' && url.endsWith('/api/users/steam-link')) {
|
|
return {ok: true, status: 200, json: async () => ({redirectUrl})};
|
|
}
|
|
if (init?.method && init.method !== 'GET') {
|
|
return {ok: true, status: 204, json: async () => { throw new SyntaxError('no body'); }};
|
|
}
|
|
return {ok: true, status: 200, json: async () => me};
|
|
});
|
|
render(<MemoryRouter initialEntries={[entry]}><PreferencesProvider><SettingsPage/></PreferencesProvider></MemoryRouter>);
|
|
}
|
|
|
|
describe('SettingsPage Steam account', () => {
|
|
const assign = vi.fn();
|
|
const realLocation = window.location;
|
|
|
|
beforeEach(() => {
|
|
localStorage.setItem('tbp_session', '1');
|
|
Object.defineProperty(window, 'location', {configurable: true, value: {...realLocation, assign}});
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
localStorage.clear();
|
|
vi.clearAllMocks();
|
|
Object.defineProperty(window, 'location', {configurable: true, value: realLocation});
|
|
});
|
|
|
|
it('shows a typed-in ID as not verified and sends the user to Steam to verify it', async () => {
|
|
renderPage(profile());
|
|
|
|
expect(await screen.findByText('SETTINGS.STEAM_LINK.NOT_VERIFIED')).toBeTruthy();
|
|
fireEvent.click(screen.getByRole('button', {name: /SETTINGS.STEAM_LINK.VERIFY/}));
|
|
|
|
await waitFor(() => expect(assign).toHaveBeenCalledWith(STEAM_URL));
|
|
expect(calls('POST').map(([url]) => url).some((url) => url.endsWith('/api/users/steam-link'))).toBe(true);
|
|
});
|
|
|
|
it('does not follow a link that is not Steam', async () => {
|
|
renderPage(profile({steamId: null}), {redirectUrl: 'https://evil.example/openid/login?x'});
|
|
|
|
fireEvent.click(await screen.findByRole('button', {name: /SETTINGS.STEAM_LINK.LINK/}));
|
|
|
|
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('SETTINGS.STEAM_LINK.ERROR'));
|
|
expect(assign).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('shows a verified ID with the option to link another account', async () => {
|
|
renderPage(profile({steamIdVerified: true}));
|
|
|
|
expect(await screen.findByText('SETTINGS.STEAM_LINK.VERIFIED')).toBeTruthy();
|
|
expect(screen.getByRole('button', {name: /SETTINGS.STEAM_LINK.CHANGE/})).toBeTruthy();
|
|
});
|
|
|
|
it('back from Steam: refreshes the session so Core gets the new Steam ID, and says so', async () => {
|
|
renderPage(profile({steamIdVerified: true}), {entry: '/settings?steam=linked'});
|
|
|
|
await screen.findByText('SETTINGS.STEAM_LINK.VERIFIED');
|
|
expect(calls('POST').some(([url]) => url.endsWith('/api/auth/refresh'))).toBe(true);
|
|
expect(toast.success).toHaveBeenCalledWith('SETTINGS.STEAM_LINK.LINKED');
|
|
});
|
|
|
|
it.each([['in-use', 'error', 'SETTINGS.STEAM_LINK.IN_USE'], ['failed', 'error', 'SETTINGS.STEAM_LINK.FAILED'],
|
|
['cancelled', 'info', 'SETTINGS.STEAM_LINK.CANCELLED']])('back from Steam with %s', async (outcome, kind, key) => {
|
|
renderPage(profile(), {entry: `/settings?steam=${outcome}`});
|
|
|
|
await screen.findByText('SETTINGS.STEAM_LINK.NOT_VERIFIED');
|
|
expect(toast[kind]).toHaveBeenCalledWith(key);
|
|
expect(calls('POST').some(([url]) => url.endsWith('/api/auth/refresh'))).toBe(false);
|
|
});
|
|
|
|
it('unlinks the Steam account', async () => {
|
|
renderPage(profile({steamIdVerified: true}));
|
|
|
|
fireEvent.click(await screen.findByRole('button', {name: /SETTINGS.STEAM_LINK.UNLINK/}));
|
|
|
|
expect(await screen.findByText('SETTINGS.STEAM_LINK.NONE')).toBeTruthy();
|
|
expect(calls('DELETE')[0][0]).toMatch(/\/api\/users\/steam-link$/);
|
|
});
|
|
|
|
it('never sends a Steam ID with the settings', async () => {
|
|
renderPage(profile());
|
|
|
|
fireEvent.click(await screen.findByRole('switch', {name: 'SETTINGS.DARK_THEME'}));
|
|
|
|
await waitFor(() => expect(calls('PUT')).toHaveLength(1));
|
|
expect(JSON.parse(calls('PUT')[0][1].body)).not.toHaveProperty('steamId');
|
|
});
|
|
});
|