UNPKG

@bbc/spartacus

Version:
396 lines (310 loc) 13.2 kB
'use strict'; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _supertest = require('supertest'); var _supertest2 = _interopRequireDefault(_supertest); var _server = require('react-dom/server'); var reactDomServer = _interopRequireWildcard(_server); var _styledComponents = require('styled-components'); var styledComponents = _interopRequireWildcard(_styledComponents); var _reactHelmet = require('react-helmet'); var _loadInitialData = require('../utilities/loadInitialData'); var _loadInitialData2 = _interopRequireDefault(_loadInitialData); var _Document = require('./Document'); var _Document2 = _interopRequireDefault(_Document); var _ResourceHints = require('../helpers/tests/mocks/ResourceHints'); var _ResourceHints2 = _interopRequireDefault(_ResourceHints); var _component = require('./Document/component'); var _component2 = _interopRequireDefault(_component); var _index = require('./index'); var _index2 = _interopRequireDefault(_index); var _routes = require('../helpers/tests/mocks/routes'); var _routes2 = _interopRequireDefault(_routes); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } var validateHttpHeader = function validateHttpHeader(headers, headerKey, expectedHeaderValue) { var headerKeys = Object.keys(headers); var headerValues = Object.values(headers); var indexOfXFrame = headerKeys.indexOf(headerKey); expect(headerKeys).toContain(headerKey); expect(headerValues[indexOfXFrame]).toEqual(expectedHeaderValue); }; jest.mock('react-dom/server', function () { return { renderToString: jest.fn().mockImplementation(function () { return '<h1>Mock app</h1>'; }), renderToStaticMarkup: jest.fn().mockImplementation(function () { return '<html><body><h1>Mock app</h1></body></html>'; }) }; }); jest.mock('react-helmet', function () { return { Helmet: { renderStatic: jest.fn().mockReturnValue({ head: 'tags' }) } }; }); jest.mock('../utilities/loadInitialData'); styledComponents.ServerStyleSheet = jest.fn().mockImplementation(function () { return { collectStyles: jest.fn().mockReturnValue(_react2.default.createElement( 'h1', null, 'Mock app' )), getStyleElement: jest.fn().mockReturnValue(_react2.default.createElement('style', null)) }; }); var ServerStyleSheet = styledComponents.ServerStyleSheet; describe('Server', function () { // open a route on the server _index2.default.get('/test-url', function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref, res) { var url = _ref.url; var data, status; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return (0, _loadInitialData2.default)(url, _routes2.default); case 2: data = _context.sent; status = data.status; _context.t0 = res.status(status); _context.next = 7; return (0, _Document2.default)(url, data, _routes2.default, _ResourceHints2.default, ServerStyleSheet, _reactHelmet.Helmet); case 7: _context.t1 = _context.sent; _context.t0.send.call(_context.t0, _context.t1); case 9: case 'end': return _context.stop(); } } }, _callee, undefined); })); return function (_x, _x2) { return _ref2.apply(this, arguments); }; }()); var makeRequest = function () { var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(path) { return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: return _context2.abrupt('return', (0, _supertest2.default)(_index2.default).get(path)); case 1: case 'end': return _context2.stop(); } } }, _callee2, undefined); })); return function makeRequest(_x3) { return _ref3.apply(this, arguments); }; }(); describe('/status', function () { it('should respond with a 200', _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() { var _ref5, statusCode; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: _context3.next = 2; return makeRequest('/status'); case 2: _ref5 = _context3.sent; statusCode = _ref5.statusCode; expect(statusCode).toBe(200); case 5: case 'end': return _context3.stop(); } } }, _callee3, undefined); }))); }); describe('Successful render', function () { var successDataResponse = { isAmp: false, data: { some: 'data' }, service: 'someService', status: 200 }; var notFoundDataResponse = { isAmp: false, data: { some: 'data' }, service: 'someService', status: 404 }; describe('200 status code', function () { beforeEach(function () { _loadInitialData2.default.mockImplementationOnce(function () { return Promise.resolve(successDataResponse); }); }); it('should respond with rendered data', _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() { var _ref7, text, status; return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: _context4.next = 2; return makeRequest('/test-url'); case 2: _ref7 = _context4.sent; text = _ref7.text; status = _ref7.status; expect(status).toBe(200); expect(reactDomServer.renderToString).toHaveBeenCalledWith(_react2.default.createElement( 'h1', null, 'Mock app' )); expect(reactDomServer.renderToStaticMarkup).toHaveBeenCalledWith(_react2.default.createElement(_component2.default, { app: '<h1>Mock app</h1>', assets: ['one.js'], data: successDataResponse, helmet: { head: 'tags' }, ResourceHints: _ResourceHints2.default, styleTags: _react2.default.createElement('style', null) })); expect(text).toEqual('<!doctype html><html><body><h1>Mock app</h1></body></html>'); case 9: case 'end': return _context4.stop(); } } }, _callee4, undefined); }))); }); // TODO: handle this 404 test better - https://github.com/bbc/SPArtacus/issues/40 describe('404 status code', function () { beforeEach(function () { _loadInitialData2.default.mockImplementationOnce(function () { return Promise.resolve(notFoundDataResponse); }); }); it('should respond with a rendered 404', _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() { var _ref9, status, text; return regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: _context5.next = 2; return makeRequest('/some-unknown-url'); case 2: _ref9 = _context5.sent; status = _ref9.status; text = _ref9.text; expect(status).toBe(404); expect(text).toEqual('<!DOCTYPE html>\n<html lang="en">\n<head>\n<meta charset="utf-8">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot GET /some-unknown-url</pre>\n</body>\n</html>\n'); case 7: case 'end': return _context5.stop(); } } }, _callee5, undefined); }))); }); }); }); describe('Server HTTP Headers', function () { var statusRequest = void 0; beforeAll(_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() { return regeneratorRuntime.wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: _context6.next = 2; return (0, _supertest2.default)(_index2.default).get('/status'); case 2: statusRequest = _context6.sent; case 3: case 'end': return _context6.stop(); } } }, _callee6, undefined); }))); it('should not contain \'x-powered-by\'', function () { var headerKeys = Object.keys(statusRequest.headers); expect(headerKeys).not.toContain('x-powered-by'); }); it('should have \'x-frame-options\' set to \'DENY\'', function () { validateHttpHeader(statusRequest.headers, 'x-frame-options', 'DENY'); }); it('should have X-DNS-Prefetch-Control set to \'off\' ', function () { validateHttpHeader(statusRequest.headers, 'x-dns-prefetch-control', 'off'); }); it('should have Strict-Transport-Security set to \'max-age=15552000; includeSubDomains\' ', function () { validateHttpHeader(statusRequest.headers, 'strict-transport-security', 'max-age=15552000; includeSubDomains'); }); it('should have X-Download-Options set to \'noopen\' ', function () { validateHttpHeader(statusRequest.headers, 'x-download-options', 'noopen'); }); it('should have X-Content-Type-Options set to \'nosniff\' ', function () { validateHttpHeader(statusRequest.headers, 'x-content-type-options', 'nosniff'); }); it('should have X-XSS-Protection set to \'1; mode=block\' ', function () { validateHttpHeader(statusRequest.headers, 'x-xss-protection', '1; mode=block'); }); describe("should set 'x-clacks-overhead' header", function () { it('should send the message on', _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee7() { return regeneratorRuntime.wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: validateHttpHeader(statusRequest.headers, 'x-clacks-overhead', 'GNU Terry Pratchett'); case 1: case 'end': return _context7.stop(); } } }, _callee7, undefined); }))); it('should not log the message', _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee9() { var makeRequest; return regeneratorRuntime.wrap(function _callee9$(_context9) { while (1) { switch (_context9.prev = _context9.next) { case 0: global.console.log = jest.fn(); makeRequest = function () { var _ref13 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8(path) { return regeneratorRuntime.wrap(function _callee8$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: return _context8.abrupt('return', (0, _supertest2.default)(_index2.default).get(path)); case 1: case 'end': return _context8.stop(); } } }, _callee8, undefined); })); return function makeRequest(_x4) { return _ref13.apply(this, arguments); }; }(); _context9.next = 4; return makeRequest('/status'); case 4: expect(global.console.log).not.toHaveBeenCalledWith('GNU Terry Pratchett'); case 5: case 'end': return _context9.stop(); } } }, _callee9, undefined); }))); // It should turn the message around at the end of the line and send it back again (Currently untested) }); });