import { fetch } from 'cross-fetch'; import { getAncestors, getDescendants, getPerson, getRelatives, wikiTreeGet, } from '../src/wikitree_api'; import FormData from 'form-data'; jest.mock('cross-fetch'); const mockedFetch = >fetch; function mockFetch(json: any) { mockedFetch.mockClear(); mockedFetch.mockResolvedValue({ json: () => Promise.resolve(json), } as Response); } function normalizeFormData(formData: FormData): string { return JSON.stringify(formData).replaceAll(formData.getBoundary(), ''); } function expectFormDataToContainData( received: FormData, actual: { [key: string]: string | number } ) { const formData = new FormData(); for (const key in actual) { if (actual[key]) { formData.append(key, actual[key]); } } expect(normalizeFormData(received)).toEqual(normalizeFormData(formData)); } describe('fetchWikiTree', () => { test('send simple request', async () => { const response = {}; mockFetch(response); const result = await wikiTreeGet({ action: 'getPerson', key: 'Test-1', fields: 'Name,Id', }); expect(result).toBe(response); expect(mockedFetch).toHaveBeenCalledTimes(1); expect(mockedFetch).toHaveBeenCalledWith( 'https://api.wikitree.com/api.php', expect.objectContaining({ method: 'POST', redirect: 'manual', credentials: 'include', }) ); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getPerson', key: 'Test-1', fields: 'Name,Id', }); }); test('send request to different URL', async () => { mockFetch({}); await wikiTreeGet( { action: 'getPerson', key: 'Test-1', }, { apiUrl: 'https://example.org/api' } ); expect(mockedFetch).toHaveBeenCalledTimes(1); expect(mockedFetch).toHaveBeenCalledWith( 'https://example.org/api', expect.objectContaining({ method: 'POST', redirect: 'manual', credentials: undefined, }) ); }); test('send request with auth cookies', async () => { mockFetch({}); await wikiTreeGet( { action: 'getPerson', key: 'Test-1', }, { auth: { cookies: 'auth-cookies' } } ); expect(mockedFetch).toHaveBeenCalledTimes(1); expect(mockedFetch).toHaveBeenCalledWith( 'https://api.wikitree.com/api.php', expect.objectContaining({ method: 'POST', redirect: 'manual', credentials: 'include', headers: { Cookie: 'auth-cookies' }, }) ); }); test('send custom appId', async () => { mockFetch({}); await wikiTreeGet( { action: 'getPerson', key: 'Test-1', }, { appId: 'custom-id' } ); expect(mockedFetch).toHaveBeenCalledTimes(1); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'custom-id', action: 'getPerson', key: 'Test-1', }); }); }); describe('getPerson', () => { test('send simple request', async () => { const person = { Name: 'Test-1' }; mockFetch([{ person }]); const result = await getPerson('Test-1'); expect(result).toBe(person); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getPerson', key: 'Test-1', }); }); test('send request with arguments', async () => { const person = { Name: 'Test-1' }; mockFetch([{ person }]); const result = await getPerson('Test-1', { fields: ['Father', 'Mother'], bioFormat: 'html', resolveRedirect: true, }); expect(result).toBe(person); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getPerson', key: 'Test-1', bioFormat: 'html', fields: 'Father,Mother', resolveRedirect: '1', }); }); }); describe('getAncestors', () => { test('send simple request', async () => { const person1 = { Name: 'Test-1' }; const person2 = { Name: 'Test-2' }; mockFetch([{ ancestors: [person1, person2] }]); const result = await getAncestors('Test-1'); expect(result).toEqual([person1, person2]); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getAncestors', key: 'Test-1', }); }); test('send request with arguments', async () => { const person1 = { Name: 'Test-1' }; const person2 = { Name: 'Test-2' }; mockFetch([{ ancestors: [person1, person2] }]); const result = await getAncestors('Test-1', { depth: 2, fields: ['Father', 'Mother'], bioFormat: 'html', resolveRedirect: true, }); expect(result).toEqual([person1, person2]); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getAncestors', key: 'Test-1', depth: '2', bioFormat: 'html', fields: 'Father,Mother', resolveRedirect: '1', }); }); }); describe('getDescendants', () => { test('send simple request', async () => { const person1 = { Name: 'Test-1' }; const person2 = { Name: 'Test-2' }; mockFetch([{ descendants: [person1, person2] }]); const result = await getDescendants('Test-1'); expect(result).toEqual([person1, person2]); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getDescendants', key: 'Test-1', }); }); test('send request with arguments', async () => { const person1 = { Name: 'Test-1' }; const person2 = { Name: 'Test-2' }; mockFetch([{ descendants: [person1, person2] }]); const result = await getDescendants('Test-1', { depth: 2, fields: ['Father', 'Mother'], bioFormat: 'html', resolveRedirect: true, }); expect(result).toEqual([person1, person2]); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getDescendants', key: 'Test-1', depth: '2', bioFormat: 'html', fields: 'Father,Mother', resolveRedirect: '1', }); }); }); describe('getRelatives', () => { test('send simple request', async () => { const person1 = { Name: 'Test-1' }; const person2 = { Name: 'Test-2' }; mockFetch([{ items: [{ person: person1 }, { person: person2 }] }]); const result = await getRelatives(['Test-1']); expect(result).toEqual([person1, person2]); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getRelatives', keys: 'Test-1', }); }); test('send request with arguments', async () => { const person1 = { Name: 'Test-1' }; const person2 = { Name: 'Test-2' }; mockFetch([{ items: [{ person: person1 }, { person: person2 }] }]); const result = await getRelatives(['Test-1'], { fields: ['Father', 'Mother'], bioFormat: 'html', getChildren: true, getParents: true, getSiblings: true, getSpouses: true, }); expect(result).toEqual([person1, person2]); const requestedData = mockedFetch.mock.calls[0][1].body as any as FormData; expectFormDataToContainData(requestedData, { format: 'json', appId: 'wikitree-js', action: 'getRelatives', keys: 'Test-1', getParents: 'true', getChildren: 'true', getSpouses: 'true', getSiblings: 'true', bioFormat: 'html', fields: 'Father,Mother', }); }); });