diff --git a/blocks/api/parser.js b/blocks/api/parser.js
index 5a7b871719fb5e..a02a75e7b80a9e 100644
--- a/blocks/api/parser.js
+++ b/blocks/api/parser.js
@@ -4,6 +4,11 @@
import { parse as hpqParse } from 'hpq';
import { pickBy } from 'lodash';
+/**
+ * WordPress dependencies
+ */
+import { bumpStat } from '@wordpress/utils';
+
/**
* Internal dependencies
*/
@@ -75,6 +80,7 @@ export function createBlockWithFallback( name, rawContent, attributes ) {
// Convert 'core/text' blocks in existing content to the new
// 'core/paragraph'.
if ( name === 'core/text' ) {
+ bumpStat( 'block_auto_convert', 'core-text-to-paragraph' );
name = 'core/paragraph';
}
diff --git a/components/button/index.js b/components/button/index.js
index dda515022caba1..39ff5967237cbc 100644
--- a/components/button/index.js
+++ b/components/button/index.js
@@ -36,7 +36,7 @@ class Button extends Component {
isToggled,
className,
disabled,
- ...additionalProps, // eslint-disable-line comma-dangle
+ ...additionalProps
} = this.props;
const classes = classnames( 'components-button', className, {
button: ( isPrimary || isSecondary || isLarge ),
diff --git a/editor/enable-tracking-prompt/index.js b/editor/enable-tracking-prompt/index.js
index 9a4077fd13a208..c7dfb271974a6c 100644
--- a/editor/enable-tracking-prompt/index.js
+++ b/editor/enable-tracking-prompt/index.js
@@ -10,12 +10,12 @@ import clickOutside from 'react-click-outside';
import { Component } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Button, Popover } from '@wordpress/components';
+import { bumpStat } from '@wordpress/utils';
/**
* Internal dependencies
*/
import './style.scss';
-import { bumpStat } from '../utils/tracking';
import { removeNotice } from '../actions';
export const TRACKING_PROMPT_NOTICE_ID = 'notice:enable-tracking-prompt';
diff --git a/editor/enable-tracking-prompt/test/index.js b/editor/enable-tracking-prompt/test/index.js
index 686fa0ec0dade2..e83ce61960de81 100644
--- a/editor/enable-tracking-prompt/test/index.js
+++ b/editor/enable-tracking-prompt/test/index.js
@@ -2,6 +2,7 @@
* External dependencies
*/
import { mount } from 'enzyme';
+import clickOutside from 'react-click-outside';
/**
* Internal dependencies
@@ -12,35 +13,37 @@ import {
} from '../';
describe( 'EnableTrackingPrompt', () => {
- const tracking = require( '../../utils/tracking' ); // no default export
const originalSetUserSetting = window.setUserSetting;
- const originalBumpStat = tracking.bumpStat;
+ const originalDocumentAddEventListener = document.addEventListener;
+ let eventMap = {};
let removeNotice;
beforeEach( () => {
window.setUserSetting = jest.fn();
- tracking.bumpStat = jest.fn();
+ document.addEventListener = jest.fn( ( event, cb ) => {
+ eventMap[ event ] = cb;
+ } );
removeNotice = jest.fn();
} );
afterEach( () => {
window.setUserSetting = originalSetUserSetting;
- tracking.bumpStat = originalBumpStat;
+ document.addEventListener = originalDocumentAddEventListener;
+ eventMap = {};
} );
- it( 'should render a prompt with Yes and No buttons', () => {
+ it( 'should render a prompt with Yes, No, and More info buttons', () => {
const prompt = mount(
);
- const buttons = prompt.find( '.button' );
- expect( buttons.length ).toBe( 2 );
+ const buttons = prompt.find( 'Button' );
+ expect( buttons.length ).toBe( 3 );
expect( buttons.at( 0 ).text() ).toBe( 'Yes' );
expect( buttons.at( 1 ).text() ).toBe( 'No' );
+ expect( buttons.at( 2 ).text() ).toBe( 'More info' );
expect( window.setUserSetting )
.not.toHaveBeenCalled();
- expect( tracking.bumpStat )
- .not.toHaveBeenCalled();
expect( removeNotice )
.not.toHaveBeenCalled();
} );
@@ -49,14 +52,12 @@ describe( 'EnableTrackingPrompt', () => {
const prompt = mount(
);
- const buttonYes = prompt.find( '.button' )
+ const buttonYes = prompt.find( 'Button' )
.filterWhere( node => node.text() === 'Yes' );
buttonYes.simulate( 'click' );
expect( window.setUserSetting )
.toHaveBeenCalledWith( 'gutenberg_tracking', 'on' );
- expect( tracking.bumpStat )
- .toHaveBeenCalledWith( 'tracking', 'opt-in' );
expect( removeNotice )
.toHaveBeenCalledWith( TRACKING_PROMPT_NOTICE_ID );
} );
@@ -65,15 +66,54 @@ describe( 'EnableTrackingPrompt', () => {
const prompt = mount(
);
- const buttonNo = prompt.find( '.button' )
+ const buttonNo = prompt.find( 'Button' )
.filterWhere( node => node.text() === 'No' );
buttonNo.simulate( 'click' );
expect( window.setUserSetting )
.toHaveBeenCalledWith( 'gutenberg_tracking', 'off' );
- expect( tracking.bumpStat )
- .not.toHaveBeenCalled();
expect( removeNotice )
.toHaveBeenCalledWith( TRACKING_PROMPT_NOTICE_ID );
} );
+
+ it( 'should show and hide a popover when clicking More info', () => {
+ const EnableTrackingPromptWrapped = clickOutside( EnableTrackingPrompt );
+ const prompt = mount(
+
+ );
+
+ expect( prompt.find( 'Popover' ).length ).toBe( 0 );
+
+ const buttonMoreInfo = prompt.find( 'Button' )
+ .filterWhere( node => node.text() === 'More info' );
+
+ // Click the "More info" button to show the info popover
+ buttonMoreInfo.simulate( 'click' );
+ expect( prompt.find( 'Popover' ).length ).toBe( 1 );
+
+ // Click the "More info" button to hide the info popover
+ buttonMoreInfo.simulate( 'click' );
+ expect( prompt.find( 'Popover' ).length ).toBe( 0 );
+
+ // Click the "More info" button to show the info popover
+ buttonMoreInfo.simulate( 'click' );
+ expect( prompt.find( 'Popover' ).length ).toBe( 1 );
+
+ // Click inside the prompt to hide the info popover
+ prompt.simulate( 'click' );
+ expect( prompt.find( 'Popover' ).length ).toBe( 0 );
+
+ // Click the "More info" button to show the info popover
+ buttonMoreInfo.simulate( 'click' );
+ expect( prompt.find( 'Popover' ).length ).toBe( 1 );
+
+ // Click outside the prompt to hide the info popover
+ eventMap.click( { target: document.body } );
+ expect( prompt.find( 'Popover' ).length ).toBe( 0 );
+
+ expect( window.setUserSetting )
+ .not.toHaveBeenCalled();
+ expect( removeNotice )
+ .not.toHaveBeenCalled();
+ } );
} );
diff --git a/editor/inserter/index.js b/editor/inserter/index.js
index aee767446526d2..84902061adf9f9 100644
--- a/editor/inserter/index.js
+++ b/editor/inserter/index.js
@@ -11,6 +11,7 @@ import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import { IconButton } from '@wordpress/components';
import { createBlock } from '@wordpress/blocks';
+import { bumpStat } from '@wordpress/utils';
/**
* Internal dependencies
@@ -18,7 +19,6 @@ import { createBlock } from '@wordpress/blocks';
import InserterMenu from './menu';
import { getBlockInsertionPoint, getEditorMode } from '../selectors';
import { insertBlock, hideInsertionPoint } from '../actions';
-import { bumpStat } from '../utils/tracking';
class Inserter extends Component {
constructor() {
diff --git a/editor/modes/visual-editor/block-list.js b/editor/modes/visual-editor/block-list.js
index 38f053917677c8..3c5dfbb520738b 100644
--- a/editor/modes/visual-editor/block-list.js
+++ b/editor/modes/visual-editor/block-list.js
@@ -12,7 +12,7 @@ import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import { serialize, getDefaultBlock, createBlock } from '@wordpress/blocks';
import { IconButton } from '@wordpress/components';
-import { keycodes } from '@wordpress/utils';
+import { keycodes, bumpStat } from '@wordpress/utils';
/**
* Internal dependencies
@@ -29,7 +29,6 @@ import {
getMultiSelectedBlockUids,
} from '../../selectors';
import { insertBlock, multiSelect } from '../../actions';
-import { bumpStat } from '../../utils/tracking';
const INSERTION_POINT_PLACEHOLDER = '[[insertion-point]]';
const { ENTER } = keycodes;
diff --git a/test/setup-globals.js b/test/setup-globals.js
index 931f6e146d7985..d5a8ed265c7899 100644
--- a/test/setup-globals.js
+++ b/test/setup-globals.js
@@ -51,3 +51,14 @@ global.wp = global.wp || {};
global.wp.a11y = {
speak: () => {},
};
+
+global.window.getUserSetting = settingName => {
+ switch ( settingName ) {
+ case 'gutenberg_tracking':
+ return 'on';
+ default:
+ throw new Error(
+ 'Unrecognized user setting requested: ' + settingName
+ );
+ }
+};
diff --git a/utils/index.js b/utils/index.js
index e24a5b1782f919..01b2b0a7b30bb3 100644
--- a/utils/index.js
+++ b/utils/index.js
@@ -3,3 +3,5 @@ import * as nodetypes from './nodetypes';
export { keycodes };
export { nodetypes };
+
+export * from './tracking';
diff --git a/editor/utils/test/tracking.js b/utils/test/tracking.js
similarity index 80%
rename from editor/utils/test/tracking.js
rename to utils/test/tracking.js
index 8c0b11f9f3a0cb..7fd360fe1b377a 100644
--- a/editor/utils/test/tracking.js
+++ b/utils/test/tracking.js
@@ -1,5 +1,10 @@
/* eslint-disable no-console */
+/**
+ * External dependencies
+ */
+import url from 'url';
+
/**
* Internal dependencies
*/
@@ -11,7 +16,6 @@ describe( 'bumpStat', () => {
beforeEach( () => {
console.error = jest.fn();
- window.getUserSetting = () => 'off';
} );
afterEach( () => {
@@ -62,22 +66,21 @@ describe( 'bumpStat', () => {
} );
it( 'should do nothing if the user has not opted in', () => {
+ window.getUserSetting = () => 'off';
expect( bumpStat( 'valid_group', 'valid-name' ) ).toBeUndefined();
expect( console.error ).not.toHaveBeenCalled();
} );
it( 'should bump valid stats', () => {
- window.getUserSetting = () => 'on';
- const url = bumpStat( 'valid_group', 'valid-name' );
- // 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:' )
- .replace( /t=[0-9.]+$/, 't=NUMBER' );
- expect( urlMatch ).toBe(
- 'PROTOCOL://pixel.wp.com/g.gif?v=wpcom-no-pv'
- + '&x_gutenberg_valid_group=valid-name'
- + '&t=NUMBER'
+ // Testing the URL protocol and the randomized `?t=` cache-buster is
+ // difficult, so only test the pieces we're actually interested in.
+ const statUrlPieces = url.parse(
+ bumpStat( 'valid_group', 'valid-name' ),
+ true
);
+ expect( statUrlPieces.hostname ).toBe( 'pixel.wp.com' );
+ expect( statUrlPieces.pathname ).toBe( '/g.gif' );
+ expect( statUrlPieces.query.v ).toBe( 'wpcom-no-pv' );
+ expect( statUrlPieces.query.x_gutenberg_valid_group ).toBe( 'valid-name' );
} );
} );
diff --git a/editor/utils/tracking.js b/utils/tracking.js
similarity index 100%
rename from editor/utils/tracking.js
rename to utils/tracking.js
diff --git a/webpack.config.js b/webpack.config.js
index d8ccb63b9a458e..72711d026f1b3a 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -37,13 +37,13 @@ const extractConfig = {
};
const entryPointNames = [
- 'element',
- 'i18n',
- 'components',
- 'utils',
'blocks',
+ 'components',
'date',
'editor',
+ 'element',
+ 'i18n',
+ 'utils',
];
const externals = {