2019-01-17 12:51:13 +00:00
import { createStubTitle } from '../stubs' ;
2017-07-28 17:32:46 +00:00
import { createModel } from '../../../src/preview/model' ;
import createRESTBaseGateway from '../../../src/gateway/rest' ;
2018-03-19 19:39:41 +00:00
const DEFAULT _CONSTANTS = {
2018-03-07 20:15:30 +00:00
THUMBNAIL _SIZE : 512 ,
endpoint : '/api/rest_v1/page/summary/'
2017-02-22 10:01:45 +00:00
} ,
RESTBASE _RESPONSE = {
2018-03-07 11:10:53 +00:00
type : 'standard' ,
2017-02-22 10:01:45 +00:00
title : 'Barack Obama' ,
extract : 'Barack Hussein Obama II born August 4, 1961) ...' ,
thumbnail : {
2017-02-28 14:28:40 +00:00
source : 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/President_Barack_Obama.jpg/200px-President_Barack_Obama.jpg' ,
2017-02-22 10:01:45 +00:00
width : 200 ,
height : 250
} ,
originalimage : {
source : 'https://upload.wikimedia.org/wikipedia/commons/8/8d/President_Barack_Obama.jpg' ,
width : 800 ,
height : 1000
} ,
lang : 'en' ,
dir : 'ltr' ,
timestamp : '2017-01-30T10:17:41Z' ,
description : '44th President of the United States of America'
} ,
2017-02-28 14:28:40 +00:00
SVG _RESTBASE _RESPONSE = {
2018-03-07 11:10:53 +00:00
type : 'standard' ,
2017-02-28 14:28:40 +00:00
title : 'Barack Obama' ,
extract : 'Barack Hussein Obama II born August 4, 1961) ...' ,
thumbnail : {
2017-03-06 14:37:42 +00:00
source : 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/President_Barack_Obama.svg/200px-President_Barack_Obama.svg.png' ,
2017-02-28 14:28:40 +00:00
width : 200 ,
height : 250
} ,
originalimage : {
source : 'https://upload.wikimedia.org/wikipedia/commons/8/8d/President_Barack_Obama.svg' ,
width : 800 ,
height : 1000
} ,
lang : 'en' ,
dir : 'ltr' ,
timestamp : '2017-01-30T10:17:41Z' ,
description : '44th President of the United States of America'
} ,
2017-02-22 10:01:45 +00:00
RESTBASE _RESPONSE _WITHOUT _IMAGE = {
2018-03-07 11:10:53 +00:00
type : 'standard' ,
2017-02-22 10:01:45 +00:00
title : 'Barack Obama' ,
extract : 'Barack Hussein Obama II born August 4, 1961) ...' ,
lang : 'en' ,
dir : 'ltr' ,
timestamp : '2017-01-30T10:17:41Z' ,
description : '44th President of the United States of America'
} ,
2017-03-06 14:37:42 +00:00
// Note well that the thumbnail and originalimage properties are
// identical. This can be the case where RESTBase requests a thumbnail at
// 320px width but the original image isn't that wide, in which instance
// PageImages - and therefore RESTBase - return the original image as the
// thumbnail.
//
// See https://phabricator.wikimedia.org/T158632#3071104 onward for additional
// context.
RESTBASE _RESPONSE _WITH _SMALL _IMAGE = {
2018-03-07 11:10:53 +00:00
type : 'standard' ,
2017-04-25 12:12:36 +00:00
title : 'PreviewsNonFreeImage/sandbox' ,
extract : 'Hello, I am the non-free image and parenthetical page (YOU CAN\'T SEE THIS). My preview should contain an image that is not free. My preview should contain a parenthetical you cannot see..' ,
2017-03-06 14:37:42 +00:00
thumbnail : {
2017-04-25 12:12:36 +00:00
source : 'https://upload.wikimedia.org/wikipedia/commons/2/2c/RH-Fedora_logo-nonfree.png' ,
2017-03-06 14:37:42 +00:00
width : 300 ,
2017-03-10 10:21:53 +00:00
height : 126 ,
2017-04-25 12:12:36 +00:00
original : 'https://upload.wikimedia.org/wikipedia/commons/2/2c/RH-Fedora_logo-nonfree.png'
2017-03-06 14:37:42 +00:00
} ,
originalimage : {
2017-04-25 12:12:36 +00:00
source : 'https://upload.wikimedia.org/wikipedia/commons/2/2c/RH-Fedora_logo-nonfree.png' ,
2017-03-06 14:37:42 +00:00
width : 300 ,
height : 126
} ,
2017-04-25 12:12:36 +00:00
lang : 'en' ,
dir : 'ltr' ,
timestamp : '2017-02-17T22:29:56Z'
2017-03-06 14:37:42 +00:00
} ,
2018-02-21 23:52:10 +00:00
// As above, a no "px-" thumbnail is provided which is not customizable.
RESTBASE _RESPONSE _WITH _NO _PX _IMAGE = {
2018-03-07 11:10:53 +00:00
type : 'standard' ,
2018-02-21 23:52:10 +00:00
title : 'Barack Obama' ,
extract : 'Barack Hussein Obama II born August 4, 1961) ...' ,
thumbnail : {
source : 'https://upload.wikimedia.org/wikipedia/commons/8/8d/President_Barack_Obama.jpg' ,
width : 800 ,
height : 1000
} ,
originalimage : {
source : 'https://upload.wikimedia.org/wikipedia/commons/8/8d/President_Barack_Obama.jpg' ,
width : 800 ,
height : 1000
} ,
lang : 'en' ,
dir : 'ltr' ,
timestamp : '2017-01-30T10:17:41Z' ,
description : '44th President of the United States of America'
} ,
2018-06-20 22:40:38 +00:00
RESTBASE _RESPONSE _NONIMAGE _ORIGINAL = {
type : 'standard' ,
title : 'Completing the square' ,
extract : 'Landscape' ,
thumbnail : {
source : 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Completing_the_square.ogv/320px--Completing_the_square.ogv.jpg' ,
width : 320 ,
height : 240
} ,
originalimage : {
source : 'https://upload.wikimedia.org/wikipedia/commons/3/3d/Completing_the_square.ogv' ,
width : 640 ,
height : 480
} ,
lang : 'en' ,
dir : 'ltr' ,
timestamp : '2018-04-14T05:31:14Z' ,
description : 'technique used to solve a quadratic equation.'
} ,
2017-03-10 10:21:53 +00:00
RESTBASE _RESPONSE _WITH _LANDSCAPE _IMAGE = {
2018-03-07 11:10:53 +00:00
type : 'standard' ,
2017-04-25 12:12:36 +00:00
title : 'Landscape' ,
extract : 'Landscape' ,
2017-03-10 10:21:53 +00:00
thumbnail : {
2017-04-25 12:12:36 +00:00
source : 'http://foo/bar/baz.png/500px-baz.png' ,
2017-03-10 10:21:53 +00:00
width : 500 ,
height : 300 ,
2017-04-25 12:12:36 +00:00
original : 'http://foo/bar/baz.png'
2017-03-10 10:21:53 +00:00
} ,
originalimage : {
2017-04-25 12:12:36 +00:00
source : 'http://foo/bar/baz.png' ,
2017-03-10 10:21:53 +00:00
width : 1000 ,
height : 600
} ,
2017-04-25 12:12:36 +00:00
lang : 'en' ,
dir : 'ltr' ,
timestamp : '2017-02-17T22:29:56Z'
2017-03-10 10:21:53 +00:00
} ,
2018-03-07 11:10:53 +00:00
RESTBASE _RESPONSE _DISAMBIGUATION = {
type : 'disambiguation' ,
title : 'Barack (disambiguation)' ,
extract : 'Barack Hussein Obama II born August 4, 1961) ...' ,
lang : 'en' ,
dir : 'ltr' ,
timestamp : '2017-02-17T22:29:56Z'
} ,
2017-02-22 10:01:45 +00:00
RESTBASE _RESPONSE _PREVIEW _MODEL = createModel (
'Barack Obama' ,
'url/Barack Obama' , // Generated in the stub below
'en' ,
'ltr' ,
2017-06-08 13:29:57 +00:00
'!Barack Hussein Obama II born August 4, 1961) ...!' ,
2018-03-07 11:10:53 +00:00
'standard' ,
2017-02-22 10:01:45 +00:00
{
2017-03-10 10:21:53 +00:00
source : 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/President_Barack_Obama.jpg/409px-President_Barack_Obama.jpg' ,
width : 409 ,
height : 512
2017-02-22 10:01:45 +00:00
}
2018-03-07 11:10:53 +00:00
) ,
RESTBASE _RESPONSE _DISAMBIGUATION _MODEL = createModel (
'Barack (disambiguation)' ,
'url/Barack (disambiguation)' ,
'en' ,
'ltr' ,
'!Barack Hussein Obama II born August 4, 1961) ...!' ,
'disambiguation'
2017-02-22 10:01:45 +00:00
) ;
2017-06-08 13:29:57 +00:00
function provideParsedExtract ( page ) {
2019-08-05 12:42:21 +00:00
return ` ! ${ page . extract } ! ` ;
2017-06-08 13:29:57 +00:00
}
2017-02-22 10:01:45 +00:00
QUnit . module ( 'gateway/rest' , {
2018-03-14 22:04:59 +00:00
beforeEach ( ) {
2019-10-17 08:51:49 +00:00
mw . Title = function ( title ) {
2019-08-05 12:42:21 +00:00
this . getUrl = ( ) => ` url/ ${ title } ` ;
2017-02-22 10:01:45 +00:00
} ;
} ,
2018-03-14 22:04:59 +00:00
afterEach ( ) {
2019-10-17 08:51:49 +00:00
mw . Title = null ;
2017-02-22 10:01:45 +00:00
}
} ) ;
QUnit . test ( 'RESTBase gateway is called with correct arguments' , function ( assert ) {
2018-07-03 22:23:27 +00:00
const config = $ . extend ( { } , DEFAULT _CONSTANTS , {
acceptLanguage : 'pl'
} ) ;
2018-03-19 19:39:41 +00:00
const getSpy = this . sandbox . spy ( ) ,
2018-07-03 22:23:27 +00:00
gateway = createRESTBaseGateway ( getSpy , config ) ,
2017-02-22 10:01:45 +00:00
expectedOptions = {
2018-03-07 20:15:30 +00:00
url : DEFAULT _CONSTANTS . endpoint + encodeURIComponent ( 'Test Title' ) ,
2017-02-22 10:01:45 +00:00
headers : {
2017-06-06 09:48:05 +00:00
Accept : 'application/json; charset=utf-8; ' +
2018-07-03 22:23:27 +00:00
'profile="https://www.mediawiki.org/wiki/Specs/Summary/1.2.0"' ,
'Accept-Language' : 'pl'
2017-02-22 10:01:45 +00:00
}
} ;
gateway . fetch ( 'Test Title' ) ;
assert . deepEqual ( getSpy . getCall ( 0 ) . args [ 0 ] , expectedOptions , 'options' ) ;
} ) ;
2017-06-08 13:29:57 +00:00
QUnit . test ( 'RESTBase provider uses extract parser' , function ( assert ) {
2018-03-19 19:39:41 +00:00
const getSpy = this . sandbox . spy ( ) ,
2017-06-08 13:29:57 +00:00
gateway = createRESTBaseGateway ( ) ;
gateway . convertPageToModel ( RESTBASE _RESPONSE , 512 , getSpy ) ;
2018-05-08 19:48:17 +00:00
assert . deepEqual (
getSpy . getCall ( 0 ) . args [ 0 ] ,
RESTBASE _RESPONSE ,
'The gateway parser was called with the correct arguments.'
) ;
2017-06-08 13:29:57 +00:00
} ) ;
2018-03-14 23:50:09 +00:00
QUnit . test ( 'RESTBase gateway is correctly converting the page data to a model' , ( assert ) => {
2018-03-19 19:39:41 +00:00
const gateway = createRESTBaseGateway ( ) ;
2017-02-22 10:01:45 +00:00
assert . deepEqual (
2017-06-08 13:29:57 +00:00
gateway . convertPageToModel ( RESTBASE _RESPONSE , 512 , provideParsedExtract ) ,
2018-05-08 19:48:17 +00:00
RESTBASE _RESPONSE _PREVIEW _MODEL ,
'The gateway unmarshals responses.'
2017-02-22 10:01:45 +00:00
) ;
} ) ;
2018-03-14 23:50:09 +00:00
QUnit . test ( 'RESTBase gateway is correctly converting the page data to a disambiguation model' , ( assert ) => {
2018-03-19 19:39:41 +00:00
const gateway = createRESTBaseGateway ( ) ;
2018-03-07 11:10:53 +00:00
assert . deepEqual (
gateway . convertPageToModel ( RESTBASE _RESPONSE _DISAMBIGUATION ,
512 , provideParsedExtract ) ,
2018-05-08 19:48:17 +00:00
RESTBASE _RESPONSE _DISAMBIGUATION _MODEL ,
'The gateway unmarshals disambiguations.'
2018-03-07 11:10:53 +00:00
) ;
} ) ;
2018-03-14 23:50:09 +00:00
QUnit . test ( 'RESTBase gateway doesn\'t stretch thumbnails' , ( assert ) => {
2018-03-19 19:39:41 +00:00
const gateway = createRESTBaseGateway ( ) ;
2017-02-22 10:01:45 +00:00
2018-03-19 19:39:41 +00:00
let model = gateway . convertPageToModel (
2018-01-18 18:48:16 +00:00
RESTBASE _RESPONSE , 2000 , provideParsedExtract ) ;
2017-02-22 10:01:45 +00:00
2017-03-06 14:37:42 +00:00
assert . deepEqual (
model . thumbnail ,
RESTBASE _RESPONSE . originalimage ,
2018-01-11 03:23:28 +00:00
'If the requested thumbnail size is bigger than that of the original, then use the original.'
2017-03-06 14:37:42 +00:00
) ;
// ---
2018-01-18 18:48:16 +00:00
model = gateway . convertPageToModel (
RESTBASE _RESPONSE ,
RESTBASE _RESPONSE . originalimage . height ,
provideParsedExtract
) ;
2017-03-06 14:37:42 +00:00
assert . deepEqual (
model . thumbnail ,
RESTBASE _RESPONSE . originalimage ,
'If the requested thumbnail size is the same as that of the original, then use the original.'
) ;
// ---
2018-01-18 18:48:16 +00:00
model = gateway . convertPageToModel (
RESTBASE _RESPONSE _WITH _SMALL _IMAGE , 320 , provideParsedExtract ) ;
2017-03-06 14:37:42 +00:00
assert . deepEqual (
model . thumbnail ,
RESTBASE _RESPONSE _WITH _SMALL _IMAGE . originalimage ,
2018-01-11 03:23:28 +00:00
'If the requested thumbnail can\'t be generated because the original is too small, then use the original.'
2017-03-06 14:37:42 +00:00
) ;
2017-03-10 10:21:53 +00:00
// ---
2018-01-18 18:48:16 +00:00
model = gateway . convertPageToModel (
RESTBASE _RESPONSE _WITH _LANDSCAPE _IMAGE , 640 , provideParsedExtract ) ;
2017-03-10 10:21:53 +00:00
assert . deepEqual (
model . thumbnail ,
{
source : 'http://foo/bar/baz.png/640px-baz.png' ,
width : 640 ,
height : 384 // ( 640 / 500 ) * 300
} ,
'When the requested thumbnail is scaled, then its largest dimension is preserved.'
) ;
2017-03-06 14:37:42 +00:00
} ) ;
2018-03-14 23:50:09 +00:00
QUnit . test ( 'RESTBase gateway handles thumbnail URLs with missing dimensions' , ( assert ) => {
2018-03-19 19:39:41 +00:00
const gateway = createRESTBaseGateway ( ) ;
const model = gateway . convertPageToModel (
2018-02-21 23:52:10 +00:00
RESTBASE _RESPONSE _WITH _NO _PX _IMAGE , 300 , provideParsedExtract ) ;
2018-05-20 12:32:51 +00:00
assert . strictEqual (
2018-02-21 23:52:10 +00:00
model . thumbnail . source ,
'https://upload.wikimedia.org/wikipedia/commons/8/8d/President_Barack_Obama.jpg' ,
'If restbase handles missing image dimensions in thumbnail URLs'
) ;
} ) ;
2018-03-14 23:50:09 +00:00
QUnit . test ( 'RESTBase gateway handles awkward thumbnails' , ( assert ) => {
2018-03-19 19:39:41 +00:00
const gateway = createRESTBaseGateway ( ) ;
2017-03-06 14:37:42 +00:00
2018-03-19 19:39:41 +00:00
const response = Object . assign ( { } , RESTBASE _RESPONSE ) ;
2017-03-06 14:37:42 +00:00
response . thumbnail = Object . assign ( { } , RESTBASE _RESPONSE . thumbnail ) ;
response . thumbnail . source = 'http://foo.bar/baz/Qux-320px-Quux.png/800px-Qux-320px-Quux.png' ;
2018-03-19 19:39:41 +00:00
const model =
gateway . convertPageToModel ( response , 500 , provideParsedExtract ) ;
2017-03-06 14:37:42 +00:00
assert . deepEqual (
2017-02-22 10:01:45 +00:00
model . thumbnail . source ,
2017-03-10 10:21:53 +00:00
'http://foo.bar/baz/Qux-320px-Quux.png/400px-Qux-320px-Quux.png' ,
2017-03-06 14:37:42 +00:00
'If the requested thumbnail size is the same as that of the original, then use the original.'
2017-02-22 10:01:45 +00:00
) ;
} ) ;
2018-06-20 22:40:38 +00:00
QUnit . test ( 'RESTBase gateway always scales SVGs' , ( assert ) => {
2018-03-19 19:39:41 +00:00
const gateway = createRESTBaseGateway ( ) ;
2017-02-22 10:01:45 +00:00
2018-03-19 19:39:41 +00:00
const model = gateway . convertPageToModel (
2018-01-18 18:48:16 +00:00
SVG _RESTBASE _RESPONSE , 2000 , provideParsedExtract ) ;
2017-02-22 10:01:45 +00:00
2018-05-20 12:32:51 +00:00
assert . strictEqual (
2017-02-22 10:01:45 +00:00
model . thumbnail . source ,
2017-03-10 10:21:53 +00:00
'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/President_Barack_Obama.svg/1600px-President_Barack_Obama.svg.png' ,
2017-03-06 14:37:42 +00:00
'If the requested thumbnail is for an SVG, then it\'s always scaled.'
2017-02-22 10:01:45 +00:00
) ;
} ) ;
2018-06-20 22:40:38 +00:00
QUnit . test ( 'RESTBase gateway only returns safe image formats' , ( assert ) => {
const gateway = createRESTBaseGateway ( ) ;
let model = gateway . convertPageToModel (
RESTBASE _RESPONSE _NONIMAGE _ORIGINAL , 640 , provideParsedExtract ) ;
assert . strictEqual (
model . thumbnail ,
undefined ,
` If the original image is a video file, and the requested thumbnail
is larger than the original video file , no thumbnail is returned . `
) ;
model = gateway . convertPageToModel (
RESTBASE _RESPONSE _NONIMAGE _ORIGINAL , 320 , provideParsedExtract ) ;
assert . strictEqual (
model . thumbnail . source ,
RESTBASE _RESPONSE _NONIMAGE _ORIGINAL . thumbnail . source ,
` If the original image is a video file, and the requested thumbnail
is smaller than the original video file , the thumbnail is returned . `
) ;
} ) ;
2018-01-11 03:23:28 +00:00
QUnit . test ( 'RESTBase gateway handles API failure' , function ( assert ) {
2018-03-19 19:39:41 +00:00
const api = this . sandbox . stub ( )
2018-01-18 18:48:16 +00:00
. returns ( $ . Deferred ( ) . reject ( { status : 500 } ) . promise ( ) ) ,
2018-03-07 20:15:30 +00:00
gateway = createRESTBaseGateway ( api , { } ) ;
2017-02-22 10:01:45 +00:00
2019-01-23 16:50:19 +00:00
return gateway . fetchPreviewForTitle ( createStubTitle ( 1 , 'Test Title' ) ) . catch ( ( ) => {
2022-02-09 15:09:19 +00:00
assert . true ( true , 'The gateway threw an error.' ) ;
2017-02-22 10:01:45 +00:00
} ) ;
2017-04-03 23:37:52 +00:00
} ) ;
2018-07-12 22:02:59 +00:00
QUnit . test ( 'RESTBase gateway handles 404 as a failure' , function ( assert ) {
const api = this . sandbox . stub ( )
. returns ( $ . Deferred ( ) . reject ( { status : 404 } ) . promise ( ) ) ,
gateway = createRESTBaseGateway ( api , { } ) ;
2017-04-03 23:37:52 +00:00
2019-01-23 16:50:19 +00:00
return gateway . fetchPreviewForTitle ( createStubTitle ( 1 , 'Test Title' ) ) . catch ( ( ) => {
2022-02-09 15:09:19 +00:00
assert . true ( true , 'The gateway threw an error.' ) ;
2017-04-03 23:37:52 +00:00
} ) ;
2017-02-22 10:01:45 +00:00
} ) ;
QUnit . test ( 'RESTBase gateway returns the correct data ' , function ( assert ) {
2018-03-19 19:39:41 +00:00
const api = this . sandbox . stub ( ) . returns (
2017-02-22 10:01:45 +00:00
$ . Deferred ( ) . resolve ( RESTBASE _RESPONSE ) . promise ( )
) ,
2018-01-18 18:48:16 +00:00
gateway = createRESTBaseGateway (
api , DEFAULT _CONSTANTS , provideParsedExtract ) ;
2017-02-22 10:01:45 +00:00
2019-01-23 16:50:19 +00:00
return gateway . fetchPreviewForTitle ( createStubTitle ( 1 , 'Test Title' ) ) . then ( ( result ) => {
2018-05-08 19:48:17 +00:00
assert . deepEqual (
result ,
RESTBASE _RESPONSE _PREVIEW _MODEL ,
'The gateway returned a response.'
) ;
2017-02-22 10:01:45 +00:00
} ) ;
} ) ;
2018-03-14 23:50:09 +00:00
QUnit . test ( 'RESTBase gateway handles missing images ' , ( assert ) => {
2018-03-19 19:39:41 +00:00
const gateway = createRESTBaseGateway ( ) ;
const model = gateway . convertPageToModel (
2018-01-18 18:48:16 +00:00
RESTBASE _RESPONSE _WITHOUT _IMAGE , 300 , provideParsedExtract ) ;
2017-02-22 10:01:45 +00:00
2018-05-20 12:32:51 +00:00
assert . strictEqual (
2017-02-22 10:01:45 +00:00
model . originalimage ,
undefined ,
'If restbase handles missing image information'
) ;
} ) ;
2017-12-12 21:25:30 +00:00
QUnit . test ( 'RESTBase gateway handles missing extracts' , function ( assert ) {
2018-03-19 19:39:41 +00:00
const
api = this . sandbox . stub ( ) . returns ( $ . Deferred ( ) . resolve ( { } ) . promise ( ) ) ,
2018-01-18 18:48:16 +00:00
gateway = createRESTBaseGateway (
api , DEFAULT _CONSTANTS , provideParsedExtract ) ;
2019-04-26 10:53:46 +00:00
return gateway . fetchPreviewForTitle ( createStubTitle ( 0 , 'Test Title with missing extract' ) )
2018-03-14 23:50:09 +00:00
. then ( ( result ) => {
2018-05-20 12:32:51 +00:00
assert . strictEqual ( result . title , 'Test Title with missing extract' , 'Title' ) ;
assert . strictEqual ( result . extract , '!!' , 'Extract' ) ;
2018-01-18 18:48:16 +00:00
} ) ;
2017-12-12 21:25:30 +00:00
} ) ;
QUnit . test ( 'RESTBase gateway handles no content success responses' , function ( assert ) {
2018-03-19 19:39:41 +00:00
const api = this . sandbox . stub ( )
2018-01-18 18:48:16 +00:00
. returns ( $ . Deferred ( ) . resolve ( { status : 204 } ) . promise ( ) ) ,
gateway = createRESTBaseGateway (
api , DEFAULT _CONSTANTS , provideParsedExtract ) ;
2019-04-26 10:53:46 +00:00
return gateway . fetchPreviewForTitle ( createStubTitle ( 0 , 'Test Title with empty response' ) )
2018-03-14 23:50:09 +00:00
. then ( ( result ) => {
2018-05-20 12:32:51 +00:00
assert . strictEqual ( result . title , 'Test Title with empty response' , 'Title' ) ;
assert . strictEqual ( result . extract , '!!' , 'Extract' ) ;
2018-01-18 18:48:16 +00:00
} ) ;
2017-12-12 21:25:30 +00:00
} ) ;
Update: cancel unused HTTP requests in flight
Whenever an HTTP request sequence is started, i.e. wait for the fetch
start time, issue a network request, and return the result, abort the
process if the results are known to no longer be needed. This occurs
when a user has dwelt upon one link and then abandoned it either during
the fetch start wait time or during the fetch network request itself.
This change is accomplished by preserving the pending promises in two
actions, LINK_DWELL and FETCH_START, and whenever the ABANDON_START
action is issued, it now aborts any previously pending XHR-like promise,
called a "AbortPromise" which is just a thenable with an abort() method.
There is a similar concept in Core:
https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/ecc812f06e7dff587b3f31dc18189adbf4616351/resources/src/mediawiki.api/index.js.
Aborting pending requests has big implications for client and server
logging as requests are quickly canceled, especially on slower
connections. These differences can be observed on the network tab of
DevTools and the log in Redux DevTools.
Consider, for instance, the scenario of dwelling upon and quickly
abandoning a single link prior to this patch:
BOOT EVENT_LOGGED LINK_DWELL FETCH_START ABANDON_START FETCH_END STATSV_LOGGED ABANDON_END EVENT_LOGGED FETCH_COMPLETE
And after this patch when the fetch timer is canceled (prior to an
actual network request):
BOOT EVENT_LOGGED LINK_DWELL ABANDON_START ABANDON_END EVENT_LOGGED
In the above sequence, FETCH_* and STATSV_LOGGED actions never occur.
And after this patch when the network request itself is canceled:
BOOT EVENT_LOGGED LINK_DWELL FETCH_START ABANDON_START FETCH_FAILED STATSV_LOGGED FETCH_COMPLETE ABANDON_END EVENT_LOGGED
FETCH_FAILED occurs intentionally, STATSV_LOGGED and FETCH_COMPLETE
still happen even though the fetch didn't complete successfully, and
FETCH_END doesn't.
Additionally, since less data is transmitted, it's possible that the
timing and success rate of logging will improve on low bandwidth
connections.
Also, this patch tries to revise the JSDocs where possible to support
type checking and fix a call to the missing assert.fail() function in
changeListener.test.js.
Bug: T197700
Change-Id: I9a73b3086fc8fb0edd897a347b5497d5362e20ef
2018-06-25 13:26:11 +00:00
QUnit . test ( 'RESTBase gateway is abortable' , function ( assert ) {
const
deferred = $ . Deferred ( ) ,
api = this . sandbox . stub ( ) . returns (
deferred . promise ( {
abort ( ) {
deferred . reject ( 'http' ) ;
}
} )
) ,
gateway = createRESTBaseGateway (
api , DEFAULT _CONSTANTS , provideParsedExtract ) ;
2019-01-23 16:50:19 +00:00
const xhr = gateway . fetchPreviewForTitle ( createStubTitle ( 1 , 'Test Title' ) ) ;
Update: cancel unused HTTP requests in flight
Whenever an HTTP request sequence is started, i.e. wait for the fetch
start time, issue a network request, and return the result, abort the
process if the results are known to no longer be needed. This occurs
when a user has dwelt upon one link and then abandoned it either during
the fetch start wait time or during the fetch network request itself.
This change is accomplished by preserving the pending promises in two
actions, LINK_DWELL and FETCH_START, and whenever the ABANDON_START
action is issued, it now aborts any previously pending XHR-like promise,
called a "AbortPromise" which is just a thenable with an abort() method.
There is a similar concept in Core:
https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/ecc812f06e7dff587b3f31dc18189adbf4616351/resources/src/mediawiki.api/index.js.
Aborting pending requests has big implications for client and server
logging as requests are quickly canceled, especially on slower
connections. These differences can be observed on the network tab of
DevTools and the log in Redux DevTools.
Consider, for instance, the scenario of dwelling upon and quickly
abandoning a single link prior to this patch:
BOOT EVENT_LOGGED LINK_DWELL FETCH_START ABANDON_START FETCH_END STATSV_LOGGED ABANDON_END EVENT_LOGGED FETCH_COMPLETE
And after this patch when the fetch timer is canceled (prior to an
actual network request):
BOOT EVENT_LOGGED LINK_DWELL ABANDON_START ABANDON_END EVENT_LOGGED
In the above sequence, FETCH_* and STATSV_LOGGED actions never occur.
And after this patch when the network request itself is canceled:
BOOT EVENT_LOGGED LINK_DWELL FETCH_START ABANDON_START FETCH_FAILED STATSV_LOGGED FETCH_COMPLETE ABANDON_END EVENT_LOGGED
FETCH_FAILED occurs intentionally, STATSV_LOGGED and FETCH_COMPLETE
still happen even though the fetch didn't complete successfully, and
FETCH_END doesn't.
Additionally, since less data is transmitted, it's possible that the
timing and success rate of logging will improve on low bandwidth
connections.
Also, this patch tries to revise the JSDocs where possible to support
type checking and fix a call to the missing assert.fail() function in
changeListener.test.js.
Bug: T197700
Change-Id: I9a73b3086fc8fb0edd897a347b5497d5362e20ef
2018-06-25 13:26:11 +00:00
const chain = xhr . then ( ( ) => {
2022-02-09 15:09:19 +00:00
assert . true ( false , 'It never calls a thenable after rejection' ) ;
2018-07-06 15:41:19 +00:00
} ) . catch ( ( data ) => {
Update: cancel unused HTTP requests in flight
Whenever an HTTP request sequence is started, i.e. wait for the fetch
start time, issue a network request, and return the result, abort the
process if the results are known to no longer be needed. This occurs
when a user has dwelt upon one link and then abandoned it either during
the fetch start wait time or during the fetch network request itself.
This change is accomplished by preserving the pending promises in two
actions, LINK_DWELL and FETCH_START, and whenever the ABANDON_START
action is issued, it now aborts any previously pending XHR-like promise,
called a "AbortPromise" which is just a thenable with an abort() method.
There is a similar concept in Core:
https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/ecc812f06e7dff587b3f31dc18189adbf4616351/resources/src/mediawiki.api/index.js.
Aborting pending requests has big implications for client and server
logging as requests are quickly canceled, especially on slower
connections. These differences can be observed on the network tab of
DevTools and the log in Redux DevTools.
Consider, for instance, the scenario of dwelling upon and quickly
abandoning a single link prior to this patch:
BOOT EVENT_LOGGED LINK_DWELL FETCH_START ABANDON_START FETCH_END STATSV_LOGGED ABANDON_END EVENT_LOGGED FETCH_COMPLETE
And after this patch when the fetch timer is canceled (prior to an
actual network request):
BOOT EVENT_LOGGED LINK_DWELL ABANDON_START ABANDON_END EVENT_LOGGED
In the above sequence, FETCH_* and STATSV_LOGGED actions never occur.
And after this patch when the network request itself is canceled:
BOOT EVENT_LOGGED LINK_DWELL FETCH_START ABANDON_START FETCH_FAILED STATSV_LOGGED FETCH_COMPLETE ABANDON_END EVENT_LOGGED
FETCH_FAILED occurs intentionally, STATSV_LOGGED and FETCH_COMPLETE
still happen even though the fetch didn't complete successfully, and
FETCH_END doesn't.
Additionally, since less data is transmitted, it's possible that the
timing and success rate of logging will improve on low bandwidth
connections.
Also, this patch tries to revise the JSDocs where possible to support
type checking and fix a call to the missing assert.fail() function in
changeListener.test.js.
Bug: T197700
Change-Id: I9a73b3086fc8fb0edd897a347b5497d5362e20ef
2018-06-25 13:26:11 +00:00
assert . strictEqual ( data , 'http' ) ;
} ) ;
xhr . abort ( ) ;
return chain ;
} ) ;