search: Add wprov to result URLs

This ensures that the wprov parameter is included when users follow the
link as a link (click, middle-click, etc.), and also prepares us for a
future where pressing Enter after selecting a search result navigates to
that result’s URL instead of submitting the form. It also matches the
behavior of the legacy search form.

We put this in App.vue + instrumentation.js, not in urlGenerator.js,
because we also want wprov to be added when custom URL generators or
search clients are used. (The reason for instrumentation.js instead of
purely App.vue is just that it’s easier to test there.)

In the tests, we need to update @wikimedia/mw-node-qunit so that we have
a sufficiently functional mw.Uri() mock.

Bug: T317682
Change-Id: I765d3bbf89b2253add7b50305c362e4bbc9ecceb
This commit is contained in:
Lucas Werkmeister 2022-09-30 16:45:38 +02:00
parent 78bccaf46e
commit d34fae74f1
5 changed files with 76 additions and 12 deletions

14
package-lock.json generated
View file

@ -17,7 +17,7 @@
"@wikimedia/codex": "0.1.0-alpha.10",
"@wikimedia/codex-icons": "0.1.0-alpha.10",
"@wikimedia/codex-search": "0.1.0-alpha.10",
"@wikimedia/mw-node-qunit": "6.4.0",
"@wikimedia/mw-node-qunit": "6.4.1",
"@wikimedia/types-wikimedia": "0.3.3",
"babel-loader": "8.0.6",
"commander": "9.1.0",
@ -4513,9 +4513,9 @@
}
},
"node_modules/@wikimedia/mw-node-qunit": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/@wikimedia/mw-node-qunit/-/mw-node-qunit-6.4.0.tgz",
"integrity": "sha512-WrAPZGsvUTb0LYG1U4S1KP8FB1+zPIYpCG2IDkJ0AyLnjXxM/AsyLFQnG+RLG3aQN3LSfbSECGWyPP4ITQocXQ==",
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/@wikimedia/mw-node-qunit/-/mw-node-qunit-6.4.1.tgz",
"integrity": "sha512-Qdku90cgO7l7anXnYoRghcaxLreqGJUxt/cxL7Rv3F6pugBHioh5dfJDv4MlEo2MD4iNzF52V7pJXRBXQ0aUmQ==",
"dev": true,
"dependencies": {
"eslint-config-wikimedia": "0.21.0",
@ -30619,9 +30619,9 @@
"requires": {}
},
"@wikimedia/mw-node-qunit": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/@wikimedia/mw-node-qunit/-/mw-node-qunit-6.4.0.tgz",
"integrity": "sha512-WrAPZGsvUTb0LYG1U4S1KP8FB1+zPIYpCG2IDkJ0AyLnjXxM/AsyLFQnG+RLG3aQN3LSfbSECGWyPP4ITQocXQ==",
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/@wikimedia/mw-node-qunit/-/mw-node-qunit-6.4.1.tgz",
"integrity": "sha512-Qdku90cgO7l7anXnYoRghcaxLreqGJUxt/cxL7Rv3F6pugBHioh5dfJDv4MlEo2MD4iNzF52V7pJXRBXQ0aUmQ==",
"dev": true,
"requires": {
"eslint-config-wikimedia": "0.21.0",

View file

@ -34,7 +34,7 @@
"@wikimedia/codex": "0.1.0-alpha.10",
"@wikimedia/codex-icons": "0.1.0-alpha.10",
"@wikimedia/codex-search": "0.1.0-alpha.10",
"@wikimedia/mw-node-qunit": "6.4.0",
"@wikimedia/mw-node-qunit": "6.4.1",
"@wikimedia/types-wikimedia": "0.3.3",
"babel-loader": "8.0.6",
"commander": "9.1.0",

View file

@ -170,7 +170,7 @@ module.exports = exports = defineComponent( {
restClient.fetchByTitle( query, searchApiUrl, 10, this.showDescription ).fetch
.then( ( data ) => {
this.suggestions = data.results;
this.suggestions = instrumentation.addWprovToSearchResultUrls( data.results );
this.searchFooterUrl = urlGenerator.generateUrl( query );
const event = {

View file

@ -123,6 +123,7 @@ function getWprovFromResultIndex( index ) {
/**
* @typedef {Object} SearchResultPartial
* @property {string} title
* @property {string} [url]
*/
/**
@ -153,11 +154,31 @@ function generateUrl( suggestion, meta ) {
return result.toString();
}
/**
* Return a new list of search results,
* with the `wprov` parameter added to each result's url (if any).
*
* @param {SearchResultPartial[]} results Not modified.
* @return {SearchResultPartial[]}
*/
function addWprovToSearchResultUrls( results ) {
return results.map( ( result, index ) => {
if ( result.url ) {
const uri = new mw.Uri( result.url );
uri.query.wprov = getWprovFromResultIndex( index );
result = Object.assign( {}, result, { url: uri.toString() } );
}
return result;
} );
}
/**
* @typedef {Object} Instrumentation
* @property {Object} listeners
* @property {Function} getWprovFromResultIndex
* @property {Function} generateUrl
* @property {Function} addWprovToSearchResultUrls
*/
/**
@ -185,5 +206,6 @@ module.exports = {
onSubmit: onSuggestionClick
},
getWprovFromResultIndex,
generateUrl
generateUrl,
addWprovToSearchResultUrls
};

View file

@ -17,8 +17,50 @@ describe( 'instrumentation', () => {
] )( 'should generate URL from %s', ( _name, suggestion ) => {
const meta = { index: 1 };
expect( instrumentation.generateUrl( suggestion, meta ) )
// mw-node-qunit provides a pretty weird mw.Uri.toString()...
.toBe( 'https://host?title=suggestion=wprov' );
.toBe( 'https://host/?title=Special%3ASearch&suggestion=title&wprov=acrw11' );
} );
} );
test( 'addWprovToSearchResultUrls', () => {
const url1 = 'https://host/?title=Special%3ASearch&search=Aa',
url2Base = 'https://host/?title=Special%3ASearch&search=Ab',
url3 = 'https://host/Ac';
const results = [
{
title: 'Aa',
url: url1
},
{
title: 'Ab',
url: `${url2Base}&wprov=xyz`
},
{
title: 'Ac',
url: url3
},
{
title: 'Ad'
}
];
expect( instrumentation.addWprovToSearchResultUrls( results ) )
.toStrictEqual( [
{
title: 'Aa',
url: `${url1}&wprov=acrw10`
},
{
title: 'Ab',
url: `${url2Base}&wprov=acrw11`
},
{
title: 'Ac',
url: `${url3}?wprov=acrw12`
},
{
title: 'Ad'
}
] );
expect( results[ 0 ].url ).toStrictEqual( url1 );
} );
} );