Commit graph

339 commits

Author SHA1 Message Date
Piotr Miazga 4684b39841 Hygiene: use actionsTest consts instead of hardcoded states
The unit tests should use defined action types instead of hardcoding
each state.

Change-Id: I6769ba057e93239e1c720c3bfa050c618ea63978
2018-07-13 17:12:49 +02:00
Piotr Miazga c823a0e6cb When request gets aborted it shouldn't finish with FETCH_FAILED
Whe user moves mouse away and we abort the http request we shouldn't
count that request as a FETCH_FAILED. The reasoning behind is that
FETCH_FAILED state increments the counter.PagePreviewsApiFailure.
Our StatsD graph gets polluted with lots of aborted requests and it
becomes unsuable. It doesn't show only the failed requests.

Changes:
 - introduced new state: FETCH_ABORTED
 - switch to FETCH_ABORTED when browser aborts the request

Bug: T199482
Change-Id: I58047eb80f0700b78b2991daff9395ecc92553b8
2018-07-13 16:52:53 +02:00
Stephen Niedzielski 89df27595b Fix: mw-node-qunit package reference
Update the mw-node-qunit require to @wikimedia/mw-node-qunit. 2d150f0
missed this and it caused tests in CI to silently succeed.

Bug: T197251
Change-Id: I9de597b0e9afc747c47bddc6debcbe5b87bcd793
2018-07-13 07:47:30 -05:00
jdlrobson 10e6e25091 Upgrade eslint-config-wikimedia
* Force arrow-parens
* Disable no-prototype-builtins for time being
* Drop unnecessary maxlen rule

Change-Id: Iceb0fe47354a5753202d2c6ad9e1a9c76791f744
2018-07-13 07:42:12 -05:00
Piotr Miazga 2527f931a2 Properly handle catch() when calling gateway fetch.
Previous implementation did not pass the `result` variable
to the catch() statement. Because of that every execution that
ended with exception inside fetch() statement was threated as
not a network exception and tried to present the null preview.

Changes:
 - properly handle data returned by rejected fetch promise
 - chaged the big if (result && result....) into something easier
 to read
 - pass Error object instead of 'http' string
 - Restbase can return exception, it doesn't have to handle the 404
 errors by itself, it's already taken care in the catch() logic
 - fixed unit tests to reflect new logic in restbase gateway

Bug: T199482
Change-Id: Ibb30fc58248623d9ad4c5388a5b2ff9b387e01de
2018-07-13 00:02:59 +02:00
Stephen Niedzielski a0dc96cac9 Hygiene: consistently refer to globals directly
Instead of mixing window.mediaWiki / mediaWiki and window.jQuery /
jQuery references, always refer to globals which exist whether code is
executed in browser or headless Node.js environments.

  find src tests -iname \*.js|
  xargs -rd\\n sed -ri 's%window.(mediaWiki|jQuery)%\1%gi'

Change-Id: I21d0a602dcbd2bc6774934bee6c487e443270fe0
2018-07-09 08:46:40 -05:00
jenkins-bot f0a19b6f18 Merge "Hygiene: forbid unused lint directives" 2018-07-06 22:22:56 +00:00
Piotr Miazga c1d281f0dc Send the Accept-Language header when calling API
Changes:
 - added acceptLanguage as a config option passed to
 both mwApi and restbaseApi, by default code will use
 the language defined in `wgContentLanguage` config
 variable. The `wgContentLanguage` is always defined
 (see ResourceLoaderStartUpModule::getConfigSettings())
 so there is no need for checking the variable existence.

The new logic was tested both on MediaWiki API and Restbase API

Bug: T198619
Change-Id: I1cb31f1999fd674a8b870b2b5effb92ed3dfaa1f
2018-07-05 11:31:55 -07:00
Stephen Niedzielski ce8a2d4c3f 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:
ecc812f06e/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-07-04 13:48:14 -05:00
Stephen Niedzielski 2a854f7649 Hygiene: forbid unused lint directives
Prevent outdated ESLint error waivers from littering the code by
enabling `--report-unused-disable-directives`.

Change-Id: I3b9c39131f030cf2c4113ecd947c3f4a8679bdfe
2018-07-02 14:59:40 -05:00
jdlrobson 6c17af260c Extracts can expand with narrow thumbnails
If a thumbnail is narrow, then the extract can expand to take
the available space. It does this via JavaScript taking the difference
between the normal space for a thumbnail minus the actual space needed
to display the thumbnail.

This removes unused whitespace in both the thumbnail and extract.

Bug: T192928
Change-Id: I59e87f9160e707fbce321a567c0a68e85f6d72ec
2018-06-28 16:34:41 -07:00
Jan Drewniak 4e43f0cf9e Truncate source_url to max 1000 characters
Prevents the source_url param in virtual page-views from getting
too long and causing an error because it exceeds varnish's max-url size.

Bug: T196904

Change-Id: Idf3667c4c2ad7e0436f013c70d5ff4ebea453d7a
2018-06-28 14:30:42 -07:00
jdlrobson 21c8e6213e Add SVG border using polyline element
Since we use an SVG mask, we cannot use border-left to visually
separate the page preview thumbnail from the text. We can however
make use of a polyline and programatically work out it's start and
end.

Bug: T192928
Change-Id: I0f983a80e3210b2f7e9aa197d2a632680675973e
2018-06-28 11:23:48 -07:00
Jan Drewniak 3b2480d6ce Ensure popup thumbnail images are a supported format
Prevents video files and other non-image files from being rendered as
popup thumbnails. Restricts thumbnail format to either jpg, png, or gif.

Bug: T193792
Change-Id: I7a9be5d1c8396c02ebf0893c960f65644acc9d99
2018-06-21 00:55:04 +02:00
Stephen Niedzielski abc2026890 Hygiene: replace QUnit assert.equal with strictEqual()
Via jscodeshift:

  jscodeshift \
    -t jscodeshift-recipes/src/qunit-assert-equal-to-strictEqual.js \
    Popups/tests

Also, some very minor manual clean up.

https://github.com/niedzielski/jscodeshift-recipes/blob/5944e50/src/qunit-assert-equal-to-strictEqual.js

Additional change:
* Drop redundant clipPath parameter from createThumbnailElement - this
parameter does not exist in the function signature.

Change-Id: I209ecf2d54b6f5c17767aa2041d8f11cb368a9b5
2018-06-18 19:48:16 +00:00
jdlrobson 79daacb235 Coalesce and cleanup use of then blocks
Bug: T190141
Change-Id: I345befc24397e27c965af0a593821333f2a71f21
2018-05-30 17:32:08 +01:00
Stephen Niedzielski ae44042cbf Hygiene: add assertion messages
Change-Id: Ic0a47bd468532824e8648c3f6371cc403896603c
2018-05-08 15:55:23 -05:00
Stephen Niedzielski cb362d125c Hygiene: replace calledOnce / Twice w/ callCount
Replace all test assertions for calledOnce / Twice with callCount.
assert.ok( calledOnce / Twice ) only lets the dev know that a test
fails. assert.strictEqual( callCount, EXPECTATION ) starts the debugging
process when it fails since it provides the difference in the failure
output. strictEqual() was deliberately used since it's a saner default
and the codebase already favors === equivalency checks.

  find tests -name \*.js|
  xargs -rd\\n sed -ri '
    s%ok\(([^,]+)calledOnce%strictEqual(\1callCount, 1%g;
    s%ok\(([^,]+)calledTwice%strictEqual(\1callCount, 2%g;
  '

Change-Id: I07c3c6d20e07c5b8107583a01d820e3fbd68a4e1
2018-05-08 15:01:16 -05:00
jdlrobson 912402e840 Remove A/B testing code
No longer needed. We can't turn something off again for people
now they expect it to exist.

Clarified usage instructions of PopupsEventLogging to make sure
it's more scary given the implications

Bug: T173952
Change-Id: I7be005b79da498d8e7b7df8f18b60c1327636a2c
2018-05-07 12:37:41 -07:00
jdlrobson 4e3282e5ff Remove BetaFeature code
Popups is out of beta feature and this code is no longer needed.
Removing code is the happiest activity a developer can do.

Other changes:
* Remove redundant type field on extension.json
(If not set, the extension will default to the "other" section.)
* Repurpose `name` with `namemsg` and make use of existing i18n
messages

Bug: T193053
Change-Id: Iea832cd1f37b0e7df6ff95efd66e4a1ff2a9004e
2018-04-26 15:51:48 -07:00
Stephen Niedzielski d7871bb9c4 Hygiene: replace okies with ointers
I've yet to meet the bloke who knew how to take a poke without an
explanation such that they have never mispoke. This patch which renames
pokies to pointers will surely be my masterstroke.

  find \
		-not \( \( -name node_modules -o -name .git -o -name vendor -o -name dist -o -name package-lock.json \) -prune \) \
		-type f|
	xargs -rd\\n sed -ri 's%([Pp])(okey|okie)%\1ointer%g; s%([Pp])oke%\1oint%g'

Bug: T190831
Change-Id: I363e6dd49bfcdb9515cd5fab2904a58725b18720
2018-04-26 13:26:48 -07:00
Stephen Niedzielski 7c98c04e0b Fix: unwanted thumbnail spacing in RTL locales
Thumbnails are displayed as SVG image elements. The SVG itself has a
width 3px greater than necessary for landscape thumbnails specifically.
For left-to-right languages, this additional space is empty and
unnoticed. For right-to-left languages, this extra spaces shows as a gap
on one side of the thumbnail and exceeds the popup's bounds on the other
side.

This extra 3px appears to have been mistakenly applied to landscape
thumbnails when it is only applicable to portrait, for which it is
already accounted for. Remove the 3px slop.

Bug: T190831
Change-Id: I6096f416f7e102975c4753a6b093b192aa1b45d7
2018-04-26 08:59:00 -05:00
Stephen Niedzielski a4e129175a Fix: show thumbnails on left for right-to-left UIs
When the UI is RTL, show preview thumbnails on the left. Otherwise, show
them on the right.

Bug: T190831
Change-Id: Ic1fc54f6547b31908905db8cb2ec4d58f37a6538
2018-04-23 16:59:19 -05:00
Stephen Niedzielski 44a7f643bc Hygiene: replace CSS class underscores w/ hyphens
Replace CSS slithery_snake_case with shish-kebab-case for consistency
with the rest of the codebase.

  find \
    -not '( (
      -name node_modules
      -o -name .git
      -o -name vendor
      -o -name doc
      -o -name dist
      ) -prune
    )' \
    -type f|
  xargs \
    -rd\\n \
    sed -ri 's%flipped_([xy])_([xy])%flipped-\1-\2%g; s%flipped_([xy])%flipped-\1%g'

Change-Id: I25dc0ddeda711faca9a79b5bf87d6b5aa0d5aea5
2018-04-23 16:23:17 -05:00
Stephen Niedzielski 3a372ac3ab Hygiene: rename triangle terminology to pokey
Everyone knows what a poke is.

  find \
    -not '( (
      -name node_modules
      -o -name .git
      -o -name vendor
      -o -name doc
      -o -name dist
      ) -prune
    )' -type f|
  xargs -rd\\n sed -ri 's%\btri(\b|angle)%pokey%g'

