@ch1/xhr
Version:
Simple XHR Wrapper
237 lines (197 loc) • 7.07 kB
text/typescript
import { noop } from '@ch1/utility';
import { Xhr, parseQuery } from './xhr';
describe('xhr wrapper', () => {
describe('Xhr constructor function', () => {
let xhrObj: XMLHttpRequest;
function FakeHttpRequest() {
return xhrObj;
}
beforeEach(() => {
xhrObj = ({
abort: noop,
open: noop,
readyState: -1,
setRequestHeader: noop,
send: noop,
status: -1
} as any) as XMLHttpRequest; // yes, this is fake :)
});
it('creates with a custom ', () => {
const x = Xhr(FakeHttpRequest);
expect(x).not.toBe(undefined);
});
it('times out if nothing happens', () => {
const x = Xhr(FakeHttpRequest, 1);
return expect(x.get('/foo')).rejects.toEqual(
new Error('xhr: request timed out')
);
});
it('resolves if the readyState is 4 and the response is 200', () => {
const x = Xhr(FakeHttpRequest);
const promise = x.get('/some/resource');
(xhrObj as any).readyState = 4;
(xhrObj as any).responseText = 'working';
(xhrObj as any).status = 200;
(xhrObj as any).onload();
return expect(promise).resolves.toEqual('working');
});
it('rejects if the readyState is 4 and the response is not 200 or 201', () => {
const x = Xhr(FakeHttpRequest);
const promise = x.get('/some/resource');
(xhrObj as any).readyState = 4;
(xhrObj as any).responseText = 'working';
(xhrObj as any).status = 404;
(xhrObj as any).onload();
return expect(promise).rejects.toEqual(
new Error('xhr: non 200 status: 404')
);
});
it('resolves if the readyState is 4 and the response is 201', () => {
const x = Xhr(FakeHttpRequest);
const promise = x.get('/some/resource');
(xhrObj as any).readyState = 4;
(xhrObj as any).responseText = 'working';
(xhrObj as any).status = 201;
(xhrObj as any).onload();
return expect(promise).resolves.toEqual('working');
});
it('defers until readyState is 4 and the response is 200', done => {
const x = Xhr(FakeHttpRequest, 100, 1);
let didRun = false;
let didCheck = false;
x.get('/some/resource')
.then((value: string) => {
didRun = true;
expect(value).toBe('working');
expect(didCheck).toBe(true);
done();
})
.catch(done);
// Trigger the test
(xhrObj as any).readyState = 2;
(xhrObj as any).onload();
setTimeout(() => {
didCheck = true;
expect(didRun).toBe(false);
// let the test pass
(xhrObj as any).readyState = 4;
}, 5);
(xhrObj as any).status = 200;
(xhrObj as any).responseText = 'working';
});
it('forwards headers', () => {
const x = Xhr(FakeHttpRequest, 100, 1);
const headers: { [key: string]: string } = {};
xhrObj.setRequestHeader = (key: string, value: string) => {
headers[key] = value;
};
x.get('/some/resource', undefined, { Authorization: 'bearer' });
expect(headers.Authorization).toBe('bearer');
});
it('allows for default headers to be set', () => {
const x = Xhr(FakeHttpRequest, 100, 1);
const headers: { [key: string]: string } = {};
xhrObj.setRequestHeader = (key: string, value: string) => {
headers[key] = value;
};
x.defaultHeader('Authorization', 'bearer');
x.get('/some/resource');
expect(headers.Authorization).toBe('bearer');
});
it('allows for default headers to be unset', () => {
const x = Xhr(FakeHttpRequest, 100, 1);
let headers: { [key: string]: string } = {};
xhrObj.setRequestHeader = (key: string, value: string) => {
headers[key] = value;
};
x.defaultHeader('Authorization', 'bearer');
x.get('/some/resource');
expect(headers.Authorization).toBe('bearer');
headers = {};
x.defaultHeader('Authorization');
x.get('/some/resource');
expect(headers.Authorization).toBe(undefined);
});
it('allows for repeated calls to unset headers', () => {
const x = Xhr(FakeHttpRequest, 100, 1);
let headers: { [key: string]: string } = {};
xhrObj.setRequestHeader = (key: string, value: string) => {
headers[key] = value;
};
x.defaultHeader('Authorization', 'bearer');
x.get('/some/resource');
expect(headers.Authorization).toBe('bearer');
headers = {};
x.defaultHeader('Authorization');
x.defaultHeader('Authorization');
x.get('/some/resource');
expect(headers.Authorization).toBe(undefined);
});
it('ignores falsey calls to defaultHeader', () => {
const x = Xhr(FakeHttpRequest, 100, 1);
const headers: { [key: string]: string } = {};
xhrObj.setRequestHeader = (key: string, value: string) => {
headers[key] = value;
};
x.defaultHeader('', 'bearer');
x.get('/some/resource');
expect(headers['']).toBe(undefined);
});
it('forces defaultHeader values to be strings', () => {
const x = Xhr(FakeHttpRequest, 100, 1);
const headers: { [key: string]: string } = {};
xhrObj.setRequestHeader = (key: string, value: string) => {
headers[key] = value;
};
x.defaultHeader('foo', 7 as any);
x.get('/some/resource');
expect(headers['foo']).toBe('7');
});
it('rejects put calls that have no data', () => {
const x = Xhr(FakeHttpRequest);
return expect(x.put('/somthing')).rejects.toEqual(
new Error('xhr: newRequest: PUT: requires data')
);
});
it('rejects post calls that have no data', () => {
const x = Xhr(FakeHttpRequest);
return expect(x.post('/somthing')).rejects.toEqual(
new Error('xhr: newRequest: POST: requires data')
);
});
it('stringifies post data', () => {
const x = Xhr(FakeHttpRequest);
const obj = { foo: 'bar' };
let rec: any = null;
xhrObj.send = (value: any) => {
rec = value;
};
x.post('/somthing', obj);
expect(rec).toEqual(JSON.stringify(obj));
});
it('rejects if something blows up synchronously', () => {
const x = Xhr(FakeHttpRequest);
const error = new Error('chaos!');
xhrObj.send = (value: any) => {
throw error;
};
return expect(x.get('/somthing')).rejects.toBe(error);
});
});
describe('parseQuery function', () => {
it('returns false if given no parameters', () => {
expect(parseQuery()).toBe(false);
});
it('returns false if given a non object', () => {
expect(parseQuery(7 as any)).toBe(false);
});
it('variablizes a single key/value pair', () => {
const query = parseQuery({ foo: 'bar' });
expect(query).toBe('?foo=bar');
});
it('variablizes a multiple key/value pairs', () => {
const query = parseQuery({ foo: 'bar', baz: 'bof' });
expect(query).toBe('?foo=bar&baz=bof');
});
});
});