| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| import React from 'react'; |
| import {mount, shallow} from 'enzyme'; |
| import sinon from 'sinon'; |
| import FauxtonAPI from '../../../../core/api'; |
| import Views from '../components'; |
| import '../../base'; |
| |
| FauxtonAPI.router = new FauxtonAPI.Router([]); |
| |
| describe('ReduceEditor', () => { |
| describe('getReduceValue', () => { |
| const defaultProps = { |
| reduceOptions: [], |
| hasReduce: false, |
| hasCustomReduce: false, |
| reduce: null, |
| reduceSelectedOption: 'NONE', |
| customReducerSupported: true, |
| updateReduceCode: () => {}, |
| selectReduceChanged: () => {} |
| }; |
| |
| it('returns null for none', () => { |
| const reduceEl = shallow(<Views.ReduceEditor |
| {...defaultProps} |
| />); |
| expect(reduceEl.instance().getReduceValue()).toBeNull(); |
| }); |
| |
| it('returns built in for built in reduce', () => { |
| const reduceEl = shallow(<Views.ReduceEditor |
| {...defaultProps} |
| reduce='_sum' |
| hasReduce={true} |
| />); |
| expect(reduceEl.instance().getReduceValue()).toBe('_sum'); |
| }); |
| |
| it('shows warning when custom reduce is not supported', () => { |
| const reduceEl = shallow(<Views.ReduceEditor |
| {...defaultProps} |
| reduce='function() {}' |
| hasReduce={true} |
| customReducerSupported={false} |
| />); |
| expect(reduceEl.find('div.reduce-editor-warning').exists()).toBe(true); |
| }); |
| |
| }); |
| }); |
| |
| describe('DesignDocSelector component', () => { |
| const defaultProps = { |
| designDocList: ['_design/test-doc', '_design/test-doc2'], |
| newDesignDocName: '', |
| selectedDesignDocPartitioned: false, |
| isDbPartitioned: false, |
| newDesignDocPartitioned: false, |
| onChangeNewDesignDocName: () => {}, |
| onSelectDesignDoc: () => {} |
| }; |
| let selectorEl; |
| |
| it('calls onSelectDesignDoc on change', () => { |
| const spy = sinon.spy(); |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDDocName={'new-doc'} |
| onSelectDesignDoc={spy} |
| />); |
| |
| selectorEl.find('.styled-select select').first().simulate('change', { |
| target: { |
| value: '_design/test-doc' |
| } |
| }); |
| sinon.assert.calledOnce(spy); |
| }); |
| |
| it('shows new design doc field when set to new-doc', () => { |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'new-doc'} |
| />); |
| |
| expect(selectorEl.find('#new-ddoc-section').length).toBe(1); |
| }); |
| |
| it('hides new design doc field when design doc selected', () => { |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'_design/test-doc'} |
| />); |
| |
| expect(selectorEl.find('#new-ddoc-section').length).toBe(0); |
| }); |
| |
| it('always passes validation when design doc selected', () => { |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'_design/test-doc'} |
| />); |
| |
| expect(selectorEl.instance().validate()).toBe(true); |
| }); |
| |
| it('fails validation if new doc name entered/not entered', () => { |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'new-doc'} |
| newDesignDocName='' |
| />); |
| |
| // it shouldn't validate at this point: no new design doc name has been entered |
| expect(selectorEl.instance().validate()).toBe(false); |
| }); |
| |
| it('passes validation if new doc name entered/not entered', () => { |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'new-doc'} |
| newDesignDocName='new-doc-name' |
| />); |
| expect(selectorEl.instance().validate()).toBe(true); |
| }); |
| |
| |
| it('omits doc URL when not supplied', () => { |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'new-doc'} |
| />); |
| expect(selectorEl.find('.help-link').length).toBe(0); |
| }); |
| |
| it('includes help doc link when supplied', () => { |
| const docLink = 'http://docs.com'; |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'new-doc'} |
| docLink={docLink} |
| />); |
| expect(selectorEl.find('.help-link').length).toBe(1); |
| expect(selectorEl.find('.help-link').prop('href')).toBe(docLink); |
| }); |
| |
| it('shows Partitioned checkbox only when db is partitioned', () => { |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'new-doc'} |
| />); |
| |
| expect(selectorEl.find('div.ddoc-selector-partitioned').exists()).toBe(false); |
| |
| selectorEl.setProps({isDbPartitioned: true}); |
| expect(selectorEl.find('div.ddoc-selector-partitioned').exists()).toBe(true); |
| }); |
| |
| it('calls onChangeNewDesignDocPartitioned when partitioned option changes', () => { |
| const spy = sinon.stub(); |
| selectorEl = mount( |
| <Views.DesignDocSelector |
| {...defaultProps} |
| selectedDesignDocName={'new-doc'} |
| isDbPartitioned={true} |
| onChangeNewDesignDocPartitioned={spy} |
| />); |
| selectorEl.find('input#js-ddoc-selector-partitioned').simulate('change'); |
| sinon.assert.called(spy); |
| }); |
| }); |
| |
| describe('IndexEditor', () => { |
| const defaultProps = { |
| isLoading: false, |
| isNewView: false, |
| isNewDesignDoc: false, |
| isDbPartitioned: false, |
| viewName: '', |
| database: { safeID: () => 'test_db' }, |
| newDesignDocName: '', |
| newDesignDocPartitioned: false, |
| originalViewName: '', |
| originalDesignDocName: '', |
| designDoc: {}, |
| designDocId: '', |
| designDocPartitioned: false, |
| designDocList: [], |
| map: '', |
| reduce: '', |
| designDocs: {}, |
| updateNewDesignDocName: () => {}, |
| updateMapCode: () => {}, |
| selectDesignDoc: () => {}, |
| onChangeNewDesignDocName: () => {}, |
| changeViewName: () => {}, |
| reduceOptions: [], |
| reduceSelectedOption: 'NONE', |
| hasReduce: false, |
| hasCustomReduce: false, |
| updateReduceCode: () => {}, |
| selectReduceChanged: () => {} |
| }; |
| |
| afterEach(() => { |
| sinon.restore(); |
| }); |
| |
| it('calls changeViewName on view name change', () => { |
| const spy = sinon.spy(); |
| const editorEl = mount(<Views.IndexEditor |
| {...defaultProps} |
| viewName='new-name' |
| changeViewName={spy} |
| />); |
| |
| editorEl.find('#index-name').simulate('change', { |
| target: { |
| value: 'newViewName' |
| } |
| }); |
| sinon.assert.calledWith(spy, 'newViewName'); |
| }); |
| |
| it('generates the correct cancel link when db, ddoc and views have special chars', () => { |
| const editorEl = mount(<Views.IndexEditor |
| {...defaultProps} |
| database={{ id: 'db%$1' }} |
| designDocId={'_design/doc/1$2'} |
| viewName={'v?abc/123'} |
| />); |
| const expectedUrl = `/${encodeURIComponent('db%$1')}/_design/${encodeURIComponent('doc/1$2')}/_view/${encodeURIComponent('v?abc/123')}`; |
| expect(editorEl.find('a.index-cancel-link').prop('href')).toMatch(expectedUrl); |
| }); |
| |
| it('shows warning when trying to save a partitioned view with custom reduce', () => { |
| sinon.stub(FauxtonAPI, 'addNotification'); |
| const editorEl = mount(<Views.IndexEditor |
| {...defaultProps} |
| viewName='new-name' |
| designDocId='new-doc' |
| newDesignDocName='test_ddoc' |
| newDesignDocPartitioned={true} |
| isDbPartitioned={true} |
| reduce='function() { /*custom reduce*/ }' |
| />); |
| |
| editorEl.find('form.view-query-save').simulate('submit', { |
| preventDefault: () => {} |
| }); |
| sinon.assert.calledWithMatch(FauxtonAPI.addNotification, { msg: 'Partitioned views do not support custom reduce functions.' }); |
| }); |
| |
| }); |