From ac169043f84909bcf78cfc4518fdf96ea0481172 Mon Sep 17 00:00:00 2001 From: Connor Jennings Date: Fri, 10 Jan 2020 15:22:08 -0500 Subject: [PATCH] Modify notification box to better showcase user specific information --- .eslintignore | 1 + common/php/class-module.php | 11 +- .../notifications/dist/notifications.build.js | 2 + modules/notifications/lib/notifications.css | 30 ++- modules/notifications/lib/notifications.js | 221 ++++++++++++------ modules/notifications/notifications.php | 22 +- modules/user-groups/lib/user-groups.css | 9 +- package-lock.json | 41 +--- package.json | 1 + tests/e2e/config/setup-test-framework.js | 8 +- tests/e2e/config/users.js | 14 ++ tests/e2e/specs/simple.test.js | 6 +- .../e2e/specs/user-notifications-post.test.js | 86 +++++++ tests/e2e/util/index.js | 24 ++ webpack.config.js | 106 ++++++--- 15 files changed, 422 insertions(+), 160 deletions(-) create mode 100644 .eslintignore create mode 100644 modules/notifications/dist/notifications.build.js create mode 100644 tests/e2e/config/users.js create mode 100644 tests/e2e/specs/user-notifications-post.test.js create mode 100644 tests/e2e/util/index.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..a0777a2a3 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +*.build.js \ No newline at end of file diff --git a/common/php/class-module.php b/common/php/class-module.php index 0d7231d66..52c53e762 100644 --- a/common/php/class-module.php +++ b/common/php/class-module.php @@ -483,15 +483,20 @@ function users_select_form( $selected = null, $args = null ) { // Add a class to checkbox of current user so we know not to add them in notified list during notifiedMessage() js function $current_user_class = ( get_current_user_id() == $user->ID ) ? 'class="post_following_list-current_user" ' : ''; ?> -
  • +
  • diff --git a/modules/notifications/dist/notifications.build.js b/modules/notifications/dist/notifications.build.js new file mode 100644 index 000000000..561a8d115 --- /dev/null +++ b/modules/notifications/dist/notifications.build.js @@ -0,0 +1,2 @@ +!function(e){var t={};function r(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,r),n.l=!0,n.exports}r.m=e,r.c=t,r.d=function(e,t,o){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(r.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)r.d(o,n,function(t){return e[t]}.bind(null,n));return o},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t){var r="error",o={NO_ACCESS:{id:"no_access",name:ef_notifications_localization.no_access,status:r},NO_EMAIL:{id:"no_email",name:ef_notifications_localization.no_email,status:r},POST_AUTHOR:{id:"post_author",name:ef_notifications_localization.post_author,class:"ef-badge-neutral"},AUTO_SUBSCRIBE:{id:"auto_subscribed",name:ef_notifications_localization.auto_subscribed,class:"ef-badge-neutral"}},n=function(e,t){var r=e.find("[data-badge-id='".concat(t.id,"']"));return r.length?jQuery(r[0]):null},a=function(e,t){n(e,t)||e.append(function(e){var t="ef-user-badge";return r===e.status&&(t+=" ef-user-badge-error"),'
    ').concat(e.name,"
    ")}(t))},i=function(e,t){var r=n(e,t);r&&r.remove()};jQuery(document).ready(function(e){jQuery("#ef-post_following_users_box ul").listFilterizer();var t,r={action:"save_notifications",post_id:jQuery("#post_ID").val()};"undefined"!=typeof ef_post_author_id&&(t=jQuery("label[for='ef-selected-users-"+ef_post_author_id+"'] .ef-user-list-badges"),a(t,o.POST_AUTHOR));"undefined"!=typeof ef_post_author_auto_subscribe&&(!function(){var e=jQuery("label[for='ef-selected-users-"+ef_post_author_id+"'] .ef-user-list-badges");a(e,o.AUTO_SUBSCRIBE)}(),jQuery("#ef-selected-users-"+ef_post_author_id).prop("disabled",!0)),jQuery(document).on("click",".ef-post_following_list li input:checkbox, .ef-following_usergroups li input:checkbox",function(){var t=[],n=jQuery(this);r.ef_notifications_name=jQuery(this).attr("name"),r._nonce=jQuery("#ef_notifications_nonce").val(),jQuery(this).parents(".ef-post_following_list").find("input:checked").map(function(){t.push(jQuery(this).val())}),r.user_group_ids=t,e.ajax({type:"POST",url:ajaxurl||wpListL10n.url,data:r,success:function(e){var t=e.data.subscribers_with_no_access.includes(parseInt(jQuery(n).val(),10)),r=e.data.subscribers_with_no_email.includes(parseInt(jQuery(n).val(),10));!function(e,t){var r=t.userHasNoAccess,n=t.userHasNoEmail,s=jQuery(e).parent().closest("li").find(".ef-user-list-badges");r?a(s,o.NO_ACCESS):i(s,o.NO_ACCESS),n?a(s,o.NO_EMAIL):i(s,o.NO_EMAIL)}(jQuery(n),{userHasNoAccess:t,userHasNoEmail:r});var s="#90d296";(t||r)&&(s="#ea8484");jQuery(n.parents("label")).animate({backgroundColor:s},200).animate({backgroundColor:"transparent"},200),jQuery("#ef-post_following_box").trigger("following_list_updated")},error:function(){jQuery("#ef-post_following_users_box").prev().append('

    There was an error. Please reload the page.

    ')}})})})}]); +//# sourceMappingURL=notifications.build.js.map \ No newline at end of file diff --git a/modules/notifications/lib/notifications.css b/modules/notifications/lib/notifications.css index db9cccff2..e1446d40b 100644 --- a/modules/notifications/lib/notifications.css +++ b/modules/notifications/lib/notifications.css @@ -7,13 +7,17 @@ } .ef-post_following_list li { + border-bottom: 1px solid #ccc; +} + +.ef-post_following_list li label { + min-height: 76px; padding: 10px 5px 5px 5px; margin: 0; - border-bottom: 1px solid #ccc; - min-height: 36px; + display: block; } -.ef-post_following_list li:hover { +.ef-post_following_list li label:hover { background: #EAF2FA; } @@ -35,17 +39,21 @@ font-size: 12px; } -.ef-post_following_list li .ef-user-subscribe-actions { - float: right; - margin-top: 5px; +.ef-post_following_list li .ef-user-list-badges { + margin-top: 10px; } -.ef-post_following_list li .ef-user-subscribe-actions .post_following_list-no_email, -.ef-post_following_list li .ef-user-subscribe-actions .post_following_list-no_access { +.ef-post_following_list li .ef-user-badge { margin-right: 10px; - border: solid 2px #DC3232; - color: #DC3232; + border: solid 2px #b8b8b8; + color: #b8b8b8; padding: 4px; + display: inline-block; +} + +.ef-post_following_list li .ef-user-badge-error { + color: #DC3232; + border: solid 2px #DC3232; } #ef-post_following_box { @@ -107,4 +115,4 @@ #ef-usergroup-users h4 { margin-top: 0; -} +} \ No newline at end of file diff --git a/modules/notifications/lib/notifications.js b/modules/notifications/lib/notifications.js index 65b161915..6822c8216 100644 --- a/modules/notifications/lib/notifications.js +++ b/modules/notifications/lib/notifications.js @@ -1,80 +1,171 @@ -jQuery(document).ready(function($) { - $('#ef-post_following_users_box ul').listFilterizer(); +/* global wp, jQuery, ajaxurl, ef_notifications_localization, document, wpListL10n, ef_post_author_id */ - var params = { +const BADGES_STATUS = { + error: 'error', + warning: 'warning', + success: 'success', +}; + +const BADGES = { + NO_ACCESS: { + id: 'no_access', + name: ef_notifications_localization.no_access, + status: BADGES_STATUS.error, + }, + NO_EMAIL: { + id: 'no_email', + name: ef_notifications_localization.no_email, + status: BADGES_STATUS.error, + }, + POST_AUTHOR: { + id: 'post_author', + name: ef_notifications_localization.post_author, + class: 'ef-badge-neutral', + }, + AUTO_SUBSCRIBE: { + id: 'auto_subscribed', + name: ef_notifications_localization.auto_subscribed, + class: 'ef-badge-neutral', + }, +}; + +const getBadge = ( $el, badge ) => { + const exists = $el.find( `[data-badge-id='${ badge.id }']` ); + + if ( exists.length ) { + return jQuery( exists[ 0 ] ); + } + return null; +}; + +const badgeTemplate = badge => { + let classes = 'ef-user-badge'; + + if ( BADGES_STATUS.error === badge.status ) { + classes += ' ef-user-badge-error'; + } + + return `
    ${ badge.name }
    `; +}; + +const addBadgeToEl = ( $el, badge ) => { + if ( getBadge( $el, badge ) ) { + return; + } + + $el.append( badgeTemplate( badge ) ); +}; + +const removeBadgeFromEl = ( $el, badge ) => { + const existingBadge = getBadge( $el, badge ); + + if ( ! existingBadge ) { + return; + } + + existingBadge.remove(); +}; + +jQuery( document ).ready( function( $ ) { + jQuery( '#ef-post_following_users_box ul' ).listFilterizer(); + + const params = { action: 'save_notifications', - post_id: $('#post_ID').val(), + post_id: jQuery( '#post_ID' ).val(), }; - - var toggle_warning_badges = function( container, response ) { - // Remove any existing badges - if ( $( container ).siblings( 'span' ).length ) { - $( container ).siblings( 'span' ).remove(); - } - + + const toggleWarningBadges = function( container, { userHasNoAccess, userHasNoEmail } ) { + const $el = jQuery( container ).parent(); + const $badgesContainer = $el.closest( 'li' ).find( '.ef-user-list-badges' ); + // "No Access" If this user was flagged as not having access - var user_has_no_access = response.data.subscribers_with_no_access.includes( parseInt( $( container ).val() ) ); - if ( user_has_no_access ) { - var span = $( '' ).addClass( 'post_following_list-no_access' ); - span.text( ef_notifications_localization.no_access ); - $( container ).parent().prepend( span ); - warning_background = true; + if ( userHasNoAccess ) { + addBadgeToEl( $badgesContainer, BADGES.NO_ACCESS ); + } else { + removeBadgeFromEl( $badgesContainer, BADGES.NO_ACCESS ); } + // "No Email" If this user was flagged as not having an email - var user_has_no_email = response.data.subscribers_with_no_email.includes( parseInt( $( container ).val() ) ); - if ( user_has_no_email ) { - var span = $( '' ).addClass( 'post_following_list-no_email' ); - span.text( ef_notifications_localization.no_email ); - $( container ).parent().prepend( span ); - warning_background = true; + if ( userHasNoEmail ) { + addBadgeToEl( $badgesContainer, BADGES.NO_EMAIL ); + } else { + removeBadgeFromEl( $badgesContainer, BADGES.NO_EMAIL ); } + }; + + const show_post_author_badge = () => { + const $userListItemActions = jQuery( "label[for='ef-selected-users-" + ef_post_author_id + "'] .ef-user-list-badges" ); + addBadgeToEl( $userListItemActions, BADGES.POST_AUTHOR ); + }; + + /** + * Until assets are correctly loaded on their respective pages, `ef_post_author_id` should + * only have a value on a post page, so only execute `show_post_author_badge` if it has a value + */ + if ( 'undefined' !== typeof ef_post_author_id ) { + show_post_author_badge(); } - $(document).on('click','.ef-post_following_list li input:checkbox, .ef-following_usergroups li input:checkbox', function() { - var user_group_ids = []; - var parent_this = $(this); - params.ef_notifications_name = $(this).attr('name'); - params._nonce = $("#ef_notifications_nonce").val(); - - $(this) - .parents('.ef-post_following_list') - .find('input:checked') - .map(function(){ - user_group_ids.push($(this).val()); - }) - - params.user_group_ids = user_group_ids; - - $.ajax({ - type : 'POST', - url : (ajaxurl) ? ajaxurl : wpListL10n.url, - data : params, - - success : function( response ) { - // Reset background color (set during toggle_warning_badges if there's a warning) - warning_background = false; - + const showAutosubscribedBadge = () => { + const $userListItemActions = jQuery( "label[for='ef-selected-users-" + ef_post_author_id + "'] .ef-user-list-badges" ); + addBadgeToEl( $userListItemActions, BADGES.AUTO_SUBSCRIBE ); + }; + + const disableAutosubscribeCheckbox = () => { + jQuery( '#ef-selected-users-' + ef_post_author_id ).prop( 'disabled', true ); + }; + + if ( typeof ef_post_author_auto_subscribe !== 'undefined' ) { + showAutosubscribedBadge(); + disableAutosubscribeCheckbox(); + } + + jQuery( document ).on( 'click', '.ef-post_following_list li input:checkbox, .ef-following_usergroups li input:checkbox', function() { + const userGroupIds = []; + const checkbox = jQuery( this ); + params.ef_notifications_name = jQuery( this ).attr( 'name' ); + params._nonce = jQuery( '#ef_notifications_nonce' ).val(); + + jQuery( this ) + .parents( '.ef-post_following_list' ) + .find( 'input:checked' ) + .map( function() { + userGroupIds.push( jQuery( this ).val() ); + } ); + + params.user_group_ids = userGroupIds; + + $.ajax( { + type: 'POST', + url: ( ajaxurl ) ? ajaxurl : wpListL10n.url, + data: params, + + success: function( response ) { // Toggle the warning badges ("No Access" and "No Email") to signal the user won't receive notifications - if ( undefined !== response.data ) { - toggle_warning_badges( $( parent_this ), response ); - } + const userHasNoAccess = response.data.subscribers_with_no_access.includes( parseInt( jQuery( checkbox ).val(), 10 ) ); + const userHasNoEmail = response.data.subscribers_with_no_email.includes( parseInt( jQuery( checkbox ).val(), 10 ) ); + + toggleWarningBadges( jQuery( checkbox ), { userHasNoAccess, userHasNoEmail } ); + // Green 40% by default - var backgroundHighlightColor = "#90d296"; - if ( warning_background ) { + let backgroundHighlightColor = '#90d296'; + + if ( userHasNoAccess || userHasNoEmail ) { // Red 40% if there's a warning - var backgroundHighlightColor = "#ea8484"; + backgroundHighlightColor = '#ea8484'; } - var backgroundColor = parent_this.css( 'background-color' ); - $(parent_this.parents('li')) - .animate( { 'backgroundColor': backgroundHighlightColor }, 200 ) - .animate( { 'backgroundColor':backgroundColor }, 200 ); - + + const backgroundColor = 'transparent'; + jQuery( checkbox.parents( 'label' ) ) + .animate( { backgroundColor: backgroundHighlightColor }, 200 ) + .animate( { backgroundColor: backgroundColor }, 200 ); + // This event is used to show an updated list of who will be notified of editorial comments and status updates. - $( '#ef-post_following_box' ).trigger( 'following_list_updated' ); + jQuery( '#ef-post_following_box' ).trigger( 'following_list_updated' ); + }, + error: function() { + jQuery( '#ef-post_following_users_box' ).prev().append( '

    There was an error. Please reload the page.

    ' ); }, - error : function(r) { - $('#ef-post_following_users_box').prev().append('

    There was an error. Please reload the page.

    '); - } - }); - }); -}); \ No newline at end of file + } ); + } ); +} ); diff --git a/modules/notifications/notifications.php b/modules/notifications/notifications.php index 9b05baa74..f5086bf40 100644 --- a/modules/notifications/notifications.php +++ b/modules/notifications/notifications.php @@ -193,13 +193,15 @@ function enqueue_admin_scripts() { if ( $this->is_whitelisted_functional_view() ) { wp_enqueue_script( 'jquery-listfilterizer' ); wp_enqueue_script( 'jquery-quicksearch' ); - wp_enqueue_script( 'edit-flow-notifications-js', $this->module_url . 'lib/notifications.js', array( 'jquery', 'jquery-listfilterizer', 'jquery-quicksearch' ), EDIT_FLOW_VERSION, true ); + wp_enqueue_script( 'edit-flow-notifications-js', EDIT_FLOW_URL . 'modules/notifications/dist/notifications.build.js', array( 'jquery', 'jquery-listfilterizer', 'jquery-quicksearch' ), EDIT_FLOW_VERSION, true ); wp_localize_script( 'edit-flow-notifications-js', 'ef_notifications_localization', array( 'no_access' => esc_html__( 'No Access', 'edit-flow' ), - 'no_email' => esc_html__( 'No Email', 'edit-flow' ) + 'no_email' => esc_html__( 'No Email', 'edit-flow' ), + 'post_author' => esc_html__( 'Post Author', 'edit-flow' ), + 'auto_subscribed' => esc_html__( 'Auto-Subscribed', 'edit-flow' ), ) ); } @@ -343,6 +345,18 @@ function notifications_meta_box() {

    get_following_users( $post->ID, 'id' ); + + $post_author_is_follower = ! empty( in_array( $post->post_author, $followers ) ) ? 'true' : 'false'; + $post_author_auto_subscribe = apply_filters( 'ef_notification_auto_subscribe_post_author', true, 'subscription_action' ) ? 'true' : 'false'; + + wp_add_inline_script( + 'edit-flow-notifications-js', + 'var ef_post_author_id = ' . wp_json_encode( $post->post_author ) . '; ' . + 'var ef_post_author_is_follower = ' . wp_json_encode( $post_author_is_follower ) . '; ' . + 'var ef_post_author_auto_subscribe = ' . wp_json_encode( $post_author_auto_subscribe ) . ';', + 'before' + ); + $select_form_args = array( 'list_class' => 'ef-post_following_list', ); @@ -384,14 +398,14 @@ function display_subscriber_warning_badges( $user_id, $checked ) { // Add No Access span if they won't be notified if (! $this->user_can_be_notified( get_user_by( 'id', $user_id ), $post->ID )) { // span.post_following_list-no_access is also added in notifications.js after AJAX that ticks/unticks a user - echo '' . esc_html__( 'No Access', 'edit-flow' ) . ''; + echo '
    ' . esc_html__( 'No Access', 'edit-flow' ) . '
    '; } // Add No Email span if they have no email $user_object = get_user_by( 'id', $user_id ); if ( !is_a( $user_object, 'WP_User') OR empty( $user_object->user_email ) ) { // span.post_following_list-no_email is also added in notifications.js after AJAX that ticks/unticks a user - echo '' . esc_html__( 'No Email', 'edit-flow' ) . ''; + echo '
    ' . esc_html__( 'No Email', 'edit-flow' ) . '
    '; } } diff --git a/modules/user-groups/lib/user-groups.css b/modules/user-groups/lib/user-groups.css index 23a66ab34..5878d8b74 100644 --- a/modules/user-groups/lib/user-groups.css +++ b/modules/user-groups/lib/user-groups.css @@ -3,13 +3,14 @@ } .ef-post_following_list li { - padding: 10px 5px 5px 5px; margin: 0; border-bottom: 1px solid #ccc; } - .ef-post_following_list li:hover { - background: #EAF2FA; - } + + .ef-post_following_list li:hover { + background: #EAF2FA; + } + .ef-post_following_list li input { float: right; } diff --git a/package-lock.json b/package-lock.json index 73a530e3e..5918f6567 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11362,8 +11362,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -11384,14 +11383,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -11406,20 +11403,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -11536,8 +11530,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -11549,7 +11542,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -11564,7 +11556,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -11572,14 +11563,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -11598,7 +11587,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -11679,8 +11667,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -11692,7 +11679,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -11778,8 +11764,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -11815,7 +11800,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -11835,7 +11819,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -11879,14 +11862,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, diff --git a/package.json b/package.json index a3aa7f86e..d37fa0413 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "lint": "eslint --quiet -f json blocks common modules | eslines --quiet", "test": "echo \"Error: no test specified\" && exit 1", "test-e2e": "wp-scripts test-e2e --config tests/e2e/jest.config.js", + "debug-test-e2e": "ndb wp-scripts test-e2e --config tests/e2e/jest.config.js", "test-e2e:watch": "npm run test-e2e -- --watch", "test-unit-php": "wp-scripts env test-php" }, diff --git a/tests/e2e/config/setup-test-framework.js b/tests/e2e/config/setup-test-framework.js index 9ba6e1973..c0042f12c 100644 --- a/tests/e2e/config/setup-test-framework.js +++ b/tests/e2e/config/setup-test-framework.js @@ -7,7 +7,6 @@ import { get } from 'lodash'; * WordPress dependencies */ import { - activatePlugin, clearLocalStorage, enablePageDialogAccept, isOfflineMode, @@ -17,6 +16,9 @@ import { visitAdminPage, } from '@wordpress/e2e-test-utils'; +import { AUTHOR1 } from "./users"; +import { createUser } from "../util"; + /** * Environment variables */ @@ -206,6 +208,10 @@ async function runAxeTestsForBlockEditor() { // other posts/comments/etc. aren't dirtying tests and tests don't depend on // each other's side-effects. beforeAll( async () => { + await createUser(AUTHOR1.username, AUTHOR1.email, AUTHOR1.password); + + await visitAdminPage('edit.php'); + capturePageEventsForTearDown(); enablePageDialogAccept(); observeConsoleLogging(); diff --git a/tests/e2e/config/users.js b/tests/e2e/config/users.js new file mode 100644 index 000000000..6ff6ed616 --- /dev/null +++ b/tests/e2e/config/users.js @@ -0,0 +1,14 @@ +const AUTHOR1 = { + username: "author1", + email: "author1@test.com", + password: "author1" +} + +const ADMIN = { + username: "admin", + email: "test@test.com", + password: "password" +} + + +export { AUTHOR1, ADMIN }; \ No newline at end of file diff --git a/tests/e2e/specs/simple.test.js b/tests/e2e/specs/simple.test.js index 543163dfd..8f5a88b4b 100644 --- a/tests/e2e/specs/simple.test.js +++ b/tests/e2e/specs/simple.test.js @@ -6,13 +6,11 @@ import { visitAdminPage, switchUserToAdmin } from "@wordpress/e2e-test-utils"; describe("Edit Flow", () => { - beforeAll(async () => { - await visitAdminPage("admin.php", "page=ef-settings"); - }); it("the plugin settings page loads", async () => { + await visitAdminPage("admin.php", "page=ef-settings"); const editFlow = await page.$(".edit-flow-admin h2"); - const html = await page.evaluate(body => body.innerHTML, editFlow); + const html = await editFlow.evaluate(ef => ef.innerHTML); expect(html).toEqual("Edit Flow"); }); diff --git a/tests/e2e/specs/user-notifications-post.test.js b/tests/e2e/specs/user-notifications-post.test.js new file mode 100644 index 000000000..157fb0c06 --- /dev/null +++ b/tests/e2e/specs/user-notifications-post.test.js @@ -0,0 +1,86 @@ +/** + * WordPress dependencies + */ + +import { createNewPost } from "@wordpress/e2e-test-utils"; +import { AUTHOR1, ADMIN } from "../config/users"; + +describe("Post User Notifications Signup", () => { + + beforeAll(async () => { + await createNewPost(); + }); + + it("loads the user list", async () => { + const userList = await page.$('.ef-post_following_list'); + expect(await userList.$$eval('.ef-user_useremail', nodes => nodes.map(n => n.innerText))).toContain(AUTHOR1.email); + }); + + it("expects the user who created the post to be auto-subscribed and marked as author", async () => { + const userList = await page.$('.ef-post_following_list'); + + const users = await userList.$$eval('.ef-user-list-item', nodes => nodes.map(n => { + return { + userEmail: n.querySelector('.ef-user_useremail').innerText, + userBadges: [].slice.call(n.querySelectorAll('.ef-user-badge')).map(b => b.getAttribute('data-badge-id')), + } + })); + + expect(users.map((u => u.userEmail))).toContain(ADMIN.email); + expect(users.find(u => u.userEmail === ADMIN.email).userBadges).toContain("post_author"); + expect(users.find(u => u.userEmail === ADMIN.email).userBadges).toContain("auto_subscribed"); + }); + + it("expects the user who created the post to be uncheckable", async () => { + const userList = await page.$('.ef-post_following_list'); + + const users = await userList.$$eval('.ef-user-list-item', nodes => nodes.map(n => { + return { + userEmail: n.querySelector('.ef-user_useremail').innerText, + userBadges: [].slice.call(n.querySelectorAll('.ef-user-badge')).map(b => b.getAttribute('data-badge-id')), + } + })); + + expect(users.map((u => u.userEmail))).toContain(ADMIN.email); + expect(users.find(u => u.userEmail === ADMIN.email).userBadges).toContain("post_author"); + expect(users.find(u => u.userEmail === ADMIN.email).userBadges).toContain("auto_subscribed"); + }); + + it("expects the user who created the post to be uncheckable", async () => { + const userList = await page.$('.ef-post_following_list'); + + const postCreatorLabel = (await userList.$x(`//span[@class="ef-user_useremail" and contains(text(),"${ADMIN.email}")]/ancestor::label`)); + await postCreatorLabel[0].click(); + + const checkbox = await postCreatorLabel[0].$('input[type="checkbox"]') + + const isChecked = await (await checkbox.getProperty('checked')).jsonValue(); + + expect(isChecked).toBe(false); + }); + + it("expects a user who did not create the post to be checkable", async () => { + const userList = await page.$('.ef-post_following_list'); + + const notPostCreatorLabel = await userList.$x(`//span[@class="ef-user_useremail" and not(contains(text(),"test@test.com"))]/ancestor::label`); + await notPostCreatorLabel[0].click(); + + const checkbox = await notPostCreatorLabel[0].$('input[type="checkbox"]') + + const isChecked = await (await checkbox.getProperty('checked')).jsonValue(); + + expect(isChecked).toBe(true); + }); + + it("expects a user who does not have access to the post to have a No Access badge", async () => { + const userList = await page.$('.ef-post_following_list'); + + const notPostCreatorLabel = await userList.$x(`//span[@class="ef-user_useremail" and not(contains(text(),"test@test.com"))]/ancestor::label`); + await notPostCreatorLabel[0].click(); + + const noAccessBadge = await notPostCreatorLabel[0].$('.ef-user-badge-error') + + expect(noAccessBadge).not.toBe(null); + }); +}); + diff --git a/tests/e2e/util/index.js b/tests/e2e/util/index.js new file mode 100644 index 000000000..a40f2e412 --- /dev/null +++ b/tests/e2e/util/index.js @@ -0,0 +1,24 @@ +import { visitAdminPage, loginUser } from "@wordpress/e2e-test-utils"; + +async function createUser(username, email, password, role = 'author') { + await loginUser('admin', 'password'); + + await visitAdminPage('user-new.php'); + + await page.$eval('#user_login', (el, username) => el.value = username, username); + await page.$eval('#email', (el, email) => el.value = email, email); + + await page.click(".wp-generate-pw"); + + await page.$eval('#pass1', (el, password) => el.value = password, password); + await page.$eval('#pass2', (el, password) => el.value = password, password); + + await page.$eval('.pw-checkbox', (el) => el.checked = true); + + await page.select('#role', role); + + + await page.click("#createusersub"); +} + +export { createUser } \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index dc0d45394..b770b4aa7 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -33,42 +33,72 @@ var scssConfig = { ] }; -module.exports = { - context: __dirname, - devtool: debug ? 'sourcemap' : null, - mode: debug ? 'development' : 'production', - // entry: './blocks/src/blocks.js', - entry: entries, - output: { - path: __dirname + '/blocks/dist/', - filename: "[name].build.js" - }, - externals: { - 'react': "React", - "react-dom": "ReactDOM" - }, - module: { - rules: [ - { - test: /\.js$/, - exclude: /node_modules/, - use: [ - { - loader: 'babel-loader' - } - ] - }, - { - test: /editor\.scss$/, - exclude: /node_modules/, - use: extractEditorSCSS.extract(scssConfig) - }, - { - test: /style\.scss$/, - exclude: /node_modules/, - use: extractBlockSCSS.extract(scssConfig) - } - ] + +module.exports = [ + { + name: 'blocks', + context: __dirname, + devtool: debug ? 'sourcemap' : null, + mode: debug ? 'development' : 'production', + // entry: './blocks/src/blocks.js', + entry: entries, + output: { + path: __dirname + '/blocks/dist/', + filename: '[name].build.js' + }, + externals: { + 'react': "React", + 'react-dom': "ReactDOM" + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + use: [ + { + loader: 'babel-loader' + } + ] + }, + { + test: /editor\.scss$/, + exclude: /node_modules/, + use: extractEditorSCSS.extract(scssConfig) + }, + { + test: /style\.scss$/, + exclude: /node_modules/, + use: extractBlockSCSS.extract(scssConfig) + } + ] + }, + plugins: plugins }, - plugins: plugins -}; \ No newline at end of file + { + name: 'notifications', + context: __dirname, + devtool: debug ? 'sourcemap' : null, + mode: debug ? 'development' : 'production', + entry: { + notifications: __dirname + '/modules/notifications/lib/notifications.js', + }, + output: { + path: __dirname + '/modules/notifications/dist', + filename: '[name].build.js' + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + use: [ + { + loader: 'babel-loader' + } + ] + } + ] + } + } +];