UNPKG

@girders-elements/core

Version:

Girders Elements is an architectural framework that assists with building data-driven apps with React or React Native.

253 lines (216 loc) 7.93 kB
'use strict' import { mount } from 'enzyme' import React from 'react' import { Iterable, List, fromJS } from 'immutable' import Cursor from 'immutable/contrib/cursor' import { kindOf, isOfKind } from '../../data' import { isSubclassOf } from '../../impl/classes' import * as Subsystem from '../../subsystem' import * as Kernel from '../../kernel' import uiSubsystem from '..' const app = Subsystem.create(() => ({ name: 'app', })) const ui = app.ui /* * Tests for the ui API. */ describe('UI Subsystem', () => { const kernel = Kernel.create([uiSubsystem, app], {}, {}) /* * Tests for ui.register. */ describe('Element UI registration', () => { afterEach(() => { ui.reset() // clears all registered components }) describe('#register', () => { it("doesn't accept undefined/null components", () => { expect(() => ui.register('component')).toThrow() expect(() => ui.register('component', null)).toThrow() }) it("doesn't accept invalid component definitions", () => { expect(() => ui.register('component', 'foo')).toThrow() expect(() => ui.register('component', 1)).toThrow() expect(() => ui.register('component', {})).toThrow() expect(() => ui.register()).toThrow() }) it('expects valid element references', () => { class Comp extends React.Component {} expect(() => ui.register(1, Comp)).toThrow() expect(() => ui.register(null, Comp)).toThrow() expect(() => ui.register(false, Comp)).toThrow() expect(() => ui.register({ component: 'comp' }, Comp)).toThrow() expect(() => ui.register('component', Comp)).not.toThrow() expect(() => ui.register(['component', 'subkind'], Comp)).not.toThrow() expect(() => ui.register(List.of('component', 'subkind'), Comp) ).not.toThrow() }) it('accepts react components', () => { class Comp extends React.Component {} expect(() => ui.register('component', Comp)).not.toThrow() }) it('accepts pure-function components', () => { function Template() { return <div /> } expect(() => ui.register('component', Template)).not.toThrow() }) // BREAKING change it.skip('returns the registered element UI (not necessarily the same component)', () => { class Comp extends React.Component {} const Klass = ui.register('component', Comp) expect(isSubclassOf(Klass, React.Component)).toBeTruthy() }) }) }) /* * Tests for ui.forElement and ui.forElements. */ describe('Element UI Lookup', () => { ui.register('c1', () => { return <div>Watson</div> }) ui.register('c2', () => { return <div>Hudson</div> }) ui.register(['c2', 'specific'], () => { return <div>Mycroft</div> }) ui.register('detectives', ({ uiFor }) => { return <div id="list">{uiFor('list')}</div> }) const globalUiFor = kernel.subsystems.ui.uiFor describe('ui.uiFor (single element)', () => { it('Requires a cursor around the element', () => { expect(() => globalUiFor(fromJS({ kind: 'c1' }))).toThrow() expect(globalUiFor(Cursor.from(fromJS({ kind: 'c1' })))).toEqual( expect.anything() ) }) it('returns the corresponding element when looked for', () => { const html = mount(globalUiFor(Cursor.from(fromJS({ kind: 'c1' })))) expect(html.find('div')).toMatchElement(<div>Watson</div>) // expect(html).toContain('<div>Watson</div>') // expect(html).not.toContain('<div>Hudson</div>') }) it('looks up for an element by resolving the kind canonically', () => { // given // when const htmlWithSpecificRegistered = mount( globalUiFor(Cursor.from(fromJS({ kind: ['c2', 'specific'] }))) ) const htmlWithSpecificUnregistered = mount( globalUiFor(Cursor.from(fromJS({ kind: ['c1', 'specific'] }))) ) // then expect(htmlWithSpecificRegistered).toContainReact(<div>Mycroft</div>) expect(htmlWithSpecificRegistered).not.toContainReact(<div>Hudson</div>) expect(htmlWithSpecificUnregistered).toContainReact(<div>Watson</div>) }) }) describe('ui.uiFor (multiple elements)', () => { it('returns a list of elements, filtering empty (not found)', () => { const html = mount( globalUiFor( Cursor.from( fromJS({ kind: 'detectives', list: [ { kind: 'c1', }, { kind: 'c2', }, { kind: 'not-registered', }, ], }) ) ) ) expect(html).toContainReact(<div>Watson</div>) expect(html).toContainReact(<div>Hudson</div>) expect(html.find('#list')).toBePresent() }) }) describe('element#uiFor', () => { ui.register('root', () => <div>Root mounted</div>) ui.register('comp1', () => <div className="c1">Comp1 mounted</div>) ui.register('comp2', () => <div className="c2">Comp2 mounted</div>) function implFor(el) { let impl = null ui.register(kindOf(el), ({ uiFor }) => { impl = uiFor return <div /> }) mount(kernel.subsystems.ui.uiFor(el)) // triggers the render return impl } describe('using a key path (string or array)', () => { const state = Cursor.from( fromJS({ kind: 'root', child1: { kind: 'comp1', items: [ { kind: 'comp2', child: { kind: 'comp2', }, }, { kind: 'comp2', }, { kind: 'comp3', }, ], }, notAnElement: { title: 'foo', }, }) ) let uiFor = implFor(state) it('renders the ui for the element under the specified sub-key path', () => { expect(mount(uiFor('child1'))).toContainReact( <div className="c1">Comp1 mounted</div> ) }) it('renders the ui for the elements under the specified sub-key-path, if said key path is an array', () => { expect(mount(uiFor(['child1', 'items', 0, 'child']))).toContainReact( <div className="c2">Comp2 mounted</div> ) }) it('returns undefined if there is no ui registered for the elemnent under the key path', () => { expect(uiFor('nonExistingChild') == null).toBe(true) expect(uiFor(['child1', 'items', 100]) == null).toBe(true) }) it('returns a list of UI if under there is a List of elements under the specified key path', () => { const ui = uiFor(['child1', 'items']) expect(Iterable.isIndexed(ui)).toEqual(true) expect(mount(ui.get(0))).toContainReact( <div className="c2">Comp2 mounted</div> ) expect(mount(ui.get(1))).toContainReact( <div className="c2">Comp2 mounted</div> ) }) it('returns a list of UI elements only for those elements that have a registered UI', () => { const ui = uiFor(['child1', 'items']) for (let u of ui) { expect(isOfKind(['comp3'], u.props.element)).toEqual(false) } }) it('throws and error if the data structure under the specified path is not an element', () => { expect(() => uiFor('notAnElement')).toThrow() }) }) }) }) })