mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
* refactor: more intuitive interfaces * refactor: simpler refresh before: on every request we were debouncing a refresh request after: call refresh only once before now() + 'expires' * refactor: prefix on base storage * fixup! refactor: simpler refresh before: on every request we were debouncing a refresh request after: call refresh only once before now() + 'expires' * refactor: simpler axios transport before: handle auth headers after: auth headers are handled on directus instance * refactor: simpler usage of Directus constructor * fixup! refactor: simpler refresh before: on every request we were debouncing a refresh request after: call refresh only once before now() + 'expires' * refactor: fix tests based on previous changes * refactor: better auth constructor before: depends on SDK instance after: depends on Transport and Storage instance * accept staticToken from auth * make transport and storage as optional on options * fix type auth refresh * simplify transport * fix test for previous changes * improve auth class * revert some IAuth props because tests * allow to force memory of localstorage on storage * add tests for previous change * document everything and simplify some things * fix override headers on request * better name typing * fix private axios * removed boolean from CLI auth.refresh() * fix missing url in some examples * soem grammar updates Co-authored-by: Jay Cammarano <jay.cammarano@gmail.com> Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
129 lines
3.8 KiB
TypeScript
129 lines
3.8 KiB
TypeScript
/**
|
|
* @jest-environment node
|
|
*/
|
|
|
|
import nock from 'nock';
|
|
|
|
import { Transport } from '../../src/base/transport';
|
|
import { TransportResponse, TransportError } from '../../src/transport';
|
|
|
|
describe('default transport', function () {
|
|
const URL = 'http://localhost';
|
|
nock.disableNetConnect();
|
|
|
|
function expectResponse<T>(response: TransportResponse<T>, expected: Partial<TransportResponse<T>>) {
|
|
if (expected.status) {
|
|
expect(response.status).toBe(expected.status);
|
|
}
|
|
if (expected.statusText) {
|
|
expect(response.statusText).toBe(expected.statusText);
|
|
}
|
|
if (expected.data) {
|
|
expect(response.data).toMatchObject<T | T[]>(expected.data);
|
|
}
|
|
if (expected.headers) {
|
|
expect(response.headers).toMatchObject(expected.headers);
|
|
}
|
|
}
|
|
|
|
['get', 'delete', 'head', 'options', 'put', 'post', 'patch'].forEach((method) => {
|
|
it(`${method} should return a response object`, async () => {
|
|
const route = `/${method}/response`;
|
|
(nock(URL) as any)[method](route).reply(200);
|
|
|
|
const transport = new Transport({ url: URL }) as any;
|
|
const response = await transport[method](route);
|
|
expectResponse(response, {
|
|
status: 200,
|
|
});
|
|
});
|
|
|
|
it(`${method} should throw on response errors`, async function () {
|
|
const route = `/${method}/500`;
|
|
(nock(URL) as any)[method](route).reply(500);
|
|
|
|
const transport = new Transport({ url: URL }) as any;
|
|
|
|
try {
|
|
await transport[method](route);
|
|
fail();
|
|
} catch (err: any) {
|
|
expect(err).toBeInstanceOf(TransportError);
|
|
}
|
|
});
|
|
|
|
it(`${method} should carry response error information`, async function () {
|
|
const route = `/${method}/403/error`;
|
|
(nock(URL) as any)[method](route).reply(403, {
|
|
errors: [
|
|
{
|
|
message: 'You don\'t have permission access to "contacts" collection.',
|
|
extensions: {
|
|
code: 'FORBIDDEN',
|
|
},
|
|
},
|
|
],
|
|
});
|
|
|
|
const transport = new Transport({ url: URL }) as any;
|
|
|
|
try {
|
|
await transport[method](route);
|
|
fail();
|
|
} catch (err: any) {
|
|
const terr = err as TransportError;
|
|
expect(terr).toBeInstanceOf(TransportError);
|
|
expect(terr.response?.status).toBe(403);
|
|
expect(terr.message).toBe('You don\'t have permission access to "contacts" collection.');
|
|
expect(terr.errors.length).toBe(1);
|
|
expect(terr.errors[0]?.message).toBe('You don\'t have permission access to "contacts" collection.');
|
|
expect(terr.errors[0]?.extensions?.code).toBe('FORBIDDEN');
|
|
}
|
|
});
|
|
|
|
it('get should throw non response errors', async function () {
|
|
const route = `/${method}/this/raises/error`;
|
|
(nock(URL) as any)[method](route).replyWithError('Random error');
|
|
|
|
const transport = new Transport({ url: URL }) as any;
|
|
|
|
try {
|
|
await transport[method](route);
|
|
fail();
|
|
} catch (err: any) {
|
|
const terr = err as TransportError;
|
|
expect(terr).toBeInstanceOf(TransportError);
|
|
expect(terr.response).toBeUndefined();
|
|
expect(terr.message).toBe('Random error');
|
|
expect(terr.parent).not.toBeUndefined();
|
|
expect(terr.parent?.message).toBe('Random error');
|
|
}
|
|
});
|
|
});
|
|
|
|
it('returns the configured url', async function () {
|
|
const transport = new Transport({ url: URL });
|
|
expect(transport.url).toBe(URL);
|
|
});
|
|
|
|
it('non axios errors are set in parent', async function () {
|
|
const transport = new Transport({ url: URL });
|
|
const mock = jest.spyOn(transport, 'beforeRequest');
|
|
mock.mockImplementation(() => {
|
|
throw new Error('this is not an axios error');
|
|
});
|
|
|
|
try {
|
|
await transport.get('/route');
|
|
fail();
|
|
} catch (err: any) {
|
|
const terr = err as TransportError;
|
|
expect(terr).toBeInstanceOf(TransportError);
|
|
expect(terr.response).toBeUndefined();
|
|
expect(terr.message).toBe('this is not an axios error');
|
|
expect(terr.parent).not.toBeUndefined();
|
|
expect(terr.parent?.message).toBe('this is not an axios error');
|
|
}
|
|
});
|
|
});
|