it('triggers `response(statusCode, headers)` when received headers', done => { nock('https://fragment') .get('/') .reply(200, 'OK', RESPONSE_HEADERS); const fragment = new Fragment(getOptions(TAG)); fragment.on('response', (statusCode, headers) => { assert.equal(statusCode, 200); assert.deepEqual(headers, RESPONSE_HEADERS); done(); }); fragment.fetch(REQUEST); });
it('triggers `error(error)` when fragment times out', done => { nock('https://fragment') .get('/') .socketDelay(101) .reply(200); const tag = { attributes: { src: 'https://fragment', timeout: '100' } }; const fragment = new Fragment(getOptions(tag)); fragment.on('error', err => { assert.equal(err.message, 'socket hang up'); done(); }); fragment.fetch(REQUEST); });
it('emits `context:error(request, error)` event', done => { const onContextError = sinon.spy(); const rejectPrm = Promise.reject('Error fetching context'); rejectPrm.catch(() => {}); mockContext.returns(rejectPrm); tailor.on('context:error', onContextError); http.get('http://localhost:8080/template', response => { const request = onContextError.args[0][0]; const error = onContextError.args[0][1]; assert.equal(request.url, '/template'); assert.equal(error, 'Error fetching context'); response.resume(); response.on('end', done); }); });
describe('Custom async fragments', () => { it('should add async fragments from handleTag', done => { nock('https://fragment') .get('/1') .reply(200, 'hello'); mockTemplate.returns('<delayed-fragment></delayed-fragment>'); mockChildTemplate.returns(''); getResponse('http://localhost:8080/test') .then(response => { assert.equal( response.body, '<html><head></head><body><script data-pipe>p.placeholder(0)</script><script data-pipe>p.start(0)</script>hello<script data-pipe>p.end(0)</script></body></html>' ); }) .then(done, done); }); });
it('emits `error(request, error)` event on template error', done => { const onTemplateError = sinon.spy(); mockTemplate.returns(false); tailor.on('error', onTemplateError); http.get('http://localhost:8080/template', response => { const request = onTemplateError.args[0][0]; const error = onTemplateError.args[0][1]; assert.equal(request.url, '/template'); assert.equal(error, 'Error fetching template'); response.resume(); response.on('end', done); }); });
it('should not trigger `response` and `end` if there was an `error`', done => { const onResponse = sinon.spy(); const onEnd = sinon.spy(); const onError = sinon.spy(); nock('https://fragment') .get('/') .reply(500); const fragment = new Fragment(getOptions(TAG)); fragment.on('response', onResponse); fragment.on('end', onEnd); fragment.on('error', onError); fragment.fetch(REQUEST); fragment.stream.on('end', () => { assert.equal(onResponse.callCount, 0); assert.equal(onEnd.callCount, 0); assert.equal(onError.callCount, 1); done(); }); fragment.stream.resume(); });
it('should return response code and location header of the 1st primary fragment', done => { nock('https://fragment') .get('/1') .reply(200, 'hello') .get('/2') .reply(300, 'world', { Location: 'https://redirect' }) .get('/3') .reply(500, '!'); mockTemplate.returns( '<fragment src="https://fragment/1"></fragment>' + '<fragment src="https://fragment/2" primary></fragment>' + '<fragment src="https://fragment/3" primary></fragment>' ); getResponse('http://localhost:8080/test') .then(response => { assert.equal(response.statusCode, 300); assert.equal(response.headers.location, 'https://redirect'); }) .then(done, done); });
it('emits `start(request)` event', done => { const onStart = sinon.spy(); nock('https://fragment') .get('/') .reply(200, 'hello'); mockTemplate.returns('<fragment src="https://fragment">'); tailor.on('start', onStart); http.get('http://localhost:8080/template', response => { response.resume(); response.on('end', () => { const request = onStart.args[0][0]; assert.equal(request.url, '/template'); assert.equal(onStart.callCount, 1); done(); }); }); });
it('should not trigger error and response event when fallback is triggered', done => { const onFallback = sinon.spy(); const onError = sinon.spy(); nock('https://fragment') .get('/') .reply(500, 'Server Error'); nock('https://fallback-fragment') .get('/') .reply(200); const fragment = new Fragment(getOptions(TAG_FALLBACK)); fragment.on('fallback', onFallback); fragment.on('error', onError); fragment.stream.on('end', () => { assert.equal(onFallback.callCount, 1); assert.equal(onError.callCount, 0); done(); }); fragment.fetch(REQUEST); fragment.stream.resume(); });
it('should disable browser cache', done => { nock('https://fragment') .get('/1') .reply(200, 'hello'); mockTemplate.returns( '<fragment src="https://fragment/1"></fragment>' ); getResponse('http://localhost:8080/test') .then(response => { const headers = response.headers; assert.equal( 'no-cache, no-store, must-revalidate', headers['cache-control'] ); assert.equal('no-cache', headers['pragma']); }) .then(done, done); });
it('triggers `error(error)` when there is socket error', done => { const ERROR = { message: 'something awful happened', code: 'AWFUL_ERROR' }; nock('https://fragment') .get('/') .replyWithError(ERROR); const fragment = new Fragment(getOptions(TAG)); fragment.on('error', error => { assert.equal(error.message, ERROR.message); done(); }); fragment.fetch(REQUEST); });
it('emits `error(request, error)` event on primary error/timeout', done => { const onPrimaryError = sinon.spy(); nock('https://fragment') .get('/') .reply(500); mockTemplate.returns('<fragment primary src="https://fragment">'); tailor.on('error', onPrimaryError); http.get('http://localhost:8080/template', response => { const request = onPrimaryError.args[0][0]; const error = onPrimaryError.args[0][1]; assert.equal(request.url, '/template'); assert.equal(error.message, 'Internal Server Error'); response.resume(); response.on('end', done); }); });
it('emits `end(request, contentSize)` event', done => { const onEnd = sinon.spy(); mockTemplate.returns( '<html><head></head><body><h2></h2></body></html>' ); tailor.on('end', onEnd); http.get('http://localhost:8080/template', response => { response.resume(); response.on('end', () => { const request = onEnd.args[0][0]; const contentSize = onEnd.args[0][1]; assert.equal(request.url, '/template'); assert.equal(contentSize, 48); assert.equal(onEnd.callCount, 1); done(); }); }); });
it('triggers `end(contentSize)` when the content is succesfully retreived', done => { nock('https://fragment') .get('/') .reply(200, '12345'); const fragment = new Fragment(getOptions(TAG)); fragment.on('end', contentSize => { assert.equal(contentSize, 5); done(); }); fragment.fetch(REQUEST); fragment.stream.resume(); });
it('forwards `fragment:start(request, fragment)` event from a fragment', done => { const onFragmentStart = sinon.spy(); nock('https://fragment') .get('/') .reply(200, 'hello'); mockTemplate.returns('<fragment src="https://fragment">'); tailor.on('fragment:start', onFragmentStart); http.get('http://localhost:8080/template', response => { const request = onFragmentStart.args[0][0]; const fragment = onFragmentStart.args[0][1]; assert.equal(request.url, '/template'); assert.equal(fragment.url, 'https://fragment'); response.resume(); response.on('end', done); }); });