Change-Id: Ie159aa6947801a98cbf358da1613c87cf66d548f
2018-04-23 16:07:51 -05:00
Stephen Niedzielski 676faa3514 Hygiene: consolidate CSS class manipulation
• Instead of removing 'mwe-popups-no-image-tri' in
  renderer#layoutPreview(), add more conditions to #getClasses().

  The addition condition in getClasses() was:

    ( !hasThumbnail || isTall ) && !flippedY

  The removal condition in layoutPreview() was:

    flippedX && !flippedY && hasThumbnail && isTall

  To combine them, the removal logic is inverted and the conjunction is
  taken:

    ( ( !hasThumbnail || isTall ) && !flippedY ) &&
    !( flippedX && !flippedY && hasThumbnail && isTall )

  Push the negation inwards:

    ( !hasThumbnail && !flippedY || isTall && !flippedY ) &&
    ( !flippedX || flippedY || !hasThumbnail || !isTall )

  Expand:

    !hasThumbnail && !flippedY && !flippedX ||
    !hasThumbnail && !flippedY && flippedY ||
    !hasThumbnail && !flippedY && !hasThumbnail ||
    !hasThumbnail && !flippedY && !isTall ||
    isTall && !flippedY && !flippedX ||
    isTall && !flippedY && flippedY ||
    isTall && !flippedY && !hasThumbnail ||
    isTall && !flippedY && !isTall

  Eliminate always false conditions and combine redundancies:

    !hasThumbnail && !flippedY && !flippedX ||
    !hasThumbnail && !flippedY ||
    !hasThumbnail && !flippedY && !isTall ||
    isTall && !flippedY && !flippedX ||
    isTall && !flippedY && !hasThumbnail

  Further eliminate redundancies:

    !hasThumbnail && !flippedY ||
    isTall && !flippedY && !flippedX ||
    isTall && !flippedY && !hasThumbnail

  Factor:

    !flippedY && (
      !hasThumbnail || isTall && !flippedX || isTall && !hasThumbnail
    )

  Factor more:

    !flippedY && (
      !hasThumbnail || isTall && ( !flippedX || !hasThumbnail )
    )

  Eliminate last redundancies:

    !flippedY && ( !hasThumbnail || isTall && !flippedX )

  The getClasses() test is updated for the new logic.

• Move thumbnail clip path manipulation from renderer#layoutPreview() to
  a new function, #setThumbnailClipPath(). The new function flips the
  order of the series of if statements so that an if / else block can be
  used instead which clarifies that clip-path state is exclusive. In
  other words:

    if ( a ) { foo.prop = 1; }
    if ( b ) { foo.prop = 2; }
    if ( c ) { foo.prop = 3; }
    if ( d ) { foo.prop = 4; }

  Can generically be refactored regardless of condition or value to:

    if ( d ) { foo.prop = 4; }
    else if ( c ) { foo.prop = 3; }
    else if ( b ) { foo.prop = 2; }
    else if ( a ) { foo.prop = 1; }

  Because prop was originally overwritten which implies if / else-like
  priority.

  Additionally:
  • The entire function call is wrapped in a hasThumbnail conditional
    which previously was checked as an input in each case.
  • Consolidate the last two conditions since they only differed by a
    single boolean input.
  • Move the setAttribute() action to the end of the function since the
    conditionals just map condition to value and the action is now
    identical.

• Revise pokey mask doc to use clip-path terminology. This inverts the
  thinking about the mask but better matches usage.

Bug: T190831
Change-Id: Ib460c6c07fcb054f8d425d127c588bb28a1d2473
2018-04-23 15:56:25 -05:00
Piotr Miazga 321d6348e1 Page_title and source_title should be in canonical form
We change page_title and source_title as a last step
just before we send the event.

Doing it elsewhere is risky at the current time because:
* the non-canonical form is needed for
mwApiGateway to bold title (formatPlainTextExtract). Needing both
would require updates to the Page model.
* title is used by EventLogging (Schema:Popups)

Bug: T191471
Change-Id: I93e7343643dcd9f32a86459907eb0b7051df91aa
2018-04-16 19:56:43 +02:00
Stephen Niedzielski 2eeaa0a2e4 Hygiene: consolidate clip-path manipulation
The clip-path SVG property was conditionally set in thumbnail.js and
also conditionally set or removed in renderer.js. This patch refactors
the logic to occur in a single place, renderer.js.

The refactor was made with the following considerations:

• The one condition under which thumbnail.js would set clip-path was,
  given a thumbnail exists, the thumbnail was not tall and clip-path
  would be set to `url(#mwe-popups-mask)`. Otherwise, thumbnail.js would
  not set clip-path.

• The logic in renderer.js for setting the attribute doesn't change
  since overwriting the clip-path is equivalent to not having a
  preexisting value. The case for removing the attribute itself is
  replaced by inverting the condition, `flippedY`, and combining it with
  the thumbnail.js condition, `!isTall`. The operation is only valid for
  an existing thumbnail so the `hasThumbnail` remains unchanged.

This patch also clarifies that the "flipped" classes are exclusively set
by using an if / else chain instead of reconsidering all inputs for each
condition.

Bug: T190831
Change-Id: I4062ec7068dcadecbdbc4791447ea2ed1ce2a1de
2018-04-13 09:25:22 -05:00
jdlrobson e6202b6ce4 VirtualPageViews bypass EventLogging for logging virtual events
We are using EventLogging to track page views not user behaviour.
This is an exception to the rule and requires special handling.

Bug: T190188
Change-Id: If096ccaf0ac884d57744ed57e2f26b51446de2d7
2018-03-29 16:53:20 +00:00
jdlrobson 3245a2ac6e Hygiene: restrict use of $.each and fix offenders
Bug: T190142
Change-Id: I5da7a4a1ffe14647ec70b10b3a7ab9b935c5ca84
2018-03-21 14:24:22 -05:00
Stephen Niedzielski 007cc5ab7c Hygiene: favor string templates over concatenation
Update the ESLint config to favor ES6 strings where variables or string
concatenation is used and fix *all* offenders automatically via:

  eslint \
    --cache \
    --max-warnings 0 \
    --report-unused-disable-directives \
    --fix \
    src tests

Change-Id: I1a9345162348e5ded21d541e7a2ce251ea72ab5a
2018-03-21 08:05:55 -05:00
Stephen Niedzielski 57762e0417 Hygiene: favor const
Bug: T165036
Change-Id: I17d374eaac6627ca6a8ba178862b2a9cff2538c0
2018-03-21 10:44:24 +00:00
Stephen Niedzielski 0bee0906d4 Hygiene: replace var with let and const
eslint \
    --cache \
    --max-warnings 0 \
    --report-unused-disable-directives \
    --fix \
    src tests

Change-Id: I051275126ae7fa9affd16c2504017c0584f2d9c7
2018-03-20 14:14:02 -05:00
Stephen Niedzielski 422a02d61a Hygiene: remove unneeded renderer test setup
Change-Id: Id3e0a4af1f88c57c3ef141dac67a8b13643a2dcb
2018-03-20 09:27:08 -05:00
Stephen Niedzielski ece4670710 Hygiene: use arrow for anonymous functions
In some places, the arrow function seems more natural. This patch
approximates the following with manual amendments:

  find \
    -not \( \( -name node_modules -o -name .git -o -name vendor -o -name doc -o -name resources \) -prune \) \
    -iname \*.js|
  xargs -rd\\n sed -ri 's%function\s*(\([^)]*\))%\1 =>%g'

Files to focus on were identified with:

  rg -slg\!/resources/dist/ -g\!/i18n/ -g\!/doc/ 'this|self|arguments|bind|call|apply|new'|
  xargs -rd\\n git difftool -y

Bug: T165036
Change-Id: Ic66b6000b8fc000f9bfde39749f9cfa69924a13c
2018-03-20 09:27:08 -05:00
Stephen Niedzielski a67466acc0 Hygiene: replace obvious function methods
Replace easily identifiable object functions with method syntax:

  find \
    -not \( \( -name node_modules -o -name .git -o -name vendor -o -name doc -o -name resources \) -prune \) \
    -iname \*.js|
  xargs -rd\\n sed -ri 's%:\s*function\s*(\([^)]*\))%\1%g'

Bug: T165036
Change-Id: I90693ee99a6a36dff820dd5ae6f6000429763058
2018-03-20 09:27:07 -05:00
Stephen Niedzielski a2a743d775 Hygiene: use object shorthand where obvious
Approximately:

  find \
    -not \( \( -name node_modules -o -name .git -o -name vendor -o -name doc -o -name resources \) -prune \) \
    -iname \*.js|
  xargs -rd\\n sed -ri 's%(\b\S+\b)\s*:\s*\b\1\b%\1%g'

Bug: T165036
Change-Id: I48869dc93b66f908e070288eb2f035bb064993e3
2018-03-20 09:26:20 -05:00
Stephen Niedzielski 42816702eb Hygiene: replace Mustache templates w/ ES6 strings
Replace Mustache.js templates with template literals. An effort was made
to minimize additional refactoring, so feel free to ask for more but it
ain't coming in this PS.

Bug: T165036
Change-Id: I4a6a1d93a2922c3a9ef3ae93c47da17a35c644f0
2018-03-20 08:06:02 -05:00
Stephen Niedzielski 674ade83e7 Hygiene: move settings dialog to separate file
Separate the settings dialog and settings dialog renderer into two
files.

Bug: T165036
Change-Id: I500add4b89ec8c5d1a76d7c5572f62204d61f62d
2018-03-14 21:39:39 +00:00
Stephen Niedzielski e26c12db52 Hygiene: move thumbnail code to separate file
Move thumbnail code from renderer to a separate file, thumbnail.

Bug: T165036
Change-Id: I6c55750ec302de6341e8e91dee34581ee66499d7
2018-03-14 14:19:41 -05:00
Stephen Niedzielski 4eb9c0efa8 Hygiene: move SVG string to file
- Add SVG Inline Loader for Webpack. This allows SVG files to be
  imported.

- Update the Webpack and test configurations to use the new loader.

- Scope the ESLint rules down to just JavaScript files so that linting
  isn't attempted on the SVG.

Bug: T165036
Change-Id: I00bccff4c3167975c19d577be6343dcaca7ddb2d
2018-03-14 12:04:28 -07:00
Jan Drewniak 1e946a379d Custom page preview for disambiguation pages
Creating a different page preview for disambiguation pages.

This patch:
- modifies the Preview model to accept a new 'type' property
- modifies the Restbase Gateway to pass the 'type' prop to the Preview model
- creates a new template to accept both generic/disambig previews
- modifies the renderer to render the new template
- generates icons for new template through resource loader
- adds new i18n strings
- modifies event-logging "preview seen" event to send new "disambiguation" previewType
- updates event logging schema version
- adds tests for Preview model and renderer for new preview type
- does way too much? yes, yes it does.

Bug: T168392
Change-Id: Idc936cc3eabbdd99a3d98f43c66b4cdbb7d24917
2018-03-14 11:24:26 -07:00
jdlrobson f5f21a8d09 RESTBase url is configurable
Allow developers to use different endpoints for summaries
= developer happiness

