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
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
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
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
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
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
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
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
... 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
... 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
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
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
The ABANDON_START action test cases were (accidentally?) nested under
the FETCH_COMPLETE action test cases...
Bug: T162373
Change-Id: Ia7866178162512602dedd7f70d62c17995ee5076
... 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
Treat these responses not as an API failure. Show a generic
preview whenever the server responds with a 404.
Bug: T160744
Change-Id: Id6169d9d4c7493f5b6511cc78fe65d448cdadc03
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
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
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
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
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
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
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
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
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
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
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
... 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
Keep all configuration-like values in one file.
Changes:
- moved EXTRACT_LENGTH to constants.js file
Change-Id: Ibe5ecfc60f2c09a30a9ecb3586bc5fb6a7365476
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
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
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
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
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
* 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
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
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
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
And on the way there actually put it in a changeListeners/ folder and
rename it to eventLogging.test.js
Change-Id: I60685021841b44f606f39b07bf7f5262344262f4
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