UNPKG

react-oc

Version:

A React component that allows OpenComponents to operate within a react application.

670 lines (615 loc) 27 kB
"use strict"; require("jest-plugin-console-matchers/setup"); var _react = _interopRequireDefault(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _server = _interopRequireDefault(require("react-dom/server")); var _jquery = _interopRequireDefault(require("jquery")); var _bluebird = _interopRequireDefault(require("bluebird")); var _reactHelpers = require("./__test__/react-helpers"); var _OpenComponentsContext = require("./OpenComponentsContext"); var _OCContext = require("./OCContext"); var _OpenComponent = require("./OpenComponent"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } describe('<OpenComponent />', function () { var callCountScript = 'window.callCount = window.callCount || 0; window.callCount++;'; beforeEach(function () { delete window.callCount; document.body.innerHTML = ''; }); describe('When not mounted within a <ComponentContext />', function () { it('throws an error', function () { var node = document.createElement('div'); return expect((0, _reactHelpers.renderAsync)(_react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" }), node)).rejects.toThrow(/must be nested within a <ComponentContext \/>/); }); }); var baseContext, baseContextServer; beforeEach(function () { baseContext = { getElement: jest.fn(function () {}), getHtml: jest.fn(function () { return 'hello world'; }), saveElement: jest.fn(function () {}), oc: { renderNestedComponent: jest.fn(function (_, cb) { return cb(); }), $: _jquery.default } }; baseContextServer = { getElement: baseContext.getElement, getHtml: baseContext.getHtml, saveElement: baseContext.saveElement }; }); it('throws an error if prefetchKey prop was not defined', function () { var node = document.createElement('div'); return expect((0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, null)), node)).rejects.toThrow(/Mandatory prop 'prefetchKey' was not provided/); }); it('should apply the given id to a container div', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee() { var node; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: node = document.createElement('div'); _context.next = 3; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { id: "my-unique-id", prefetchKey: "my-component" })), node); case 3: expect(node.childNodes[0].id).toBe('my-unique-id'); case 4: case "end": return _context.stop(); } } }, _callee, this); }))); it('should apply the given className to a container div', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee2() { var node; return regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: node = document.createElement('div'); _context2.next = 3; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { className: "my-class", prefetchKey: "my-component" })), node); case 3: expect(node.childNodes[0].className).toBe('my-class'); case 4: case "end": return _context2.stop(); } } }, _callee2, this); }))); it('renders an empty div if no html is provided by context.getHtml', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee3() { var node; return regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: node = document.createElement('div'); baseContext.getHtml.mockImplementation(function () { return undefined; }); _context3.next = 4; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node); case 4: expect(node.innerHTML).toBe('<div></div>'); case 5: case "end": return _context3.stop(); } } }, _callee3, this); }))); it('renders the fallback if no html is provided by context.getHtml and fallback is provided', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee4() { var node; return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: node = document.createElement('div'); baseContext.getHtml.mockImplementation(function () { return undefined; }); _context4.next = 4; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component", fallback: "<span>Hello world</span>" })), node); case 4: expect(node.innerHTML).toBe('<div><span>Hello world</span></div>'); case 5: case "end": return _context4.stop(); } } }, _callee4, this); }))); it('should render markup from context.getHtml with prefetchKey in container div', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee5() { var node, fakeHtml; return regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: node = document.createElement('div'); fakeHtml = "<h1>Hello world</h1>"; baseContext.getHtml.mockImplementation(function (key) { return key === 'my-component' ? fakeHtml : undefined; }); _context5.next = 5; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node); case 5: expect(node.innerHTML).toContain(fakeHtml); case 6: case "end": return _context5.stop(); } } }, _callee5, this); }))); it('should run any scripts from context.getHtml with prefetchKey in container div', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee6() { var node, fakeHtml; return regeneratorRuntime.wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: node = document.createElement('div'); document.body.append(node); fakeHtml = "<h1>Hello world</h1><script>".concat(callCountScript, "</script>"); baseContext.getHtml.mockImplementation(function (key) { return key === 'my-component' ? fakeHtml : undefined; }); _context6.next = 6; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node); case 6: expect(window.callCount).toBe(1); case 7: case "end": return _context6.stop(); } } }, _callee6, this); }))); describe('when getHtml returns an unrendered oc-component tag', function () { var fakeHtml = "<oc-component data-rendered=\"false\" name=\"my-component\"></oc-component>"; it('should call oc.renderNestedComponent', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee7() { var node; return regeneratorRuntime.wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: node = document.createElement('div'); baseContext.getHtml.mockImplementation(function () { return fakeHtml; }); _context7.next = 4; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node); case 4: expect(baseContext.oc.renderNestedComponent).toBeCalledWith(expect.objectContaining({ jquery: expect.anything(), 0: expect.objectContaining({ outerHTML: fakeHtml }) }), expect.anything()); case 5: case "end": return _context7.stop(); } } }, _callee7, this); }))); }); it('should render markup from context.getHtml with prefetchKey in container div', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee8() { var node, fakeHtml; return regeneratorRuntime.wrap(function _callee8$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: node = document.createElement('div'); fakeHtml = "<h1>Hello world</h1>"; baseContext.getHtml.mockImplementation(function (key) { return key === 'my-component' ? fakeHtml : undefined; }); _context8.next = 5; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node); case 5: expect(node.innerHTML).toContain(fakeHtml); case 6: case "end": return _context8.stop(); } } }, _callee8, this); }))); describe('when server side rendering', function () { it('should render markup from context.getHtml with prefetchKey in container div', function () { var fakeHtml = "<h1>Hello world</h1>"; baseContextServer.getHtml.mockImplementation(function (key) { return key === 'my-component' ? fakeHtml : undefined; }); var render = _server.default.renderToString(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContextServer) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" }))); expect(render).toContain(fakeHtml); }); }); describe('when hydrating over server side rendered markup', function () { it('should not change markup', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee9() { var node, existingMarkup; return regeneratorRuntime.wrap(function _callee9$(_context9) { while (1) { switch (_context9.prev = _context9.next) { case 0: node = document.createElement('div'); node.innerHTML = _server.default.renderToString(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContextServer, { getHtml: function getHtml() { return '<h1>Hello</h1><p>World</p>'; } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" }))); existingMarkup = node.innerHTML; _context9.next = 5; return new _bluebird.default(function (resolve) { return _reactDom.default.hydrate(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext, { getHtml: function getHtml() { return undefined; } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node, resolve); }); case 5: expect(node.innerHTML).toBe(existingMarkup); case 6: case "end": return _context9.stop(); } } }, _callee9, this); }))); it('should warn if getHtml provides a different value than server', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee10() { var node, existingMarkup, expectedWarning; return regeneratorRuntime.wrap(function _callee10$(_context10) { while (1) { switch (_context10.prev = _context10.next) { case 0: node = document.createElement('div'); node.innerHTML = _server.default.renderToString(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContextServer, { getHtml: function getHtml() { return '<h1>Hello</h1><p>World</p>'; } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" }))); existingMarkup = node.innerHTML; expectedWarning = /Warning: Prop `[^`]+` did not match./; suppress.console('error', expectedWarning); _context10.next = 7; return new _bluebird.default(function (resolve) { return _reactDom.default.hydrate(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext, { getHtml: function getHtml() { return '<h1>Goodbye</h1><p>Universe</p>'; } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node, resolve); }); case 7: expect(console.error).toHaveBeenCalledWith(expect.stringMatching(expectedWarning), 'dangerouslySetInnerHTML', expect.anything(), expect.anything()); case 8: case "end": return _context10.stop(); } } }, _callee10, this); }))); it('should not run script tags again', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee11() { var node, existingMarkup; return regeneratorRuntime.wrap(function _callee11$(_context11) { while (1) { switch (_context11.prev = _context11.next) { case 0: node = document.createElement('div'); document.body.append(node); node.innerHTML = _server.default.renderToString(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContextServer, { getHtml: function getHtml() { return "<h1>Hello</h1><p>World</p><script>".concat(callCountScript, "</script>"); } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" }))); // simulate browser called script tag. eval(callCountScript); existingMarkup = node.innerHTML; _context11.next = 7; return new _bluebird.default(function (resolve) { return _reactDom.default.hydrate(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext, { getHtml: function getHtml() { return undefined; } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node, resolve); }); case 7: expect(window.callCount).toBe(1); case 8: case "end": return _context11.stop(); } } }, _callee11, this); }))); it('should run script tags again if getHtml returns the same markup during hydration', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee12() { var node, fakeMarkup, existingMarkup; return regeneratorRuntime.wrap(function _callee12$(_context12) { while (1) { switch (_context12.prev = _context12.next) { case 0: node = document.createElement('div'); document.body.append(node); fakeMarkup = "<h1>Hello</h1><p>World</p><script>".concat(callCountScript, "</script>"); node.innerHTML = _server.default.renderToString(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContextServer, { getHtml: function getHtml() { return fakeMarkup; } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" }))); // simulate browser called script tag. eval(callCountScript); existingMarkup = node.innerHTML; _context12.next = 8; return new _bluebird.default(function (resolve) { return _reactDom.default.hydrate(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext, { getHtml: function getHtml() { return fakeMarkup; } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component" })), node, resolve); }); case 8: expect(window.callCount).toBe(2); case 9: case "end": return _context12.stop(); } } }, _callee12, this); }))); }); describe('when given a captureAs prop', function () { it('calls saveElements on context with the captureAs value and elements from getHtml', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee13() { var node, html, saveElements, getElements; return regeneratorRuntime.wrap(function _callee13$(_context13) { while (1) { switch (_context13.prev = _context13.next) { case 0: node = document.createElement('div'); html = '<div>hello</div><h1>world</h1>'; saveElements = jest.fn(); getElements = jest.fn(); _context13.next = 6; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext, { saveElements: saveElements, getElements: getElements, getHtml: function getHtml() { return html; } }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component", captureAs: "my-component-1" })), node); case 6: expect(saveElements).toBeCalledWith('my-component-1', [expect.objectContaining({ innerHTML: 'hello', tagName: 'DIV' }), expect.objectContaining({ innerHTML: 'world', tagName: 'H1' })]); case 7: case "end": return _context13.stop(); } } }, _callee13, this); }))); describe('when context.getElements returns a html element', function () { it('calls getElements with the captureAs key', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee14() { var node, element, getElements; return regeneratorRuntime.wrap(function _callee14$(_context14) { while (1) { switch (_context14.prev = _context14.next) { case 0: node = document.createElement('div'); element = document.createElement('span'); getElements = jest.fn().mockImplementation(function (key) { return element; }); _context14.next = 5; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext, { getElements: getElements }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component", captureAs: "my-component-1" })), node); case 5: expect(getElements).toBeCalledWith('my-component-1'); case 6: case "end": return _context14.stop(); } } }, _callee14, this); }))); it('injects the elements into the container', /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee15() { var node, prevNode, elements, getElements, div, i; return regeneratorRuntime.wrap(function _callee15$(_context15) { while (1) { switch (_context15.prev = _context15.next) { case 0: node = document.createElement('div'); prevNode = document.createElement('span'); prevNode.innerHTML = '<span>span</span>hello<div>div</div>'; elements = _toConsumableArray(prevNode.childNodes); getElements = jest.fn().mockImplementation(function (key) { return elements; }); _context15.next = 7; return (0, _reactHelpers.renderAsync)(_react.default.createElement(_OCContext.OCContext.Provider, { value: _objectSpread({}, baseContext, { getElements: getElements }) }, _react.default.createElement(_OpenComponent.OpenComponent.Prefetched, { prefetchKey: "my-component", captureAs: "my-component-1" })), node); case 7: div = node.childNodes[0]; expect(div.childNodes.length).toBe(elements.length); for (i = 0; i < elements.length; i++) { // using toBe ensures that it is the same element with // all event handlers etc. in-tact. expect(div.childNodes[i]).toBe(elements[i]); } case 10: case "end": return _context15.stop(); } } }, _callee15, this); }))); }); }); }); //# sourceMappingURL=OpenComponent.Prefetched.test.js.map