This is useful for the following use cases:
* A developer wants to test against a production endpoint via
CORS
* A developer has setup an API where REST is hosted elsewhere
e.g. http://localhost:6927/en.wikipedia.org/v1/
* A user wants to create their own REST summary compatible
endpoint
* A wiki e.g. wikidata wants to use a different endpoint which is compatible
with the summary endpoint.

We are unlikely to use it ourselves on Wikimedia wikis (the
default should suffice) but this will be a powerful tool for

When not configured this will continue to work as per normal

Change-Id: I8a7e12fbc43cddbac678e0d7b81d1e877b747b22
2018-03-09 16:15:19 +00:00
jdlrobson ca440dfbed Remove client side formatters in Popups code base for MW API.
Stripping parentheticals were designed specifically for working around
issues with content inside wikimedia wikis and error prone.

This problem for wikimedia wikis is solved by the mobile content
service.

Given we have no intentions to use the MediaWiki API for summaries.
They are not necessarily useful to third parties and it makes little
sense to maintain them (a third party can configure their own API or
use their own REST endpoint if they really do need them).

Bug: T189042
Change-Id: I2729dc9f172af0afee1c6f0cd563c556b4ae0aeb
2018-03-08 21:05:49 +00:00
jdlrobson 535149c16c Upgrade schema and log the required fields
This change updates the schema and begins to log
additional information such as source_namespace, id
and title. This information is provided inside the
boot action.

Additional changes:
* Allow camel case in bundle artifact

Bug: T184793
Bug: T186728
Change-Id: I425ffecc018bef2958d0dfe957a40a065e3e6c56
2018-02-26 10:25:30 -08:00
jdlrobson fe654d7f5e Hygiene: namespaceID => namespaceId
For consistency with pageId and sessionId let's rename
namespaceID to namespaceId

Change-Id: Id0f6f6434691b62d3c5c7ae941970b79e0a99366
2018-02-26 10:23:38 -08:00
Stephen Niedzielski e406d4556f Fix: don't assume thumbnail URLs contain pixel size
Don't assume that thumbnail URLs contain a dimension delimiter of "px-".
Previously, thumbnail URLs always contained the width. e.g.:

  https://upload.wikimedia.org/wikipedia/commons/a/aa/100px-Red_Giant_Earth_warm.jpg

However, thumbnail URLs that actually point to the original are not
sizable:

  https://upload.wikimedia.org/wikipedia/commons/a/aa/Red_Giant_Earth_warm.jpg

These are provided, for example, when the thumbnail size requested is
larger than the original. There was code designed to handle this
scenario but it only applies when RESTBase and page preview thumbnail
sizes happen to be in sync. In other words, if RESTBase requests a large
thumbnail on behalf of page previews, and page previews only requested a
small thumbnail, the original may be unexpectedly provided. A
conditional is introduced in this patch to verify that "px-" is actually
detected. If it is not present, the original is used.

Bug: T187955
Change-Id: If4e29dd870aecd6d461cc8203f6576d1bb8844f2
2018-02-22 12:36:30 -06:00
Sam Smith 35daa2a689 Hygiene: Page view -> Pageview
Pageview is consistent with verbiage used by Research and Analytics
Engineering in their reports and documentation, e.g.
https://wikitech.wikimedia.org/wiki/Analytics/Pageviews.

Bug: T184793
Change-Id: I8ae085b4af85aa72f234f3db27f0cac2c4d014e5
2018-02-21 18:51:49 +00:00
jdlrobson 21f2d4ab0f Model should capture page id
We're going to need this for logging page views.

Change-Id: I1fc46a9fab54f512edaf5feb5abbaa4f025dcb4a
2018-02-19 16:46:13 +00:00
jdlrobson a702c0f499 Capture page view-like interactions
* New action added PREVIEW_SEEN
* The action will be used to signal that a page view needs
to be recorded.
* PREVIEW_SEEN is a delayed action which is triggered
as a side-effect of the previewShow action. It is only dispatched
if the user is still previewing the same card and the page
related to the card has preview type `page`
* The pageview changelistener is added when
$wgPopupsVirtualPageViews is set to true.
* The page view changelistener listens for page views and logs
them using EventLogging when needed using
https://meta.wikimedia.org/wiki/Schema:VirtualPageView

Note:
* Currently if a user has enabled the DNT header, the
event will not be logged. There is ongoing discussion on the
ticket and fixing this will be addressed separately.
* Only title and referrer are logged in the initial version.
The task demands that "namespace" is logged but this information
is not provided by the summary endpoints we use so will need
to be added later (if indeed needed) either via a change to that
endpoint of by using JavaScript to parse the URL.

Bug: T184793
Change-Id: Id1fe34e4bdada3a41f0d888a753af366d4756590
2018-02-16 23:03:33 +00:00
joakin 1fff0d2ea7 Improve & fix action and integration tests
This change fixes some issues with assertions not running, removes
unnecessary promise dances, and improves legibility and some code
patterns in the action and integration node tests mainly.

Detailed changes:

* actions.js
  * Fully migrate out of jQuery 1 promises (no done/fail)
  * Fix linkDwell action not returning the fetch action promise

* actions.test.js
  * Simplify setupWait for the tests
    * It always autoresolves immediately the wait call to ensure speedy tests
    * No waitDeferreds or waitPromises array coordination, rely on action
      returned promises instead
  * Get rid of that = this in favor of arrow functions
  * Rename generic "p" promises to meaningful names
  * Add assert.expect for more solid tests (so that we don't skip assertions in
    the future if we change them)
  * Fix some assertions that weren't being run because of the incorrect promise
    being returned (p.then, and then just returning p)
  * Get rid of $.when stubbing in favor of waiting for the promise returned from
    the action
    * Get rid of hacky setTimeout(..., 0) to run assertions after the promises

* integration.test.js
  * Get rid of wait(0) calls to hack around asynchronous actions
    * Use the action returned promises instead of the waitPromises/Deferreds
  * Remove unused "el" parameter being passed to this.abandon in several tests
  * Remove unnecessary test helper this.abandonPreview (it was the same as
    this.abandon)
  * Clarify a bit the last and more complex test with some comments and variable
    name changes
  * Get rid of that=this in favor of arrow functions

* container.test.js
  * Get rid of that=this in favor of arrow functions

* previewBehavior.test.js
  * Get rid of that=this in favor of arrow functions
  * Get rid of $.each in favor of .forEach

Bug: T170807
Change-Id: I06fafd92a1712f143018e2ddff24fadf1a6882b3
2018-02-16 13:52:56 +01:00
Jan Drewniak 95b880aa29 Return promises from action thunks
Returning promises from the `linkDwell` and `abandon` thunks and
removing some of the `wait` stubs in the unit test for these actions.

Also converting a fetch callback from a `.fail` to a Promise A+
compatible `.catch`.

Bug: T170807
Change-Id: I4bbf2863db090e222ba926d3bc36a99da4bdb601
2018-02-14 20:08:05 +00:00
Jan Drewniak f4d04b95b6 Updating mw-node-qunit to v3
Fixes tests for sinon v4, which is a dependency of mw-node-qunit v3.

Bug: T180255
Change-Id: I8c7b703f81140e06546aa954f98b8766f5225ff5
2018-02-08 12:20:52 +01:00
joakin 807100bcca Limit line length to 80 characters
Enforce it with eslint.

