-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add opt-in usage tracking for blocks added to post content #2140
Conversation
isToggled, | ||
className, | ||
disabled, | ||
...additionalProps, // eslint-disable-line comma-dangle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without the eslint-disable-line
here, eslint
reports this line as an error. This seems like a bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found quite a bit of prior discussion, which consensus seeming as though the specification does not allow a trailing comma in these cases:
- comma-dangle always-multiline incorrectly reports error for object rest spread eslint/eslint#7463
- Breaking change in [email protected] with babel-eslint parser (comma-dangle and rest object destructuring) eslint/eslint#7422
comma-dangle
incorrectly requires commas after rest properties eslint/eslint#7297- Fix: Don't require commas after rest properties (fixes #7297) eslint/eslint#7298
- eslint/eslint@52da71e
- Version 3.8.0 comma-dangle breaks Flowtype annotations when a object rest parameter is used eslint/eslint#7370 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that sort of makes sense, though it would be nice to have a better error message. I'll incorporate this change into #2205.
|
||
export default connect( | ||
undefined, | ||
{ dispatchRemoveNotice: removeNotice } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm renaming this variable here because otherwise eslint
reports an error under the no-shadow
rule.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative (used elsewhere) would be to avoid destructuring: props.removeNotice
Codecov Report
@@ Coverage Diff @@
## master #2140 +/- ##
==========================================
+ Coverage 22.3% 22.98% +0.68%
==========================================
Files 137 141 +4
Lines 4291 4415 +124
Branches 722 743 +21
==========================================
+ Hits 957 1015 +58
- Misses 2815 2874 +59
- Partials 519 526 +7
Continue to review full report at Codecov.
|
To test this PR, you can use the following commands in the browser console:
|
@@ -0,0 +1,61 @@ | |||
/* eslint-disable no-console */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the tracking could be its own module, it could be useful outside of the editor (and other WP feature plugins later)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a path forward for making this work? (Working build system, publishing to npm
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking, just moving this to a root folder in gutenberg for now. And once we have a WP.org infrastructure we could move to the packages repository
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this belongs in a new root folder. Maybe as part of utils
, but the prompt component should stay in editor
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then later we can move it over to https://github.com/WordPress/packages (I thought that was what you meant).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this belongs in a new root folder. Maybe as part of utils
For me a root folder is a separate module just like the packages repo, and I don't think we should add a lot of things to the utils
module, I prefer smaller separate modules (like the ongoing PR for wordCounter)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should avoid adding a lot of small packages in this repo. This is what WordPress/packages
is designed for; I'm fine with moving stats tracking over there once we get the build system working well. We will probably want to make it a bit more generic (remove the gutenberg_
prefix and modify the opt-in logic).
|
||
export default connect( | ||
undefined, | ||
{ dispatchRemoveNotice: removeNotice } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative (used elsewhere) would be to avoid destructuring: props.removeNotice
Longer term (or not), WP.org needs its own tracking infrastructure, this could be very useful to enhance WordPress. |
I plan to rebase and merge this later today. I expect it will provide a lot of good data that we can use to inform decisions. Making the data available to the public is also doable, but will require some separate work on the WP.com side. |
+ '=' + encodeURIComponent( name ) | ||
+ '&t=' + Math.random(); | ||
|
||
if ( process.env.NODE_ENV === 'development' ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this should be unified with the process.env.NODE_ENV !== 'production'
check below.
Especially since the console message says "non-production build".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, good point.
I wrote it this way so the URL-building logic can be unit-tested (NODE_ENV === 'test'
). However, we only want to display the URL message in development
. I'll add those tests and change the message to say development build
as well.
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from 'i18n'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note with #2172, these need to be updated to prefix the dependencies with @wordpress/
. You will need to perform a rebase against the latest version of master and apply your changes:
git fetch origin
git rebase origin/master
7f4d5be
to
16b882b
Compare
// There are a couple of pieces of the URL where we don't care about | ||
// testing the specific value. Replace them with placeholders. | ||
const urlMatch = url | ||
.replace( /^[a-z]+:/, 'PROTOCOL:' ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In actual usage this will either be http:
or https:
. During test suite runs it is about:
. This is difficult to change (jsdom/jsdom#1700) and it doesn't seem worth testing for a specific value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, we could run assertions against individual pieces from url.parse
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've incorporated this change into #2205.
/** | ||
* External dependencies | ||
*/ | ||
import { mount } from 'enzyme'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case I think we could have used shallow
rendering which tends to be more performant (doesn't mount into DOM, doesn't render descendants).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shallow
doesn't work here because we reach inside a Button
element and grab its text. Open to other suggestions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shallow
doesn't work here because we reach inside aButton
element and grab its text. Open to other suggestions.
Remarked at #2140 (comment). It wasn't entirely as simple, but close:
diff --git a/editor/enable-tracking-prompt/test/index.js b/editor/enable-tracking-prompt/test/index.js
index 686fa0ec..098b95e0 100644
--- a/editor/enable-tracking-prompt/test/index.js
+++ b/editor/enable-tracking-prompt/test/index.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { mount } from 'enzyme';
+import { shallow } from 'enzyme';
/**
* Internal dependencies
@@ -29,13 +29,13 @@ describe( 'EnableTrackingPrompt', () => {
} );
it( 'should render a prompt with Yes and No buttons', () => {
- const prompt = mount(
+ const prompt = shallow(
<EnableTrackingPrompt />
);
- const buttons = prompt.find( '.button' );
+ const buttons = prompt.find( 'Button' );
expect( buttons.length ).toBe( 2 );
- expect( buttons.at( 0 ).text() ).toBe( 'Yes' );
- expect( buttons.at( 1 ).text() ).toBe( 'No' );
+ expect( buttons.at( 0 ).children().text() ).toBe( 'Yes' );
+ expect( buttons.at( 1 ).children().text() ).toBe( 'No' );
expect( window.setUserSetting )
.not.toHaveBeenCalled();
@@ -46,11 +46,11 @@ describe( 'EnableTrackingPrompt', () => {
} );
it( 'should enable tracking when clicking Yes', () => {
- const prompt = mount(
+ const prompt = shallow(
<EnableTrackingPrompt removeNotice={ removeNotice } />
);
- const buttonYes = prompt.find( '.button' )
- .filterWhere( node => node.text() === 'Yes' );
+ const buttonYes = prompt.find( 'Button' )
+ .filterWhere( node => node.children().text() === 'Yes' );
buttonYes.simulate( 'click' );
expect( window.setUserSetting )
@@ -62,11 +62,11 @@ describe( 'EnableTrackingPrompt', () => {
} );
it( 'should disable tracking when clicking No', () => {
- const prompt = mount(
+ const prompt = shallow(
<EnableTrackingPrompt removeNotice={ removeNotice } />
);
- const buttonNo = prompt.find( '.button' )
- .filterWhere( node => node.text() === 'No' );
+ const buttonNo = prompt.find( 'Button' )
+ .filterWhere( node => node.children().text() === 'No' );
buttonNo.simulate( 'click' );
expect( window.setUserSetting )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still having problems getting this to work, specifically with the it( 'should show and hide a popover when clicking More info' )
test not covered in the above diff. See 861218d.
const prompt = mount( | ||
<EnableTrackingPrompt removeNotice={ removeNotice } /> | ||
); | ||
const buttonNo = prompt.find( '.button' ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To point above, this selector would not work with shallow rendering, but then again, it is not the place of the EnableTrackingPrompt
to know that an element of class .button
is rendered by the Button
component. Replacing this with 'Button'
should work just as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found that we couldn't look inside a shallow-rendered Button
element to find its text:
console.log( { text: prompt.find( 'Button' ).at( 0 ).text() } );
{ text: '<Button />' }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've incorporated the change to Button
instead of .button
into #2205.
// There are a couple of pieces of the URL where we don't care about | ||
// testing the specific value. Replace them with placeholders. | ||
const urlMatch = url | ||
.replace( /^[a-z]+:/, 'PROTOCOL:' ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, we could run assertions against individual pieces from url.parse
.
This PR asks users for permission to enable usage tracking:
When the user clicks "Yes" or "No", the preference is stored using the existing WordPress method of saving user preferences (the
setUserSetting
function used elsewhere in wp-admin; props @swissspidy for telling us about this function in #1948). This preference is saved as a cookie and eventually persisted as a user option.If the user clicks "Yes", tracking events will be recorded using existing WP.com infrastructure every time a block is added to the editor. The approach taken here is very similar to Calypso's event tracking code.
We can use the data added in this PR to inform various decisions such as default order for blocks and whether some blocks are less suitable for core, and more generally this is a very useful technique to collect user experience data.