/*! * VisualEditor DataModel MWTemplateModel tests. * * @copyright 2011-2020 VisualEditor Team and others; see AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt */ { const transclusionData = { params: { foo: { wt: 'Foo value' }, bar: { wt: 'Bar value' }, Bar: { wt: 'Bar value' }, empty: { wt: '' }, '': { wt: '' } }, target: { href: './Template:Test', wt: 'Test' } }; QUnit.module( 've.dm.MWTemplateModel' ); /** * Create a new MWTemplateModel initialized with a static transclusion data fixture. * * @return {ve.dm.MWTemplateModel} */ const newTemplateModel = function () { const doc = ve.dm.Document.static.newBlankDocument(), transclusion = new ve.dm.MWTransclusionModel( doc ), clonedTransclusionData = ve.extendObject( {}, transclusionData ); return ve.dm.MWTemplateModel.newFromData( transclusion, clonedTransclusionData ); }; /* Tests */ [ [ undefined, null ], [ '', null ], [ 'no_prefix', 'no prefix' ], [ '/unexpected_prefix', '/unexpected prefix' ], [ './Template:%C3%9Cnicode%5Fexample/subpage', 'Template:Ünicode example/subpage' ], [ './Template:Possibly_invalid%5B%5D', 'Template:Possibly invalid[]' ] ].forEach( ( [ href, expected ] ) => QUnit.test( 'getTitle: ' + href, ( assert ) => { const transclusion = { nextUniquePartId: () => '' }, template = new ve.dm.MWTemplateModel( transclusion, { href } ); assert.strictEqual( template.getTitle(), expected ); } ) ); QUnit.test( 'hasParameter', ( assert ) => { const template = newTemplateModel(); // All parameters are primary as long as the TemplateData documentation isn't known assert.strictEqual( template.hasParameter( 'bar' ), true ); assert.strictEqual( template.hasParameter( 'resolved-bar' ), false ); assert.strictEqual( template.hasParameter( 'alternative-bar' ), false ); template.getSpec().setTemplateData( { params: { 'resolved-bar': { aliases: [ 'bar', 'alternative-bar' ] } } } ); // Now "bar" and "alternative-bar" are aliases, and "resolved-bar" is the primary name assert.strictEqual( template.hasParameter( 'bar' ), true ); assert.strictEqual( template.hasParameter( 'resolved-bar' ), true ); assert.strictEqual( template.hasParameter( 'alternative-bar' ), true ); } ); QUnit.test( 'getOriginalParameterName', ( assert ) => { const template = newTemplateModel(); template.addParameter( new ve.dm.MWParameterModel( template, 'p1' ) ); template.addParameter( new ve.dm.MWParameterModel( template, 'p2-alias' ) ); // These are all independent parameters as long as we don't know anything about aliases assert.strictEqual( template.getOriginalParameterName( 'p1' ), 'p1' ); assert.strictEqual( template.getOriginalParameterName( 'p1-alias' ), 'p1-alias' ); assert.strictEqual( template.getOriginalParameterName( 'p2' ), 'p2' ); assert.strictEqual( template.getOriginalParameterName( 'p2-alias' ), 'p2-alias' ); assert.strictEqual( template.getOriginalParameterName( 'p3' ), 'p3' ); assert.strictEqual( template.getOriginalParameterName( 'p3-alias' ), 'p3-alias' ); template.getSpec().setTemplateData( { params: { p1: { aliases: [ 'p1-alias' ] }, p2: { aliases: [ 'p2-alias' ] }, p3: { aliases: [ 'p3-alias' ] } } } ); assert.strictEqual( template.getOriginalParameterName( 'p1' ), 'p1' ); assert.strictEqual( template.getOriginalParameterName( 'p1-alias' ), 'p1' ); assert.strictEqual( template.getOriginalParameterName( 'p2' ), 'p2-alias' ); assert.strictEqual( template.getOriginalParameterName( 'p2-alias' ), 'p2-alias' ); assert.strictEqual( template.getOriginalParameterName( 'p3' ), 'p3' ); assert.strictEqual( template.getOriginalParameterName( 'p3-alias' ), 'p3' ); } ); QUnit.test( 'serialize input parameters', ( assert ) => { const template = newTemplateModel(); const serialization = template.serialize(); assert.deepEqual( serialization, { template: { params: { foo: { wt: 'Foo value' }, bar: { wt: 'Bar value' }, Bar: { wt: 'Bar value' }, empty: { wt: '' } }, target: { href: './Template:Test', wt: 'Test' } } } ); } ); QUnit.test( 'serialize changed input parameters', ( assert ) => { const template = newTemplateModel(), newParameter = new ve.dm.MWParameterModel( template, 'baz', 'Baz value' ); template.addParameter( newParameter ); const serialization = template.serialize(); assert.deepEqual( serialization.template.params.baz, { wt: 'Baz value' } ); } ); // T75134 QUnit.test( 'serialize after parameter was removed', ( assert ) => { const template = newTemplateModel(), existingParameter = template.getParameter( 'bar' ); template.removeParameter( existingParameter ); const serialization = template.serialize(); assert.deepEqual( serialization.template.params, { foo: { wt: 'Foo value' }, Bar: { wt: 'Bar value' }, empty: { wt: '' } } ); } ); // T101075 QUnit.test( 'serialize without empty parameter not present in original parameter set', ( assert ) => { const template = newTemplateModel(), parameterWithoutValue = new ve.dm.MWParameterModel( template, 'new_empty', '' ); template.addParameter( parameterWithoutValue ); const serialization = template.serialize(); assert.deepEqual( serialization.template.params, { foo: { wt: 'Foo value' }, bar: { wt: 'Bar value' }, Bar: { wt: 'Bar value' }, empty: { wt: '' } } ); } ); [ { name: 'serialize with explicit parameter order', spec: { params: { foo: {}, empty: {}, bar: {}, Bar: {} }, paramOrder: [ 'bar', 'foo', 'empty', 'Bar' ] }, expected: [ 'foo', 'bar', 'Bar', 'empty' ] }, { name: 'serialize with no parameter order', spec: { params: { foo: {}, empty: {}, bar: {}, Bar: {} } }, expected: [ 'foo', 'bar', 'Bar', 'empty' ] }, { name: 'serialize with aliases', spec: { params: { foo: {}, Bar: {}, empty: {}, hasaliases: { aliases: [ 'bar', 'baz' ] } } }, expected: [ 'foo', 'bar', 'Bar', 'empty' ] }, { name: 'serialize with unknown params', spec: { params: { bar: {} } }, expected: [ 'foo', 'bar', 'Bar', 'empty' ] } ].forEach( ( { name, spec, expected } ) => QUnit.test( name, ( assert ) => { const template = newTemplateModel(); template.getSpec().setTemplateData( spec ); const serialization = template.serialize(); assert.deepEqual( Object.keys( serialization.template.params ), expected ); } ) ); [ { name: 'no spec retrieved', spec: null, expected: [ 'bar', 'Bar', 'empty', 'foo', '' ] }, { name: 'empty spec', spec: {}, expected: [ 'bar', 'Bar', 'empty', 'foo', '' ] }, { name: 'spec with explicit paramOrder and all known params', spec: { params: { bar: {}, Bar: {}, empty: {}, unused: {}, foo: {} }, paramOrder: [ 'foo', 'Bar', 'empty', 'bar', 'unused' ] }, expected: [ 'foo', 'Bar', 'empty', 'bar', '' ] }, { name: 'spec with explicit paramOrder and some unknown params', spec: { params: { empty: {}, unused: {}, foo: {} }, paramOrder: [ 'foo', 'empty', 'unused' ] }, expected: [ 'foo', 'empty', 'bar', 'Bar', '' ] }, { name: 'spec with explicit paramOrder but all unknown params', spec: { params: {}, paramOrder: [] }, expected: [ 'bar', 'Bar', 'empty', 'foo', '' ] }, { name: 'spec with no paramOrder, all known params', spec: { params: { bar: {}, Bar: {}, foo: {}, unused: {}, empty: {} } }, expected: [ 'bar', 'Bar', 'foo', 'empty', '' ] }, { name: 'spec with no paramOrder and some unknown params', spec: { params: { empty: {}, unused: {}, foo: {} } }, expected: [ 'empty', 'foo', 'bar', 'Bar', '' ] } ].forEach( ( { name, spec, expected } ) => QUnit.test( 'getOrderedParameterNames: ' + name, ( assert ) => { const template = newTemplateModel(); if ( spec ) { template.getSpec().setTemplateData( spec ); } assert.deepEqual( template.getOrderedParameterNames(), expected ); } ) ); [ { name: 'no spec retrieved', spec: null, expected: [ 'bar', 'Bar', 'empty', 'foo', '' ] }, { name: 'spec with explicit paramOrder and all known params', spec: { params: { bar: {}, Bar: {}, empty: {}, unused: {}, foo: {} }, paramOrder: [ 'foo', 'Bar', 'empty', 'unused', 'bar' ] }, expected: [ 'foo', 'Bar', 'empty', 'unused', 'bar', '' ] }, { name: 'spec with explicit paramOrder and some unknown params', spec: { params: { empty: {}, unused: {}, foo: {} }, paramOrder: [ 'foo', 'empty', 'unused' ] }, expected: [ 'foo', 'empty', 'unused', 'bar', 'Bar', '' ] }, { name: 'spec with explicit paramOrder but all unknown params', spec: { params: {}, paramOrder: [] }, expected: [ 'bar', 'Bar', 'empty', 'foo', '' ] }, { name: 'spec with no paramOrder, all known params', spec: { params: { bar: {}, Bar: {}, foo: {}, unused: {}, empty: {} } }, expected: [ 'bar', 'Bar', 'foo', 'unused', 'empty', '' ] }, { name: 'spec with no paramOrder and some unknown params', spec: { params: { empty: {}, unused: {}, foo: {} } }, expected: [ 'empty', 'unused', 'foo', 'bar', 'Bar', '' ] }, { name: 'spec with explicit paramOrder and aliases', spec: { params: { empty: {}, unused: {}, hasalias: { aliases: [ 'bar', 'baz' ] } }, paramOrder: [ 'hasalias', 'empty', 'unused' ] }, expected: [ 'bar', 'empty', 'unused', 'Bar', 'foo', '' ] } ].forEach( ( { name, spec, expected } ) => QUnit.test( 'getAllParametersOrdered: ' + name, ( assert ) => { const template = newTemplateModel(); if ( spec ) { template.getSpec().setTemplateData( spec ); } assert.deepEqual( template.getAllParametersOrdered(), expected ); } ) ); QUnit.test( 'same documented parameter used with different aliases', ( assert ) => { const transclusion = new ve.dm.MWTransclusionModel(); const template = ve.dm.MWTemplateModel.newFromData( transclusion, { target: {}, params: { d: {}, c: {}, b: {}, a: {} } } ); template.getSpec().setTemplateData( { params: { a: { aliases: [ 'b', 'c' ] }, e: {} } } ); assert.deepEqual( template.getOrderedParameterNames(), [ 'a', 'c', 'b', 'd' ] ); assert.deepEqual( template.getAllParametersOrdered(), [ 'a', 'c', 'b', 'e', 'd' ] ); } ); [ [ 'a', 'b', 'Template:A', 'prefers .wt when it is a valid title' ], [ '{{a}}', 'subst:b', 'subst:b', 'falls back to unmodified getTitle' ], [ 'subst:a', 'b', 'Template:A', 'strips subst:' ], [ 'safesubst:a', 'b', 'Template:A', 'strips safesubst:' ], [ ' SUBST: a', 'b', 'Template:A', 'ignores capitalization and whitespace' ], [ 'subst :a', 'b', 'Template:Subst :a', 'leaves bad whitespace untouched' ], [ 'int:a', 'b', 'Template:Int:a', 'leaves other prefixes untouched' ] ].forEach( ( [ wt, href, expected, message ] ) => QUnit.test( 'getTemplateDataQueryTitle: ' + message, ( assert ) => { const transclusion = { nextUniquePartId: () => '' }, data = { target: { wt, href } }, model = ve.dm.MWTemplateModel.newFromData( transclusion, data ); assert.strictEqual( model.getTemplateDataQueryTitle(), expected ); } ) ); [ [ {}, false, 'no parameters' ], [ { p1: {}, p2: { wt: 'foo' } }, true, 'multiple parameters' ], [ { p1: {} }, false, 'undefined' ], [ { p1: { wt: null } }, false, 'null' ], [ { p1: { wt: '' } }, false, 'empty string' ], [ { p1: { wt: ' ' } }, true, 'space' ], [ { p1: { wt: '0' } }, true, '0' ], [ { p1: { wt: '\nfoo' } }, true, 'newline' ] ].forEach( ( [ params, expected, message ] ) => QUnit.test( 'containsValuableData: ' + message, ( assert ) => { const transclusion = { nextUniquePartId: () => '' }, data = { target: {}, params }, model = ve.dm.MWTemplateModel.newFromData( transclusion, data ); assert.strictEqual( model.containsValuableData(), expected ); } ) ); }