Ignore:
* Comment lines with eslint disable directives
* QUnit test lines as they contain long subjects (QUnit.* (only, test,
  module, skip, etc)
* Strings, since long strings are used extensively in tests
  * Ignore template literals for similar reasons
* Regex literals as they may be too long, but can't be easily
  split in several lines
* Long urls

See bug for more general proposal for eslint-wikimedia-config.

Bug: T185295
Change-Id: I3aacaf46e61a4d96547c513073e179ef997deb09
2018-01-19 14:20:39 +01:00
joakin c6efe18f6a Restore test subject
Test subject was changed and stopped matching the implementation. In
this particular change the test (a bit convoluted but) tests that wait
is called appropriately, which is why the subject read "should delay
dispatching ..."

Change-Id: I3c8d9d8769f3d1c2869a267af105b9489df86cf5
2018-01-18 18:33:58 +01:00
Stephen Niedzielski 9114981380 Update: show placeholder preview for more failures
Functional changes

- Show the default / error preview for all extract request failures
  except those due to network circumstances (such as CORS) or no
  connectivity (offline). Previously, the error preview was displayed
  only for missing pages.

- FETCH_COMPLETE was previously only dispatched after FETCH_END. Now
  it's also dispatched after FETCH_FAILED. The additional "fetch
  complete" is not expected to impact logging. The states of success
  are: START, END, COMPLETE. The new failure states are consistent with
  success: START, FAILED, COMPLETE.

Testing

Errors may be stimulated in a number of ways including:

- Timeout: add a timeout field to RESTBaseGateway /
  MediaWikiGateway.fetch().

  http://api.jquery.com/jquery.ajax/

- Bad request: change MediaWikiGateway.fetch's action field to
  `Math.random() > 0.5 ? 'query' : 'fail'` and RESTBaseGateway.fetch's
  url field to
  `RESTBASE_ENDPOINT + ( Math.random() > 0.5 ? encodeURIComponent( title ) : '%%%' )`.

- Desired Gateway can be configured in Gateway#createGateway().

- Note: T184534 describes a circumstance where cached previews may not
  appear when offline. Disable browser caching to avoid confusion.

Bug: T183151
Bug: T184534
Change-Id: I7332284da0e0fb1ecd234a6f1e146ebd9ad8d81f
2018-01-16 18:44:00 -06:00
Stephen Niedzielski d9d85ab971 Hygiene: add more fetch failure test cases
Add fetch failure tests for integration and preview state.

Bug: T183151
Change-Id: I1a541d96f3a83b99c26a5180ad5ee8626cda97d2
2018-01-16 18:37:03 -06:00
Stephen Niedzielski 6ba57786fb Update: missing preview copy
Update the placeholder extract and button text shown when a page preview
is unavailable from:

  "popups-preview-no-preview": "Looks like there isn't a preview for this page"
  "popups-preview-footer-read": "Read"

To:

  "popups-preview-no-preview": "There was an issue displaying this preview"
  "popups-preview-footer-read": "Go to this page"

Bug: T183151
Change-Id: I0600dbc2e4d51a13675041d3c0741a793f4eae37
2018-01-16 18:36:54 -06:00
Stephen Niedzielski 8ca0cf2088 Fix: preview page URL for 404 RESTBase responses
Functional changes:

- Require page URL when constructing a PreviewModel null object. These
  models have valid titles and are used to display a preview when an
  extract is unobtainable. When presented with an empty URL, their
  linkage incorrectly pointed to the browser's current URL. Additional
  tests were added to verify the fix.

- Check missing title in addition to falsy response in RESTBase gateway
  and update the test assertion to check title. It isn't clear if this
  can happen in the wild.

- Forbid state mutation in the conclusion of
  MediaWikiGateway.getPageSummary() with a call to Deferred.promise().
  This is consistent with the rest of repo including RESTBaseGateway.

  http://api.jquery.com/deferred.promise/

Nonfunctional changes:

- Collapse two RESTBase gateway 404 tests into one as the scenarios and
  expectations were very similar.

- Add failure HTTP status to 'MediaWiki API gateway handles API failure'
  test stub HTTP response for consistency with other cases.

- Add nullity expectations to JSDocs touched and fix a couple typos
  throughout.

- Make the gateway tests a little more consistent by collapsing Deferred
  variable usage where appropriate.

This change is necessary to the completion of T183151 which uses the
PreviewModel null objects for additional error cases.

Bug: T183151
Change-Id: Ib77627fb9c80d8e806208bbafcfc615b130e3278
2018-01-16 18:36:48 -06:00
jdlrobson ff49e7627b Better error handling for unexpected responses
Bug: T182639
Change-Id: Iea04fe41b4be8e15927e93f16cbb4bb44328374f
2018-01-02 10:42:12 -08:00
Baha 58cdac8882 Schema:Popups - use revision 17430287
Event timestamp (as reported by `window.performance.now()`) is also sent
along with every action.

Bug: T180036
Change-Id: Ie3a648298005d51b8b4fbaa6a53e78caf50fa2d3
2017-11-17 12:49:22 -05:00
Ed Sanders 7f4dd1159b build: Update eslint and other linters
Change-Id: I0a20ad5d16d46afbc2a328f8e254295972f58ab0
2017-10-09 15:56:15 +01:00
smarita 3ec185cb01 Consider using more common image sizes for Page previews
Modified necessary files to increase size of popup from 300px to 320px

Bug: T173434
Change-Id: I47bbe9defe961008163551d5be4fc7b1ca08d0d1
2017-10-01 22:02:29 +05:30
joakin e865409593 Hygiene: Don't rely on .fail, use Promises/A+
Instead of using the non-standard old Promise implementation by relying
on .fail, migrate it to .catch.

In this specific case, where we were chaining promises with $.when, the
semantics from going from fail to catch actually change. .fail keeps the
promise in a rejected state, while .catch will change it to resolved
unless another error is thrown.

As such, when changing it to .catch, the catched error will be re-thrown
to keep the promise in a rejected state, so that $.when.then is not
executed.

Additional changes:
* Make actions.js#fetch return its promise for ease of testing.
* Test FETCH_FAILED, which was fully untested.

Bug: T173819
Change-Id: Ibd380b714586979c6e60b4c969d17f36a0796b52
2017-08-23 19:36:05 +02:00
jenkins-bot 8bb322b15d Merge "Hygiene: Use promises A/A+ everywhere" 2017-08-22 14:34:26 +00:00
joakin 4d8364a999 Hygiene: Use promises A/A+ everywhere
Remove usages of deprecated methods like .done which make jquery
promises fall back to non-standard behavior

Additional changes:
* Rename var promise to a more descriptive name in tests

Bug: T173819
Change-Id: I7b041d0a7a8c42a8eac947295d265e898085c60a
2017-08-22 13:36:00 +02:00
jdlrobson e4e9bb3bd6 Popups A/B test infrastructure
Introduce PopupsAnonsExperimentalGroupSize config variable. This defines
a population size who will be subject to experimentation. If the group
size is undefined or 0 (default) and PopupsBetaFeature is false
(default value) Popups will be enabled for everyone. If it is any other
value, half that group will see page previews.

Drop the config variable PopupsSchemaSamplingRate - we will now only
EventLog when an experiment is occuring. This means we can simplify the
MWEventLogger class as shouldLog will always be truthy. Given server
side eventlogging is only used for preference changes
traffic should be low and not need sampling.

Introduce getUserBucket which determines whether a user is in a bucket
on, off or control based on the value of
PopupsAnonsExperimentalGroupSize. Add tests showing how these
buckets are calculated.

Caution:
A kill switch wgPopupsEventLogging is provided for safety.
It defaults to false. Before merging, please check if any config changes
are necessary.

Bug: T171853
Change-Id: If2a0c5fceae78262c44cb522af38a925cc5919d3
2017-08-17 21:07:07 +00:00
Piotr Miazga 910dd0408f if preview count stored in localStorage is not a number override it
There are some cases when the preview count stored in local storage
evaluates to NaN. When this happens we should override the value
to zero, store it in localStorage, and return it.

Bug: T168371
Change-Id: Ic44b7c7b5b716f6a0859f33278d56d2d95bbfb3e
2017-08-17 18:29:56 +02:00
jdlrobson 08331ba199 Return promises from QUnit test
Simplify all our tests to return to promises
Use catch rather than fail when testing error cases.

Bug: T170812
Change-Id: I37c4e3f86343052c946d8586f8ff840a81f631f8
2017-08-17 14:34:39 +00:00
Baha 3ac3769aa7 Remove event logging duplication detection and logging
We haven't seen the PP EventLogging instrumentation produce duplicate events
for weeks.

Bug: T172106
Change-Id: I6f3d7c0cdbf23161f63259e4d20d8a710376468b
2017-08-16 11:46:35 -04:00
Piotr Miazga d07441ec7f getPreviewCountBucket should return unknown when no bucket is found
Under some unknown circumstances getPreviewCountBucket() is called
with a value that is not a -1 or a natural number. When that happens
function returns 'undefined bucket' which causes eventLogging to
fail. I wasn't able to reproduce the issue, it might be specific
to browser/os. The safest way is to return 'unknown' for any other
case.

Bug: T168371
Change-Id: I374bb629762a86ac06a18e775d3c1a14682c9f55
2017-08-15 16:12:26 +02:00
joakin f37b76f8b4 Hygiene: make integrations/mwpopups pure
Instead of registering global variables in a function, make it pure
return the external interface and set it to mw.popups in the
src/index.js entry point.

Explicitly comment on index.js what is being set and why.

Bug: T171287
Change-Id: I94d467bfa7fa6e56033dd254518ad50b5dde5bfc
2017-08-09 16:07:08 +02:00
Piotr Miazga 8510b4b942 Allow 3rd party to check Popups enabled state by accessing mw.popups object
Changes:
 - introduced js module defining mw.popups object
 - introduced isEnabled() method which checks the redux store to retrieve
 isEnabled status

Bug: T171287
Change-Id: I523369831e2aa8a915ed1cb001b35d13b770f9da
2017-08-08 15:38:01 +02:00
joakin e6081106f1 Use EcmaScript modules instead of common.js modules
Why: Because they are the approved standard by TC39 and Ecma for
JavaScript modules.

Changes:
  * Wrap mw-node-qunit in run.js to register babel to transpile modules
    for node v6
  * Change all sources in src/ to use ES modules
    * Change constants.js to be able to run without
      jQuery.bracketedDevicePixelRatio given ES modules are hoisted to
      the top by spec so we can't patch globals before importing it
  * Change all tests in tests/node-qunit/ to use ES modules
  * Drop usage of mock-require given ES modules are easy to stub with
    sinon

Additional changes:
  * Rename tests/node-qunit/renderer.js to renderer.test.js to follow
    the convention of all the other files
  * Make npm run test:node run only .test.js test files so that it
    doesn't run the stubs.js or run.js file.

Bug: T171951
Change-Id: I17a0b76041d5e2fd18e2d54950d9d7c0db99a941
2017-07-31 23:05:44 +00:00
joakin 02507fb74d Hygiene: Move settingsDialog UI code to ui/
Bug: T171951
Change-Id: I58f77737456e1f4b9db6631f83e4b0f14212c939
2017-07-31 19:14:18 +00:00
joakin 31fa60d32c Hygiene: Move ui renderer.js to ui/ folder
Seems appropiate to group the UI portions of the source under a ui
folder.

Bug: T171951
Change-Id: I6d4317abea4e2a8e273e13fc40a7445bb54628ef
2017-07-31 19:11:41 +00:00
Sam Smith ba3c0b7f76 Hygiene: i13n: Return false over not sampling
Previously, if the browser didn't support the Beacon API, then
instrumentation/eventLogging#isEnabled would bucket the user with a
sampling rate of 0, which is equivalent to returning false. This change
simply does the latter.

Additional changes:
* Update the documented module names of the instrumentation/eventLogging
  and statsv modules.

Bug: T168847
Change-Id: I7ae5c10da42ca614b5b1a6619f9555e5665344cf
2017-07-26 17:06:58 +00:00
Sam Smith 8e00ecc5d1 i13n: popupEnabled = false for disabled event
... for consistency with the server-sent disabled event introduced in
I63faecb0.

Bug: T167365
Change-Id: I3a96df5279f6f0f4e573765735ab0e1fc6f406a8
2017-07-24 17:31:59 +00:00
Piotr Miazga 426356e822 Remove duplicate events filtering
We had instrumentation for over 4 weeks and duplicate events rate
was very low. We want to keep stats so we check the duplicate events
rate but there is no need to filter those.

Bug: T167365
Change-Id: I72585beb21e9db589e45eeace657ef25f432abc9
2017-07-06 17:38:42 +02:00
Piotr Miazga 7e2c79ae0d Send disabled event from settings windows
Changes:
 - introduced new event 'disabled', sent from settings popup
 - added unit tests for 'disabled' event handling

Bug: T167365
Change-Id: I048b38122b8843199c86fd1ed9ec2ff21767e114
2017-07-04 19:08:37 +02:00
Piotr Miazga a82e54bf2d Override eventLogging to enabled when debug flag is on
In order to debug the EventLogging instrumentation in production
environments, we want to be able to bucket ourselves at will.
When the debug flag (?debug=true) is passed send all events
for given page view.

Bug: T168847
Change-Id: Id1b13b0ecaa791b4f26be4d1151bdbbe5270b64d
2017-06-30 18:52:51 +00:00
Piotr Miazga 450e6bc34c Allow events without linkInteractionToken to be logged
Changes:
 - when event doesn't have linkInteractionToken do not check for
   duplicated tokens
 - hygiene, move event duplication logic into separate functions
   for better readability

Bug: T168449
Change-Id: I3ae197567ec9f67e104af109d4f1a1c1a6769d32
2017-06-30 18:03:40 +02:00
Sam Smith dcf8532cdf Hygiene: Group instrumentation modules
Following on from I4f653bba, since the schema and statsvInstrumentation
modules are similar, let's group/rename them:

  schema -> instrumentation/eventLogging
  statsvInstrumentation -> instrumentation/statsv

Change-Id: Ic59e0da7d4917f6733fd090f15d3c269af863f05
2017-06-20 11:41:37 +01:00
Sam Smith 67eb3b1dcf i13n: Log EL events with mw.track
Currently, the mw.eventLog.Schema class samples per pageview. However,
we expect that if a user is bucketed for a session, then all
EventLogging events logged during that session are in the sample.

Moreover, loading the class in the way that we did - asynchronously,
using mw.loader#using - introduced an issue where the eventLogging
change listener would subscribe in the next tick of the JavaScript VM's
event loop and miss the "pageLoaded" event being queued (see T167273).

Changes:
* Make the schema module follow the form of the statsvInstrumentation
  module, i.e. make it expose the #isEnabled method, and add the
  associated getEventLoggingTracker function.
* Update the eventLogging change listener accept the tracker returned by
  getEventLoggingTracker.
* Update/fix related JSDoc documentation.

Bug: T167236
Bug: T167273
Change-Id: I4f653bbaf1bbc2c2f70327e338080e17cd3443d4
2017-06-17 00:51:32 +00:00
joakin 010a4d91a6 Hygiene: Simplify gateways
gateway/*/rest were copies of gateway/restProvider just passing
a different provider. Docs were the same, they were untested, and
looking at them they seemed like unnecessary abstraction.

This patch removes the plain vs html structure, and separates gateways
like before, by endpoint.

There is a light utility in gateway/restFormatters.js that adapts the
call from the rest gateway to use formatters.js functions. It needs
testing, that I'll add in the next patch.

The flow for creating a gateway ends up as follows:

1. index.js calls gateway/index#createGateway( mw.config )
2. createGateway chooses based on wgPopupsGateway and invokes
  * mediawiki.js#createMediaWikiApiGateway or
  * rest.js#createRESTBaseGateway w/ restFormatters.js#parsePlainTextResponse or
  * rest.js#createRESTBaseGateway w/ restFormatters.js#parseHTMLResponse

Changes:
* Removed src/gateway/{plain,html}/rest.js
  * Extracted formatter functions to src/gateway/restFormatters.js
* src/gateway/plain/mediawiki.js -> src/gateway/mediawiki.js
         * tests/node-qunit/gateway/plain/mediawiki.test.js ->
           tests/node-qunit/gateway/mediawiki.test.js
* gateway/restProvider{,.test}.js -> gateway/rest{,.test}.js
* Change gateway/index.js#createGateway to properly call the rest
  gateways with the rest formatters

Bug: T165018
Change-Id: Ia75695dfc192aad5bc581a68882514bad6c29646
2017-06-16 14:49:59 +02:00
joakin 8f408e2937 Fix the npm script test:node
npm scripts are run under sh. globstar support is only available in bash
> 4 with globstar enabled, so **/*.js was actually being resolved to
*/*.js only running tests 2 directories deep.

This made the test mediawiki.test.js not run since it was moved to the
3rd level deep folder (and actually broke), resulting in:

  208 tests
  403 passed

With this change, it fixes getting the test files, and fixes the
mediawiki.test.js, resulting in:

  215 tests
  413 passed

instead.

This makes it work everywhere and as nested as it will get for now. Will
consider adding glob support to mw-node-qunit later for easier use in
other projects too.

Bug: T165018
Change-Id: Id0164b2673c8afe8a24fd0eb4aa255c134253862
2017-06-16 14:49:33 +02:00
joakin b12599c871 Hygiene: Move createGateway to gateway/index.js
And add tests, given it is growing in complexity.

Additional changes:
* Interface ext.popups.Gateway -> Gateway in docs

Bug: T165018
Change-Id: I8a12333ad9d14d6a7fbde11afc42f607881e8ea3
2017-06-16 12:46:05 +02:00
Sam Smith 6159af3151 i13n: Extract experiments module
... from the statsvInstrumentation module so that the bucketing logic
can be shared with other instrumentation modules.

Change-Id: I5732fa539a3911939fa85fa88c102fa8dcfa5613
2017-06-14 11:04:32 -07:00
Piotr Miazga f2fbef6ec7 Implement html/rest.js gateway which handles HTML Restbase responses
Refactor existing Restbase gateway and extract shared logic into
shared Restbase provider. Also introduced new createNullModel()
which defines an empty preview model.

Additionally improve naming in new gateways/formatter so function
names are more explicity.
 * Htmlize() became formatPlainTextExtract() as it should be used
   only with plain text extracts
 * removeEllipsis() became  removeTrailingEllipsis() as it removes
   only trailing ellipsis.
 * src/gateway/index.js defines gateways by configuration name stored
   in extension.json

Bug: T165018
Change-Id: Ibe54dddfc1080e94814d1562d41e85cb6b43bfc1
Depends-On: I4f42c61b155a37c5dd42bc40034583865abd5d7a
2017-06-13 20:19:05 +02:00
Sam Smith fb8d54c7ce actions/rest: Use DB-key version of title
This reduces the number of 301 Redirect responses when fetching previews
from RESTBase.

Bug: T167633
Change-Id: I830947ab79e72dcc023193412c8d5bcee986e23f
2017-06-12 11:22:55 +01:00
Piotr Miazga ef283c2509 Extract rendering/parsing mediawiki responses into separate class
Page Previews should be able to consume HTML response generated by
MediaWiki. First we need to move out plain text crunching from
renderer.js and model.js. Mediawiki and Restbase gateways will have
to parse/htmlize plaintext into nice HTML by themselves.

Bug: T165018
Change-Id: I5d7e9f610bb809aa9fb035a4a9f96e9e8796c9d8
2017-06-09 18:34:25 +02:00
joakin b16a6fe735 Remove unused files processLinks{,.test}.js
Bug: T165572
Change-Id: I3139167e7caec7b7b2707c648e777e448b7de426
2017-06-08 19:37:37 +00:00
joakin 002f4c8e0c Use delegated events in container
...instead of 1 event per link

Supporting changes:
* Delegate events on the container when booting up
  * Check eligibility of title on event triggered
  * Pass the title from the event handlers into the actions instead of
    storing it in the dom
* Add title.fromElement as sugar over isvalid(gettitle())
  * Not tested as it is sugar over the other 2 functions
* Fix action tests and integration tests

processLinks to be removed next

Bug: T165572
Change-Id: I4d9837706dc77ec64121ac94410c0d2da83692e4
2017-06-08 12:31:06 -07:00
joakin 356678ffcd Add title#isValid
Which checks if a title is an eligible one for showing previews

Bug: T165572
Change-Id: I5ade3fb84d400293d24de05e10119996e711b41e
2017-06-08 12:29:33 -07:00
Sam Smith 343506bdfb gateway: Fix Accept header sent by rest gateway
... and update the RESTBASE_PROFILE constant to the latest "stable"
profile for the endpoint.

Prior to this change the Accept header sent by the rest gateway was

  application/json; charset=utf-8profile="..."

This was discovered while responding to T166605.

Change-Id: I00f277e724c561634b26c9ab10bd35332c6dba91
2017-06-08 12:19:32 -07:00
joakin ef2f99ef65 Rename getTitle.js to title.js
In order to create a title#shouldShowPreview function next in the
module.

Bug: T165572
Change-Id: I9e59bb0f525d2698f882543ca0d4a1bde6b2d5d2
2017-06-08 12:10:14 +02:00
Sam Smith 98864a7ce3 eventLogging: Add missing properties to "tapped settings cog" event
When there's an interaction, then the "tapped settings cog" event should
have the same properties set as the other interaction-specific events.

This was discovered while QAing T164256.

Bug: T164256
Change-Id: I4749b52656203c7e0c42ae742556ee996eee322a
2017-06-07 10:13:23 +01:00
Sam Smith 66234e021e eventLogging: Add perceivedWait prop to all events
... and the previewType property as well.

Per the Popups schema [0], the "opened" action should have the
perceivedWait and previewType properties set.

Bug: T166323
Change-Id: I957d123434a6b750aff6f5279865321a08367382
2017-05-25 17:00:13 -04:00
Sam Smith 4728c63342 Add service container
Change-Id: I554fa160e1848a0398e32c796578138e4cc506ec
2017-05-23 06:25:44 +01:00
joakin 293d7ebe8d Clear interaction after an event for it is logged in EL
Given that interactions end up with an event logged, there shouldn't be
a reason to keep an interaction active after it's corresponding final
event has been logged. See Tbayer's state graph.

This patch removes the current interaction if an event with that token
is logged, effectively finalizing it and making it impossible for the
token to be reused from the state tree again.

Additional changes:
* Pass the logged event with the action EVENT_LOGGED so that the reducer
  can determine if it needs to do anything else.
* Since the interaction is removed, when undefined, guard against
  actions that use state.interaction freely. (Only allow BOOT,
  LINK_PREVIEW, and EVENT_LOGGED)

Bug: T161769
Bug: T163198
Change-Id: I99fd5716dc17da32929b6e8ae4aa164f9d84c387
2017-05-16 11:25:41 +02:00
Sam Smith cf0ea9db7b actions: Mix title and namespaceID into LINK_DWELL
This fixes a bug in I8a63d82, where the pageTitleHover and
namespaceIdHover properties of EventLogging events weren't being set.

Bug: T164256
Change-Id: Ie2c2d253f6508b89d48129fd17a902e5ded7cad5
2017-05-15 19:02:27 +01:00
Sam Smith 35bf613964 eventLogging: Add missing *Hover properties
Action changes:
* Include the namespace ID in LINK_DWELL.

Reducer changes:
* Add the createEvent helper, which adds the pageTitleHover and
  namespaceIdHover properties in the event.
* Create "dismissed", "dwelledButAbandoned", and "opened" events using
  the createEvent helper.

Additional changes:
* Store the target page's associated mw.Title using jQuery.
* Update the eventLogging reducer's test cases so that all LINK_DWELL
  representations include title and namespaceID attributes.
* Create the createStubTitle factory function, which returns a minimal
  usable mw.Title stub, and use it in the actions and integration test
  cases.

Bug: T164256
Change-Id: I8a63d82a65324680dff9176020a8ea97695428c4
2017-05-13 08:27:58 +01:00
Sam Smith c44fddf8cd eventLogging: Discard events with duplicate tokens
I6a38a261 made the eventLogging change listener count and discard
duplicate events and count duplicate tokens.

While we isolate the issue(s) that lead to duplication (reuse, likely)
of tokens, make the eventLogging change listener discard events with
duplicate tokens as well.

Bug: T161769
Bug: T163198
Change-Id: I0dbb16c37814d39d7aec35c8fb7cc7309704c550
2017-05-10 11:43:05 +01:00
Baha d6424cb59d QA: Test renderer#show
Binding the behavior has been left out as it requires some refactoring.
Ideally, that functionality should be tested via integration tests, which
is already done.

Bug: T133022
Change-Id: If2fd472847eb3557de97c7ec9619e8831e9bda6d
2017-05-09 17:15:01 -04:00
Baha 108f205e12 QA: Test renderer#layoutPreview
Bug: T133022
Change-Id: I7b7aa544b850e5487a621c522b28653db6056633
2017-05-09 17:13:16 -04:00
Sam Smith 35cfc38b0b eventLogging: Add missing perceivedWait property
Per the Popups schema [0], the "dismissed" action expects the
perceivedWait property to be set.

Happily, the time until the preview was shown is already recorded and
used to determine whether or not to create a "dismissed" or
"dwelledButAbandoned" event.

Reducer changes:
* When creating the "dismissed" event, set the perceivedWait property to
  the already accumulated timeToPreviewShow.

[0] https://meta.wikimedia.org/wiki/Schema:Popups

Bug: T164256
Change-Id: I3fd253f1c2ff5fa8e24c9225060d728ffd8dfd27
2017-05-09 06:51:05 +01:00
Baha 6d95bbf630 Refactor and test renderer#createLayout
* Make function dependencies explicit;
* Only pass data that's needed, no more.

Bug: T133022
Change-Id: Ia973bd9636a477a76db907a37e2a0689daf4e3fa
2017-05-05 14:20:46 -04:00
Baha da2e8c82b0 QA: Improve renderer#createThumbnail tests
* Test for cases when a thumbnail won't be generated;
* Test thumbnail widths and heights;
* Test thumbnail coordinates.

Bug: T133022
Change-Id: I0f7d94816a2faab488b84f55b4462c8732d1031d
2017-05-05 10:43:59 -04:00
Ed Sanders 81a6d49e99 build: Update eslint to 0.4.0 and make pass
Change-Id: I7d301049f0c91f79e82f996b2dce770840c27e72
2017-05-05 05:43:16 +01:00
Baha 0b169321d8 QA: Test renderer#bindBehavior
Bug: T133022
Change-Id: I3b0b199010f0460d83f80c57e4bab8e3606a4b4f
2017-05-04 15:48:10 -04:00
Sam Smith 742f341e5c Hygiene: Tidy up QUnit references
Since Ieea378c9 all QUnit tests are run in Node.js and not in the
browser. Tidy up references to QUnit inside of the codebase and tooling.

Changes:
* Don't exclude src/processLinks.js in Istanbul code coverage reports.
* Don't test for window.QUnit in createSchema. We no longer run the risk
  of sending beacons while running the QUnit test suite as it's no
  longer run in the browser.

Bug: T160406
Change-Id: Ifb6adb84b8019dd69231b50af00bf978b708fc60
2017-05-04 15:53:44 +01:00
Baha d95badc614 QA: Test renderer#hide
Bug: T133022
Change-Id: I752c4266b6be1909a3265d8292e7c5229e5724fb
2017-05-03 13:26:19 -04:00
Baha 76d323da60 QA: Test renderer#createThumbnail
Bug: T133022
Change-Id: Ia6f4de8cbb7ba3b389fb326007db0f859ae1d80a
2017-05-03 13:24:54 -04:00
Baha eb9ceb6238 QA: Test renderer#createPreview
Bug: T133022
Change-Id: Ied8e798851d5aebf2910aba5866f8a801c20923b
2017-05-03 13:23:43 -04:00
Baha a46a5fc02f QA: Test renderer#createEmptyPreview
Bug: T133022
Change-Id: If93d2c679bd7edcf98946e1cb688bc5c3744f69b
2017-05-03 13:21:24 -04:00
Baha ccca8b7a90 QA: Test renderer#createThumbnailElement
Bug: T133022
Change-Id: I7909c208e3d69b2ee510dcd8bfbcafc0118397ca
2017-05-03 16:25:28 +00:00
Bmansurov 520c57e30d Merge "QA: Test renderer#getClasses" 2017-05-03 16:24:28 +00:00
Baha 7f89341cc6 QA: Test renderer#getClasses
Bug: T133022
Change-Id: If3b8888a948f6e14d8847fdc1d4ea16e42329bb8
2017-05-03 16:24:18 +00:00
jenkins-bot a656d7278b Merge "QA: Bring back renderer#renderExtract tests" 2017-05-03 16:22:45 +00:00
Ed Sanders 2a4a235dec Fix ,->; typos
Change-Id: I9b490fcb35459bc0318506e049fbd573bf17e050
2017-05-03 10:19:19 +01:00
Baha 872691e293 QA: Bring back renderer#renderExtract tests
The tests were removed in Iae0a78d0b8a13353de70794b67387f2c3bab44c6.
The ultimate goal is to refactor the renderer code and make it
testable, but before doing so we need to add tests to cover the existing
code. This will give us confidence that we won’t accidentally break
anything when we refactor.

Some of the tests have been removed as the functionality covered by
those were moved to model.js in I20f29657fcf94101a71ed13c0920508db71292ce.

Bug: T133022
Change-Id: I7b20324dd5fe8a428cdd96959b65bc82d44fb515
2017-05-02 12:09:11 -04:00
Baha 234282d1a2 QA: Test renderer#createPokeyMasks
The ultimate goal is to refactor the renderer code and make it
testable, but before doing so we need to add tests to cover the existing
code. This will give us confidence that we won’t accidentally break
anything when we refactor.

Bug: T133022
Change-Id: I3ecbfb9bb3ac9c63fdd40df502796748c62949fe
2017-05-01 11:00:42 -04:00
Baha 2030cb6b06 QA: Bring back renderer#getClosestYPosition tests
The tests were removed in Iae0a78d0b8a13353de70794b67387f2c3bab44c6.
The ultimate goal is to refactor the renderer code and make it
testable, but before doing so we need to add tests to cover the existing
code. This will give us confidence that we won’t accidentally break
anything when we refactor.

Bug: T133022
Change-Id: I897276a1a953f6be62e4c2d4a24e0f22fc6ef141
2017-05-01 10:56:41 -04:00
joakin 406d41d9ae Hygiene: Tests: Remove unused stubs
Bug: T160406
Change-Id: Ifa58ebfd53c037ac483f4b480efc581f18ecb936
2017-04-28 22:39:49 +01:00
joakin f2039605d5 Tests: Unit test getTitle
Real stubs on stubs.js to be removed in followup

Bug: T160406
Change-Id: I0b56e70f3ff95fc5c0f6f6dc4cf0a6625f1e5fe4
2017-04-28 22:39:49 +01:00
joakin 1da916ee73 Tests: Refactor processlinks test
With the final goal to remove the real mw stubs, move the processLinks
tests away from test cases, and split getTitle to be tested standalone.

Supporting changes:
* Move getTitle out to it's own module
  * Will be tested separately in a followup commit
* Remove global declaration of mw.popups.processLinks (not needed any more)

Bug: T160406
Change-Id: Ieebd1257a2476081c67a318d3f05dffa1d3b9bdd
2017-04-28 22:39:49 +01:00
Sam Smith 79f3b318d0 Track and discard duplicate enqueued events
The eventLogging change listener is responsible for ensuring that the
internal state of Page Previews matches its external state (that
perceived by the user and UA). It does this by logging events with
ext.eventLog.Schema#log. This makes it the perfect place to track and
discard duplicate events enqueued by the Page Previews codebase observed
in T161769.

Make the change listener track events that it's logged by storing hashes
of the dynamic parts of them in memory. If the eventLogging change
listener sees the same event more than once, then it discards it and
increments a counter in StatsD.

This behaviour should be enabled for a matter of days as we should see
whether the duplicate events are being enqueued by the Page Previews
codebase immediately.

Bug: T163198
Change-Id: I6a38a2619d777a76dd45eb7300079e1f07b07b12
2017-04-28 15:12:40 +01:00
Sam Smith 3d0899c0a0 Remove isLoggingEnabled with Null Object pattern
The statsv change listener depended on both the analytics tracking
function and whether it should log metrics to StatsD. We can simplify
the behaviour of the change listener by passing in a function which
doesn't log metrics to StatsD if such logging is disabled.

The change listener is now more isolated from other components.
Moreover, sharing the analytics tracking function with other components
is simpler as there's no repeated code.

Bug: T163198
Change-Id: Ibf4785fa4c27c1ad4739f02410f57412f56ff481
2017-04-27 14:29:04 +01:00
joakin 698a93f5bc Hygiene: QUnit setup -> beforeEach & teardown -> afterEach
The setup and teardown hooks on QUnit.module are deprecated on the
latest versions.

See https://api.qunitjs.com/QUnit/module

mw-node-qunit supports them but we shouldn't be using them.

Bug: T160406
Change-Id: I32c07f22d01d16449a6e37f46ff20c577a1f14c6
2017-04-26 12:34:12 +02:00
joakin 2516299bd2 Hygiene: Lint JS files on tests/node-qunit too
For consistency.

Bug: T160406
Change-Id: I2fd67649e9dc4bdb3b963b8ee70ed0234dbcb5ce
2017-04-26 12:34:12 +02:00
joakin c9d325d01e Tests: Migrate processLinks.test.js to node-qunit
Tests are basically unchanged, except for some stubs on beforeEach.

Supporting changes:
* Bring stubs from the mediawiki library for mw.Uri,
  mw.Title.newFromText and mw.RegExp into stubs.js
* Remove hook onResourceLoaderTestModules given there are no resource
  loader test modules after migrating processLinks.test.js

Why bring stubs from real source? This is not optimal. It could be the
case that the stubs would need to be updated at some point in the
future. That's why in the comment of each stub, it is specified where it
came from, and what was changed to make it work. It is not optimal but
it should help with a future update if necessary.

Also checked the history of the stubs and these three stubs are very
stable with a small commits per year, usually adding some extra
functionality (not breaking changes) (the rest of the commits are
docs/format stuff), so the core behavior that we rely on here shouldn't
change in a fundamental way. See the github links:

* https://github.com/wikimedia/mediawiki/commits/master/resources/src/mediawiki/mediawiki.Uri.js
* https://github.com/wikimedia/mediawiki/commits/master/resources/src/mediawiki/mediawiki.Title.js
* https://github.com/wikimedia/mediawiki/commits/master/resources/src/mediawiki/mediawiki.RegExp.js

Right now this stubs allow us to bring the test to run in isolation in
node.

The initial plan was to do change the test to be less test-case oriented
with dependencies on mediawiki.*.js and not to bring fake "real" stubs,
but after looking into it, given that:
1. the test cases in the test seem pretty informative showing the kind
   of links that popups accepts
2. the stubs are acceptably easy to bring in, and are pretty stable
I decided to go with this approach initially to finish the migration
without changing the meaning of the tests.

If we want to remove the stubs and morph the test to verify stub calls
and move the test cases to documentation on the source, I'll tackle that
on a future commit.

Bug: T160406
Change-Id: Ieea378c9b7fec9116222b4a099c226d1f1131f65
2017-04-26 12:26:43 +02:00
joakin 3a39dfd07d Hygiene: Clear global stub after the test
Bug: T160406
Change-Id: I3d8b644a3be12841ba31402fa12dd71e100dbed4
2017-04-25 14:13:29 +02:00
Sam Smith 7f91068ecf Don't show preview if user has abandoned link
If the user dwells on a link for long enough, then the gateway makes a
request, which is allowed to complete regardless of whether or not the
response is required.

If the user abandons the link but the request completes before the
abandon completes - currently, ABANDON_END_DELAY is 300 ms - then the
preview will be rendered temporarily.

Fix this by not rendering the preview if the user has started to abandon
the link.

Bug: T163350
Change-Id: I154dde4e3ccaed3d11cb023c85c44451fc0ad957
2017-04-24 15:35:07 +01:00
Sam Smith 8c611d069f actions: Conditionally dispatch ABANDON_*
If the user CmdOrCtrl+Clicks on a link, then the link will remain
focussed. If a preview is shown, clicks another element on the page, and
then there'll be no token to include in ABANDON_* with.

Bug: T162924
Change-Id: Ie2237aa55ea9a11070498b66c73b8bf1898d8d44
2017-04-18 20:03:58 +01:00
Sam Smith 2c171d7f25 reducers: Don't destroy interaction on LINK_CLICK
I09d8776 introduced a bug in the eventLogging reducer where reducing
LINK_CLICK would remove any accumulated interaction state but not close
the interaction.

Update the associated tests so that they correctly test the reduction of
this action.

Bug: T162924
Change-Id: Ia03e719c228ee96f279c1fa89252dc6b6371a8e9
2017-04-18 19:43:31 +01:00
Sam Smith 56aeeccb0d reducers: Make LINK_CLICK finalize but not close
... the interaction.

Following on from Iccba3c4c, LINK_CLICK shouldn't be considered the end
of an interaction because the link or preview can still be abandoned by
the user. Unlike ABANDON_END and LINK_DWELL, therefore, LINK_CLICK
musn't destroy the interaction but indicate that no more events should
be enqueued for the interaction.

More concretely, if the user has clicked the link or the preview, then
a "dwelledButAbandoned" or "dismissed" event shouldn't be logged.

Changes:
* Distinguish between "finalizing" and "closing" an interaction, where
  the latter is the current behavior of ABANDON_END, LINK_DWELL, and
  LINK_CLICK, in the eventLogging reducer and associated tests.
* If the interaction is finalized, then either the "dwelledButAbandoned"
  or "dismissed" events shouldn't be logged.

Bug: T162924
Change-Id: I09d8776da992053f89a77508e29a7cde3cfeeac6
2017-04-17 15:06:00 -07:00
Sam Smith 83e32c255d reducers: Make LINK_CLICK finalize interaction
... in the eventLogging reducer.

Like ABANDON_END, the LINK_CLICK should be considered the end of the
interaction in the context of the EventLogging instrumentation, i.e. no
events should be logged after the user clicks the preview or the link.

See T159490#3172692 for additional context.

Bug: T159490
Change-Id: Iccba3c4c2b6121016ff7923c11b1622bc046ad6b
2017-04-12 11:45:04 +01:00
Sam Smith 76b8c18ca5 reducers: Make PREVIEW_SHOW require a token
Like the FETCH_COMPLETE and ABANDON_END actions, the PREVIEW_SHOW action
was delayed but not conditionally reduced. As ABANDON_END is delayed,
there's a potential for a race and if ABANDON_END is reduced before
PREVIEW_SHOW, then there's no interaction to reduce the action into,
which causes an error, e.g. T159490#3165276 and T162373. Making
PREVIEW_SHOW require a token stops the error occurring in this scenario.

An alternative would be to clear the timeout created in
ext.popups.Preview#show in #hide. However, this would be inconsistent
with actions#fetch and actions#abandon.

Bug: T159490
Change-Id: Ibd2c0c6f45e4392582cc6ed08517f6ca1146d57a
2017-04-11 14:06:04 +01:00
Sam Smith 77943704f8 actions: Add token to PREVIEW_SHOW
Mirroring all other actions that are dispatched after some delay, add
the token to the PREVIEW_SHOW action.

Supporting changes:
* Pass the token to ext.popups.Preview#show so that it can be passed to
  actions#previewShow.

Bug: T159490
Change-Id: I128fd56e770ed09d5d0dc55db73d11b013049c79
2017-04-11 09:26:22 +01:00
Sam Smith 91b1d5da42 Hygiene: Reduce nesting of test cases
The ABANDON_START action test cases were (accidentally?) nested under
the FETCH_COMPLETE action test cases...

Bug: T162373
Change-Id: Ia7866178162512602dedd7f70d62c17995ee5076
2017-04-07 14:11:52 +01:00
Sam Smith 87be4be855 reducers: Reduce FETCH_COMPLETE if token matches
... instead of using the active element.

In the case of the eventLogging reducer, this fixes scenario 4.1 from
T159490#3150331, which was caused by late FETCH_COMPLETE actions being
reduced regardless of whether interaction had been finalised or a new
interaction had started.

Bug: T159490
Change-Id: If9d718625b0302ea2f75a778005643b4eef62bde
2017-04-07 14:06:14 +01:00
Sam Smith d3d9100637 actions: Add token to FETCH_COMPLETE
Bug: T159490
Change-Id: Ic71dd3ce5e7933273f84a9a64d41e7f3a4cb03f4
2017-04-07 14:06:11 +01:00
Sam Smith f86f388fd3 Hygiene: Remove trailing whitespace
... from tests/node-qunit/actions.test.js.

Spotted during the review of Ic3165620.

Change-Id: I0fb78d2dc3aadc6b42bd9f441bca9a72300f720c
2017-04-06 21:29:07 +01:00
Sam Smith 52d128863e actions: Correctly delay FETCH_COMPLETE
I496fe317 caused a regression where the FETCH_COMPLETE was delayed for a
total of 650 ms rather than 500 ms. This is evidenced by a 150 ms step
in the median Time To Preview immediately after today's (Thursday, 6th
April) MediaWiki train [0].

[0] https://grafana.wikimedia.org/dashboard/db/reading-web-page-previews?refresh=1m&orgId=1&from=1491505806387&to=1491507027263

Change-Id: Ic31656208671766f2c08cfaf55babba64455a614
2017-04-06 21:17:44 +01:00
Baha 5b613b1698 Disable Previews when Navigation Popups Gadget is enabled
Only showing a preview is disabled, EL and other stuff should work.

Bug: T160081
Change-Id: Ia837816081781dcaea9a8b4c722f8df5b3e3ca03
2017-04-06 13:11:17 -04:00
Baha e3fde6e360 Handle RESTBase 404
Treat these responses not as an API failure. Show a generic
preview whenever the server responds with a 404.

Bug: T160744
Change-Id: Id6169d9d4c7493f5b6511cc78fe65d448cdadc03
2017-04-06 18:03:11 +02:00
Sam Smith 1e199b67f0 actions: Simplify delaying FETCH_COMPLETE
Require that two promises are resolved (or one is rejected) before the
FETCH_COMPLETE action is dispatched. The first promise represents the
gateway request and the second represents an arbitrarily long delay. If
the first resolves before the second, then there'll be a delay until the
second resolves; whereas if the first rejects, then there's no delay.

Change-Id: I496fe317337745c593594efff26688c46d661bf3
2017-03-30 17:48:58 -07:00
Sam Smith a7d353767e tests: Don't assume 1 wait call per test
The delay/timeout logic in actions#fetch will require more than one wait
call, for example.

Changes:
* Update the stub created in setupWait to store all deferred-promise
  pairs and update the integration tests so that they don't use the stub
  accidentally.
* Remove all references to the waitDeferred/waitPromise properties.
* Fix tests that relied on the waitDeferred/waitPromise properties being
  available regardless of whether wait had been called.
* Update outdated or brittle - in the sense that it didn't reference
  constants but their values - inline documentation.

Change-Id: I94345cdf4126b6c540d4fb8135a7a7e4d0507bed
2017-03-31 00:48:23 +00:00
Sam Smith 6042000eb1 actions: Don't mix delay into FETCH_COMPLETE
Mixing in the delay was introduced in If3f1a06f so that the total RTT
for an API request could be calculated. Now that the FETCH_END action is
dispatched when the gateway request ends and not when the preview model
is resolved, this additional information (state) is redundant.

Change-Id: I7e6ffe0945ffedd9425525fa7da855e729d50b77
2017-03-30 17:48:05 -07:00
Sam Smith 3646b04876 actions: Dispatch FETCH_END
... when the gateway request ends, per I62c9cb04.

Change-Id: Ifbed65d6b97877e859e81f256fa44344a64fc64f
2017-03-30 17:47:39 -07:00
Sam Smith 8b311aa159 Hygiene: FETCH_END -> FETCH_COMPLETE
Ideally, the preview model is resolved after 500 ms, regardless of
whether the internal gateway takes 100 or 300 ms. Given this, there's an
important distinction to be made between the "fetch" ending and it
completing and their associated actions.

Changes:
* Dispatch the FETCH_COMPLETE action when the preview model is resolved.
* Update the reducers accordingly.

Change-Id: I62c9cb0430284b76338ea80bd170cac5af4be9d0
2017-03-30 17:47:13 -07:00
Sam Smith da7325a169 changeListeners: Conditionally empty link titles
If the user has disabled PP via the settings dialog or they aren't in
the experimental condition, then link titles shouldn't be emptied.

Because this behavior has to respond to the user enabling/disabling PP
within the same page session, change the linkTitle change listener
rather than conditionally registering it.

Bug: T161277
Change-Id: I53c1a1d3e4436e2ffe08da27da388f394f4e8817
2017-03-30 17:39:39 -07:00
Sam Smith ae9733b2f0 eventLogging: Log abandon event when user dwells
If the user abandons link A (or preview A) and immediately dwells on
link B, then log a "dismissed" or "dwelledButAbandoned" event.

In this context, "immediately" means before the ABANDON_END action is
dispatched, which, currently, is 300 ms after the ABANDON_START action
is dispatched.

Bug: T159490
Change-Id: I49f0f5dfb3e6c08844f1794fee8cb6170e93981b
2017-03-30 17:15:26 -07:00
Sam Smith 90d54eca64 eventLogging: Extract createAbandonEvent function
Reducer changes:
* Add tests for ABANDON_END case.
* Extract the body of the ABANDON_END case into the createAbandonEvent
  helper function.

Additional changes:
* totalInteractionProperty -> totalInteractionTime elsewhere in the same
  file.

Bug: T159490
Change-Id: Ifff34271395f330b83cfe487e84800fe2d6f3811
2017-03-30 17:14:52 -07:00
Sam Smith d6cc8fa7cb eventLogging: SETTINGS_SHOW logs an event
Reducer changes:
* Make the eventLogging reducer queue a "tapped settings cog" event when
  reducing the SETTINGS_SHOW action.

This was discovered while testing I6ce7d72b.

Bug: T159490
Change-Id: I6ce7d72b364d20c71b0e2cfed98e99f7997895e5
2017-03-30 17:14:08 -07:00
Sam Smith 29963edb09 preview: Add click behavior
Like dwelling and abandoning, clicking on a preview is the same as
clicking on a link.

This fixes scenario 3 from T159490.

Bug: T159490
Change-Id: I6d9ff52b62bec93ebfcc9b6d267a46cf961852fb
2017-03-30 17:08:08 -07:00
Sam Smith df7868ea3f eventLogging: Model interactions in EL reducer
For now, mirror the interaction modelling in the preview reducer in the
eventLogging reducer to handle the user either:

* Repeatedly dwelling on and abandoning a link.
* (Repeatedly) moving their mouse between the link and the preview.

This fixes scenarios 1, 2, 5, and the general issue from T159490.

Bug: T159490
Change-Id: Ia771f325e541c107348b16b47c5b786c97847652
2017-03-30 17:03:06 -07:00
Baha 9a94300858 Log events to statsv for monitoring PagePreviews performance
For logging to work:
1. $wgWMEStatsdBaseUri needs to point to a valid statsv endpoint,
   e.g. 'https://en.wikipedia.org/beacon/statsv'.
2. $wgPopupsStatsvSamplingRate needs to be set. Note that the codebase
   already contains the EventLogging functionality, which is configured
   separately. Separately configuring different logging mechanisms
   allows us to avoid sampling mistakes that may arise while choosing
   one or the other. For example, let's say we want to use EventLogging for
   10% of users and statsv for 5%. We'd sample all users into two
   buckets: 50/50. And then we'd have to set the sampling rates as
   20% and 10% respectively, only because of the bucketing above. To avoid
   this kind of complications, separate sampling rates are used for each
   logging mechanism. This, of course, may result in situations where a
   session is logged via both EventLogging and statsv.
3. The WikimediaEvents extension needs to be installed. The extension
   adds the `ext.wikimediaEvents` module to the output page. The
   logging functionality is delegated to this module.

Notable changes:
* The FETCH_START and FETCH_END actions are converted to a timed action.
* The experiments stub used in tests has been extracted to the stubs
  file.

Logged data is visualized at
https://grafana.wikimedia.org/dashboard/db/reading-web-page-previews

Bug: T157111
Change-Id: If3f1a06f1f623e8e625b6c30a48b7f5aa9de24db
2017-03-14 08:51:10 +00:00
Sam Smith 568b7a09a1 rest: Always scale thumbnail's largest dimension
... thumbnails.

A good example of the difference in behaviour of the PageImages API is
here <T156800#3087507>. The API defers to File#transform, which scales
the largest dimension of an image, not always the width, e.g. if an
image is 1000px x 2000px and the request is for a thumbnail "of 1800px",
then the thumbnail will be 900px x 1800px.

Bug: T156800
Change-Id: I64bc2244ee78a594298d8637233b0da1083700eb
2017-03-10 10:44:37 +00:00
Piotr Miazga 5328cf4681 Hygiene: Move EXTRACT_LENGTH to constants
Keep all configuration-like values in one file.
Changes:
 - moved EXTRACT_LENGTH to constants.js file

Change-Id: Ibe5ecfc60f2c09a30a9ecb3586bc5fb6a7365476
2017-03-09 22:08:10 +00:00
Sam Smith d4caff9774 rest: Don't scale unscalable thumbnails
If the image isn't an SVG then it shouldn't be scaled past its original
dimensions. Handle the case where the requested thumbnail can't be
generated on the server as the original is too small ( < 320px,
currently [0]) in the same way.

Moreover, if the image happens to have the exact dimensions that we're
requesting (300px or 600px wide, currently [1]), then use the original
image to avoid unnecessary work/pressure on caches.

Supporting changes:
* Update the SVG_RESTBASE_RESPONSE fixture to use the extension returned
  by RESTBase (and the PageImages extension) for the thumbnail:
  .svg.png.

[0] https://github.com/wikimedia/restbase/blob/master/v1/summary.yaml#L121
[1] https://github.com/wikimedia/mediawiki-extensions-Popups/blob/master/src/constants.js#L2

Bug: T156800
Change-Id: I5d0aa161e80869e4b4f5425d906d1e753047a3a3
2017-03-08 18:44:23 +01:00
joakin 91fd2dfd50 Hygiene: Remove duplicate file preview/index.js
The same file is on preview/model.js which is the one actually used by
the application. For some reason the file is a duplicate of model.js,
and it is the file that is required on its QUnit tests.

This patch removes it and points the unit tests to the correct file,
preview/model.js

It was also required by popups.js which was removed in the previous
commit.

Change-Id: Id175a764d9b67fb8d0e8fbf4a4623a3420f76094
2017-03-06 18:07:43 +01:00
Baha b40a24c15c Allow showing non-free images when using MediaWiki API
We used to query the MediaWiki API to only return non-free images.
This patch allows us to query the API for images with any license.
The RESTBase end point is already returning images with any license.

Bug: T158632
Change-Id: I9ac60b6f74a7f7eb2cb160ee522c2c3a26dd0858
2017-03-06 11:33:17 +00:00
jenkins-bot 3791f245a7 Merge "Tests: Migrate userSettings.test.js to node-qunit" 2017-03-02 11:57:52 +00:00
jenkins-bot bba9e88fda Merge "Tests: Extract createStubMap" 2017-03-01 23:27:31 +00:00
jenkins-bot f11f177351 Merge "Tests: Migrate schema.test.js to node-qunit" 2017-03-01 23:27:30 +00:00
Sam Smith 720cfbdcd7 restbase: Use thumbnail when generating thumbnail
Rather than manipulating the URL of the original image to get the URL of
the appropriately sized thumbnail, manipulate the URL of the thumbnail
image.

While we could manipulate either the thumbnail or original image URL,
there are subtle differences between the two, so manipulating the latter
makes the generateThumbnailData function as simple as possible, e.g. we
don't have to splice in "/thumb" after "/commons".

Also, ensure that the thumbnail's dimensions are scaled appropriately.

Bug: T156800
Change-Id: I6825bad14b1131dc81f23dcf120cf8ffb7d7b4f6
2017-03-01 15:41:50 +00:00
joakin 57854d4176 Tests: Migrate userSettings.test.js to node-qunit
Supporting changes:
* Use mw.Map stub
* Use assert.expect instead of number of assertions in QUnit.test
  (deprecated in newer QUnit)
* Don't specify assert.expect( 1 ), because it is the default (no
  assertions will make the test fail).

Change-Id: I64a3e76917e75b8c6d496f20e5b5dcafb338a46a
2017-03-01 12:47:07 +01:00
joakin 35c7068fbe Tests: Extract createStubMap
Minimal mw.Map stub that covers get with key and a default value

Change-Id: I15d60d78ed86747a94f371fd3df400906f0c6dab
2017-03-01 12:40:42 +01:00
joakin d662bc62b2 Tests: Migrate schema.test.js to node-qunit
Additional changes:
* Stub map with get( key, default ) which is mediawiki specific
  behavior

Change-Id: Ie6c4842604e59b5b06cc5d462216bdaa1784f558
2017-03-01 12:40:42 +01:00
Baha 5d4cc8d15a Allow bucketing anons
* Logged in users bypass bucketing. They keep working as before.
* When Page Previews is configured as a beta feature, logged out users
  won't see the feature.
* If an anonymous user has enabled/disabled the feature using
  the settings cog then they will see or not see the feature
  depending on the value of their setting.
* The other anonymous users are bucketed. By default 90% of these
  users see the feature, the other 10% don't. These numbers can be
  controlled by the config variable `wgPopupsAnonsEnabledSamplingRate`.

Bug: T157700
Change-Id: I5307587b10f4849c4e82d3b064ff759121c2de67
2017-03-01 10:45:32 +00:00
joakin 82e315b124 Tests: Migrate {integration,actions}.test.js to node qunit
Because of the globals mw.popups.wait usage and mocking in both actions
and integration, they need to be migrated in a single step, fixing them
both to require wait.js and mock using mock-require instead of the
global variable.

Additional changes:
* Fix FIXMEs about actions.js using the global mw.popups.wait instead of
  the require one.
* Fix the unit tests to use require mocking for wait.js instead of
  global variable mocking in both integration and actions tests
* Change tests that use deferreds and promises to be async qunit tests
  (Deferreds are asynchronous with jQuery in node, apparently they
  weren't in the browser)
* Change integration.test.js to use require on Redux and ReduxThunk

Change-Id: I8e3e87b158bd11c9620e77d0a73e611cf9e82183
2017-02-27 18:17:28 +01:00
joakin 8e78005b30 Tests: Migrate previewBehavior.test.js to node qunit
Additional changes:
* Mock global usage of mw.Title.newFromText().getUrl

Change-Id: Idcabea0f996f481194d1b6ecbea6f9f63b253bc6
2017-02-22 12:14:07 +01:00
joakin fb4649d469 Tests: Migrate settingsDialog.test.js to node qunit
Additional changes:
* Mock usage of global mw.{msg,template,config}

Change-Id: I67e5cdd5bb275b9083eae0df80af2195c41a7f8e
2017-02-22 12:14:07 +01:00
joakin 4f71f6f740 Tests: Migrate gateway/rest.test.js to node qunit
Additional changes:
* Fix eslint errors in the test file
* Mock global mw.Title usage in the test

Change-Id: Ia2778457239184639150d03ab0f0a1ca597a862e
2017-02-22 12:14:07 +01:00
joakin 2ca5fed3ee Tests: Migrate changeListeners/render.test.js to node-qunit
The render change listener is hard coupled to the renderer file, so in
order to migrate the test, instead of stubbing a global variable, we had
to either inject the renderer into the change listener factory as done
everywhere else, or mock the require call.

In order to do one thing per commit, we're mocking the require call
here to get the migration done, but added a FIXME to use dependency
injection instead in a future change.

Change-Id: I50f82cdc9664d34b8a8ccc1ff368f7209404159d
2017-02-22 12:14:05 +01:00
joakin 4e0c054a19 Tests: Migrate changeListeners/syncUserSettings.test.js to node-qunit
Change-Id: I3bf86e0452557e938fe7066978e553d583d974f7
2017-02-22 12:13:38 +01:00
joakin 715389443c Tests: Migrate changeListeners/linkTitle.test.js to node-qunit
Change-Id: I714b8737d61ce3db35852ceb977449c709002537
2017-02-22 12:13:38 +01:00
joakin 010502b9b1 Tests: Migrate changeListeners/footerLink.test.js to node-qunit
Given this is a jsdom environment assertions using jQuery's :visible
have been changed to check the display property for visibility.

See https://github.com/tmpvar/jsdom/issues/1048

Change-Id: Ifad8067c0b50053a94ac977ee1f1f5a3066bfa16
2017-02-22 12:13:37 +01:00
joakin 48988e30da Tests: Migrate gateway/mediawiki.test.js to node-qunit
Change-Id: Ia47b0f793430b355eb2e39d74a05e72ea55de0b1
2017-02-22 12:13:37 +01:00
joakin 30550e2670 Test: Migrate wait.test.js to node-qunit
Don't use fake timers for now because of some problems with other async
tests.

Change-Id: If48a8c7390416938d50c9c0c39539fe4a6a9a6af
2017-02-22 12:13:37 +01:00
joakin 620c97c53d Test: Migrate changeListeners/settings.test.js to node-qunit
Change-Id: Ic7651133ee2ac6eee68d30b3c7069c26da1abf8b
2017-02-20 20:01:01 +01:00
joakin 600b21182d Test: Migrate eventLoggingChangeListener.test.js to node-qunit
And on the way there actually put it in a changeListeners/ folder and
rename it to eventLogging.test.js

Change-Id: I60685021841b44f606f39b07bf7f5262344262f4
2017-02-20 20:01:01 +01:00
joakin d2d7ab10fa Test: Migrate changeListener.test.js to node-qunit
Change-Id: Ib6d5156d2f1bc56c113866ed0510966586d9ca07
2017-02-20 20:01:01 +01:00
joakin f3839189dc Test: Migrate isEnabled.test.js to node-qunit
Change-Id: I85a08725c9138f47a51cdc34c20bc3a60b61af34
2017-02-20 20:01:01 +01:00
joakin c233ffb4a5 Test: Migrate preview/model.test.js to node-qunit
Change-Id: Ie5a895a1760dbfc58e11369fdb8b979021b8ae74
2017-02-20 20:01:01 +01:00
joakin b7a4029adb Test: Migrate reducers/eventLogging.test.js to node-qunit
Change-Id: I4bc6d77a496a8c4bf1ecafbf3a6a71986c77e423
2017-02-20 20:01:01 +01:00
joakin d06bbe5871 Test: Migrate reducers/preview.test.js to node-qunit
Change-Id: I700bc43dace64503058337a6b458673070bc5db0
2017-02-20 20:01:01 +01:00
joakin 33c05394f4 Set up qunit running in node to migrate tests to commonjs
In order to run qunit tests on sources that use common.js modules, set
up infra to run qunit tests in the node cli when running:

    npm run test:node

Changes:
* Add npm script test:node that runs the tests
* Run node tests on CI (npm test)
* Add a qunit node test runner: mw-node-qunit
* Migrate a test from the root hierarchy and another one from the nested
  one to prove it works (globs fail otherwise)
  * reducers/settings.test.js to node qunit to prove it works
  * counts.test.js to node qunit to prove it works

Change-Id: I55d76b7db168f3745e0ac69852c152322ab385c3
2017-02-20 20:01:01 +01:00