Skip to content
This repository has been archived by the owner on Aug 27, 2018. It is now read-only.

Commit

Permalink
Merge pull request #33 from get-focus/feature-list-test
Browse files Browse the repository at this point in the history
Feature list test
  • Loading branch information
pierr authored Jun 17, 2016
2 parents 0ddccd6 + d0f30ac commit b39eb6f
Show file tree
Hide file tree
Showing 15 changed files with 355 additions and 63 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,8 @@ export default connectToDomains(MyChildComponentWhoNeedsInformationsFromTheDomai
## Explainations

Provider(informationsToPassToTheComponentsTree) => Tree => connectToInformations(Child) => The child gets this information in its props.


// todo:

- [] Check the Provider chain presence (form needs metadata)
2 changes: 1 addition & 1 deletion index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "focus-redux",
"version": "0.1.1",
"version": "0.2.0",
"description": "Form, data behaviours",
"main": "src/index.js",
"files": [
Expand All @@ -12,7 +12,7 @@
"start": "better-npm-run dev-server",
"build:node": "better-npm-run babelify",
"build": "npm run build:node",
"publish": "npm run build"
"prepublish": "npm run build"
},

"betterScripts": {
Expand Down
4 changes: 2 additions & 2 deletions src/behaviours/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ export function connect() {
function FieldConnectedComponent({_behaviours, ...otherProps}, {fieldHelpers}) {
const fieldFor = fieldHelpers.fieldForBuilder(otherProps);
const selectFor = fieldHelpers.fieldForBuilder(otherProps, true);
const list = fieldHelpers.fieldForBuilder( otherProps, false, true, fieldHelpers.fieldForListBuilder);
const listFor = fieldHelpers.fieldForBuilder( otherProps, false, true, fieldHelpers.fieldForListBuilder);
const behaviours = {connectedToFieldHelpers: true, ..._behaviours};
return <ComponentToConnect {...otherProps} _behaviours={behaviours} fieldFor={fieldFor} selectFor={selectFor} list={list}/>;
return <ComponentToConnect {...otherProps} _behaviours={behaviours} fieldFor={fieldFor} selectFor={selectFor} listFor={listFor}/>;
}
FieldConnectedComponent.displayName = `${ComponentToConnect.displayName}FieldConnected`;
FieldConnectedComponent.contextTypes = FIELD_CONTEXT_TYPE;
Expand Down
9 changes: 4 additions & 5 deletions src/components/line.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import React, {PropTypes} from 'react';

function Line({onClick, children, fieldForLine, options,index, ...otherProps}) {
const Line = ({onClick, children, fieldForLine, options,index, ...otherProps}) => {
return (
<div>
<div> {fieldForLine('firstName', {entityPath: 'child'}, index)} </div>
<div> {fieldForLine('lastName', {entityPath: 'child'}, index)} </div>
<div> {fieldForLine('firstName', {entityPath: 'child'})} </div>
<div> {fieldForLine('lastName', {entityPath: 'child'})} </div>
</div>
);
}


Line.displayName = 'Line';
Line.propTypes = {
onClick: PropTypes.func.isRequired,
onClick: PropTypes.func,
options: PropTypes.arrayOf(PropTypes.string)
};
Line.defaultProps = {
Expand Down
9 changes: 5 additions & 4 deletions src/components/list.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, {PropTypes} from 'react';
import DefaultLineComponent from './line'


function List({onClick, fieldForLine, LineComponent = DefaultLineComponent, children, options, error, values, ...otherProps}) {
function List({onClick, fieldForLine, LineComponent, children, options, error, values, ...otherProps}) {
const renderLine = () => {
return (values ? values.map((element, index) => {
return <LineComponent value={element} fieldForLine={fieldForLine} index={index}/>
// fieldFor which wrapp the index.
const lineFieldFor = (linePropertyName, lineOptions) => fieldForLine(linePropertyName, lineOptions, index)
return <LineComponent key={otherProps.idField ? element[idField]: index} value={element} fieldForLine={lineFieldFor} index={index} {...otherProps}/>
}): <div></div>) // todo: null ?
}
return (
Expand All @@ -16,7 +17,7 @@ function List({onClick, fieldForLine, LineComponent = DefaultLineComponent, chil

List.displayName = 'List';
List.propTypes = {
LineComponent: PropTypes.element.isRequired,
LineComponent: PropTypes.func.isRequired,
fieldForLine: PropTypes.func.isRequired,
onClick: PropTypes.func,
options: PropTypes.arrayOf(PropTypes.string)
Expand Down
6 changes: 3 additions & 3 deletions src/example/components/user-and-address-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {loadMixedAction, saveMixedAction} from '../actions/mixed-actions';

import Panel from '../../components/panel';
import compose from 'lodash/flowRight';

import LineComponent from '../../components/line'
class UserAddressForm extends Component {
componentWillMount() {
const {id, load, loadMasterData} = this.props;
Expand All @@ -16,11 +16,11 @@ class UserAddressForm extends Component {
}

render() {
const {editing, fields, fieldFor, list, selectFor} = this.props;
const {editing, fields, fieldFor, listFor, selectFor} = this.props;
return (
<Panel title='User and address' {...this.props}>
{fieldFor('uuid', {onChange: () => {console.log(fields)}, entityPath: 'user'})}
{list('childs', {entityPath : 'user', redirectEntityPath: 'child'})}
{listFor('childs', {LineComponent, entityPath : 'user', redirectEntityPath: 'child'})}
</Panel>
);
}
Expand Down
9 changes: 5 additions & 4 deletions src/example/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export const definitions = {
lastName: { domain: 'DO_DON_DIEGO', isRequired: true},
date: { domain: 'DO_DATE', isRequired: false},
civility: { domain: 'DO_CIVILITE', isRequired: true},
childs : {redirect: 'child'}
// TODO: ['childs'] ?
childs : {redirect: ['child']}
},
child : {
firstName : { domain: 'DO_RODRIGO', isRequired: false},
Expand All @@ -25,7 +26,7 @@ export const definitions = {
export const domains = {
DO_RODRIGO: {
type: 'text',
validator: [{
validators: [{
type: 'string',
options: {
maxLength: 50
Expand All @@ -35,7 +36,7 @@ export const domains = {
},
DO_DON_DIEGO: {
type: 'text',
validator: [{
validators: [{
type: 'string',
options: {
maxLength: 200
Expand All @@ -48,7 +49,7 @@ export const domains = {
},
DO_CIVILITE: {
type: 'text',
validator: [{
validators: [{
type: 'string',
options: {
maxLength: 200
Expand Down
62 changes: 62 additions & 0 deletions src/middlewares/__tests__/field-middleware-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import fieldMiddleware from '../field';
import {
INPUT_CHANGE,
INPUT_BLUR,
INPUT_ERROR,
INPUT_BLUR_LIST,
INPUT_ERROR_LIST
} from '../../actions/input'
import {definitions, domains} from '../../example/config';
describe('The field middleware', () => {
const getStateSpy = sinon.spy();
const nextSpy = sinon.spy();
const dispatchSpy = sinon.spy();
const store = {
getState: () => {
getStateSpy();
return {
dataset: {
user: {
data: {
firstName: 'Joe',
lastName: 'Lopez'
},
loading: true,
saving: false
}
},
definitions,
domains,
forms: [{
formKey: 'formKey',
entityPathArray: ['user'],
fields: [{
name: 'firstName',
dataSetValue: 'Joe',
entityPath: 'user',
loading: false,
saving: false
}]
}]
}
},
dispatch: dispatchSpy
};
beforeEach(() => {
getStateSpy.reset();
nextSpy.reset();
dispatchSpy.reset();
});
describe('when no store is given tho the middleware ', ()=>{
it('should throw an error', () =>{
expect(() => fieldMiddleware()(nextSpy)({type: 'lol'}))
.to.throw('FIELD_MIDDLEWARE: Your middleware needs a redux store.');
});
it('when an INPUT_BLUR action is passed', () => {
fieldMiddleware(store)(nextSpy)({type: INPUT_BLUR, entityPath: 'user', fieldName: 'firstName'})
});
it('when an INPUT_BLUR_LIST action is passed', () => {});
it('when an INPUT_CHANGE action is passed', () => {});
it('when an SYNC_FORM_ENTITIES action is passed', () => {});
});
});
8 changes: 7 additions & 1 deletion src/middlewares/__tests__/form-middleware-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,18 @@ describe('The form middleware', () => {
nextSpy.reset();
dispatchSpy.reset();
})
describe('when no store is given tho the middleware ', ()=>{
it('should throw an error', () =>{
expect(() => formMiddleware()(nextSpy)({type: 'lol'}))
.to.throw('FORM_MIDDLEWARE: You middleware needs a redux store.');
})
});
describe('when a random action is passed', () => {
const randomAction = {
type: 'LOL'
};
it('should just pass the action to next', () => {
formMiddleware(null)(nextSpy)(randomAction);
formMiddleware(store)(nextSpy)(randomAction);
expect(nextSpy).to.have.been.callCount(1);
expect(nextSpy).to.have.been.calledWith(randomAction);
});
Expand Down
76 changes: 66 additions & 10 deletions src/middlewares/__tests__/form-middleware-validation.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,73 @@
import {filterNonValidatedFields} from '../validations';

import {filterNonValidatedFields, validateField} from '../validations';
import {definitions, domains} from '../../example/config';
import {INPUT_ERROR} from '../../actions/input';

const FIELDS_CONFIG = JSON.parse('{"fields":[{"valid":true,"error":false,"active":true,"dirty":false,"loading":false,"saving":false,"name":"city","entityPath":"address","dataSetValue":"Kubland","rawInputValue":"Kubland","formattedInputValue":"Kubland - formaté"},{"valid":true,"error":false,"active":true,"dirty":false,"loading":false,"saving":false,"name":"uuid","entityPath":"user","dataSetValue":"1234","rawInputValue":"1234","formattedInputValue":"1234"},{"valid":true,"error":false,"active":true,"dirty":false,"loading":false,"saving":false,"name":"lastName","entityPath":"user","dataSetValue":"De Libercourt","rawInputValue":"De Libercourt","formattedInputValue":"De Libercourt - formaté"},{"valid":true,"error":false,"active":true,"dirty":false,"loading":false,"saving":false,"name":"childs","entityPath":"user","dataSetValue":[{"firstName":"FirstChildOne","lastName":"LastChildOne"},{"firstName":"FirstChildTwo","lastName":"LastChildTwo"}],"rawInputValue":[{"firstName":"FirstChildOne","lastName":"LastChildOne"},{"firstName":"FirstChildTwo","lastName":"LastChildTwo"}],"formattedInputValue":[{"firstName":"FirstChildOne","lastName":"LastChildOne"},{"firstName":"FirstChildTwo","lastName":"LastChildTwo"}],"redirectEntityPath":"child"},{"valid":true,"error":false,"active":true,"dirty":false,"loading":false,"saving":false,"name":"uuid","entityPath":"address","dataSetValue":"1234","rawInputValue":"1234","formattedInputValue":"1234"}],"nonValidatedFields":["user.firstName",{"user.childs":["firstName"]}]}')


describe.only('Form: validation', () => {
describe('Form: validation', () => {
describe('when the validateField is called', ()=> {
const dispatchSpy = sinon.spy();
beforeEach(() => {
dispatchSpy.reset();
})
describe('with a simple field', ()=> {
it('should validate the name given correct defintion and value' , ()=>{
const validationResult = validateField(definitions, domains, 'formBalec', 'user', 'firstName', 'NewName', dispatchSpy);
expect(validationResult).to.be.true;
expect(dispatchSpy).to.have.callCount(0);
});
it('should dispatch an invalid the name given correct defintion and value' , ()=>{
const validationResult = validateField(definitions, domains, 'formBalec', 'user', 'firstName', 12, dispatchSpy);
expect(validationResult).to.be.false;
expect(dispatchSpy).to.have.callCount(1);
const dispatchArgs = dispatchSpy.lastCall.args[0];
expect(dispatchArgs.type = INPUT_ERROR);
expect(dispatchArgs.formKey === 'formBalec');
expect(dispatchArgs.entityPath === 'user');
expect(dispatchArgs.fieldName === 'firstName');
expect(dispatchArgs.error.length > 0 );
});
});
describe('with a list field', ()=> {
it('should validate the name given correct defintion and value' , ()=>{
const newListValue = [
{firstName:'FirstChildOne',lastName:'LastChildOne'},
{firstName:'FirstChildTwo',lastName:'LastChildTwo'}
];
const validationResult = validateField(definitions, domains, 'formBalec', 'user', 'childs', newListValue, dispatchSpy);
expect(validationResult).to.be.true;
expect(dispatchSpy).to.have.callCount(0);
});
it('should throw an error when the data type is not an array in case of a redirect', () => {
const WRONG_DEFINITION_ERROR = `MIDDLEWARES_FIELD_VALIDATION: Your field childs in the entity user don't have a domain, you may have an array field which have a **redirect** property in it`;
const wrongDefinition = () => validateField(definitions, domains, 'formBalec', 'user', 'childs', 12, dispatchSpy);
expect(wrongDefinition).to.throw(WRONG_DEFINITION_ERROR)
});
it('should throw an error when the redirect is incorrect', () => {
const WRONG_REDIRECT_ERROR = `MIDDLEWARES_FIELD_VALIDATION: Your field childs in the entity user don't have a domain, you may have an array field which have a **redirect** property in it.`
const def = {...definitions, user: {...definitions.user, redirect: 12}};
const wrongDefinition = () => validateField(definitions, domains, 'formBalec', 'user', 'childs', 12, dispatchSpy);
expect(wrongDefinition).to.throw(WRONG_REDIRECT_ERROR)
});
it('should dispatch an invalid the name given correct defintion and an incorrect value' , ()=>{
const newListValue = [
{firstName:1,lastName:'LastChildOne'},
{firstName:'FirstChildTwo',lastName: 'test'}
];
const validationResult = validateField(definitions, domains, 'formBalec', 'user', 'childs', newListValue, dispatchSpy);
expect(validationResult).to.be.false;
expect(dispatchSpy).to.have.callCount(2);
const dispatchArgs = dispatchSpy.lastCall.args[0];
expect(dispatchArgs.type = INPUT_ERROR);
expect(dispatchArgs.formKey === 'formBalec');
expect(dispatchArgs.entityPath === 'user');
expect(dispatchArgs.fieldName === 'firstName');
// expect(dispatchArgs.error.length > 0 );
});
});
})

it('filterNonValidatedInListField', () => {
const FIELD_TO_VALIDATE = [
{"valid":true,"error":false,"active":true,"dirty":false,"loading":false,"saving":false,"name":"city","entityPath":"address","dataSetValue":"Kubland","rawInputValue":"Kubland","formattedInputValue":"Kubland - formaté"},
Expand All @@ -17,14 +80,7 @@ describe.only('Form: validation', () => {
{"valid":true,"error":false,"active":true,"dirty":false,"loading":false,"saving":false,"name":"uuid","entityPath":"address","dataSetValue":"1234","rawInputValue":"1234","formattedInputValue":"1234"}
];




/*expect(
filterNonValidatedInListField(FIELDS_CONFIG.fields,FIELDS_CONFIG.nonValidatedFields )
).to.deep.equal(FIELD_TO_VALIDATE)*/
const CANDIDATE_FIELD_TO_VALIDATE = filterNonValidatedFields(FIELDS_CONFIG.fields,FIELDS_CONFIG.nonValidatedFields );
console.log(CANDIDATE_FIELD_TO_VALIDATE);
expect(
CANDIDATE_FIELD_TO_VALIDATE
).to.deep.equal(FIELD_TO_VALIDATE)
Expand Down
Loading

0 comments on commit b39eb6f

Please sign in to comment.