system.jsx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. import React, { PureComponent } from "react"
  2. import System from "core/system"
  3. import { fromJS } from "immutable"
  4. import { render } from "enzyme"
  5. import ViewPlugin from "core/plugins/view/index.js"
  6. import filterPlugin from "core/plugins/filter/index.js"
  7. import { connect, Provider } from "react-redux"
  8. describe("bound system", function(){
  9. describe("wrapActions", function(){
  10. it("should replace an action", function(){
  11. // Given
  12. const system = new System({
  13. plugins: {
  14. statePlugins: {
  15. josh: {
  16. actions: {
  17. simple: () => {
  18. return { type: "simple" }
  19. }
  20. },
  21. wrapActions: {
  22. simple: () => () => {
  23. return { type: "newSimple" }
  24. }
  25. }
  26. }
  27. }
  28. }
  29. })
  30. // When
  31. let action = system.getSystem().joshActions.simple(1)
  32. expect(action).toEqual({
  33. type: "newSimple"
  34. })
  35. })
  36. it("should expose the original action, and the system as args", function(){
  37. // Given
  38. const simple = () => ({type: "simple" })
  39. const system = new System({
  40. plugins: {
  41. statePlugins: {
  42. josh: {
  43. actions: { simple },
  44. wrapActions: {
  45. simple: (oriAction, system) => (actionArg) => {
  46. return {
  47. type: "newSimple",
  48. oriActionResult: oriAction(),
  49. system: system.getSystem(),
  50. actionArg
  51. }
  52. }
  53. }
  54. }
  55. }
  56. }
  57. })
  58. // When
  59. let action = system.getSystem().joshActions.simple(1)
  60. expect(action).toEqual({
  61. type: "newSimple",
  62. oriActionResult: { type: "simple" },
  63. system: system.getSystem(),
  64. actionArg: 1
  65. })
  66. })
  67. it("should support multiple wraps of the same action", function(){
  68. const system = new System({
  69. plugins: [
  70. {
  71. statePlugins: {
  72. kyle: {
  73. actions: {
  74. simple: () => {
  75. return {
  76. type: "simple",
  77. }
  78. }
  79. }
  80. }
  81. }
  82. },
  83. {
  84. statePlugins: {
  85. kyle: {
  86. wrapActions: {
  87. simple: (ori) => () => {
  88. return {
  89. ...ori(),
  90. firstWrap: true
  91. }
  92. }
  93. }
  94. }
  95. }
  96. },
  97. {
  98. statePlugins: {
  99. kyle: {
  100. wrapActions: {
  101. simple: (ori) => () => {
  102. return {
  103. ...ori(),
  104. secondWrap: true
  105. }
  106. }
  107. }
  108. }
  109. }
  110. }
  111. ]
  112. })
  113. // When
  114. let action = system.getSystem().kyleActions.simple(1)
  115. expect(action).toEqual({
  116. type: "simple",
  117. firstWrap: true,
  118. secondWrap: true,
  119. })
  120. })
  121. it("should execute wrapActions in the order they appear ( via plugins )", function(){
  122. const system = new System({
  123. plugins: [
  124. {
  125. statePlugins: {
  126. kyle: {
  127. actions: {
  128. simple: () => {
  129. return {
  130. type: "one",
  131. }
  132. }
  133. }
  134. }
  135. }
  136. },
  137. {
  138. statePlugins: {
  139. kyle: {
  140. wrapActions: {
  141. simple: (ori) => () => {
  142. const obj = ori()
  143. obj.type += "-two"
  144. return obj
  145. }
  146. }
  147. }
  148. }
  149. },
  150. {
  151. statePlugins: {
  152. kyle: {
  153. wrapActions: {
  154. simple: (ori) => () => {
  155. const obj = ori()
  156. obj.type += "-three"
  157. return obj
  158. }
  159. }
  160. }
  161. }
  162. }
  163. ]
  164. })
  165. // When
  166. let action = system.getSystem().kyleActions.simple(1)
  167. expect(action.type).toEqual("one-two-three")
  168. })
  169. it("should have a the latest system", function(){
  170. // Given
  171. const system = new System({
  172. plugins: [
  173. {
  174. statePlugins: {
  175. kyle: {
  176. actions: {
  177. simple: () => {
  178. return {
  179. type: "one",
  180. }
  181. }
  182. },
  183. wrapActions: {
  184. simple: (ori, {joshActions}) => () => {
  185. return joshActions.hello()
  186. }
  187. }
  188. }
  189. }
  190. },
  191. ]
  192. })
  193. // When
  194. const kyleActions = system.getSystem().kyleActions
  195. system.register({
  196. statePlugins: {
  197. josh: {
  198. actions: {
  199. hello(){ return {type: "hello" } }
  200. }
  201. }
  202. }
  203. })
  204. const action = kyleActions.simple()
  205. expect(action).toEqual({ type: "hello"})
  206. })
  207. it.skip("should be able to create async actions", function(){
  208. const system = new System({
  209. plugins: [
  210. {
  211. statePlugins: {
  212. kyle: {
  213. actions: {
  214. simple: () => {
  215. return {
  216. type: "one",
  217. }
  218. }
  219. }
  220. }
  221. }
  222. },
  223. {
  224. statePlugins: {
  225. kyle: {
  226. wrapActions: {
  227. // eslint-disable-next-line no-unused-vars
  228. simple: (ori) => (arg) => (sys) => {
  229. return { type: "called" }
  230. }
  231. }
  232. }
  233. }
  234. },
  235. ]
  236. })
  237. // When
  238. let action = system.getSystem().kyleActions.simple(1)
  239. expect(action.type).toEqual("called")
  240. })
  241. })
  242. describe("fn", function() {
  243. it("should return helper functions", function () {
  244. // Given
  245. const system = new System({
  246. plugins: [
  247. filterPlugin
  248. ]
  249. })
  250. // When
  251. const fn = system.getSystem().fn.opsFilter
  252. expect(typeof fn).toEqual("function")
  253. })
  254. })
  255. describe("selectors", function(){
  256. it("should have the first arg be the nested state, and all other args to follow", function(){
  257. // Given
  258. const system = new System({
  259. state: {
  260. josh: {
  261. one: 1
  262. }
  263. },
  264. plugins: {
  265. statePlugins: {
  266. josh: {
  267. selectors: {
  268. simple: (state, arg1) => {
  269. return { state, arg1 }
  270. }
  271. }
  272. }
  273. }
  274. }
  275. })
  276. // When
  277. let res = system.getSystem().joshSelectors.simple(1)
  278. expect(res).toEqual({
  279. state: fromJS({
  280. one: 1
  281. }),
  282. arg1: 1
  283. })
  284. })
  285. describe("when selector returns a function", function(){
  286. it("should pass the system to that function", function(){
  287. // Given
  288. const system = new System({
  289. plugins: {
  290. statePlugins: {
  291. josh: {
  292. selectors: {
  293. advanced: () => (mySystem) => {
  294. // Then
  295. expect(mySystem).toEqual(system.getSystem())
  296. return "hi"
  297. }
  298. }
  299. }
  300. }
  301. }
  302. })
  303. // When
  304. let res = system.getSystem().joshSelectors.advanced(1)
  305. expect(res).toEqual("hi")
  306. })
  307. })
  308. describe("wrapSelectors", () => {
  309. it("should wrap a selector and provide a reference to the original", function(){
  310. // Given
  311. const system = new System({
  312. plugins: [
  313. {
  314. statePlugins: {
  315. doge: {
  316. selectors: {
  317. wow: () => (system) => {
  318. return "original"
  319. }
  320. }
  321. }
  322. }
  323. },
  324. {
  325. statePlugins: {
  326. doge: {
  327. wrapSelectors: {
  328. wow: (ori) => (system) => {
  329. // Then
  330. return ori() + " wrapper"
  331. }
  332. }
  333. }
  334. }
  335. }
  336. ]
  337. })
  338. // When
  339. let res = system.getSystem().dogeSelectors.wow(1)
  340. expect(res).toEqual("original wrapper")
  341. })
  342. it("should provide a live reference to the system to a wrapper", function(done){
  343. // Given
  344. const mySystem = new System({
  345. plugins: [
  346. {
  347. statePlugins: {
  348. doge: {
  349. selectors: {
  350. wow: () => (system) => {
  351. return "original"
  352. }
  353. }
  354. }
  355. }
  356. },
  357. {
  358. statePlugins: {
  359. doge: {
  360. wrapSelectors: {
  361. wow: (ori, system) => () => {
  362. // Then
  363. expect(mySystem.getSystem()).toEqual(system.getSystem())
  364. done()
  365. return ori() + " wrapper"
  366. }
  367. }
  368. }
  369. }
  370. }
  371. ]
  372. })
  373. mySystem.getSystem().dogeSelectors.wow(1)
  374. })
  375. it("should provide the state as the first argument to the inner function", function(done){
  376. // Given
  377. const mySystem = new System({
  378. state: {
  379. doge: {
  380. abc: "123"
  381. }
  382. },
  383. plugins: [
  384. {
  385. statePlugins: {
  386. doge: {
  387. selectors: {
  388. wow: () => (system) => {
  389. return "original"
  390. }
  391. }
  392. }
  393. }
  394. },
  395. {
  396. statePlugins: {
  397. doge: {
  398. wrapSelectors: {
  399. wow: (ori, system) => (dogeState) => {
  400. // Then
  401. expect(dogeState.toJS().abc).toEqual("123")
  402. done()
  403. return ori() + " wrapper"
  404. }
  405. }
  406. }
  407. }
  408. }
  409. ]
  410. })
  411. mySystem.getSystem().dogeSelectors.wow(1)
  412. })
  413. })
  414. })
  415. describe("getComponent", function() {
  416. it("returns a component from the system", function() {
  417. const system = new System({
  418. plugins: [
  419. ViewPlugin,
  420. {
  421. components: {
  422. test: ({ name }) => <div>{name} component</div>
  423. }
  424. }
  425. ]
  426. })
  427. // When
  428. let Component = system.getSystem().getComponent("test")
  429. const renderedComponent = render(<Component name="Test" />)
  430. expect(renderedComponent.text()).toEqual("Test component")
  431. })
  432. it("allows container components to provide their own `mapStateToProps` function", function() {
  433. // Given
  434. class ContainerComponent extends PureComponent {
  435. mapStateToProps(nextState, props) {
  436. return {
  437. "fromMapState": "This came from mapStateToProps"
  438. }
  439. }
  440. static defaultProps = {
  441. "fromMapState" : ""
  442. }
  443. render() {
  444. const { exampleSelectors, fromMapState, fromOwnProps } = this.props
  445. return (
  446. <div>{ fromMapState } {exampleSelectors.foo()} {fromOwnProps}</div>
  447. )
  448. }
  449. }
  450. const system = new System({
  451. plugins: [
  452. ViewPlugin,
  453. {
  454. components: {
  455. ContainerComponent
  456. }
  457. },
  458. {
  459. statePlugins: {
  460. example: {
  461. selectors: {
  462. foo() { return "and this came from the system" }
  463. }
  464. }
  465. }
  466. }
  467. ]
  468. })
  469. // When
  470. let Component = system.getSystem().getComponent("ContainerComponent", true)
  471. const renderedComponent = render(
  472. <Provider store={system.getStore()}>
  473. <Component fromOwnProps="and this came from my own props" />
  474. </Provider>
  475. )
  476. // Then
  477. expect(renderedComponent.text()).toEqual("This came from mapStateToProps and this came from the system and this came from my own props")
  478. })
  479. it("gives the system and own props as props to a container's `mapStateToProps` function", function() {
  480. // Given
  481. class ContainerComponent extends PureComponent {
  482. mapStateToProps(nextState, props) {
  483. const { exampleSelectors, fromMapState, fromOwnProps } = props
  484. return {
  485. "fromMapState": `This came from mapStateToProps ${exampleSelectors.foo()} ${fromOwnProps}`
  486. }
  487. }
  488. static defaultProps = {
  489. "fromMapState" : ""
  490. }
  491. render() {
  492. const { fromMapState } = this.props
  493. return (
  494. <div>{ fromMapState }</div>
  495. )
  496. }
  497. }
  498. const system = new System({
  499. plugins: [
  500. ViewPlugin,
  501. {
  502. components: {
  503. ContainerComponent
  504. }
  505. },
  506. {
  507. statePlugins: {
  508. example: {
  509. selectors: {
  510. foo() { return "and this came from the system" }
  511. }
  512. }
  513. }
  514. }
  515. ]
  516. })
  517. // When
  518. let Component = system.getSystem().getComponent("ContainerComponent", true)
  519. const renderedComponent = render(
  520. <Provider store={system.getStore()}>
  521. <Component fromOwnProps="and this came from my own props" />
  522. </Provider>
  523. )
  524. // Then
  525. expect(renderedComponent.text()).toEqual("This came from mapStateToProps and this came from the system and this came from my own props")
  526. })
  527. })
  528. describe("afterLoad", function() {
  529. it("should call a plugin's `afterLoad` method after the plugin is loaded", function() {
  530. // Given
  531. const system = new System({
  532. plugins: [
  533. {
  534. afterLoad(system) {
  535. this.rootInjects.wow = system.dogeSelectors.wow
  536. },
  537. statePlugins: {
  538. doge: {
  539. selectors: {
  540. wow: () => (system) => {
  541. return "so selective"
  542. }
  543. }
  544. }
  545. }
  546. }
  547. ]
  548. })
  549. // When
  550. let res = system.getSystem().wow()
  551. expect(res).toEqual("so selective")
  552. })
  553. it("should call a preset plugin's `afterLoad` method after the plugin is loaded", function() {
  554. // Given
  555. const MyPlugin = {
  556. afterLoad(system) {
  557. this.rootInjects.wow = system.dogeSelectors.wow
  558. },
  559. statePlugins: {
  560. doge: {
  561. selectors: {
  562. wow: () => (system) => {
  563. return "so selective"
  564. }
  565. }
  566. }
  567. }
  568. }
  569. const system = new System({
  570. plugins: [
  571. [MyPlugin]
  572. ]
  573. })
  574. // When
  575. let res = system.getSystem().wow()
  576. expect(res).toEqual("so selective")
  577. })
  578. it("should call a function preset plugin's `afterLoad` method after the plugin is loaded", function() {
  579. // Given
  580. const MyPlugin = {
  581. afterLoad(system) {
  582. this.rootInjects.wow = system.dogeSelectors.wow
  583. },
  584. statePlugins: {
  585. doge: {
  586. selectors: {
  587. wow: () => (system) => {
  588. return "so selective"
  589. }
  590. }
  591. }
  592. }
  593. }
  594. const system = new System({
  595. plugins: [
  596. () => {
  597. return [MyPlugin]
  598. }
  599. ]
  600. })
  601. // When
  602. let res = system.getSystem().wow()
  603. expect(res).toEqual("so selective")
  604. })
  605. it("should call a registered plugin's `afterLoad` method after the plugin is loaded", function() {
  606. // Given
  607. const MyPlugin = {
  608. afterLoad(system) {
  609. this.rootInjects.wow = system.dogeSelectors.wow
  610. },
  611. statePlugins: {
  612. doge: {
  613. selectors: {
  614. wow: () => (system) => {
  615. return "so selective"
  616. }
  617. }
  618. }
  619. }
  620. }
  621. const system = new System({
  622. plugins: []
  623. })
  624. system.register([MyPlugin])
  625. // When
  626. let res = system.getSystem().wow()
  627. expect(res).toEqual("so selective")
  628. })
  629. })
  630. describe("rootInjects", function() {
  631. it("should attach a rootInject function as an instance method", function() {
  632. // This is the same thing as the `afterLoad` tests, but is here for posterity
  633. // Given
  634. const system = new System({
  635. plugins: [
  636. {
  637. afterLoad(system) {
  638. this.rootInjects.wow = system.dogeSelectors.wow
  639. },
  640. statePlugins: {
  641. doge: {
  642. selectors: {
  643. wow: () => (system) => {
  644. return "so selective"
  645. }
  646. }
  647. }
  648. }
  649. }
  650. ]
  651. })
  652. // When
  653. let res = system.getSystem().wow()
  654. expect(res).toEqual("so selective")
  655. })
  656. })
  657. describe("error catching", function() {
  658. it("should encapsulate thrown errors in an afterLoad method", function() {
  659. // Given
  660. const ThrowyPlugin = {
  661. afterLoad(system) {
  662. throw new Error("afterLoad BREAKS STUFF!")
  663. },
  664. statePlugins: {
  665. doge: {
  666. selectors: {
  667. wow: () => (system) => {
  668. return "so selective"
  669. }
  670. }
  671. }
  672. }
  673. }
  674. const system = new System({
  675. plugins: []
  676. })
  677. // When
  678. expect(() => {
  679. system.register([ThrowyPlugin])
  680. // let resSystem = system.getSystem()
  681. }).not.toThrow()
  682. })
  683. it("should encapsulate thrown errors in an action creator", function(){
  684. // Given
  685. const system = new System({
  686. plugins: {
  687. statePlugins: {
  688. throw: {
  689. actions: {
  690. func() {
  691. throw new Error("this action creator THROWS!")
  692. }
  693. }
  694. }
  695. }
  696. }
  697. })
  698. expect(() => {
  699. // TODO: fix existing action error catcher that creates THROWN ERR actions
  700. system.getSystem().throwActions.func()
  701. }).not.toThrow()
  702. })
  703. it("should encapsulate thrown errors in a reducer", function(){
  704. // Given
  705. const system = new System({
  706. plugins: {
  707. statePlugins: {
  708. throw: {
  709. actions: {
  710. func: () => {
  711. return {
  712. type: "THROW_FUNC",
  713. payload: "BOOM!"
  714. }
  715. }
  716. },
  717. reducers: {
  718. "THROW_FUNC": (state, action) => {
  719. throw new Error("this reducer EXPLODES!")
  720. }
  721. }
  722. }
  723. }
  724. }
  725. })
  726. expect(() => {
  727. system.getSystem().throwActions.func()
  728. }).not.toThrow()
  729. })
  730. it("should encapsulate thrown errors in a selector", function(){
  731. // Given
  732. const system = new System({
  733. plugins: {
  734. statePlugins: {
  735. throw: {
  736. selectors: {
  737. func: (state, arg1) => {
  738. throw new Error("this selector THROWS!")
  739. }
  740. }
  741. }
  742. }
  743. }
  744. })
  745. expect(system.getSystem().throwSelectors.func).not.toThrow()
  746. })
  747. it("should encapsulate thrown errors in a complex selector", function(){
  748. // Given
  749. const system = new System({
  750. plugins: {
  751. statePlugins: {
  752. throw: {
  753. selectors: {
  754. func: (state, arg1) => system => {
  755. throw new Error("this selector THROWS!")
  756. }
  757. }
  758. }
  759. }
  760. }
  761. })
  762. expect(system.getSystem().throwSelectors.func).not.toThrow()
  763. })
  764. it("should encapsulate thrown errors in a wrapAction", function(){
  765. // Given
  766. const system = new System({
  767. plugins: {
  768. statePlugins: {
  769. throw: {
  770. actions: {
  771. func: () => {
  772. return {
  773. type: "THROW_FUNC",
  774. payload: "this original action does NOT throw"
  775. }
  776. }
  777. },
  778. wrapActions: {
  779. func: (ori) => (...args) => {
  780. throw new Error("this wrapAction UNRAVELS EVERYTHING!")
  781. }
  782. }
  783. }
  784. }
  785. }
  786. })
  787. expect(system.getSystem().throwActions.func).not.toThrow()
  788. })
  789. it("should encapsulate thrown errors in a wrapSelector", function(){
  790. // Given
  791. const system = new System({
  792. plugins: {
  793. statePlugins: {
  794. throw: {
  795. selectors: {
  796. func: (state, arg1) => {
  797. return 123
  798. }
  799. },
  800. wrapSelectors: {
  801. func: (ori) => (...props) => {
  802. return ori(...props)
  803. }
  804. }
  805. }
  806. }
  807. }
  808. })
  809. expect(system.getSystem().throwSelectors.func).not.toThrow()
  810. })
  811. describe("components", function() {
  812. it("should catch errors thrown inside of React Component Class render methods", function() {
  813. // Given
  814. class BrokenComponent extends React.Component {
  815. // eslint-disable-next-line react/require-render-return
  816. render() {
  817. throw new Error("This component is broken")
  818. }
  819. }
  820. const system = new System({
  821. plugins: [
  822. ViewPlugin,
  823. {
  824. components: {
  825. BrokenComponent
  826. }
  827. }
  828. ]
  829. })
  830. // When
  831. let Component = system.getSystem().getComponent("BrokenComponent")
  832. const renderedComponent = render(<Component />)
  833. // Then
  834. expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
  835. })
  836. it("should catch errors thrown inside of pure component render methods", function() {
  837. // Given
  838. class BrokenComponent extends PureComponent {
  839. // eslint-disable-next-line react/require-render-return
  840. render() {
  841. throw new Error("This component is broken")
  842. }
  843. }
  844. const system = new System({
  845. plugins: [
  846. ViewPlugin,
  847. {
  848. components: {
  849. BrokenComponent
  850. }
  851. }
  852. ]
  853. })
  854. // When
  855. let Component = system.getSystem().getComponent("BrokenComponent")
  856. const renderedComponent = render(<Component />)
  857. // Then
  858. expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
  859. })
  860. it("should catch errors thrown inside of stateless component functions", function() {
  861. // Given
  862. // eslint-disable-next-line react/require-render-return
  863. let BrokenComponent = function BrokenComponent() { throw new Error("This component is broken") }
  864. const system = new System({
  865. plugins: [
  866. ViewPlugin,
  867. {
  868. components: {
  869. BrokenComponent
  870. }
  871. }
  872. ]
  873. })
  874. // When
  875. let Component = system.getSystem().getComponent("BrokenComponent")
  876. const renderedComponent = render(<Component />)
  877. // Then
  878. expect(renderedComponent.text().startsWith("😱 Could not render")).toEqual(true)
  879. })
  880. it("should catch errors thrown inside of container components", function() {
  881. // Given
  882. class BrokenComponent extends React.Component {
  883. // eslint-disable-next-line react/require-render-return
  884. render() {
  885. throw new Error("This component is broken")
  886. }
  887. }
  888. const system = new System({
  889. plugins: [
  890. ViewPlugin,
  891. {
  892. components: {
  893. BrokenComponent
  894. }
  895. }
  896. ]
  897. })
  898. // When
  899. let Component = system.getSystem().getComponent("BrokenComponent", true)
  900. const renderedComponent = render(
  901. <Provider store={system.getStore()}>
  902. <Component />
  903. </Provider>
  904. )
  905. // Then
  906. expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
  907. })
  908. })
  909. })
  910. })