EBernhardson has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/381510 )
Change subject: Implement prefix_search_api.feature in nodejs tests
......................................................................
Implement prefix_search_api.feature in nodejs tests
* Adds a new withApi() function that attaches more error information
to exceptions from api.
* Implements a bunch of steps needed by prefix_search_api.feature
* Stores api errors on world so we can test them
Change-Id: Idbf43b536cd5185d32c4b5988f4daa0f1d6d319c
---
M Gruntfile.js
A tests/integration/features/prefix_search_api.feature
M tests/integration/features/step_definitions/page_step_helpers.js
M tests/integration/features/step_definitions/page_steps.js
M tests/integration/features/support/hooks.js
M tests/integration/features/support/world.js
6 files changed, 480 insertions(+), 23 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CirrusSearch
refs/changes/10/381510/1
diff --git a/Gruntfile.js b/Gruntfile.js
index 5d38ddf..02fda03 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,3 +1,4 @@
+/*jshint esversion: 6, node:true */
/*!
* Grunt file
*
@@ -58,14 +59,16 @@
webdriver: {
test: {
configFile: WebdriverIOconfigFile,
- spec: (() => {
+ spec: ( () => {
let spec = grunt.option( 'spec' );
- return !spec
- ? undefined
- : (spec[0] === '/'
- ? spec
- : path.join(__dirname,
'tests/integration/features', spec))
- })()
+ if (!spec) {
+ return undefined;
+ }
+ if ( spec[0] === '/' ) {
+ return spec;
+ }
+ return path.join(__dirname,
'tests/integration/features', spec);
+ } )()
}
}
} );
diff --git a/tests/integration/features/prefix_search_api.feature
b/tests/integration/features/prefix_search_api.feature
new file mode 100644
index 0000000..e84e830
--- /dev/null
+++ b/tests/integration/features/prefix_search_api.feature
@@ -0,0 +1,157 @@
+@clean @api @prefix @redirect @accent_squashing @accented_namespace @suggest
+Feature: Prefix search via api
+# @suggest needs to be at the end because it will update the completion
suggester index
+ Scenario: Suggestions don't appear when you search for a string that is too
long
+ When I get api suggestions for
贵州省瞬时速度团头鲂身体c实施ysstsstsg说tyttxy以推销员会同香港推广系统在同他讨厌她团体淘汰>赛系统大选于它拥有一天天用于与体育学院国ttxzyttxtxytdttyyyztdsytstsstxtttd天天体育系统的摄像头听到他他偷笑>偷笑太阳团体杏眼桃腮他要tttxx
y贵州省瞬时速度团头鲂身体c实施ysstsstsg说tyttxy以推销员会同香港推广系统在同他讨厌她团体淘汰>赛系统大选于它拥有一天天用于与体育学院国ttxzyttxtxytdttyyyztdsytstsstxtttd天天体育系统的摄像头听到他他偷笑>偷笑太阳团体杏眼桃腮他要tttxx
y
+# Then the api warns Prefix search request was longer than the maximum
allowed length. (288 > 255)
+ Then the api returns error code request_too_long
+
+ Scenario: Prefix search lists page name if both redirect and page name match
+ When I get api suggestions for Redirecttest Y using the classic profile
+ Then Redirecttest Yay is the first api suggestion
+ And Redirecttest Yikes is not in the api suggestions
+ When I get api suggestions for Redirecttest Y using the fuzzy profile
+ Then Redirecttest Yay is the first api suggestion
+ And Redirecttest Yikes is not in the api suggestions
+
+ Scenario: Prefix search ranks redirects under title matches
+ When I get api suggestions for PrefixRedirectRanking using the classic
profile
+ Then PrefixRedirectRanking 1 is the first api suggestion
+ And PrefixRedirectRanking 2 is the second api suggestion
+ When I get api suggestions for PrefixRedirectRanking using the fuzzy
profile
+ Then PrefixRedirectRanking 1 is the first api suggestion
+ And PrefixRedirectRanking 2 is the second api suggestion
+
+ Scenario: Prefix search with classic profile is stricter than the fuzzy
profile
+ When I get api suggestions for PrefixRedirectRankng using the classic
profile
+ Then the API should produce list of length 0
+ When I get api suggestions for PrefixRedirectRankng using the fuzzy profile
+ Then PrefixRedirectRanking 1 is the first api suggestion
+ And PrefixRedirectRanking 2 is the second api suggestion
+
+ Scenario Outline: Search suggestions with accents
+ When I get api suggestions for <term> using the classic profile
+ Then <first_suggestion> is the first api suggestion
+ And <second_suggestion> is the second api suggestion
+ When I get api suggestions for <term> using the fuzzy profile
+ Then <first_suggestion> is the first api suggestion
+ And <second_suggestion> is the second api suggestion
+ Examples:
+ | term | first_suggestion | second_suggestion |
+ | Áccent Sorting | Áccent Sorting | Accent Sorting |
+ | áccent Sorting | Áccent Sorting | Accent Sorting |
+ | Accent Sorting | Accent Sorting | Áccent Sorting |
+ | accent Sorting | Accent Sorting | Áccent Sorting |
+
+ Scenario: Searching for a bare namespace finds everything in the namespace
+ Given a page named Template talk:Foo exists
+ And within 20 seconds api searching for Template talk:Foo yields
Template talk:Foo as the first result
+ When I get api suggestions for template talk:
+ Then Template talk:Foo is in the api suggestions
+
+ Scenario Outline: Search suggestions
+ When I get api suggestions for <term> using the classic profile
+ Then <first_result> is the first api suggestion
+ And the api should offer to search for pages containing <term>
+ When I get api suggestions for <term> using the fuzzy profile
+ Then <first_result> is the first api suggestion
+ And the api should offer to search for pages containing <term>
+ When I get api near matches for <term>
+ Then <title> is the first api search result
+ Examples:
+ | term | first_result | title
|
+# Note that there are more links to catapult then to any other page that
starts with the
+# word "catapult" so it should be first
+ | catapult | Catapult | Catapult
|
+ | catapul | Catapult | none
|
+ | two words | Two Words | Two Words
|
+# | ~catapult | none | none
|
+ | Template:Template Test | Template:Template Test | Template:Template Test
|
+ | l'or | L'Oréal | none
|
+ | l or | L'Oréal | none
|
+ | L'orea | L'Oréal | none
|
+ | L'Oréal | L'Oréal | L'Oréal
|
+ | L’Oréal | L'Oréal | L'Oréal
|
+ | L Oréal | L'Oréal | L'Oréal
|
+ | Jean-Yves Le Drian | Jean-Yves Le Drian | Jean-Yves Le Drian
|
+ | Jean Yves Le Drian | Jean-Yves Le Drian | Jean-Yves Le Drian
|
+
+ Scenario: Prefix search includes redirects
+ When I get api suggestions for SEO Redirecttest using the classic profile
+ Then SEO Redirecttest is the first api suggestion
+ When I get api near matches for SEO Redirecttest
+ Then SEO Redirecttest is the first api search result
+ When I get api suggestions for SEO Redirecttest using the fuzzy profile
+ Then SEO Redirecttest is the first api suggestion
+ When I get api near matches for SEO Redirecttest
+ Then SEO Redirecttest is the first api search result
+
+ Scenario: Prefix search includes redirects for pages outside the main
namespace
+ When I get api suggestions for User_talk:SEO Redirecttest using the
classic profile
+ Then User talk:SEO Redirecttest is the first api suggestion
+ When I get api near matches for User_talk:SEO Redirecttest
+ Then User talk:SEO Redirecttest is the first api search result
+ When I get api suggestions for User_talk:SEO Redirecttest using the fuzzy
profile
+ Then User talk:SEO Redirecttest is the first api suggestion
+ When I get api near matches for User_talk:SEO Redirecttest
+ Then User talk:SEO Redirecttest is the first api search result
+
+ Scenario Outline: Search suggestions with accents
+ When I get api suggestions for <term> using the classic profile
+ Then <first_result> is the first api suggestion
+ And the api should offer to search for pages containing <term>
+ When I get api suggestions for <term> using the fuzzy profile
+ Then <first_result> is the first api suggestion
+ And the api should offer to search for pages containing <term>
+ When I get api near matches for <term>
+ Then <title> is the first api search result
+ Examples:
+ | term | first_result | title
|
+ | África | África | África
|
+ | Africa | África | África
|
+ | AlphaBeta | AlphaBeta | AlphaBeta
|
+ | ÁlphaBeta | AlphaBeta | AlphaBeta
|
+ | Mó:Test | Mó:Test | Mó:Test
|
+ | Mo:Test | Mó:Test | Mó:Test
|
+ | file:Mo:Test | none | none
|
+
+ Scenario Outline: Search suggestions with various profiles
+ When I get api suggestions for <term> using the <profile> profile
+ Then <result>
+ And the api should offer to search for pages containing <term>
+ Examples:
+ | term | profile | result
|
+ | África | strict | África is the first api suggestion
|
+ | Africa | strict | the API should produce list of length 0
|
+ | Agrica | strict | the API should produce list of length 0
|
+ | África | normal | África is the first api suggestion
|
+ | Africa | normal | África is the first api suggestion
|
+ | Agrica | normal | the API should produce list of length 0
|
+ | África | classic | África is the first api suggestion
|
+ | Africa | classic | África is the first api suggestion
|
+ | Agrica | classic | the API should produce list of length 0
|
+ | África | fuzzy | África is the first api suggestion
|
+ | Africa | fuzzy | África is the first api suggestion
|
+ | Agrica | fuzzy | África is the first api suggestion
|
+ | doors | strict | the API should produce list of length 0
|
+ | doors | classic | the API should produce list of length 0
|
+ | doors | normal | The Doors is the first api suggestion
|
+ | the doors | normal | The Doors is the first api suggestion
|
+ | thedoors | normal | the API should produce list of length 0
|
+ | doors | fuzzy | The Doors is the first api suggestion
|
+ | the doors | fuzzy | The Doors is the first api suggestion
|
+ | thedoors | fuzzy | The Doors is the first api suggestion
|
+ | endym | classic | the API should produce list of length 0
|
+ | endym | normal | the API should produce list of length 0
|
+ | endym | fuzzy | the API should produce list of length 0
|
+ | endym | normal-subphrases | Hyperion Cantos/Endymion is the first
api suggestion |
+ | endym | fuzzy-subphrases | Hyperion Cantos/Endymion is the first
api suggestion |
+ | endimion | normal-subphrases | the API should produce list of length 0
|
+ | endimion | fuzzy-subphrases | Hyperion Cantos/Endymion is the first
api suggestion |
+ # Just take too long to run on a regular basis
+ # @redirect @huge
+ # Scenario: Prefix search on pages with tons of redirects is reasonably fast
+ # Given a page named IHaveTonsOfRedirects exists
+ # And there are 1000 redirects to IHaveTonsOfRedirects of the form
TonsOfRedirects%s
+ # When I type TonsOfRedirects into the search box
+ # Then suggestions should appear
diff --git a/tests/integration/features/step_definitions/page_step_helpers.js
b/tests/integration/features/step_definitions/page_step_helpers.js
index 2ca50c6..a67761e 100644
--- a/tests/integration/features/step_definitions/page_step_helpers.js
+++ b/tests/integration/features/step_definitions/page_step_helpers.js
@@ -10,7 +10,9 @@
* https://github.com/cucumber/cucumber-js/issues/634
*/
-const expect = require( 'chai' ).expect;
+const expect = require( 'chai' ).expect,
+ fs = require( 'fs' ),
+ path = require( 'path' );
class StepHelpers {
constructor( world, wiki ) {
@@ -33,10 +35,39 @@
} );
} );
}
- editPage( title, content ) {
+
+ editPage( title, text, append = false ) {
return this.apiPromise.then( ( api ) => {
- return api.loginGetEditToken().then( () => {
- return api.edit( title, content, "CirrusSearch
integration test edit" );
+ if ( text[0] === '@' ) {
+ text = fs.readFileSync( path.join( __dirname,
'articles', text.substr( 1 ) ) ).toString();
+ }
+ return this.getWikitext( title ).then( ( fetchedText )
=> {
+ if ( append ) {
+ text = fetchedText + text;
+ }
+ if ( text.trim() !== fetchedText.trim() ) {
+ return api.loginGetEditToken().then( ()
=> api.edit( title, text ) );
+ }
+ }, ( error ) => {
+ throw error;
+ } );
+ } );
+ }
+
+ getWikitext( title ) {
+ return this.apiPromise.then( ( api ) => {
+ return api.request( {
+ action: "query",
+ format: "json",
+ formatversion: 2,
+ prop: "revisions",
+ rvprop: "content",
+ titles: title
+ } ).then( ( response ) => {
+ if ( response.query.pages[0].missing ) {
+ return "";
+ }
+ return
response.query.pages[0].revisions[0].content;
} );
} );
}
@@ -49,9 +80,36 @@
cirrusUseCompletionSuggester: 'yes',
limit: limit
} );
- } ).then( ( response ) => this.world.setApiResponse( response )
);
+ } ).then(
+ ( response ) => this.world.setApiResponse( response ),
+ ( error ) => this.world.setApiError( error ) );
}
+ suggestionsWithProfile( query, profile ) {
+ return this.apiPromise.then( ( api ) => {
+ return api.request( {
+ action: 'opensearch',
+ search: query,
+ profile: profile
+ } );
+ } ).then(
+ ( response ) => this.world.setApiResponse( response ),
+ ( error ) => this.world.setApiError( error ) );
+ }
+
+ searchFor( query, options = {} ) {
+ return this.apiPromise.then( ( api ) => {
+ return api.request( Object.assign( options, {
+ action: "query",
+ list: "search",
+ srsearch: query,
+ srprop:
"snippet|titlesnippet|redirectsnippet|sectionsnippet|categorysnippet|isfilematch",
+ formatversion: 2
+ } ) );
+ } ).then(
+ ( response ) => this.world.setApiResponse( response ),
+ ( error ) => this.world.setApiError( error ) );
+ }
}
module.exports = StepHelpers;
diff --git a/tests/integration/features/step_definitions/page_steps.js
b/tests/integration/features/step_definitions/page_steps.js
index 703857d..c53b403 100644
--- a/tests/integration/features/step_definitions/page_steps.js
+++ b/tests/integration/features/step_definitions/page_steps.js
@@ -10,10 +10,27 @@
*/
const defineSupportCode = require('cucumber').defineSupportCode,
-SpecialVersion = require('../support/pages/special_version'),
+ SpecialVersion = require('../support/pages/special_version'),
ArticlePage = require('../support/pages/article_page'),
- expect = require( 'chai' ).expect;
+ expect = require( 'chai' ).expect,
+ querystring = require( 'querystring' );
+// Attach extra information to assertion errors about what api call triggered
the problem
+function withApi( world, fn ) {
+ try {
+ return fn();
+ } catch ( e ) {
+ let request = world.apiResponse ? world.apiResponse.__request :
world.apiError.request,
+ qs = Object.assign( {}, request.qs, request.form ),
+ href = request.uri + '?' + querystring.stringify( qs );
+
+ e.message += `\nLast Api: ${href}`;
+ if ( world.apiError ) {
+ e.message += `\nError reported:
${JSON.stringify(world.apiError)}`;
+ }
+ throw e;
+ }
+}
defineSupportCode( function( {Given, When, Then} ) {
When( /^I go to (.*)$/, function ( title ) {
@@ -33,19 +50,151 @@
} );
Then( /^the API should produce list containing (.*)/, function( term ) {
- expect( this.apiResponse[ 1 ] ).to.include( term );
+ withApi( this, () => {
+ expect( this.apiResponse[ 1 ] ).to.include( term );
+ } );
} );
Then( /^the API should produce empty list/, function() {
- expect( this.apiResponse[ 1 ] ).to.have.length( 0 );
+ withApi( this, () => {
+ expect( this.apiResponse[ 1 ] ).to.have.length( 0 );
+ } );
} );
Then( /^the API should produce list starting with (.*)/, function( term
) {
- expect( this.apiResponse[ 1 ][ 0 ] ).to.equal( term );
+ withApi( this, () => {
+ expect( this.apiResponse[ 1 ][ 0 ] ).to.equal( term );
+ } );
} );
Then( /^the API should produce list of length (\d+)/, function( length
) {
- expect( this.apiResponse[ 1 ] ).to.have.length( parseInt(
length, 10 ) );
+ withApi( this, () => {
+ expect( this.apiResponse[ 1 ] ).to.have.length(
parseInt( length, 10 ) );
+ } );
+ } );
+
+ When( /^the api returns error code (.*)$/, function ( code ) {
+ withApi( this, () => {
+ expect( this.apiError ).to.include( {
+ code: code
+ } );
+ } );
+ } );
+
+ When( /^I get api suggestions for (.*?)(?: using the (.*) profile)?$/,
function( search, profile ) {
+ // TODO: Add step helper
+ return this.stepHelpers.suggestionsWithProfile( search, profile
|| "fuzzy" );
+ } );
+
+ Then( /^(.+) is the (.+) api suggestion$/, function ( title, position )
{
+ withApi( this, () => {
+ let pos = ['first', 'second', 'third', 'fourth',
'fifth', 'sixth', 'seventh', 'eigth', 'ninth', 'tenth'].indexOf( position );
+ if ( title === "none" ) {
+ if ( this.apiError && pos === 1 ) {
+ // TODO: Why 1? maybe 0?
+ return;
+ } else {
+ expect( this.apiResponse[1]
).to.have.lengthOf.at.most( pos );
+ }
+ } else {
+ expect( this.apiResponse[1]
).to.have.lengthOf.at.least( pos );
+ expect( this.apiResponse[1][pos] ).to.equal(
title );
+ }
+ } );
+ } );
+
+ Then( /^(.+) is( not)? in the api suggestions$/, function ( title,
should_not ) {
+ withApi( this, () => {
+ if ( should_not ) {
+ expect( this.apiResponse[1] ).to.not.include(
title );
+ } else {
+ expect( this.apiResponse[1] ).to.include( title
);
+ }
+ } );
+ } );
+
+ Then( /^the api should offer to search for pages containing (.+)$/,
function( term ) {
+ withApi( this, () => {
+ expect( this.apiResponse[0] ).to.equal( term );
+ } );
+ } );
+
+ When( /^a page named (.+) exists(?: with contents (.+))?$/, function (
title, text ) {
+ return this.stepHelpers.editPage( title, text || title, false );
+ } );
+
+ Then( /^I get api near matches for (.+)$/, function ( search ) {
+ return this.stepHelpers.searchFor( search, { srwhat:
"nearmatch" } );
+ } );
+
+ function checkApiSearchResultStep( title, in_ok, indexes ) {
+ indexes = indexes.split( ' or ' ).map( ( index ) => {
+ return 'first second third fourth fifth sixth seventh
eighth ninth tenth'.split( ' ' ).indexOf( index );
+ } );
+ if ( title === "none" ) {
+ expect( this.apiResponse.query.search
).to.have.lengthOf.below( 1 + Math.min.apply( null, indexes ) );
+ } else {
+ withApi( this, () => {
+ let found = indexes.map( pos => {
+ if ( this.apiResponse.query.search[pos]
) {
+ return
this.apiResponse.query.search[pos].title;
+ } else {
+ return null;
+ }
+ } );
+ if ( in_ok ) {
+ // What exactly does this do?
+ // expect(found).to
include(include(title))
+ throw new Error( 'Not Implemented' );
+ } else {
+ expect( found ).to.include(title);
+ }
+ } );
+ }
+ }
+ Then( /^(.+) is( in)? the ((?:[^ ])+(?: or (?:[^ ])+)*) api search
result$/, checkApiSearchResultStep );
+
+ function apiSearchStep( enableRewrites, qiprofile, offset, lang,
namespaces, search ) {
+ // JSON.stringify will remove keys that have `undefined` as
their value
+ let options = {
+ sroffset: offset,
+ srnamespace: (namespaces || "0").split(' '),
+ uselang: lang,
+ enablerewrites: enableRewrites ? 1 : 0,
+ srqiprofile: qiprofile ? qiprofile : undefined
+ };
+ // This is reset between scenarios
+ if ( this.didyoumeanOptions ) {
+ Object.assign(options, this.didyoumeanOptions );
+ }
+
+ // Generic string replacement of patterns stored in
this.searchVars
+ search = Object.keys(this.searchVars).reduce( ( str, pattern )
=> str.replace( pattern, this.searchVars[pattern] ), search );
+ // Replace %{\uXXXX}% with the appropriate unicode code point
+ search = search.replace(/%\{\\i([\dA-Fa-f]{4,6})\}%/, ( match,
codepoint ) => JSON.parse( `"\\u${codepoint}"` ) );
+
+ return this.stepHelpers.searchFor( search, options );
+ }
+ When(/^I api search( with rewrites enabled)?(?: with query independent
profile ([^ ]+))?(?: with offset (\d+))?(?: in the (.*) language)?(?: in
namespaces? (\d+(?: \d+)*))? for (.*)$/, apiSearchStep );
+
+ Then( /^within (\d+) seconds api searching for (.+) yields (.+) as the
(.+) result$/, function( seconds, query, title, indexes ) {
+ let timeout = Date.now() + ( 1000 * seconds );
+ let runSteps = ( resolve, reject ) => {
+ apiSearchStep.call( this, undefined, undefined,
undefined, undefined, 0, query ).then( () => {
+ checkApiSearchResultStep.call( this, title,
false, indexes );
+ } ).then( resolve, ( error ) => {
+ if ( Date.now() > timeout ) {
+ console.log( 'within rejected due to
timeout' );
+ reject( error );
+ }
+ console.log( 're-running within' );
+ // Use process.nextTick to keep from exploding
the stack.
+ process.nextTick( () => runSteps( resolve,
reject ) );
+ } );
+ };
+ withApi( this, () => {
+ return new Promise( runSteps );
+ } );
} );
});
diff --git a/tests/integration/features/support/hooks.js
b/tests/integration/features/support/hooks.js
index f5ab71b..fd94196 100644
--- a/tests/integration/features/support/hooks.js
+++ b/tests/integration/features/support/hooks.js
@@ -21,6 +21,71 @@
return true;
} );
+ BeforeOnce( { tags: "@prefix" }, function () {
+ console.log( 'starting prefix hook' );
+ let batchJobs = {
+ edit: {
+ "L'Oréal": "L'Oréal",
+ "Jean-Yves Le Drian": "Jean-Yves Le Drian"
+ }
+ };
+ return this.onWiki().then( ( api ) => {
+ return api.loginGetEditToken().then( () => {
+ return api.batch(batchJobs, 'CirrusSearch
integration test edit');
+ } );
+ } );
+ } );
+
+ BeforeOnce( { tags: "@redirect" }, function () {
+ let batchJobs = {
+ edit: {
+ "SEO Redirecttest": "#REDIRECT [[Search Engine
Optimization Redirecttest]]",
+ "Redirecttest Yikes": "#REDIRECT [[Redirecttest
Yay]]",
+ "User_talk:SEO Redirecttest": "#REDIRECT
[[User_talk:Search Engine Optimization Redirecttest]]",
+ "Seo Redirecttest": "Seo Redirecttest",
+ "Search Engine Optimization Redirecttest":
"Search Engine Optimization Redirecttest",
+ "Redirecttest Yay": "Redirecttest Yay",
+ "User_talk:Search Engine Optimization
Redirecttest": "User_talk:Search Engine Optimization Redirecttest",
+ "PrefixRedirectRanking 1":
"PrefixRedirectRanking 1",
+ "LinksToPrefixRedirectRanking 1":
"[[PrefixRedirectRanking 1]]",
+ "TargetOfPrefixRedirectRanking 2":
"TargetOfPrefixRedirectRanking 2",
+ "PrefixRedirectRanking 2": "#REDIRECT
[[TargetOfPrefixRedirectRanking 2]]"
+ }
+ };
+ return this.onWiki().then( ( api ) => {
+ return api.loginGetEditToken().then( () => {
+ return api.batch(batchJobs, 'CirrusSearch
integration test edit');
+ } );
+ } );
+ } );
+
+ BeforeOnce( { tags: "@accent_squashing" }, function () {
+ let batchJobs = {
+ edit: {
+ "Áccent Sorting": "Áccent Sorting",
+ "Accent Sorting": "Accent Sorting"
+ }
+ };
+ return this.onWiki().then( ( api ) => {
+ return api.loginGetEditToken().then( () => {
+ return api.batch(batchJobs, 'CirrusSearch
integration test edit');
+ } );
+ } );
+ } );
+
+ BeforeOnce( { tags: "@accented_namespace" }, function () {
+ let batchJobs = {
+ edit: {
+ "Mó:Test": "some text"
+ }
+ };
+ return this.onWiki().then( ( api ) => {
+ return api.loginGetEditToken().then( () => {
+ return api.batch(batchJobs, 'CirrusSearch
integration test edit');
+ } );
+ } );
+ } );
+
BeforeOnce( { tags: "@suggest" }, function () {
let batchJobs = {
edit: {
@@ -52,6 +117,10 @@
return this.onWiki().then( ( api ) => {
return api.loginGetEditToken().then( () => {
return api.batch(batchJobs, 'CirrusSearch
integration test edit');
+ } ).then( () => {
+ return api.request( {
+ action: 'cirrus-suggest-index'
+ } );
} );
} );
} );
diff --git a/tests/integration/features/support/world.js
b/tests/integration/features/support/world.js
index c7d94bb..b405433 100644
--- a/tests/integration/features/support/world.js
+++ b/tests/integration/features/support/world.js
@@ -28,7 +28,7 @@
this.pendingResponses = {};
this.connection.on( 'data', ( data ) => {
let parsed = JSON.parse( data );
- console.log( `received response for request
${parsed.requestId}` );
+ console.log( `received response for request
${parsed.requestId}: ${data}` );
if ( parsed && this.pendingResponses[parsed.requestId]
) {
this.pendingResponses[parsed.requestId]( parsed
);
delete this.pendingResponses[parsed.requestId];
@@ -77,10 +77,16 @@
// (I have a feeling this is prone to race conditions).
// By suggestion of this stack overflow question.
//
https://stackoverflow.com/questions/26372724/pass-variables-between-step-definitions-in-cucumber-groovy
- this.apiResponse= "";
+ this.apiResponse = "";
+ this.apiError = "";
this.setApiResponse = function( value ) {
this.apiResponse = value;
+ this.apiError = undefined;
+ };
+ this.setApiError = function ( error ) {
+ this.apiResponse = undefined;
+ this.apiError = error;
};
// Shortcut to environment configs
@@ -108,9 +114,19 @@
apiUrl: w.apiUrl
} );
};
- return new Promise( ( resolve ) => {
- resolve( client );
- } );
+
+ // Add a generic method to get access to the request that
triggered a response, so we
+ // can add generic error reporting that includes the requested
api url
+ let origRawRequest = client.rawRequest;
+ client.rawRequest = function ( requestOptions ) {
+ return origRawRequest.call( client, requestOptions
).then( ( response ) => {
+ response.__request = requestOptions;
+ return response;
+ } );
+ };
+
+ // TODO: Why a promise? I guess it's just easier to chain...
+ return Promise.resolve( client );
};
// Binding step helpers to this World.
@@ -137,6 +153,11 @@
// logs full URL in case of typos, misplaced backslashes.
console.log( `Visited page: ${browser.getUrl()}` );
};
+
+ // Variables held between steps and substituted into queries
+ this.searchVars = {
+ "%ideographic_whitspace%": "\u3000"
+ };
}
defineSupportCode( function( { setWorldConstructor } ) {
--
To view, visit https://gerrit.wikimedia.org/r/381510
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Idbf43b536cd5185d32c4b5988f4daa0f1d6d319c
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/CirrusSearch
Gerrit-Branch: master
Gerrit-Owner: EBernhardson <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits