diff --git a/.github/workflows/smoke-test-release.yml b/.github/workflows/smoke-test-release.yml
new file mode 100644
index 00000000000..83e0f287ac2
--- /dev/null
+++ b/.github/workflows/smoke-test-release.yml
@@ -0,0 +1,46 @@
+name: Smoke test release
+on:
+ release:
+ types: [published]
+jobs:
+ login-run:
+ name: Daily smoke test on release.
+ runs-on: ubuntu-18.04
+ steps:
+
+ - name: Create dirs.
+ run: |
+ mkdir -p code/woocommerce
+ mkdir -p package/woocommerce
+ mkdir -p tmp/woocommerce
+ mkdir -p node_modules
+
+ - name: Checkout code.
+ uses: actions/checkout@v2
+ with:
+ ref: trunk
+
+ - name: Install prerequisites.
+ run: |
+ npm install
+ composer install --no-dev
+ npm run build:assets
+ npm install jest
+
+ - name: Run smoke test.
+ env:
+ SMOKE_TEST_URL: ${{ secrets.RELEASE_TEST_URL }}
+ SMOKE_TEST_ADMIN_USER: ${{ secrets.RELEASE_TEST_ADMIN_USER }}
+ SMOKE_TEST_ADMIN_PASSWORD: ${{ secrets.RELEASE_TEST_ADMIN_PASSWORD }}
+ SMOKE_TEST_ADMIN_USER_EMAIL: ${{ secrets.RELEASE_TEST_ADMIN_USER_EMAIL }}
+ SMOKE_TEST_CUSTOMER_USER: ${{ secrets.RELEASE_TEST_CUSTOMER_USER }}
+ SMOKE_TEST_CUSTOMER_PASSWORD: ${{ secrets.RELEASE_TEST_CUSTOMER_PASSWORD }}
+ WC_E2E_SCREENSHOTS: 1
+ E2E_RETEST: 1
+ E2E_SLACK_TOKEN: ${{ secrets.SMOKE_TEST_SLACK_TOKEN }}
+ E2E_SLACK_CHANNEL: ${{ secrets.SMOKE_TEST_SLACK_CHANNEL }}
+ TEST_RELEASE: 1
+ UPDATE_WC: 1
+ run: |
+ npx wc-e2e test:e2e ./tests/e2e/specs/smoke-tests/update-woocommerce.js
+ npx wc-e2e test:e2e
diff --git a/.github/workflows/stalebot.yml b/.github/workflows/stalebot.yml
index 23c1a0eec6e..7257ea1b7ec 100644
--- a/.github/workflows/stalebot.yml
+++ b/.github/workflows/stalebot.yml
@@ -5,6 +5,8 @@ on:
jobs:
stale:
+ if: |
+ ! contains(github.event.issue.labels.*.name, 'enhancement')
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
diff --git a/assets/js/select2/select2.full.js b/assets/js/select2/select2.full.js
index d0776a6022b..e750834ef5d 100644
--- a/assets/js/select2/select2.full.js
+++ b/assets/js/select2/select2.full.js
@@ -1,41 +1,27 @@
/*!
- * SelectWoo 1.0.9
- * https://github.com/woocommerce/selectWoo
+ * Select2 4.0.3
+ * https://select2.github.io
*
* Released under the MIT license
- * https://github.com/woocommerce/selectWoo/blob/master/LICENSE.md
+ * https://github.com/select2/select2/blob/master/LICENSE.md
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
- } else if (typeof module === 'object' && module.exports) {
+ } else if (typeof exports === 'object') {
// Node/CommonJS
- module.exports = function (root, jQuery) {
- if (jQuery === undefined) {
- // require('jQuery') returns a factory that requires window to
- // build a jQuery instance, we normalize how we use modules
- // that require this pattern but the window provided is a noop
- // if it's defined (how jquery works)
- if (typeof window !== 'undefined') {
- jQuery = require('jquery');
- }
- else {
- jQuery = require('jquery')(root);
- }
- }
- factory(jQuery);
- return jQuery;
- };
+ factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
-} (function (jQuery) {
+}(function (jQuery) {
// This is needed so we can catch the AMD loader configuration and use it
// The inner file should be wrapped (by `banner.start.js`) in a function that
// returns the AMD loader references.
- var S2 =(function () {
+ var S2 =
+(function () {
// Restore the Select2 AMD loader so it can be used
// Needed mostly in the language files, where the loader is not inserted
if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
@@ -44,11 +30,13 @@
var S2;(function () { if (!S2 || !S2.requirejs) {
if (!S2) { S2 = {}; } else { require = S2; }
/**
- * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
- * Released under MIT license, http://github.com/requirejs/almond/LICENSE
+ * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/almond for details
*/
//Going sloppy to avoid 'use strict' string cost, but strict practices should
//be followed.
+/*jslint sloppy: true */
/*global setTimeout: false */
var requirejs, require, define;
@@ -76,58 +64,60 @@ var requirejs, require, define;
*/
function normalize(name, baseName) {
var nameParts, nameSegment, mapValue, foundMap, lastIndex,
- foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
+ foundI, foundStarMap, starI, i, j, part,
baseParts = baseName && baseName.split("/"),
map = config.map,
starMap = (map && map['*']) || {};
//Adjust any relative paths.
- if (name) {
- name = name.split('/');
- lastIndex = name.length - 1;
+ if (name && name.charAt(0) === ".") {
+ //If have a base name, try to normalize against it,
+ //otherwise, assume it is a top-level require that will
+ //be relative to baseUrl in the end.
+ if (baseName) {
+ name = name.split('/');
+ lastIndex = name.length - 1;
- // If wanting node ID compatibility, strip .js from end
- // of IDs. Have to do this here, and not in nameToUrl
- // because node allows either .js or non .js to map
- // to same file.
- if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
- name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
- }
+ // Node .js allowance:
+ if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
+ name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
+ }
- // Starts with a '.' so need the baseName
- if (name[0].charAt(0) === '.' && baseParts) {
- //Convert baseName to array, and lop off the last part,
- //so that . matches that 'directory' and not name of the baseName's
- //module. For instance, baseName of 'one/two/three', maps to
- //'one/two/three.js', but we want the directory, 'one/two' for
- //this normalization.
- normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
- name = normalizedBaseParts.concat(name);
- }
+ //Lop off the last part of baseParts, so that . matches the
+ //"directory" and not name of the baseName's module. For instance,
+ //baseName of "one/two/three", maps to "one/two/three.js", but we
+ //want the directory, "one/two" for this normalization.
+ name = baseParts.slice(0, baseParts.length - 1).concat(name);
- //start trimDots
- for (i = 0; i < name.length; i++) {
- part = name[i];
- if (part === '.') {
- name.splice(i, 1);
- i -= 1;
- } else if (part === '..') {
- // If at the start, or previous value is still ..,
- // keep them so that when converted to a path it may
- // still work when converted to a path, even though
- // as an ID it is less than ideal. In larger point
- // releases, may be better to just kick out an error.
- if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
- continue;
- } else if (i > 0) {
- name.splice(i - 1, 2);
- i -= 2;
+ //start trimDots
+ for (i = 0; i < name.length; i += 1) {
+ part = name[i];
+ if (part === ".") {
+ name.splice(i, 1);
+ i -= 1;
+ } else if (part === "..") {
+ if (i === 1 && (name[2] === '..' || name[0] === '..')) {
+ //End of the line. Keep at least one non-dot
+ //path segment at the front so it can be mapped
+ //correctly to disk. Otherwise, there is likely
+ //no path mapping for a path starting with '..'.
+ //This can still fail, but catches the most reasonable
+ //uses of ..
+ break;
+ } else if (i > 0) {
+ name.splice(i - 1, 2);
+ i -= 2;
+ }
}
}
- }
- //end trimDots
+ //end trimDots
- name = name.join('/');
+ name = name.join("/");
+ } else if (name.indexOf('./') === 0) {
+ // No baseName, so this is ID is resolved relative
+ // to baseUrl, pull off the leading dot.
+ name = name.substring(2);
+ }
}
//Apply map config if available.
@@ -240,39 +230,32 @@ var requirejs, require, define;
return [prefix, name];
}
- //Creates a parts array for a relName where first part is plugin ID,
- //second part is resource ID. Assumes relName has already been normalized.
- function makeRelParts(relName) {
- return relName ? splitPrefix(relName) : [];
- }
-
/**
* Makes a name map, normalizing the name, and using a plugin
* for normalization if necessary. Grabs a ref to plugin
* too, as an optimization.
*/
- makeMap = function (name, relParts) {
+ makeMap = function (name, relName) {
var plugin,
parts = splitPrefix(name),
- prefix = parts[0],
- relResourceName = relParts[1];
+ prefix = parts[0];
name = parts[1];
if (prefix) {
- prefix = normalize(prefix, relResourceName);
+ prefix = normalize(prefix, relName);
plugin = callDep(prefix);
}
//Normalize according
if (prefix) {
if (plugin && plugin.normalize) {
- name = plugin.normalize(name, makeNormalize(relResourceName));
+ name = plugin.normalize(name, makeNormalize(relName));
} else {
- name = normalize(name, relResourceName);
+ name = normalize(name, relName);
}
} else {
- name = normalize(name, relResourceName);
+ name = normalize(name, relName);
parts = splitPrefix(name);
prefix = parts[0];
name = parts[1];
@@ -319,14 +302,13 @@ var requirejs, require, define;
};
main = function (name, deps, callback, relName) {
- var cjsModule, depName, ret, map, i, relParts,
+ var cjsModule, depName, ret, map, i,
args = [],
callbackType = typeof callback,
usingExports;
//Use name if no relName
relName = relName || name;
- relParts = makeRelParts(relName);
//Call the callback to define the module, if necessary.
if (callbackType === 'undefined' || callbackType === 'function') {
@@ -335,7 +317,7 @@ var requirejs, require, define;
//Default to [require, exports, module] if no deps
deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
for (i = 0; i < deps.length; i += 1) {
- map = makeMap(deps[i], relParts);
+ map = makeMap(deps[i], relName);
depName = map.f;
//Fast path CommonJS standard dependencies.
@@ -391,7 +373,7 @@ var requirejs, require, define;
//deps arg is the module name, and second arg (if passed)
//is just the relName.
//Normalize module name, if it contains . or ..
- return callDep(makeMap(deps, makeRelParts(callback)).f);
+ return callDep(makeMap(deps, callback).f);
} else if (!deps.splice) {
//deps is a config object, not an array.
config = deps;
@@ -755,12 +737,6 @@ S2.define('select2/utils',[
});
};
- Utils.entityDecode = function (html) {
- var txt = document.createElement('textarea');
- txt.innerHTML = html;
- return txt.value;
- }
-
// Append an array of jQuery nodes to a given element.
Utils.appendMany = function ($element, $nodes) {
// jQuery 1.7.x does not support $.fn.append() with an array
@@ -778,14 +754,6 @@ S2.define('select2/utils',[
$element.append($nodes);
};
- // Determine whether the browser is on a touchscreen device.
- Utils.isTouchscreen = function() {
- if ('undefined' === typeof Utils._isTouchscreenCache) {
- Utils._isTouchscreenCache = 'ontouchstart' in document.documentElement;
- }
- return Utils._isTouchscreenCache;
- }
-
return Utils;
});
@@ -805,7 +773,7 @@ S2.define('select2/results',[
Results.prototype.render = function () {
var $results = $(
- '
'
+ '
'
);
if (this.options.get('multiple')) {
@@ -828,7 +796,7 @@ S2.define('select2/results',[
this.hideLoading();
var $message = $(
- ''
);
@@ -890,9 +858,9 @@ S2.define('select2/results',[
Results.prototype.highlightFirstItem = function () {
var $options = this.$results
- .find('.select2-results__option[data-selected]');
+ .find('.select2-results__option[aria-selected]');
- var $selected = $options.filter('[data-selected=true]');
+ var $selected = $options.filter('[aria-selected=true]');
// Check if there are any selected options
if ($selected.length > 0) {
@@ -916,7 +884,7 @@ S2.define('select2/results',[
});
var $options = self.$results
- .find('.select2-results__option[data-selected]');
+ .find('.select2-results__option[aria-selected]');
$options.each(function () {
var $option = $(this);
@@ -928,9 +896,9 @@ S2.define('select2/results',[
if ((item.element != null && item.element.selected) ||
(item.element == null && $.inArray(id, selectedIds) > -1)) {
- $option.attr('data-selected', 'true');
+ $option.attr('aria-selected', 'true');
} else {
- $option.attr('data-selected', 'false');
+ $option.attr('aria-selected', 'false');
}
});
@@ -962,18 +930,17 @@ S2.define('select2/results',[
option.className = 'select2-results__option';
var attrs = {
- 'role': 'option',
- 'data-selected': 'false',
- 'tabindex': -1
+ 'role': 'treeitem',
+ 'aria-selected': 'false'
};
if (data.disabled) {
- delete attrs['data-selected'];
+ delete attrs['aria-selected'];
attrs['aria-disabled'] = 'true';
}
if (data.id == null) {
- delete attrs['data-selected'];
+ delete attrs['aria-selected'];
}
if (data._resultId != null) {
@@ -985,8 +952,9 @@ S2.define('select2/results',[
}
if (data.children) {
+ attrs.role = 'group';
attrs['aria-label'] = data.text;
- delete attrs['data-selected'];
+ delete attrs['aria-selected'];
}
for (var attr in attrs) {
@@ -1003,7 +971,6 @@ S2.define('select2/results',[
var $label = $(label);
this.template(data, label);
- $label.attr('role', 'presentation');
var $children = [];
@@ -1016,11 +983,10 @@ S2.define('select2/results',[
}
var $childrenContainer = $('
', {
- 'class': 'select2-results__options select2-results__options--nested',
- 'role': 'listbox'
+ 'class': 'select2-results__options select2-results__options--nested'
});
+
$childrenContainer.append($children);
- $option.attr('role', 'list');
$option.append(label);
$option.append($childrenContainer);
@@ -1116,7 +1082,7 @@ S2.define('select2/results',[
var data = $highlighted.data('data');
- if ($highlighted.attr('data-selected') == 'true') {
+ if ($highlighted.attr('aria-selected') == 'true') {
self.trigger('close', {});
} else {
self.trigger('select', {
@@ -1128,7 +1094,7 @@ S2.define('select2/results',[
container.on('results:previous', function () {
var $highlighted = self.getHighlightedResults();
- var $options = self.$results.find('[data-selected]');
+ var $options = self.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
@@ -1162,7 +1128,7 @@ S2.define('select2/results',[
container.on('results:next', function () {
var $highlighted = self.getHighlightedResults();
- var $options = self.$results.find('[data-selected]');
+ var $options = self.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
@@ -1190,8 +1156,7 @@ S2.define('select2/results',[
});
container.on('results:focus', function (params) {
- params.element.addClass('select2-results__option--highlighted').attr('aria-selected', 'true');
- self.$results.attr('aria-activedescendant', params.element.attr('id'));
+ params.element.addClass('select2-results__option--highlighted');
});
container.on('results:message', function (params) {
@@ -1223,13 +1188,13 @@ S2.define('select2/results',[
});
}
- this.$results.on('mouseup', '.select2-results__option[data-selected]',
+ this.$results.on('mouseup', '.select2-results__option[aria-selected]',
function (evt) {
var $this = $(this);
var data = $this.data('data');
- if ($this.attr('data-selected') === 'true') {
+ if ($this.attr('aria-selected') === 'true') {
if (self.options.get('multiple')) {
self.trigger('unselect', {
originalEvent: evt,
@@ -1248,13 +1213,12 @@ S2.define('select2/results',[
});
});
- this.$results.on('mouseenter', '.select2-results__option[data-selected]',
+ this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
function (evt) {
var data = $(this).data('data');
self.getHighlightedResults()
- .removeClass('select2-results__option--highlighted')
- .attr('aria-selected', 'false');
+ .removeClass('select2-results__option--highlighted');
self.trigger('results:focus', {
data: data,
@@ -1281,7 +1245,7 @@ S2.define('select2/results',[
return;
}
- var $options = this.$results.find('[data-selected]');
+ var $options = this.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
@@ -1359,7 +1323,7 @@ S2.define('select2/selection/base',[
BaseSelection.prototype.render = function () {
var $selection = $(
- '' +
''
);
@@ -1385,7 +1349,6 @@ S2.define('select2/selection/base',[
var id = container.id + '-container';
var resultsId = container.id + '-results';
- var searchHidden = this.options.get('minimumResultsForSearch') === Infinity;
this.container = container;
@@ -1427,11 +1390,7 @@ S2.define('select2/selection/base',[
self.$selection.removeAttr('aria-activedescendant');
self.$selection.removeAttr('aria-owns');
- // This needs to be delayed as the active element is the body when the
- // key is pressed.
- window.setTimeout(function () {
- self.$selection.trigger( 'focus' );
- }, 1);
+ self.$selection.focus();
self._detachCloseHandler(container);
});
@@ -1481,14 +1440,8 @@ S2.define('select2/selection/base',[
}
var $element = $this.data('element');
- $element.select2('close');
- // Remove any focus when dropdown is closed by clicking outside the select area.
- // Timeout of 1 required for close to finish wrapping up.
- setTimeout(function(){
- $this.find('*:focus').blur();
- $target.focus();
- }, 1);
+ $element.select2('close');
});
});
};
@@ -1547,21 +1500,8 @@ S2.define('select2/selection/single',[
var id = container.id + '-container';
- this.$selection.find('.select2-selection__rendered')
- .attr('id', id)
- .attr('role', 'textbox')
- .attr('aria-readonly', 'true');
-
- var label = this.options.get( 'label' );
-
- if ( typeof( label ) === 'string' ) {
- this.$selection.attr( 'aria-label', label );
- } else {
- this.$selection.attr( 'aria-labelledby', id );
- }
-
- // This makes single non-search selects work in screen readers. If it causes problems elsewhere, remove.
- this.$selection.attr('role', 'combobox');
+ this.$selection.find('.select2-selection__rendered').attr('id', id);
+ this.$selection.attr('aria-labelledby', id);
this.$selection.on('mousedown', function (evt) {
// Only respond to left clicks
@@ -1578,20 +1518,13 @@ S2.define('select2/selection/single',[
// User focuses on the container
});
- this.$selection.on('keydown', function (evt) {
- // If user starts typing an alphanumeric key on the keyboard, open if not opened.
- if (!container.isOpen() && evt.which >= 48 && evt.which <= 90) {
- container.open();
- }
- });
-
this.$selection.on('blur', function (evt) {
// User exits the container
});
container.on('focus', function (evt) {
if (!container.isOpen()) {
- self.$selection.trigger( 'focus' );
+ self.$selection.focus();
}
});
@@ -1624,9 +1557,9 @@ S2.define('select2/selection/single',[
var selection = data[0];
var $rendered = this.$selection.find('.select2-selection__rendered');
- var formatted = Utils.entityDecode(this.display(selection, $rendered));
+ var formatted = this.display(selection, $rendered);
- $rendered.empty().text(formatted);
+ $rendered.empty().append(formatted);
$rendered.prop('title', selection.title || selection.text);
};
@@ -1650,7 +1583,7 @@ S2.define('select2/selection/multiple',[
$selection.addClass('select2-selection--multiple');
$selection.html(
- '
'
+ '
'
);
return $selection;
@@ -1687,18 +1620,6 @@ S2.define('select2/selection/multiple',[
});
}
);
-
- this.$selection.on('keydown', function (evt) {
- // If user starts typing an alphanumeric key on the keyboard, open if not opened.
- if (!container.isOpen() && evt.which >= 48 && evt.which <= 90) {
- container.open();
- }
- });
-
- // Focus on the search field when the container is focused instead of the main container.
- container.on( 'focus', function(){
- self.focusOnSearch();
- });
};
MultipleSelection.prototype.clear = function () {
@@ -1715,7 +1636,7 @@ S2.define('select2/selection/multiple',[
MultipleSelection.prototype.selectionContainer = function () {
var $container = $(
'
' +
- '' +
+ '' +
'×' +
'' +
'
'
@@ -1724,24 +1645,6 @@ S2.define('select2/selection/multiple',[
return $container;
};
- /**
- * Focus on the search field instead of the main multiselect container.
- */
- MultipleSelection.prototype.focusOnSearch = function() {
- var self = this;
-
- if ('undefined' !== typeof self.$search) {
- // Needs 1 ms delay because of other 1 ms setTimeouts when rendering.
- setTimeout(function(){
- // Prevent the dropdown opening again when focused from this.
- // This gets reset automatically when focus is triggered.
- self._keyUpPrevented = true;
-
- self.$search.focus();
- }, 1);
- }
- }
-
MultipleSelection.prototype.update = function (data) {
this.clear();
@@ -1755,14 +1658,9 @@ S2.define('select2/selection/multiple',[
var selection = data[d];
var $selection = this.selectionContainer();
- var removeItemTag = $selection.html();
var formatted = this.display(selection, $selection);
- if ('string' === typeof formatted) {
- formatted = Utils.entityDecode(formatted.trim());
- }
- $selection.text(formatted);
- $selection.prepend(removeItemTag);
+ $selection.append(formatted);
$selection.prop('title', selection.title || selection.text);
$selection.data('data', selection);
@@ -1801,7 +1699,7 @@ S2.define('select2/selection/placeholder',[
Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
var $placeholder = this.selectionContainer();
- $placeholder.text(Utils.entityDecode(this.display(placeholder)));
+ $placeholder.html(this.display(placeholder));
$placeholder.addClass('select2-selection__placeholder')
.removeClass('select2-selection__choice');
@@ -1938,8 +1836,8 @@ S2.define('select2/selection/search',[
Search.prototype.render = function (decorated) {
var $search = $(
'
' +
- '' +
'
'
);
@@ -1956,19 +1854,16 @@ S2.define('select2/selection/search',[
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
- var resultsId = container.id + '-results';
decorated.call(this, container, $container);
container.on('open', function () {
- self.$search.attr('aria-owns', resultsId);
self.$search.trigger('focus');
});
container.on('close', function () {
self.$search.val('');
self.$search.removeAttr('aria-activedescendant');
- self.$search.removeAttr('aria-owns');
self.$search.trigger('focus');
});
@@ -1987,7 +1882,7 @@ S2.define('select2/selection/search',[
});
container.on('results:focus', function (params) {
- self.$search.attr('aria-activedescendant', params.data._resultId);
+ self.$search.attr('aria-activedescendant', params.id);
});
this.$selection.on('focusin', '.select2-search--inline', function (evt) {
@@ -2018,9 +1913,6 @@ S2.define('select2/selection/search',[
evt.preventDefault();
}
- } else if (evt.which === KEYS.ENTER) {
- container.open();
- evt.preventDefault();
}
});
@@ -2109,7 +2001,7 @@ S2.define('select2/selection/search',[
this.resizeSearch();
if (searchHadFocus) {
- this.$search.trigger( 'focus' );
+ this.$search.focus();
}
};
@@ -3112,15 +3004,8 @@ S2.define('select2/data/base',[
};
BaseAdapter.prototype.generateResultId = function (container, data) {
- var id = '';
+ var id = container.id + '-result-';
- if (container != null) {
- id += container.id
- } else {
- id += Utils.generateChars(4);
- }
-
- id += '-result-';
id += Utils.generateChars(4);
if (data.id != null) {
@@ -3306,7 +3191,7 @@ S2.define('select2/data/select',[
}
}
- if (data.id !== undefined) {
+ if (data.id) {
option.value = data.id;
}
@@ -3404,7 +3289,7 @@ S2.define('select2/data/select',[
item.text = item.text.toString();
}
- if (item._resultId == null && item.id) {
+ if (item._resultId == null && item.id && this.container != null) {
item._resultId = this.generateResultId(this.container, item);
}
@@ -3547,7 +3432,7 @@ S2.define('select2/data/ajax',[
if (this._request != null) {
// JSONP requests cannot always be aborted
- if ( typeof this._request.abort === 'function' ) {
+ if ($.isFunction(this._request.abort)) {
this._request.abort();
}
@@ -3572,7 +3457,7 @@ S2.define('select2/data/ajax',[
if (self.options.get('debug') && window.console && console.error) {
// Check to make sure that the response included a `results` key.
- if (!results || !results.results || ! Array.isArray( results.results ) ) {
+ if (!results || !results.results || !$.isArray(results.results)) {
console.error(
'Select2: The AJAX results did not return an array in the ' +
'`results` key of the response.'
@@ -3581,7 +3466,6 @@ S2.define('select2/data/ajax',[
}
callback(results);
- self.container.focusOnActiveElement();
}, function () {
// Attempt to detect if a request was aborted
// Only works if the transport exposes a status property
@@ -3631,7 +3515,7 @@ S2.define('select2/data/tags',[
decorated.call(this, $element, options);
- if ( Array.isArray( tags ) ) {
+ if ($.isArray(tags)) {
for (var t = 0; t < tags.length; t++) {
var tag = tags[t];
var item = this._normalizeItem(tag);
@@ -3666,10 +3550,7 @@ S2.define('select2/data/tags',[
}, true)
);
- var optionText = (option.text || '').toUpperCase();
- var paramsTerm = (params.term || '').toUpperCase();
-
- var checkText = optionText === paramsTerm;
+ var checkText = option.text === params.term;
if (checkText || checkChildren) {
if (child) {
@@ -3707,7 +3588,7 @@ S2.define('select2/data/tags',[
};
Tags.prototype.createTag = function (decorated, params) {
- var term = ( params.term || 0 == params.term ) ? params.term.toString().trim() : '';
+ var term = $.trim(params.term);
if (term === '') {
return null;
@@ -3800,7 +3681,7 @@ S2.define('select2/data/tokenizer',[
// Replace the search term if we have the search box
if (this.$search.length) {
this.$search.val(tokenData.term);
- this.$search.trigger( 'focus' );
+ this.$search.focus();
}
params.term = tokenData.term;
@@ -4006,9 +3887,9 @@ S2.define('select2/dropdown/search',[
var $search = $(
'' +
- '' +
+ '' +
''
);
@@ -4022,7 +3903,6 @@ S2.define('select2/dropdown/search',[
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
- var resultsId = container.id + '-results';
decorated.call(this, container, $container);
@@ -4046,24 +3926,23 @@ S2.define('select2/dropdown/search',[
container.on('open', function () {
self.$search.attr('tabindex', 0);
- self.$search.attr('aria-owns', resultsId);
- self.$search.trigger( 'focus' );
+
+ self.$search.focus();
window.setTimeout(function () {
- self.$search.trigger( 'focus' );
+ self.$search.focus();
}, 0);
});
container.on('close', function () {
self.$search.attr('tabindex', -1);
- self.$search.removeAttr('aria-activedescendant');
- self.$search.removeAttr('aria-owns');
+
self.$search.val('');
});
container.on('focus', function () {
- if (!container.isOpen()) {
- self.$search.trigger( 'focus' );
+ if (container.isOpen()) {
+ self.$search.focus();
}
});
@@ -4078,10 +3957,6 @@ S2.define('select2/dropdown/search',[
}
}
});
-
- container.on('results:focus', function (params) {
- self.$search.attr('aria-activedescendant', params.data._resultId);
- });
};
Search.prototype.handleSearch = function (evt) {
@@ -4223,7 +4098,7 @@ S2.define('select2/dropdown/infiniteScroll',[
var $option = $(
''
+ 'role="treeitem" aria-disabled="true">'
);
var message = this.options.get('translations').get('loadingMore');
@@ -4878,7 +4753,7 @@ S2.define('select2/defaults',[
}
}
- if ( Array.isArray( options.language ) ) {
+ if ($.isArray(options.language)) {
var languages = new Translation();
options.language.push('en');
@@ -4941,7 +4816,7 @@ S2.define('select2/defaults',[
function matcher (params, data) {
// Always return the object if there is nothing to compare
- if ( params.term == null || params.term.toString().trim() === '' ) {
+ if ($.trim(params.term) === '') {
return data;
}
@@ -5469,22 +5344,16 @@ S2.define('select2/core',[
});
});
- this.on('open', function(){
- // Focus on the active element when opening dropdown.
- // Needs 1 ms delay because of other 1 ms setTimeouts when rendering.
- setTimeout(function(){
- self.focusOnActiveElement();
- }, 1);
- });
-
- $(document).on('keydown', function (evt) {
+ this.on('keypress', function (evt) {
var key = evt.which;
+
if (self.isOpen()) {
- if (key === KEYS.ESC || (key === KEYS.UP && evt.altKey)) {
+ if (key === KEYS.ESC || key === KEYS.TAB ||
+ (key === KEYS.UP && evt.altKey)) {
self.close();
evt.preventDefault();
- } else if (key === KEYS.ENTER || key === KEYS.TAB) {
+ } else if (key === KEYS.ENTER) {
self.trigger('results:select', {});
evt.preventDefault();
@@ -5501,42 +5370,17 @@ S2.define('select2/core',[
evt.preventDefault();
}
-
- var $searchField = self.$dropdown.find('.select2-search__field');
- if (! $searchField.length) {
- $searchField = self.$container.find('.select2-search__field');
- }
-
- // Move the focus to the selected element on keyboard navigation.
- // Required for screen readers to work properly.
- if (key === KEYS.DOWN || key === KEYS.UP) {
- self.focusOnActiveElement();
- } else {
- // Focus on the search if user starts typing.
- $searchField.focus();
- // Focus back to active selection when finished typing.
- // Small delay so typed character can be read by screen reader.
- setTimeout(function(){
- self.focusOnActiveElement();
- }, 1000);
- }
- } else if (self.hasFocus()) {
+ } else {
if (key === KEYS.ENTER || key === KEYS.SPACE ||
- key === KEYS.DOWN) {
+ (key === KEYS.DOWN && evt.altKey)) {
self.open();
+
evt.preventDefault();
}
}
});
};
- Select2.prototype.focusOnActiveElement = function () {
- // Don't mess with the focus on touchscreens because it causes havoc with on-screen keyboards.
- if (this.isOpen() && ! Utils.isTouchscreen()) {
- this.$results.find('li.select2-results__option--highlighted').focus();
- }
- };
-
Select2.prototype._syncAttributes = function () {
this.options.set('disabled', this.$element.prop('disabled'));
@@ -5724,7 +5568,7 @@ S2.define('select2/core',[
var newVal = args[0];
- if ( Array.isArray( newVal ) ) {
+ if ($.isArray(newVal)) {
newVal = $.map(newVal, function (obj) {
return obj.toString();
});
@@ -5801,7 +5645,7 @@ S2.define('select2/compat/utils',[
function syncCssClasses ($dest, $src, adapter) {
var classes, replacements = [], adapted;
- classes = ( $dest.attr('class') || 0 == $dest.attr('class') ) ? $dest.attr('class').toString().trim() : '';
+ classes = $.trim($dest.attr('class'));
if (classes) {
classes = '' + classes; // for IE which returns object
@@ -5814,7 +5658,7 @@ S2.define('select2/compat/utils',[
});
}
- classes = ( $src.attr('class') || 0 == $src.attr('class') ) ? $src.attr('class').toString().trim() : '';
+ classes = $.trim($src.attr('class'));
if (classes) {
classes = '' + classes; // for IE which returns object
@@ -5855,7 +5699,7 @@ S2.define('select2/compat/containerCss',[
var containerCssClass = this.options.get('containerCssClass') || '';
- if ( typeof containerCssClass === 'function' ) {
+ if ($.isFunction(containerCssClass)) {
containerCssClass = containerCssClass(this.$element);
}
@@ -5881,7 +5725,7 @@ S2.define('select2/compat/containerCss',[
var containerCss = this.options.get('containerCss') || {};
- if ( typeof containerCss === 'function' ) {
+ if ($.isFunction(containerCss)) {
containerCss = containerCss(this.$element);
}
@@ -5912,7 +5756,7 @@ S2.define('select2/compat/dropdownCss',[
var dropdownCssClass = this.options.get('dropdownCssClass') || '';
- if ( typeof dropdownCssClass === 'function' ) {
+ if ($.isFunction(dropdownCssClass)) {
dropdownCssClass = dropdownCssClass(this.$element);
}
@@ -5938,7 +5782,7 @@ S2.define('select2/compat/dropdownCss',[
var dropdownCss = this.options.get('dropdownCss') || {};
- if ( typeof dropdownCss === 'function' ) {
+ if ($.isFunction(dropdownCss)) {
dropdownCss = dropdownCss(this.$element);
}
@@ -5985,7 +5829,7 @@ S2.define('select2/compat/initSelection',[
this.initSelection.call(null, this.$element, function (data) {
self._isInitialized = true;
- if ( ! Array.isArray( data ) ) {
+ if (!$.isArray(data)) {
data = [data];
}
@@ -6131,7 +5975,7 @@ S2.define('select2/compat/matcher',[
function wrappedMatcher (params, data) {
var match = $.extend(true, {}, data);
- if ( params.term == null || params.term.trim() === '' ) {
+ if (params.term == null || $.trim(params.term) === '') {
return match;
}
@@ -6374,11 +6218,11 @@ S2.define('select2/selection/stopPropagation',[
$.fn.extend({
mousewheel: function(fn) {
- return fn ? this.on('mousewheel', fn) : this.trigger('mousewheel');
+ return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
},
unmousewheel: function(fn) {
- return this.off('mousewheel', fn);
+ return this.unbind('mousewheel', fn);
}
});
@@ -6520,11 +6364,11 @@ S2.define('jquery.select2',[
'./select2/core',
'./select2/defaults'
], function ($, _, Select2, Defaults) {
- if ($.fn.selectWoo == null) {
+ if ($.fn.select2 == null) {
// All methods that should return the element
var thisMethods = ['open', 'close', 'destroy'];
- $.fn.selectWoo = function (options) {
+ $.fn.select2 = function (options) {
options = options || {};
if (typeof options === 'object') {
@@ -6564,17 +6408,10 @@ S2.define('jquery.select2',[
};
}
- if ($.fn.select2 != null && $.fn.select2.defaults != null) {
- $.fn.selectWoo.defaults = $.fn.select2.defaults;
+ if ($.fn.select2.defaults == null) {
+ $.fn.select2.defaults = Defaults;
}
- if ($.fn.selectWoo.defaults == null) {
- $.fn.selectWoo.defaults = Defaults;
- }
-
- // Also register selectWoo under select2 if select2 is not already present.
- $.fn.select2 = $.fn.select2 || $.fn.selectWoo;
-
return Select2;
});
@@ -6593,7 +6430,6 @@ S2.define('jquery.select2',[
// This allows Select2 to use the internal loader outside of this file, such
// as in the language files.
jQuery.fn.select2.amd = S2;
- jQuery.fn.selectWoo.amd = S2;
// Return the Select2 instance for anyone who is importing it.
return select2;
diff --git a/assets/js/select2/select2.js b/assets/js/select2/select2.js
index f0e059f17d3..13b84fadff6 100644
--- a/assets/js/select2/select2.js
+++ b/assets/js/select2/select2.js
@@ -1,41 +1,27 @@
/*!
- * SelectWoo 1.0.9
- * https://github.com/woocommerce/selectWoo
+ * Select2 4.0.3
+ * https://select2.github.io
*
* Released under the MIT license
- * https://github.com/woocommerce/selectWoo/blob/master/LICENSE.md
+ * https://github.com/select2/select2/blob/master/LICENSE.md
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
- } else if (typeof module === 'object' && module.exports) {
+ } else if (typeof exports === 'object') {
// Node/CommonJS
- module.exports = function (root, jQuery) {
- if (jQuery === undefined) {
- // require('jQuery') returns a factory that requires window to
- // build a jQuery instance, we normalize how we use modules
- // that require this pattern but the window provided is a noop
- // if it's defined (how jquery works)
- if (typeof window !== 'undefined') {
- jQuery = require('jquery');
- }
- else {
- jQuery = require('jquery')(root);
- }
- }
- factory(jQuery);
- return jQuery;
- };
+ factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
-} (function (jQuery) {
+}(function (jQuery) {
// This is needed so we can catch the AMD loader configuration and use it
// The inner file should be wrapped (by `banner.start.js`) in a function that
// returns the AMD loader references.
- var S2 =(function () {
+ var S2 =
+(function () {
// Restore the Select2 AMD loader so it can be used
// Needed mostly in the language files, where the loader is not inserted
if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
@@ -44,11 +30,13 @@
var S2;(function () { if (!S2 || !S2.requirejs) {
if (!S2) { S2 = {}; } else { require = S2; }
/**
- * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
- * Released under MIT license, http://github.com/requirejs/almond/LICENSE
+ * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/almond for details
*/
//Going sloppy to avoid 'use strict' string cost, but strict practices should
//be followed.
+/*jslint sloppy: true */
/*global setTimeout: false */
var requirejs, require, define;
@@ -76,58 +64,60 @@ var requirejs, require, define;
*/
function normalize(name, baseName) {
var nameParts, nameSegment, mapValue, foundMap, lastIndex,
- foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
+ foundI, foundStarMap, starI, i, j, part,
baseParts = baseName && baseName.split("/"),
map = config.map,
starMap = (map && map['*']) || {};
//Adjust any relative paths.
- if (name) {
- name = name.split('/');
- lastIndex = name.length - 1;
+ if (name && name.charAt(0) === ".") {
+ //If have a base name, try to normalize against it,
+ //otherwise, assume it is a top-level require that will
+ //be relative to baseUrl in the end.
+ if (baseName) {
+ name = name.split('/');
+ lastIndex = name.length - 1;
- // If wanting node ID compatibility, strip .js from end
- // of IDs. Have to do this here, and not in nameToUrl
- // because node allows either .js or non .js to map
- // to same file.
- if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
- name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
- }
+ // Node .js allowance:
+ if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
+ name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
+ }
- // Starts with a '.' so need the baseName
- if (name[0].charAt(0) === '.' && baseParts) {
- //Convert baseName to array, and lop off the last part,
- //so that . matches that 'directory' and not name of the baseName's
- //module. For instance, baseName of 'one/two/three', maps to
- //'one/two/three.js', but we want the directory, 'one/two' for
- //this normalization.
- normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
- name = normalizedBaseParts.concat(name);
- }
+ //Lop off the last part of baseParts, so that . matches the
+ //"directory" and not name of the baseName's module. For instance,
+ //baseName of "one/two/three", maps to "one/two/three.js", but we
+ //want the directory, "one/two" for this normalization.
+ name = baseParts.slice(0, baseParts.length - 1).concat(name);
- //start trimDots
- for (i = 0; i < name.length; i++) {
- part = name[i];
- if (part === '.') {
- name.splice(i, 1);
- i -= 1;
- } else if (part === '..') {
- // If at the start, or previous value is still ..,
- // keep them so that when converted to a path it may
- // still work when converted to a path, even though
- // as an ID it is less than ideal. In larger point
- // releases, may be better to just kick out an error.
- if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
- continue;
- } else if (i > 0) {
- name.splice(i - 1, 2);
- i -= 2;
+ //start trimDots
+ for (i = 0; i < name.length; i += 1) {
+ part = name[i];
+ if (part === ".") {
+ name.splice(i, 1);
+ i -= 1;
+ } else if (part === "..") {
+ if (i === 1 && (name[2] === '..' || name[0] === '..')) {
+ //End of the line. Keep at least one non-dot
+ //path segment at the front so it can be mapped
+ //correctly to disk. Otherwise, there is likely
+ //no path mapping for a path starting with '..'.
+ //This can still fail, but catches the most reasonable
+ //uses of ..
+ break;
+ } else if (i > 0) {
+ name.splice(i - 1, 2);
+ i -= 2;
+ }
}
}
- }
- //end trimDots
+ //end trimDots
- name = name.join('/');
+ name = name.join("/");
+ } else if (name.indexOf('./') === 0) {
+ // No baseName, so this is ID is resolved relative
+ // to baseUrl, pull off the leading dot.
+ name = name.substring(2);
+ }
}
//Apply map config if available.
@@ -240,39 +230,32 @@ var requirejs, require, define;
return [prefix, name];
}
- //Creates a parts array for a relName where first part is plugin ID,
- //second part is resource ID. Assumes relName has already been normalized.
- function makeRelParts(relName) {
- return relName ? splitPrefix(relName) : [];
- }
-
/**
* Makes a name map, normalizing the name, and using a plugin
* for normalization if necessary. Grabs a ref to plugin
* too, as an optimization.
*/
- makeMap = function (name, relParts) {
+ makeMap = function (name, relName) {
var plugin,
parts = splitPrefix(name),
- prefix = parts[0],
- relResourceName = relParts[1];
+ prefix = parts[0];
name = parts[1];
if (prefix) {
- prefix = normalize(prefix, relResourceName);
+ prefix = normalize(prefix, relName);
plugin = callDep(prefix);
}
//Normalize according
if (prefix) {
if (plugin && plugin.normalize) {
- name = plugin.normalize(name, makeNormalize(relResourceName));
+ name = plugin.normalize(name, makeNormalize(relName));
} else {
- name = normalize(name, relResourceName);
+ name = normalize(name, relName);
}
} else {
- name = normalize(name, relResourceName);
+ name = normalize(name, relName);
parts = splitPrefix(name);
prefix = parts[0];
name = parts[1];
@@ -319,14 +302,13 @@ var requirejs, require, define;
};
main = function (name, deps, callback, relName) {
- var cjsModule, depName, ret, map, i, relParts,
+ var cjsModule, depName, ret, map, i,
args = [],
callbackType = typeof callback,
usingExports;
//Use name if no relName
relName = relName || name;
- relParts = makeRelParts(relName);
//Call the callback to define the module, if necessary.
if (callbackType === 'undefined' || callbackType === 'function') {
@@ -335,7 +317,7 @@ var requirejs, require, define;
//Default to [require, exports, module] if no deps
deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
for (i = 0; i < deps.length; i += 1) {
- map = makeMap(deps[i], relParts);
+ map = makeMap(deps[i], relName);
depName = map.f;
//Fast path CommonJS standard dependencies.
@@ -391,7 +373,7 @@ var requirejs, require, define;
//deps arg is the module name, and second arg (if passed)
//is just the relName.
//Normalize module name, if it contains . or ..
- return callDep(makeMap(deps, makeRelParts(callback)).f);
+ return callDep(makeMap(deps, callback).f);
} else if (!deps.splice) {
//deps is a config object, not an array.
config = deps;
@@ -755,12 +737,6 @@ S2.define('select2/utils',[
});
};
- Utils.entityDecode = function (html) {
- var txt = document.createElement('textarea');
- txt.innerHTML = html;
- return txt.value;
- }
-
// Append an array of jQuery nodes to a given element.
Utils.appendMany = function ($element, $nodes) {
// jQuery 1.7.x does not support $.fn.append() with an array
@@ -778,14 +754,6 @@ S2.define('select2/utils',[
$element.append($nodes);
};
- // Determine whether the browser is on a touchscreen device.
- Utils.isTouchscreen = function() {
- if ('undefined' === typeof Utils._isTouchscreenCache) {
- Utils._isTouchscreenCache = 'ontouchstart' in document.documentElement;
- }
- return Utils._isTouchscreenCache;
- }
-
return Utils;
});
@@ -805,7 +773,7 @@ S2.define('select2/results',[
Results.prototype.render = function () {
var $results = $(
- '
'
+ '
'
);
if (this.options.get('multiple')) {
@@ -828,7 +796,7 @@ S2.define('select2/results',[
this.hideLoading();
var $message = $(
- ''
);
@@ -890,9 +858,9 @@ S2.define('select2/results',[
Results.prototype.highlightFirstItem = function () {
var $options = this.$results
- .find('.select2-results__option[data-selected]');
+ .find('.select2-results__option[aria-selected]');
- var $selected = $options.filter('[data-selected=true]');
+ var $selected = $options.filter('[aria-selected=true]');
// Check if there are any selected options
if ($selected.length > 0) {
@@ -916,7 +884,7 @@ S2.define('select2/results',[
});
var $options = self.$results
- .find('.select2-results__option[data-selected]');
+ .find('.select2-results__option[aria-selected]');
$options.each(function () {
var $option = $(this);
@@ -928,9 +896,9 @@ S2.define('select2/results',[
if ((item.element != null && item.element.selected) ||
(item.element == null && $.inArray(id, selectedIds) > -1)) {
- $option.attr('data-selected', 'true');
+ $option.attr('aria-selected', 'true');
} else {
- $option.attr('data-selected', 'false');
+ $option.attr('aria-selected', 'false');
}
});
@@ -962,18 +930,17 @@ S2.define('select2/results',[
option.className = 'select2-results__option';
var attrs = {
- 'role': 'option',
- 'data-selected': 'false',
- 'tabindex': -1
+ 'role': 'treeitem',
+ 'aria-selected': 'false'
};
if (data.disabled) {
- delete attrs['data-selected'];
+ delete attrs['aria-selected'];
attrs['aria-disabled'] = 'true';
}
if (data.id == null) {
- delete attrs['data-selected'];
+ delete attrs['aria-selected'];
}
if (data._resultId != null) {
@@ -985,8 +952,9 @@ S2.define('select2/results',[
}
if (data.children) {
+ attrs.role = 'group';
attrs['aria-label'] = data.text;
- delete attrs['data-selected'];
+ delete attrs['aria-selected'];
}
for (var attr in attrs) {
@@ -1003,7 +971,6 @@ S2.define('select2/results',[
var $label = $(label);
this.template(data, label);
- $label.attr('role', 'presentation');
var $children = [];
@@ -1016,11 +983,10 @@ S2.define('select2/results',[
}
var $childrenContainer = $('
', {
- 'class': 'select2-results__options select2-results__options--nested',
- 'role': 'listbox'
+ 'class': 'select2-results__options select2-results__options--nested'
});
+
$childrenContainer.append($children);
- $option.attr('role', 'list');
$option.append(label);
$option.append($childrenContainer);
@@ -1116,7 +1082,7 @@ S2.define('select2/results',[
var data = $highlighted.data('data');
- if ($highlighted.attr('data-selected') == 'true') {
+ if ($highlighted.attr('aria-selected') == 'true') {
self.trigger('close', {});
} else {
self.trigger('select', {
@@ -1128,7 +1094,7 @@ S2.define('select2/results',[
container.on('results:previous', function () {
var $highlighted = self.getHighlightedResults();
- var $options = self.$results.find('[data-selected]');
+ var $options = self.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
@@ -1162,7 +1128,7 @@ S2.define('select2/results',[
container.on('results:next', function () {
var $highlighted = self.getHighlightedResults();
- var $options = self.$results.find('[data-selected]');
+ var $options = self.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
@@ -1190,8 +1156,7 @@ S2.define('select2/results',[
});
container.on('results:focus', function (params) {
- params.element.addClass('select2-results__option--highlighted').attr('aria-selected', 'true');
- self.$results.attr('aria-activedescendant', params.element.attr('id'));
+ params.element.addClass('select2-results__option--highlighted');
});
container.on('results:message', function (params) {
@@ -1223,13 +1188,13 @@ S2.define('select2/results',[
});
}
- this.$results.on('mouseup', '.select2-results__option[data-selected]',
+ this.$results.on('mouseup', '.select2-results__option[aria-selected]',
function (evt) {
var $this = $(this);
var data = $this.data('data');
- if ($this.attr('data-selected') === 'true') {
+ if ($this.attr('aria-selected') === 'true') {
if (self.options.get('multiple')) {
self.trigger('unselect', {
originalEvent: evt,
@@ -1248,13 +1213,12 @@ S2.define('select2/results',[
});
});
- this.$results.on('mouseenter', '.select2-results__option[data-selected]',
+ this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
function (evt) {
var data = $(this).data('data');
self.getHighlightedResults()
- .removeClass('select2-results__option--highlighted')
- .attr('aria-selected', 'false');
+ .removeClass('select2-results__option--highlighted');
self.trigger('results:focus', {
data: data,
@@ -1281,7 +1245,7 @@ S2.define('select2/results',[
return;
}
- var $options = this.$results.find('[data-selected]');
+ var $options = this.$results.find('[aria-selected]');
var currentIndex = $options.index($highlighted);
@@ -1359,7 +1323,7 @@ S2.define('select2/selection/base',[
BaseSelection.prototype.render = function () {
var $selection = $(
- '' +
''
);
@@ -1385,7 +1349,6 @@ S2.define('select2/selection/base',[
var id = container.id + '-container';
var resultsId = container.id + '-results';
- var searchHidden = this.options.get('minimumResultsForSearch') === Infinity;
this.container = container;
@@ -1427,11 +1390,7 @@ S2.define('select2/selection/base',[
self.$selection.removeAttr('aria-activedescendant');
self.$selection.removeAttr('aria-owns');
- // This needs to be delayed as the active element is the body when the
- // key is pressed.
- window.setTimeout(function () {
- self.$selection.trigger( 'focus' );
- }, 1);
+ self.$selection.focus();
self._detachCloseHandler(container);
});
@@ -1481,14 +1440,8 @@ S2.define('select2/selection/base',[
}
var $element = $this.data('element');
- $element.select2('close');
- // Remove any focus when dropdown is closed by clicking outside the select area.
- // Timeout of 1 required for close to finish wrapping up.
- setTimeout(function(){
- $this.find('*:focus').blur();
- $target.focus();
- }, 1);
+ $element.select2('close');
});
});
};
@@ -1547,21 +1500,8 @@ S2.define('select2/selection/single',[
var id = container.id + '-container';
- this.$selection.find('.select2-selection__rendered')
- .attr('id', id)
- .attr('role', 'textbox')
- .attr('aria-readonly', 'true');
-
- var label = this.options.get( 'label' );
-
- if ( typeof( label ) === 'string' ) {
- this.$selection.attr( 'aria-label', label );
- } else {
- this.$selection.attr( 'aria-labelledby', id );
- }
-
- // This makes single non-search selects work in screen readers. If it causes problems elsewhere, remove.
- this.$selection.attr('role', 'combobox');
+ this.$selection.find('.select2-selection__rendered').attr('id', id);
+ this.$selection.attr('aria-labelledby', id);
this.$selection.on('mousedown', function (evt) {
// Only respond to left clicks
@@ -1578,20 +1518,13 @@ S2.define('select2/selection/single',[
// User focuses on the container
});
- this.$selection.on('keydown', function (evt) {
- // If user starts typing an alphanumeric key on the keyboard, open if not opened.
- if (!container.isOpen() && evt.which >= 48 && evt.which <= 90) {
- container.open();
- }
- });
-
this.$selection.on('blur', function (evt) {
// User exits the container
});
container.on('focus', function (evt) {
if (!container.isOpen()) {
- self.$selection.trigger( 'focus' );
+ self.$selection.focus();
}
});
@@ -1624,9 +1557,9 @@ S2.define('select2/selection/single',[
var selection = data[0];
var $rendered = this.$selection.find('.select2-selection__rendered');
- var formatted = Utils.entityDecode(this.display(selection, $rendered));
+ var formatted = this.display(selection, $rendered);
- $rendered.empty().text(formatted);
+ $rendered.empty().append(formatted);
$rendered.prop('title', selection.title || selection.text);
};
@@ -1650,7 +1583,7 @@ S2.define('select2/selection/multiple',[
$selection.addClass('select2-selection--multiple');
$selection.html(
- '
'
+ '
'
);
return $selection;
@@ -1687,18 +1620,6 @@ S2.define('select2/selection/multiple',[
});
}
);
-
- this.$selection.on('keydown', function (evt) {
- // If user starts typing an alphanumeric key on the keyboard, open if not opened.
- if (!container.isOpen() && evt.which >= 48 && evt.which <= 90) {
- container.open();
- }
- });
-
- // Focus on the search field when the container is focused instead of the main container.
- container.on( 'focus', function(){
- self.focusOnSearch();
- });
};
MultipleSelection.prototype.clear = function () {
@@ -1715,7 +1636,7 @@ S2.define('select2/selection/multiple',[
MultipleSelection.prototype.selectionContainer = function () {
var $container = $(
'
' +
- '' +
+ '' +
'×' +
'' +
'
'
@@ -1724,24 +1645,6 @@ S2.define('select2/selection/multiple',[
return $container;
};
- /**
- * Focus on the search field instead of the main multiselect container.
- */
- MultipleSelection.prototype.focusOnSearch = function() {
- var self = this;
-
- if ('undefined' !== typeof self.$search) {
- // Needs 1 ms delay because of other 1 ms setTimeouts when rendering.
- setTimeout(function(){
- // Prevent the dropdown opening again when focused from this.
- // This gets reset automatically when focus is triggered.
- self._keyUpPrevented = true;
-
- self.$search.focus();
- }, 1);
- }
- }
-
MultipleSelection.prototype.update = function (data) {
this.clear();
@@ -1755,14 +1658,9 @@ S2.define('select2/selection/multiple',[
var selection = data[d];
var $selection = this.selectionContainer();
- var removeItemTag = $selection.html();
var formatted = this.display(selection, $selection);
- if ('string' === typeof formatted) {
- formatted = Utils.entityDecode(formatted.trim());
- }
- $selection.text(formatted);
- $selection.prepend(removeItemTag);
+ $selection.append(formatted);
$selection.prop('title', selection.title || selection.text);
$selection.data('data', selection);
@@ -1801,7 +1699,7 @@ S2.define('select2/selection/placeholder',[
Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
var $placeholder = this.selectionContainer();
- $placeholder.text(Utils.entityDecode(this.display(placeholder)));
+ $placeholder.html(this.display(placeholder));
$placeholder.addClass('select2-selection__placeholder')
.removeClass('select2-selection__choice');
@@ -1938,8 +1836,8 @@ S2.define('select2/selection/search',[
Search.prototype.render = function (decorated) {
var $search = $(
'
' +
- '' +
'
'
);
@@ -1956,19 +1854,16 @@ S2.define('select2/selection/search',[
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
- var resultsId = container.id + '-results';
decorated.call(this, container, $container);
container.on('open', function () {
- self.$search.attr('aria-owns', resultsId);
self.$search.trigger('focus');
});
container.on('close', function () {
self.$search.val('');
self.$search.removeAttr('aria-activedescendant');
- self.$search.removeAttr('aria-owns');
self.$search.trigger('focus');
});
@@ -1987,7 +1882,7 @@ S2.define('select2/selection/search',[
});
container.on('results:focus', function (params) {
- self.$search.attr('aria-activedescendant', params.data._resultId);
+ self.$search.attr('aria-activedescendant', params.id);
});
this.$selection.on('focusin', '.select2-search--inline', function (evt) {
@@ -2018,9 +1913,6 @@ S2.define('select2/selection/search',[
evt.preventDefault();
}
- } else if (evt.which === KEYS.ENTER) {
- container.open();
- evt.preventDefault();
}
});
@@ -2109,7 +2001,7 @@ S2.define('select2/selection/search',[
this.resizeSearch();
if (searchHadFocus) {
- this.$search.trigger( 'focus' );
+ this.$search.focus();
}
};
@@ -3112,15 +3004,8 @@ S2.define('select2/data/base',[
};
BaseAdapter.prototype.generateResultId = function (container, data) {
- var id = '';
+ var id = container.id + '-result-';
- if (container != null) {
- id += container.id
- } else {
- id += Utils.generateChars(4);
- }
-
- id += '-result-';
id += Utils.generateChars(4);
if (data.id != null) {
@@ -3306,7 +3191,7 @@ S2.define('select2/data/select',[
}
}
- if (data.id !== undefined) {
+ if (data.id) {
option.value = data.id;
}
@@ -3404,7 +3289,7 @@ S2.define('select2/data/select',[
item.text = item.text.toString();
}
- if (item._resultId == null && item.id) {
+ if (item._resultId == null && item.id && this.container != null) {
item._resultId = this.generateResultId(this.container, item);
}
@@ -3547,7 +3432,7 @@ S2.define('select2/data/ajax',[
if (this._request != null) {
// JSONP requests cannot always be aborted
- if ( typeof this._request.abort === 'function' ) {
+ if ($.isFunction(this._request.abort)) {
this._request.abort();
}
@@ -3572,7 +3457,7 @@ S2.define('select2/data/ajax',[
if (self.options.get('debug') && window.console && console.error) {
// Check to make sure that the response included a `results` key.
- if (!results || !results.results || ! Array.isArray( results.results ) ) {
+ if (!results || !results.results || !$.isArray(results.results)) {
console.error(
'Select2: The AJAX results did not return an array in the ' +
'`results` key of the response.'
@@ -3581,7 +3466,6 @@ S2.define('select2/data/ajax',[
}
callback(results);
- self.container.focusOnActiveElement();
}, function () {
// Attempt to detect if a request was aborted
// Only works if the transport exposes a status property
@@ -3631,7 +3515,7 @@ S2.define('select2/data/tags',[
decorated.call(this, $element, options);
- if ( Array.isArray( tags ) ) {
+ if ($.isArray(tags)) {
for (var t = 0; t < tags.length; t++) {
var tag = tags[t];
var item = this._normalizeItem(tag);
@@ -3666,10 +3550,7 @@ S2.define('select2/data/tags',[
}, true)
);
- var optionText = (option.text || '').toUpperCase();
- var paramsTerm = (params.term || '').toUpperCase();
-
- var checkText = optionText === paramsTerm;
+ var checkText = option.text === params.term;
if (checkText || checkChildren) {
if (child) {
@@ -3707,7 +3588,7 @@ S2.define('select2/data/tags',[
};
Tags.prototype.createTag = function (decorated, params) {
- var term = ( params.term || 0 == params.term ) ? params.term.toString().trim() : '';
+ var term = $.trim(params.term);
if (term === '') {
return null;
@@ -3800,7 +3681,7 @@ S2.define('select2/data/tokenizer',[
// Replace the search term if we have the search box
if (this.$search.length) {
this.$search.val(tokenData.term);
- this.$search.trigger( 'focus' );
+ this.$search.focus();
}
params.term = tokenData.term;
@@ -4006,9 +3887,9 @@ S2.define('select2/dropdown/search',[
var $search = $(
'' +
- '' +
+ '' +
''
);
@@ -4022,7 +3903,6 @@ S2.define('select2/dropdown/search',[
Search.prototype.bind = function (decorated, container, $container) {
var self = this;
- var resultsId = container.id + '-results';
decorated.call(this, container, $container);
@@ -4046,24 +3926,23 @@ S2.define('select2/dropdown/search',[
container.on('open', function () {
self.$search.attr('tabindex', 0);
- self.$search.attr('aria-owns', resultsId);
- self.$search.trigger( 'focus' );
+
+ self.$search.focus();
window.setTimeout(function () {
- self.$search.trigger( 'focus' );
+ self.$search.focus();
}, 0);
});
container.on('close', function () {
self.$search.attr('tabindex', -1);
- self.$search.removeAttr('aria-activedescendant');
- self.$search.removeAttr('aria-owns');
+
self.$search.val('');
});
container.on('focus', function () {
- if (!container.isOpen()) {
- self.$search.trigger( 'focus' );
+ if (container.isOpen()) {
+ self.$search.focus();
}
});
@@ -4078,10 +3957,6 @@ S2.define('select2/dropdown/search',[
}
}
});
-
- container.on('results:focus', function (params) {
- self.$search.attr('aria-activedescendant', params.data._resultId);
- });
};
Search.prototype.handleSearch = function (evt) {
@@ -4223,7 +4098,7 @@ S2.define('select2/dropdown/infiniteScroll',[
var $option = $(
''
+ 'role="treeitem" aria-disabled="true">'
);
var message = this.options.get('translations').get('loadingMore');
@@ -4878,7 +4753,7 @@ S2.define('select2/defaults',[
}
}
- if ( Array.isArray( options.language ) ) {
+ if ($.isArray(options.language)) {
var languages = new Translation();
options.language.push('en');
@@ -4941,7 +4816,7 @@ S2.define('select2/defaults',[
function matcher (params, data) {
// Always return the object if there is nothing to compare
- if ( params.term == null || params.term.toString().trim() === '' ) {
+ if ($.trim(params.term) === '') {
return data;
}
@@ -5469,22 +5344,16 @@ S2.define('select2/core',[
});
});
- this.on('open', function(){
- // Focus on the active element when opening dropdown.
- // Needs 1 ms delay because of other 1 ms setTimeouts when rendering.
- setTimeout(function(){
- self.focusOnActiveElement();
- }, 1);
- });
-
- $(document).on('keydown', function (evt) {
+ this.on('keypress', function (evt) {
var key = evt.which;
+
if (self.isOpen()) {
- if (key === KEYS.ESC || (key === KEYS.UP && evt.altKey)) {
+ if (key === KEYS.ESC || key === KEYS.TAB ||
+ (key === KEYS.UP && evt.altKey)) {
self.close();
evt.preventDefault();
- } else if (key === KEYS.ENTER || key === KEYS.TAB) {
+ } else if (key === KEYS.ENTER) {
self.trigger('results:select', {});
evt.preventDefault();
@@ -5501,42 +5370,17 @@ S2.define('select2/core',[
evt.preventDefault();
}
-
- var $searchField = self.$dropdown.find('.select2-search__field');
- if (! $searchField.length) {
- $searchField = self.$container.find('.select2-search__field');
- }
-
- // Move the focus to the selected element on keyboard navigation.
- // Required for screen readers to work properly.
- if (key === KEYS.DOWN || key === KEYS.UP) {
- self.focusOnActiveElement();
- } else {
- // Focus on the search if user starts typing.
- $searchField.focus();
- // Focus back to active selection when finished typing.
- // Small delay so typed character can be read by screen reader.
- setTimeout(function(){
- self.focusOnActiveElement();
- }, 1000);
- }
- } else if (self.hasFocus()) {
+ } else {
if (key === KEYS.ENTER || key === KEYS.SPACE ||
- key === KEYS.DOWN) {
+ (key === KEYS.DOWN && evt.altKey)) {
self.open();
+
evt.preventDefault();
}
}
});
};
- Select2.prototype.focusOnActiveElement = function () {
- // Don't mess with the focus on touchscreens because it causes havoc with on-screen keyboards.
- if (this.isOpen() && ! Utils.isTouchscreen()) {
- this.$results.find('li.select2-results__option--highlighted').focus();
- }
- };
-
Select2.prototype._syncAttributes = function () {
this.options.set('disabled', this.$element.prop('disabled'));
@@ -5724,7 +5568,7 @@ S2.define('select2/core',[
var newVal = args[0];
- if ( Array.isArray( newVal ) ) {
+ if ($.isArray(newVal)) {
newVal = $.map(newVal, function (obj) {
return obj.toString();
});
@@ -5809,11 +5653,11 @@ S2.define('jquery.select2',[
'./select2/core',
'./select2/defaults'
], function ($, _, Select2, Defaults) {
- if ($.fn.selectWoo == null) {
+ if ($.fn.select2 == null) {
// All methods that should return the element
var thisMethods = ['open', 'close', 'destroy'];
- $.fn.selectWoo = function (options) {
+ $.fn.select2 = function (options) {
options = options || {};
if (typeof options === 'object') {
@@ -5853,17 +5697,10 @@ S2.define('jquery.select2',[
};
}
- if ($.fn.select2 != null && $.fn.select2.defaults != null) {
- $.fn.selectWoo.defaults = $.fn.select2.defaults;
+ if ($.fn.select2.defaults == null) {
+ $.fn.select2.defaults = Defaults;
}
- if ($.fn.selectWoo.defaults == null) {
- $.fn.selectWoo.defaults = Defaults;
- }
-
- // Also register selectWoo under select2 if select2 is not already present.
- $.fn.select2 = $.fn.select2 || $.fn.selectWoo;
-
return Select2;
});
@@ -5882,7 +5719,6 @@ S2.define('jquery.select2',[
// This allows Select2 to use the internal loader outside of this file, such
// as in the language files.
jQuery.fn.select2.amd = S2;
- jQuery.fn.selectWoo.amd = S2;
// Return the Select2 instance for anyone who is importing it.
return select2;
diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart.test.js
index e9bc8c8445c..c11636fa68d 100644
--- a/tests/e2e/core-tests/specs/shopper/front-end-cart.test.js
+++ b/tests/e2e/core-tests/specs/shopper/front-end-cart.test.js
@@ -1,9 +1,9 @@
-/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */
/**
* Internal dependencies
*/
const {
shopper,
+ withRestApi,
createSimpleProduct,
uiUnblocked
} = require( '@woocommerce/e2e-utils' );
@@ -26,6 +26,9 @@ const runCartPageTest = () => {
describe('Cart page', () => {
beforeAll(async () => {
await createSimpleProduct();
+ await withRestApi.resetSettingsGroupToDefault('general');
+ await withRestApi.resetSettingsGroupToDefault('products');
+ await withRestApi.resetSettingsGroupToDefault('tax');
});
it('should display no item in the cart', async () => {
diff --git a/tests/e2e/core-tests/specs/shopper/front-end-checkout.test.js b/tests/e2e/core-tests/specs/shopper/front-end-checkout.test.js
index 812d7385d25..fb73d94b565 100644
--- a/tests/e2e/core-tests/specs/shopper/front-end-checkout.test.js
+++ b/tests/e2e/core-tests/specs/shopper/front-end-checkout.test.js
@@ -1,10 +1,10 @@
-/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect, jest/no-standalone-expect */
/**
* Internal dependencies
*/
const {
shopper,
merchant,
+ withRestApi,
createSimpleProduct,
setCheckbox,
settingsPageSaveChanges,
@@ -28,6 +28,9 @@ const runCheckoutPageTest = () => {
describe('Checkout page', () => {
beforeAll(async () => {
await createSimpleProduct();
+ await withRestApi.resetSettingsGroupToDefault('general');
+ await withRestApi.resetSettingsGroupToDefault('products');
+ await withRestApi.resetSettingsGroupToDefault('tax');
// Set free shipping within California
await merchant.login();
diff --git a/tests/e2e/env/CHANGELOG.md b/tests/e2e/env/CHANGELOG.md
index e57468d8e24..430535092db 100644
--- a/tests/e2e/env/CHANGELOG.md
+++ b/tests/e2e/env/CHANGELOG.md
@@ -6,6 +6,7 @@
- Added plugin zip utility functions:
- `checkNestedZip( zipFilePath, savePath )` checks a plugin zip file for any nested zip files. If one is found, it is extracted. Returns the path where the zip file is located.
- `downloadZip( fileUrl, downloadPath )` downloads a plugin zip file from a remote location to the provided path.
+- Added `getLatestReleaseZipUrl( owner, repository, getPrerelease, perPage )` util function to get the latest release zip from a GitHub repository
# 0.2.2
diff --git a/tests/e2e/env/README.md b/tests/e2e/env/README.md
index c3b38dd3bd2..6420d746d5e 100644
--- a/tests/e2e/env/README.md
+++ b/tests/e2e/env/README.md
@@ -196,6 +196,14 @@ The above method also makes use of the following utility methods which can also
- `checkNestedZip( zipFilePath, savePath )` used to check a plugin zip file for any nested zip files. If one is found, it is extracted. Returns the path where the zip file is located.
- `downloadZip( fileUrl, downloadPath )` can be used to directly download a plugin zip file from a remote location to the provided path.
+### Get the latest released zip URL
+
+If you would like to get the latest release zip URL, which can be used in the methods mentioned above, you can use the following helper function to do so:
+
+`getLatestReleaseZipUrl( owner, repository, getPrerelease, perPage )`
+
+This will return a string with the latest release URL. Optionally, you can use the `getPrerelease` boolean flag, which defaults to false, on whether or not to get a prerelease instead. The `perPage` flag can be used to return more results when getting the list of releases. The default value is 3.
+
## Additional information
Refer to [`tests/e2e/core-tests`](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/core-tests) for some test examples, and [`tests/e2e`](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e) for general information on e2e tests.
diff --git a/tests/e2e/env/utils/get-plugin-zip.js b/tests/e2e/env/utils/get-plugin-zip.js
index edd9f404be9..856478719db 100644
--- a/tests/e2e/env/utils/get-plugin-zip.js
+++ b/tests/e2e/env/utils/get-plugin-zip.js
@@ -29,6 +29,52 @@ const getRemotePluginZip = async ( fileUrl ) => {
return filePath;
};
+/**
+ * Get the latest release zip for a plugin from a GiHub repository.
+ *
+ * @param {string} owner The owner of the plugin repository.
+ * @param {string} repository The repository name.
+ * @param {boolean} getPrerelease Flag on whether to get a prelease or not.
+ * @param {number} perPage Limit of entries returned from the latest releases list, defaults to 3.
+ * @returns {Promise}} Returns the URL for the release zip file.
+ */
+const getLatestReleaseZipUrl = async ( owner, repository, getPrerelease = false, perPage = 3 ) => {
+ let requesturl;
+
+ if ( getPrerelease ) {
+ requesturl = `https://api.github.com/repos/${owner}/${repository}/releases?per_page=${perPage}`;
+ } else {
+ requesturl = `https://api.github.com/repos/${owner}/${repository}/releases/latest`;
+ }
+
+ const options = {
+ url: requesturl,
+ method: 'GET',
+ json: true,
+ headers: {'user-agent': 'node.js'}
+ };
+
+ // Wrap in a promise to make the request async
+ return new Promise( function( resolve, reject ) {
+ request.get(options, function( err, resp, body ) {
+ if ( err ) {
+ reject( err );
+ } else {
+ if ( getPrerelease ) {
+ // Loop until we find the first pre-release, then return it.
+ body.forEach(release => {
+ if ( release.prerelease ) {
+ resolve( release.zipball_url );
+ }
+ });
+ } else {
+ resolve( body.zipball_url );
+ }
+ }
+ })
+ });
+}
+
/**
* Check the zip file for any nested zips. If one is found, extract it.
*
@@ -80,6 +126,7 @@ const downloadZip = async ( fileUrl, downloadPath ) => {
module.exports = {
getRemotePluginZip,
+ getLatestReleaseZipUrl,
checkNestedZip,
downloadZip,
};
diff --git a/tests/e2e/env/utils/index.js b/tests/e2e/env/utils/index.js
index 6df8984caf7..3a3e220c88c 100644
--- a/tests/e2e/env/utils/index.js
+++ b/tests/e2e/env/utils/index.js
@@ -1,7 +1,7 @@
const getAppRoot = require( './app-root' );
const { getAppName, getAppBase } = require( './app-name' );
const { getTestConfig, getAdminConfig } = require( './test-config' );
-const { getRemotePluginZip } = require('./get-plugin-zip');
+const { getRemotePluginZip, getLatestReleaseZipUrl } = require('./get-plugin-zip');
const takeScreenshotFor = require( './take-screenshot' );
const updateReadyPageStatus = require('./update-ready-page');
const consoleUtils = require( './filter-console' );
@@ -13,6 +13,7 @@ module.exports = {
getTestConfig,
getAdminConfig,
getRemotePluginZip,
+ getLatestReleaseZipUrl,
takeScreenshotFor,
updateReadyPageStatus,
...consoleUtils,
diff --git a/tests/e2e/specs/smoke-tests/update-woocommerce.js b/tests/e2e/specs/smoke-tests/update-woocommerce.js
index 8b1d2380a15..a6c2794b884 100644
--- a/tests/e2e/specs/smoke-tests/update-woocommerce.js
+++ b/tests/e2e/specs/smoke-tests/update-woocommerce.js
@@ -3,7 +3,7 @@
*/
const { merchant, utils } = require( '@woocommerce/e2e-utils' );
-const { getRemotePluginZip } = require( '@woocommerce/e2e-environment' );
+const { getRemotePluginZip, getLatestReleaseZipUrl } = require( '@woocommerce/e2e-environment' );
/**
* External dependencies
@@ -13,16 +13,23 @@ const {
beforeAll,
} = require( '@jest/globals' );
-const { UPDATE_WC } = process.env;
+const { UPDATE_WC, TEST_RELEASE } = process.env;
-const nightlyZip = 'https://github.com/woocommerce/woocommerce/releases/download/nightly/woocommerce-trunk-nightly.zip';
+let zipUrl;
const pluginName = 'WooCommerce';
let pluginPath;
utils.describeIf( UPDATE_WC )( 'WooCommerce plugin can be uploaded and activated', () => {
beforeAll( async () => {
- pluginPath = await getRemotePluginZip( nightlyZip );
+
+ if ( TEST_RELEASE ) {
+ zipUrl = await getLatestReleaseZipUrl('woocommerce', 'woocommerce');
+ } else {
+ zipUrl = 'https://github.com/woocommerce/woocommerce/releases/download/nightly/woocommerce-trunk-nightly.zip';
+ }
+
+ pluginPath = await getRemotePluginZip( zipUrl );
await merchant.login();
});