QUnit.module( 've.ui.MWTransclusionOutlineTemplateWidget' ); QUnit.test( 'Constructor', ( assert ) => { const transclusion = new ve.dm.MWTransclusionModel(), template = ve.dm.MWTemplateModel.newFromData( transclusion, { target: { wt: 'Example' }, params: { 1: {}, 2: {}, 3: {}, 4: {}, // Representation of a parameter placeholder in the model, should be skipped '': {} } } ); template.getSpec().setTemplateData( { params: { // A deprecated parameter must be shown as long as it's used 4: { deprecated: true }, // An unused deprecated parameter should never be shown 5: { deprecated: true }, 6: {} } } ); const widget = new ve.ui.MWTransclusionOutlineTemplateWidget( template ), // We need to skip .getItems() for this test because it makes a copy parameters = widget.parameterList.items; assert.strictEqual( widget.getData(), 'part_0' ); assert.strictEqual( widget.$element.find( '.ve-ui-mwTransclusionOutlineButtonWidget .oo-ui-buttonElement-button' ).text(), 'Example' ); assert.true( widget.searchWidget.isVisible() ); assert.true( widget.toggleUnusedWidget.isVisible() ); assert.false( widget.infoWidget.isVisible() ); // Note that documented parameters go first assert.deepEqual( parameters.map( ( item ) => item.data ), [ '4', '1', '2', '3' ] ); widget.toggleUnusedWidget.emit( 'click' ); assert.deepEqual( parameters.map( ( item ) => item.data ), [ '4', '6', '1', '2', '3' ] ); widget.searchWidget.setValue( 'can not find anything' ); assert.false( widget.toggleUnusedWidget.isVisible() ); assert.true( widget.infoWidget.isVisible() ); assert.strictEqual( parameters.filter( ( p ) => p.isVisible() ).length, 0 ); } ); QUnit.test( 'findCanonicalPosition()', ( assert ) => { function assertOrder( w, expected ) { assert.deepEqual( w.parameterList.items.map( ( item ) => item.data ), expected ); } const transclusion = new ve.dm.MWTransclusionModel(), template = ve.dm.MWTemplateModel.newFromData( transclusion, { target: { wt: '' }, params: { b: {}, e: {} } } ); // Skip .addPart(), the TemplateData API, specCache and everything related transclusion.parts.push( template ); template.getSpec().setTemplateData( { params: { e: { deprecated: true }, h: { deprecated: true }, g: {} }, paramOrder: [ 'g', 'h', 'e' ] } ); const widget = new ve.ui.MWTransclusionOutlineTemplateWidget( template ); // Expected order on construction time is: // - Documented params in paramOrder (g, h, e), excluding unused deprected params (- h) // - Undocumented params currently used in the template (+ b) assertOrder( widget, [ 'g', 'e', 'b' ] ); let insertAt = widget.findCanonicalPosition( 'h' ); // Most minimal mock instead of an actual ve.ui.MWTransclusionOutlineParameterWidget widget.parameterList.addItems( [ new OO.ui.Widget( { data: 'h' } ) ], insertAt ); // Deprecated param appears at its canonical position via paramOrder assert.strictEqual( insertAt, 1 ); assertOrder( widget, [ 'g', 'h', 'e', 'b' ] ); const newParam = new ve.dm.MWParameterModel( template, 'a1' ); // This fires an "add" event the widget listens to, i.e. this covers onAddParameter() as well template.addParameter( newParam ); assertOrder( widget, [ 'g', 'h', 'e', 'a1', 'b' ] ); // Removing the param doesn't remove it's checkbox item from the widget template.removeParameter( newParam ); assertOrder( widget, [ 'g', 'h', 'e', 'a1', 'b' ] ); // This is effectively the same as above: teach the spec a new param without adding it to the // template. This doesn't fire events, which allows us to test the private method in isolation. template.getSpec().seenParameterNames.a2 = true; insertAt = widget.findCanonicalPosition( 'a2' ); // Most minimal mock instead of an actual ve.ui.MWTransclusionOutlineParameterWidget widget.parameterList.addItems( [ new OO.ui.Widget( { data: 'a2' } ) ], insertAt ); assert.strictEqual( insertAt, 4 ); assertOrder( widget, [ 'g', 'h', 'e', 'a1', 'a2', 'b' ] ); } ); QUnit.test( 'filterParameters() when it cannot find anything', ( assert ) => { const transclusion = new ve.dm.MWTransclusionModel(), template = ve.dm.MWTemplateModel.newFromData( transclusion, { target: { wt: '' }, params: { 1: {}, 2: {}, 3: {}, 4: {} } } ), widget = new ve.ui.MWTransclusionOutlineTemplateWidget( template ); let eventsFired = 0; widget.connect( this, { filterParametersById: ( visibility ) => { assert.deepEqual( visibility, { 'part_0/1': false, 'part_0/2': false, 'part_0/3': false, 'part_0/4': false } ); eventsFired++; } } ); widget.filterParameters( 'b' ); assert.true( widget.infoWidget.isVisible() ); assert.strictEqual( eventsFired, 1 ); } ); QUnit.test( 'filterParameters() considers everything from the spec', ( assert ) => { const transclusion = new ve.dm.MWTransclusionModel(), template = ve.dm.MWTemplateModel.newFromData( transclusion, { target: { wt: '' }, params: { a: {}, b: {}, c: {}, d: {}, e: {} } } ), widget = new ve.ui.MWTransclusionOutlineTemplateWidget( template ); template.getSpec().setTemplateData( { params: { c: { label: 'Contains a' }, d: { description: 'Contains a' }, e: { aliases: [ 'Contains a' ] }, f: { label: 'Also contains a, but is not used in the template' } } } ); let eventsFired = 0; widget.connect( this, { filterParametersById: ( visibility ) => { assert.deepEqual( visibility, { 'part_0/a': true, 'part_0/b': false, 'part_0/c': true, 'part_0/d': true, 'part_0/e': true } ); eventsFired++; } } ); assert.true( widget.searchWidget.isVisible() ); widget.filterParameters( ' A ' ); assert.false( widget.infoWidget.isVisible() ); assert.strictEqual( eventsFired, 1 ); } );