144 lines
4.4 KiB
TypeScript
144 lines
4.4 KiB
TypeScript
import { isActionFailure } from '@sveltejs/kit';
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
import type { ApiClient } from '$lib/server/api';
|
|
import {
|
|
inviteCoauthors,
|
|
loadInvitationCount,
|
|
parseUserIds,
|
|
removeCoauthor,
|
|
respondToInvitation,
|
|
searchUsers
|
|
} from '$lib/server/coauthors';
|
|
|
|
const asApi = (fake: unknown) => fake as ApiClient;
|
|
|
|
function failed(status: number) {
|
|
return { error: { status }, response: { status } };
|
|
}
|
|
|
|
describe('parseUserIds', () => {
|
|
it('trims, drops blanks and removes duplicates', () => {
|
|
expect(parseUserIds([' a ', '', 'b', 'a'])).toEqual(['a', 'b']);
|
|
});
|
|
});
|
|
|
|
describe('inviteCoauthors', () => {
|
|
it('rejects an empty selection without calling the API', async () => {
|
|
const POST = vi.fn();
|
|
const result = await inviteCoauthors(asApi({ POST }), 't1', ['', ' ']);
|
|
expect(isActionFailure(result)).toBe(true);
|
|
expect(POST).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('rejects more users than the API accepts', async () => {
|
|
const POST = vi.fn();
|
|
const ids = Array.from({ length: 21 }, (_, i) => String(i));
|
|
const result = await inviteCoauthors(asApi({ POST }), 't1', ids);
|
|
expect(isActionFailure(result)).toBe(true);
|
|
expect(POST).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('returns the full invite list of the track', async () => {
|
|
const POST = vi.fn(async () => ({
|
|
data: [
|
|
{ userId: 'u1', name: 'Ana', status: 'Pending' },
|
|
{ userId: 'u2', name: 'Leo', status: 'Accepted' }
|
|
]
|
|
}));
|
|
const result = await inviteCoauthors(asApi({ POST }), 't1', ['u1', 'u1']);
|
|
expect(POST).toHaveBeenCalledWith('/tracks/{id}/coauthors', {
|
|
params: { path: { id: 't1' } },
|
|
body: { userIds: ['u1'] }
|
|
});
|
|
expect(result).toEqual({
|
|
invites: [
|
|
{ userId: 'u1', name: 'Ana', status: 'Pending' },
|
|
{ userId: 'u2', name: 'Leo', status: 'Accepted' }
|
|
]
|
|
});
|
|
});
|
|
|
|
it.each([
|
|
[400, 'ti mismo'],
|
|
[403, 'autor'],
|
|
[409, 'ya tiene']
|
|
])('explains a %i response', async (status, text) => {
|
|
const POST = vi.fn(async () => failed(status));
|
|
const result = await inviteCoauthors(asApi({ POST }), 't1', ['u1']);
|
|
expect(isActionFailure(result)).toBe(true);
|
|
if (!isActionFailure(result)) return;
|
|
expect(result.status).toBe(status);
|
|
expect(result.data).toMatchObject({ message: expect.stringContaining(text) });
|
|
});
|
|
});
|
|
|
|
describe('removeCoauthor', () => {
|
|
it('returns the removed user', async () => {
|
|
const DELETE = vi.fn(async () => ({}));
|
|
expect(await removeCoauthor(asApi({ DELETE }), 't1', 'u1')).toEqual({ removed: 'u1' });
|
|
expect(DELETE).toHaveBeenCalledWith('/tracks/{id}/coauthors/{userId}', {
|
|
params: { path: { id: 't1', userId: 'u1' } }
|
|
});
|
|
});
|
|
|
|
it('fails when the API refuses', async () => {
|
|
const DELETE = vi.fn(async () => failed(403));
|
|
expect(isActionFailure(await removeCoauthor(asApi({ DELETE }), 't1', 'u1'))).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('respondToInvitation', () => {
|
|
it('calls the endpoint matching the decision', async () => {
|
|
const POST = vi.fn(async () => ({}));
|
|
await respondToInvitation(asApi({ POST }), 'i1', 'accept');
|
|
await respondToInvitation(asApi({ POST }), 'i1', 'reject');
|
|
expect(POST).toHaveBeenNthCalledWith(1, '/coauthor-invitations/{id}/accept', {
|
|
params: { path: { id: 'i1' } }
|
|
});
|
|
expect(POST).toHaveBeenNthCalledWith(2, '/coauthor-invitations/{id}/reject', {
|
|
params: { path: { id: 'i1' } }
|
|
});
|
|
});
|
|
|
|
it('reports an already answered invitation', async () => {
|
|
const POST = vi.fn(async () => failed(409));
|
|
const result = await respondToInvitation(asApi({ POST }), 'i1', 'accept');
|
|
expect(isActionFailure(result)).toBe(true);
|
|
if (isActionFailure(result)) expect(result.status).toBe(409);
|
|
});
|
|
});
|
|
|
|
describe('loadInvitationCount', () => {
|
|
it('reads the total of pending invitations', async () => {
|
|
const GET = vi.fn(async () => ({ data: { items: [], totalItemCount: '3' } }));
|
|
expect(await loadInvitationCount(asApi({ GET }))).toBe(3);
|
|
});
|
|
|
|
it('falls back to zero when the request fails', async () => {
|
|
const GET = vi.fn(async () => failed(500));
|
|
expect(await loadInvitationCount(asApi({ GET }))).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('searchUsers', () => {
|
|
it('keeps only what the invite UI needs', async () => {
|
|
const GET = vi.fn(async () => ({
|
|
data: {
|
|
items: [
|
|
{
|
|
id: 'u1',
|
|
name: 'Ana',
|
|
firstName: 'A',
|
|
secondName: null,
|
|
profilePictureUrl: null,
|
|
isFollowedByViewer: true
|
|
}
|
|
]
|
|
}
|
|
}));
|
|
expect(await searchUsers(asApi({ GET }), 'an')).toEqual([
|
|
{ id: 'u1', name: 'Ana', profilePictureUrl: null }
|
|
]);
|
|
});
|
|
});
|