Clear class failures on field hide
Previous work was done to have field errors clear when any classification in the assertion stack changes. The last remaining piece was to have field errors clear when the field itself is no longer applicable.† - Handling in `Client` was replaced with `FieldVisibilityEventHandler`. The event system already existed. - `DataValidator` and `ValidStateMonitor` just needed the ability to clear specific fields (`#clearFields`). † Technically the "hide" in liza means "not applicable"; I've been using that new terminology, but this event can't be renamed right now because it's so heavily used.master
commit
e5e40020ce
|
@ -326,10 +326,6 @@ module.exports = Class( 'Client' )
|
||||||
// used to communicate with the server
|
// used to communicate with the server
|
||||||
this.dataProxy = this._createDataProxy( jQuery );
|
this.dataProxy = this._createDataProxy( jQuery );
|
||||||
|
|
||||||
this._eventHandler = this._factory.createClientEventHandler(
|
|
||||||
this, this.elementStyler, this.dataProxy, jQuery
|
|
||||||
);
|
|
||||||
|
|
||||||
this.uiDialog = this._factory.createUiDialog();
|
this.uiDialog = this._factory.createUiDialog();
|
||||||
this.programId = this._getProgramId();
|
this.programId = this._getProgramId();
|
||||||
this.program = this._createProgram();
|
this.program = this._createProgram();
|
||||||
|
@ -347,6 +343,10 @@ module.exports = Class( 'Client' )
|
||||||
|
|
||||||
this.ui = this._createUi( this.nav );
|
this.ui = this._createUi( this.nav );
|
||||||
|
|
||||||
|
this._eventHandler = this._factory.createClientEventHandler(
|
||||||
|
this, this._dataValidator, this.elementStyler, this.dataProxy, jQuery
|
||||||
|
);
|
||||||
|
|
||||||
this._classMatcher = this._factory.createFieldClassMatcher(
|
this._classMatcher = this._factory.createFieldClassMatcher(
|
||||||
this.program.whens
|
this.program.whens
|
||||||
);
|
);
|
||||||
|
@ -699,7 +699,7 @@ module.exports = Class( 'Client' )
|
||||||
.getExclusiveFieldNames();
|
.getExclusiveFieldNames();
|
||||||
|
|
||||||
|
|
||||||
var showq = [], hideq = [];
|
var visq = [];
|
||||||
for ( var field in cmatch )
|
for ( var field in cmatch )
|
||||||
{
|
{
|
||||||
// ignore fields that are not on the current step
|
// ignore fields that are not on the current step
|
||||||
|
@ -761,13 +761,14 @@ module.exports = Class( 'Client' )
|
||||||
|
|
||||||
if ( show.length )
|
if ( show.length )
|
||||||
{
|
{
|
||||||
showq[ field ] = show;
|
visq[ field ] = { event_id: 'show', name: field, indexes: show };
|
||||||
_self._mergeCmatchHidden( field, show, false );
|
this._mergeCmatchHidden( field, show, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( hide.length )
|
if ( hide.length )
|
||||||
{
|
{
|
||||||
hideq[ field ] = hide;
|
visq[ field ] = { event_id: 'hide', name: field, indexes: hide };
|
||||||
_self._mergeCmatchHidden( field, hide, true );
|
this._mergeCmatchHidden( field, hide, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,10 +781,19 @@ module.exports = Class( 'Client' )
|
||||||
// manipulations on it (TODO: this is a workaround for group
|
// manipulations on it (TODO: this is a workaround for group
|
||||||
// show/hide issues; we need a better solution to guarantee
|
// show/hide issues; we need a better solution to guarantee
|
||||||
// order
|
// order
|
||||||
setTimeout( function()
|
setTimeout( () =>
|
||||||
{
|
{
|
||||||
_self._hideFields( showq, 'show' );
|
Object.keys( visq ).forEach( field =>
|
||||||
_self._hideFields( hideq, 'hide' );
|
{
|
||||||
|
const { event_id, name, indexes } = visq[ field ];
|
||||||
|
|
||||||
|
this.handleEvent( event_id, {
|
||||||
|
elementName: name,
|
||||||
|
indexes: indexes,
|
||||||
|
} );
|
||||||
|
|
||||||
|
this._dapiTrigger( name );
|
||||||
|
} );
|
||||||
}, 25 );
|
}, 25 );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2598,16 +2608,6 @@ module.exports = Class( 'Client' )
|
||||||
// perform event (XXX: replace me; see above)
|
// perform event (XXX: replace me; see above)
|
||||||
switch ( event_name )
|
switch ( event_name )
|
||||||
{
|
{
|
||||||
case 'enable':
|
|
||||||
case 'disable':
|
|
||||||
case 'hide':
|
|
||||||
case 'show':
|
|
||||||
var fdata = {};
|
|
||||||
fdata[ data.elementName ] = data.indexes;
|
|
||||||
|
|
||||||
this._hideFields( fdata, event_name );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'set':
|
case 'set':
|
||||||
var setdata = {};
|
var setdata = {};
|
||||||
setdata[ data.elementName ] = [];
|
setdata[ data.elementName ] = [];
|
||||||
|
@ -2644,73 +2644,6 @@ module.exports = Class( 'Client' )
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
'private _hideFields': function( fields, event_name )
|
|
||||||
{
|
|
||||||
var stepui = this.ui.getCurrentStep();
|
|
||||||
|
|
||||||
if ( !stepui )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( var field in fields )
|
|
||||||
{
|
|
||||||
var indexes = fields[ field ],
|
|
||||||
indexes_len = indexes.length;
|
|
||||||
|
|
||||||
for ( var i = 0; i < indexes_len; i++ )
|
|
||||||
{
|
|
||||||
var index = indexes[ i ];
|
|
||||||
|
|
||||||
if ( index === undefined )
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var group = stepui.getElementGroup( field );
|
|
||||||
if ( group === null )
|
|
||||||
{
|
|
||||||
window.console && console.warn && console.warn(
|
|
||||||
'No group found for %s event: %s[%s]',
|
|
||||||
event_name,
|
|
||||||
field,
|
|
||||||
index
|
|
||||||
);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._dapiTrigger( field );
|
|
||||||
|
|
||||||
if ( event_name === 'show' )
|
|
||||||
{
|
|
||||||
group.showField( field, index );
|
|
||||||
}
|
|
||||||
else if ( event_name === 'hide' )
|
|
||||||
{
|
|
||||||
group.hideField( field, index );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// locate the element within the group
|
|
||||||
var $element = group.getElementByName(
|
|
||||||
field, index
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( event_name === 'enable' )
|
|
||||||
{
|
|
||||||
$element.attr( 'readonly', false );
|
|
||||||
}
|
|
||||||
else if ( event_name === 'disable' )
|
|
||||||
{
|
|
||||||
$element.attr( 'readonly', true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger DataApi event for field FIELD
|
* Trigger DataApi event for field FIELD
|
||||||
*
|
*
|
||||||
|
|
|
@ -103,12 +103,12 @@ var Step = require( '../step/Step' ),
|
||||||
Class = require( 'easejs' ).Class;
|
Class = require( 'easejs' ).Class;
|
||||||
|
|
||||||
|
|
||||||
var event = require( '../event' );
|
var liza_event = require( '../event' );
|
||||||
|
|
||||||
|
|
||||||
function requireh( name )
|
function requireh( name )
|
||||||
{
|
{
|
||||||
return event[ name ];
|
return liza_event[ name ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -347,8 +347,15 @@ module.exports = Class( 'ClientDependencyFactory',
|
||||||
createFieldClassMatcher: FieldClassMatcher,
|
createFieldClassMatcher: FieldClassMatcher,
|
||||||
|
|
||||||
|
|
||||||
createClientEventHandler: function( client, styler, data_proxy, jquery )
|
createClientEventHandler: function(
|
||||||
|
client, data_validator, styler, data_proxy, jquery
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
const field_vis_handler = requireh( 'FieldVisibilityEventHandler' )(
|
||||||
|
client.getUi(),
|
||||||
|
data_validator
|
||||||
|
);
|
||||||
|
|
||||||
return DelegateEventHandler( {
|
return DelegateEventHandler( {
|
||||||
'indvRate': requireh( 'IndvRateEventHandler' )(
|
'indvRate': requireh( 'IndvRateEventHandler' )(
|
||||||
client, data_proxy
|
client, data_proxy
|
||||||
|
@ -358,6 +365,9 @@ module.exports = Class( 'ClientDependencyFactory',
|
||||||
'kickBack': requireh( 'KickbackEventHandler' )( client ),
|
'kickBack': requireh( 'KickbackEventHandler' )( client ),
|
||||||
'status': requireh( 'StatusEventHandler' )( styler ),
|
'status': requireh( 'StatusEventHandler' )( styler ),
|
||||||
|
|
||||||
|
'show': field_vis_handler,
|
||||||
|
'hide': field_vis_handler,
|
||||||
|
|
||||||
'action$cvv2Dialog': requireh( 'Cvv2DialogEventHandler' )( jquery )
|
'action$cvv2Dialog': requireh( 'Cvv2DialogEventHandler' )( jquery )
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
/**
|
||||||
|
* Field visibility event handler
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 LoVullo Associates, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework
|
||||||
|
*
|
||||||
|
* Liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Class = require( 'easejs' ).Class;
|
||||||
|
const EventHandler = require( './EventHandler' );
|
||||||
|
const UnknownEventError = require( './UnknownEventError' );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows/hides fields according to event id
|
||||||
|
*
|
||||||
|
* @todo use something more appropriate than Ui
|
||||||
|
* @todo should not be concerned with data validators
|
||||||
|
*/
|
||||||
|
module.exports = Class( 'FieldVisibilityEventHandler' )
|
||||||
|
.implement( EventHandler )
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Client UI
|
||||||
|
* @type {Ui}
|
||||||
|
*/
|
||||||
|
'private _ui': null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field data validator
|
||||||
|
* @type {DataValidator}
|
||||||
|
*/
|
||||||
|
'private _data_validator': null,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize with Client UI
|
||||||
|
*
|
||||||
|
* @param {Ui} stepui Client UI
|
||||||
|
* @param {DataValidator} data_validator field data validator
|
||||||
|
*/
|
||||||
|
__construct( stepui, data_validator )
|
||||||
|
{
|
||||||
|
this._ui = stepui;
|
||||||
|
this._data_validator = data_validator;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show/hide specified fields
|
||||||
|
*
|
||||||
|
* If a given field is not known then it will be silently ignored; the
|
||||||
|
* callback `callback` will still be invoked.
|
||||||
|
*
|
||||||
|
* This relies on a poorly designed API that should change in the future.
|
||||||
|
*
|
||||||
|
* @param {string} event_id event id
|
||||||
|
* @param {function(*,Object)} callback continuation to invoke on completion
|
||||||
|
*
|
||||||
|
* @param {elementName:string, indexes:Array.<number>} data
|
||||||
|
*
|
||||||
|
* @return {EventHandler} self
|
||||||
|
*/
|
||||||
|
'public handle'( event_id, callback, { elementName: field_name, indexes } )
|
||||||
|
{
|
||||||
|
// TODO: Law of Demeter!
|
||||||
|
const group = this._ui.getCurrentStep()
|
||||||
|
.getElementGroup( field_name );
|
||||||
|
|
||||||
|
// we probably should care, but we don't right now
|
||||||
|
if ( !group )
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const action = ( () =>
|
||||||
|
{
|
||||||
|
switch ( event_id )
|
||||||
|
{
|
||||||
|
case 'show':
|
||||||
|
return group.showField.bind( group );
|
||||||
|
|
||||||
|
case 'hide':
|
||||||
|
return group.hideField.bind( group );
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw UnknownEventError( `Unknown visibility event: ${event_id}` );
|
||||||
|
}
|
||||||
|
} )();
|
||||||
|
|
||||||
|
this._data_validator.clearFailures( [ field_name ] );
|
||||||
|
indexes.forEach( field_i => action( field_name, field_i ) );
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
} );
|
|
@ -159,13 +159,21 @@ module.exports = Class( 'DataValidator',
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all recorded failures
|
* Clear specified failures, or otherwise all recorded failures
|
||||||
|
*
|
||||||
|
* `fields` must be a key-value map with the field name as the key and
|
||||||
|
* an array of indexes as the value. Any field in `fields` that has no
|
||||||
|
* failure is ignored.
|
||||||
|
*
|
||||||
|
* See `ValidStateMonitor#clearFailures` for more information.
|
||||||
|
*
|
||||||
|
* @param {Object} fields key-value names of fields/indexes to clear
|
||||||
*
|
*
|
||||||
* @return {DataValidator} self
|
* @return {DataValidator} self
|
||||||
*/
|
*/
|
||||||
'public clearFailures'()
|
'public clearFailures'( failures )
|
||||||
{
|
{
|
||||||
this._field_monitor.clearFailures();
|
this._field_monitor.clearFailures( failures );
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -263,7 +263,6 @@ module.exports = Class( 'ValidStateMonitor' )
|
||||||
// looks like it has been resolved
|
// looks like it has been resolved
|
||||||
this._fixFailure( fixed, name, fail_i, result );
|
this._fixFailure( fixed, name, fail_i, result );
|
||||||
|
|
||||||
delete past_fail[ fail_i ];
|
|
||||||
return true;
|
return true;
|
||||||
} );
|
} );
|
||||||
} ) ).then( fixes => fixes.some( fix => fix === true ) );
|
} ) ).then( fixes => fixes.some( fix => fix === true ) );
|
||||||
|
@ -328,48 +327,58 @@ module.exports = Class( 'ValidStateMonitor' )
|
||||||
'private _fixFailure'( fixed, name, index, value )
|
'private _fixFailure'( fixed, name, index, value )
|
||||||
{
|
{
|
||||||
( fixed[ name ] = fixed[ name ] || [] )[ index ] = value;
|
( fixed[ name ] = fixed[ name ] || [] )[ index ] = value;
|
||||||
|
|
||||||
|
// caller is expected to have ensured that this exists
|
||||||
|
delete this._failures[ name ][ index ];
|
||||||
|
|
||||||
return fixed;
|
return fixed;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all recorded failures
|
* Clear specified failures, or otherwise all recorded failures
|
||||||
*
|
*
|
||||||
* For each recorded failure, a `fix` even is emitted. All failure
|
* `fields` must be a key-value map with the field name as the key and
|
||||||
* records are then cleared.
|
* an array of indexes as the value. Any field in `fields` that has no
|
||||||
|
* failure is ignored.
|
||||||
|
*
|
||||||
|
* For each specified failure, a `fix` event is emitted. If no failures
|
||||||
|
* are specified by `fields`, all recorded failures are marked as
|
||||||
|
* fixed. If a field in `fields` is not known, it is ignored.
|
||||||
*
|
*
|
||||||
* Normally the resulting fix object contains the values that triggered
|
* Normally the resulting fix object contains the values that triggered
|
||||||
* the fix. Instead, each fixed index will contain `undefined`.
|
* the fix. Instead, each fixed index will contain `null`.
|
||||||
*
|
*
|
||||||
* This process is synchronous, and only a single `fix` event is emitted
|
* This process is synchronous, and only a single `fix` event is emitted
|
||||||
* after all failures have been cleared.
|
* after all failures have been cleared.
|
||||||
*
|
*
|
||||||
|
* @param {Object} fields key-value names of fields/indexes to clear
|
||||||
|
*
|
||||||
* @return {ValidStateMonitor} self
|
* @return {ValidStateMonitor} self
|
||||||
*/
|
*/
|
||||||
'public clearFailures'()
|
'public clearFailures'( fields )
|
||||||
{
|
{
|
||||||
|
const failures = this._failures;
|
||||||
|
|
||||||
let fixed = {};
|
let fixed = {};
|
||||||
|
|
||||||
for ( let name in this._failures )
|
const isRequestedIndex = ( fields )
|
||||||
{
|
? field => ( fields[ field.getName() ] || [] ).indexOf(
|
||||||
const failure = this._failures[ name ];
|
field.getIndex()
|
||||||
|
) !== -1
|
||||||
|
: () => true;
|
||||||
|
|
||||||
for ( let cause_i in failure )
|
Object.keys( failures )
|
||||||
{
|
.reduce(
|
||||||
const cause = failure[ cause_i ];
|
( all_fields, name ) => all_fields.concat(
|
||||||
|
failures[ name ].map( cause => cause.getField() )
|
||||||
for ( let cause_i in cause )
|
),
|
||||||
{
|
[]
|
||||||
let fail_i = cause.getField().getIndex();
|
)
|
||||||
|
.filter( isRequestedIndex )
|
||||||
this._fixFailure( fixed, name, fail_i, undefined );
|
.forEach( field => this._fixFailure(
|
||||||
}
|
fixed, field.getName(), field.getIndex(), null
|
||||||
}
|
) );
|
||||||
}
|
|
||||||
|
|
||||||
// clear _before_ emitting the fixes (listeners might trigger
|
|
||||||
// additional failures, for example, or call `#hasFailures`)
|
|
||||||
this._failures = {};
|
|
||||||
|
|
||||||
this.emit( 'fix', fixed );
|
this.emit( 'fix', fixed );
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
/**
|
||||||
|
* Test case for FieldVisibilityEventHandler
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 LoVullo Associates, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of the Liza Data Collection Framework
|
||||||
|
*
|
||||||
|
* Liza is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const event = require( '../../' ).event;
|
||||||
|
const expect = require( 'chai' ).expect;
|
||||||
|
const Class = require( 'easejs' ).Class;
|
||||||
|
|
||||||
|
const {
|
||||||
|
FieldVisibilityEventHandler: Sut,
|
||||||
|
UnknownEventError
|
||||||
|
} = event;
|
||||||
|
|
||||||
|
|
||||||
|
describe( 'FieldVisibilityEventHandler', () =>
|
||||||
|
{
|
||||||
|
it( 'shows/hides each element index', done =>
|
||||||
|
{
|
||||||
|
const name = 'field_name';
|
||||||
|
const shown = { [name]: [] };
|
||||||
|
const hidden = { [name]: [] };
|
||||||
|
|
||||||
|
const sut = Sut(
|
||||||
|
createMockStepUi(
|
||||||
|
name,
|
||||||
|
( field, index ) => shown[ field ].push( index ),
|
||||||
|
( field, index ) => hidden[ field ].push( index )
|
||||||
|
),
|
||||||
|
createStubDataProvider()
|
||||||
|
);
|
||||||
|
|
||||||
|
// purposefully sparse indexes
|
||||||
|
const show_indexes = [ 2, 4, ];
|
||||||
|
const hide_indexes = [ 0, 3, ];
|
||||||
|
|
||||||
|
const show_data = {
|
||||||
|
elementName: name,
|
||||||
|
indexes: show_indexes,
|
||||||
|
};
|
||||||
|
|
||||||
|
const hide_data = {
|
||||||
|
elementName: name,
|
||||||
|
indexes: hide_indexes,
|
||||||
|
};
|
||||||
|
|
||||||
|
sut.handle( 'show', () =>
|
||||||
|
{
|
||||||
|
// implicitly ensures proper name is passed
|
||||||
|
expect( shown[ name ] ).to.deep.equal( show_indexes );
|
||||||
|
|
||||||
|
sut.handle( 'hide', () =>
|
||||||
|
{
|
||||||
|
expect( hidden[ name ] ).to.deep.equal( hide_indexes );
|
||||||
|
done();
|
||||||
|
}, hide_data );
|
||||||
|
}, show_data );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
it( 'throws error given unknown event', () =>
|
||||||
|
{
|
||||||
|
expect( () =>
|
||||||
|
{
|
||||||
|
Sut( createMockStepUi() ).handle( 'unknown', () => {}, {} );
|
||||||
|
} ).to.throw( UnknownEventError );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
it( 'ignores unknown groups', done =>
|
||||||
|
{
|
||||||
|
expect( () =>
|
||||||
|
{
|
||||||
|
Sut( {
|
||||||
|
getCurrentStep: () => ( { getElementGroup: () => null } )
|
||||||
|
} ).handle( 'hide', done, {} )
|
||||||
|
} ).to.not.throw( Error );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
it( 'clears failures on hidden fields', done =>
|
||||||
|
{
|
||||||
|
const name = 'foo_bar';
|
||||||
|
|
||||||
|
const hide_data = {
|
||||||
|
elementName: name,
|
||||||
|
indexes: [ 0 ],
|
||||||
|
};
|
||||||
|
|
||||||
|
Sut(
|
||||||
|
createMockStepUi( name, () => {}, () => {} ),
|
||||||
|
createStubDataProvider( failures =>
|
||||||
|
{
|
||||||
|
expect( failures )
|
||||||
|
.to.deep.equal( [ name ] )
|
||||||
|
|
||||||
|
// we don't care about the rest of the processing at this
|
||||||
|
// point
|
||||||
|
done();
|
||||||
|
} )
|
||||||
|
).handle( 'hide', () => {}, hide_data );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
function createMockStepUi( expected_name, showf, hidef )
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
getCurrentStep: () => ( {
|
||||||
|
getElementGroup( field_name )
|
||||||
|
{
|
||||||
|
expect( field_name ).to.equal( expected_name );
|
||||||
|
|
||||||
|
return {
|
||||||
|
showField: showf,
|
||||||
|
hideField: hidef,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} ),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createStubDataProvider( fail_callback )
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
clearFailures: fail_callback || () => {},
|
||||||
|
};
|
||||||
|
}
|
|
@ -217,7 +217,7 @@ describe( 'DataValidator', () =>
|
||||||
|
|
||||||
describe( '#clearFailures', () =>
|
describe( '#clearFailures', () =>
|
||||||
{
|
{
|
||||||
it( 'marks all failures as fixed', () =>
|
it( 'proxies to validator', () =>
|
||||||
{
|
{
|
||||||
const bvalidator = createMockBucketValidator();
|
const bvalidator = createMockBucketValidator();
|
||||||
const vmonitor = ValidStateMonitor();
|
const vmonitor = ValidStateMonitor();
|
||||||
|
@ -229,9 +229,14 @@ describe( 'DataValidator', () =>
|
||||||
bvalidator, vmonitor, dep_factory, createStubStore()
|
bvalidator, vmonitor, dep_factory, createStubStore()
|
||||||
);
|
);
|
||||||
|
|
||||||
mock_vmonitor.expects( 'clearFailures' ).once();
|
const failures = [ 'foo', 'bar' ];
|
||||||
|
|
||||||
expect( sut.clearFailures() )
|
mock_vmonitor
|
||||||
|
.expects( 'clearFailures' )
|
||||||
|
.once()
|
||||||
|
.withExactArgs( failures );
|
||||||
|
|
||||||
|
expect( sut.clearFailures( failures ) )
|
||||||
.to.equal( sut );
|
.to.equal( sut );
|
||||||
|
|
||||||
mock_vmonitor.verify();
|
mock_vmonitor.verify();
|
||||||
|
|
|
@ -596,7 +596,7 @@ describe( 'ValidStateMonitor', function()
|
||||||
|
|
||||||
describe( '#clearFailures', () =>
|
describe( '#clearFailures', () =>
|
||||||
{
|
{
|
||||||
it( 'clears all failures', () =>
|
it( 'clears all failures when provided no arguments', () =>
|
||||||
{
|
{
|
||||||
return new Promise( ( accept, reject ) =>
|
return new Promise( ( accept, reject ) =>
|
||||||
{
|
{
|
||||||
|
@ -608,7 +608,7 @@ describe( 'ValidStateMonitor', function()
|
||||||
.on( 'fix', fixed =>
|
.on( 'fix', fixed =>
|
||||||
{
|
{
|
||||||
expect( fixed )
|
expect( fixed )
|
||||||
.to.deep.equal( { foo: [ undefined ] } );
|
.to.deep.equal( { foo: [ null ] } );
|
||||||
|
|
||||||
expect( sut.hasFailures() ).to.be.false;
|
expect( sut.hasFailures() ).to.be.false;
|
||||||
|
|
||||||
|
@ -620,6 +620,52 @@ describe( 'ValidStateMonitor', function()
|
||||||
.catch( e => reject( e ) );
|
.catch( e => reject( e ) );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
it( 'clears only provided failures when provided array argument', () =>
|
||||||
|
{
|
||||||
|
return new Promise( ( accept, reject ) =>
|
||||||
|
{
|
||||||
|
mkstore( {} ).then( empty =>
|
||||||
|
{
|
||||||
|
const sut = Sut();
|
||||||
|
|
||||||
|
return sut
|
||||||
|
.on( 'fix', fixed =>
|
||||||
|
{
|
||||||
|
debugger;
|
||||||
|
// `bar' not cleared
|
||||||
|
expect( fixed )
|
||||||
|
.to.deep.equal( {
|
||||||
|
foo: [ null ],
|
||||||
|
baz: [ , null ],
|
||||||
|
} );
|
||||||
|
|
||||||
|
// still has `bar'
|
||||||
|
expect( sut.hasFailures() ).to.be.true;
|
||||||
|
|
||||||
|
accept( true );
|
||||||
|
} )
|
||||||
|
.update( empty, {
|
||||||
|
foo: mkfail( 'foo', [ 'bar1', 'bar2' ] ),
|
||||||
|
bar: mkfail( 'bar', [ 'baz' ] ),
|
||||||
|
baz: mkfail( 'baz', [ 'quux', 'quuux' ] ),
|
||||||
|
} )
|
||||||
|
.then( sut => sut.clearFailures( {
|
||||||
|
foo: [ 0 ],
|
||||||
|
baz: [ 1 ],
|
||||||
|
} ) );
|
||||||
|
} )
|
||||||
|
.catch( e => reject( e ) );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
it( 'does not error on non-existent failure', () =>
|
||||||
|
{
|
||||||
|
expect( () => Sut().clearFailures( [ 'foo', 'baz' ] ) )
|
||||||
|
.to.not.throw( Error );
|
||||||
|
} );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue