Migrate clipboard-action-default to functional approach. Update tests. Add tests

This commit is contained in:
Beto Muniz 2021-04-15 00:59:47 -03:00
parent 455b7fdb0c
commit e7e38a18e0
9 changed files with 198 additions and 436 deletions

199
dist/clipboard.js vendored
View File

@ -125,170 +125,66 @@ var ClipboardActionCopy = function ClipboardActionCopy(target) {
;// CONCATENATED MODULE: ./src/clipboard-action-default.js ;// CONCATENATED MODULE: ./src/clipboard-action-default.js
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/** /**
* Inner class which performs selection from either `text` or `target` * Inner function which performs selection from either `text` or `target`
* properties and then executes copy or cut operations. * properties and then executes copy or cut operations.
*/
var ClipboardActionDefault = /*#__PURE__*/function () {
/**
* @param {Object} options
*/
function ClipboardActionDefault(options) {
_classCallCheck(this, ClipboardActionDefault);
this.resolveOptions(options);
this.initSelection();
}
/**
* Defines base properties passed from constructor.
* @param {Object} options * @param {Object} options
*/ */
var ClipboardActionDefault = function ClipboardActionDefault() {
_createClass(ClipboardActionDefault, [{
key: "resolveOptions",
value: function resolveOptions() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.action = options.action; // Defines base properties passed from constructor.
this.container = options.container; var _options$action = options.action,
this.emitter = options.emitter; action = _options$action === void 0 ? 'copy' : _options$action,
this.target = options.target; container = options.container,
this.text = options.text; target = options.target,
this.trigger = options.trigger; text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.
this.selectedText = '';
}
/**
* Decides which selection strategy is going to be applied based
* on the existence of `text` and `target` properties.
*/
}, { if (action !== 'copy' && action !== 'cut') {
key: "initSelection",
value: function initSelection() {
if (this.text) {
this.selectedText = clipboard_action_copy(this.text, {
container: this.container
});
} else if (this.target) {
if (this.action === 'cut') {
this.selectedText = clipboard_action_cut(this.target);
} else if (this.action === 'copy') {
this.selectedText = clipboard_action_copy(this.target, {
container: this.container
});
}
}
this.handleResult(Boolean(this.selectedText));
}
/**
* Fires an event based on the copy operation result.
* @param {Boolean} succeeded
*/
}, {
key: "handleResult",
value: function handleResult(succeeded) {
this.emitter.emit(succeeded ? 'success' : 'error', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
}
/**
* Moves focus away from `target` and back to the trigger, removes current selection.
*/
}, {
key: "clearSelection",
value: function clearSelection() {
if (this.trigger) {
this.trigger.focus();
}
document.activeElement.blur();
window.getSelection().removeAllRanges();
}
/**
* Sets the `action` to be performed which can be either 'copy' or 'cut'.
* @param {String} action
*/
}, {
key: "action",
set: function set() {
var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';
this._action = action;
if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "action" value, use either "copy" or "cut"'); throw new Error('Invalid "action" value, use either "copy" or "cut"');
} } // Sets the `target` property using an element that will be have its content copied.
}
/**
* Gets the `action` property.
* @return {String}
*/
,
get: function get() {
return this._action;
}
/**
* Sets the `target` property using an element
* that will be have its content copied.
* @param {Element} target
*/
}, {
key: "target",
set: function set(target) {
if (target !== undefined) { if (target !== undefined) {
if (target && _typeof(target) === 'object' && target.nodeType === 1) { if (target && _typeof(target) === 'object' && target.nodeType === 1) {
if (this.action === 'copy' && target.hasAttribute('disabled')) { if (action === 'copy' && target.hasAttribute('disabled')) {
throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');
} }
if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {
throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');
} }
this._target = target;
} else { } else {
throw new Error('Invalid "target" value, use a valid Element'); throw new Error('Invalid "target" value, use a valid Element');
} }
} } // Define selection strategy based on `text` property.
}
/**
* Gets the `target` property.
* @return {String|HTMLElement}
*/
,
get: function get() {
return this._target;
}
}]);
return ClipboardActionDefault;
}(); if (text) {
return clipboard_action_copy(text, {
container: container
});
} // Defines which selection strategy based on `target` property.
if (target) {
return action === 'cut' ? clipboard_action_cut(target) : clipboard_action_copy(target, {
container: container
});
}
};
/* harmony default export */ var clipboard_action_default = (ClipboardActionDefault); /* harmony default export */ var clipboard_action_default = (ClipboardActionDefault);
;// CONCATENATED MODULE: ./src/clipboard.js ;// CONCATENATED MODULE: ./src/clipboard.js
function clipboard_typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return clipboard_typeof(obj); } function clipboard_typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return clipboard_typeof(obj); }
function clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function clipboard_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function clipboard_createClass(Constructor, protoProps, staticProps) { if (protoProps) clipboard_defineProperties(Constructor.prototype, protoProps); if (staticProps) clipboard_defineProperties(Constructor, staticProps); return Constructor; } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
@ -342,7 +238,7 @@ var Clipboard = /*#__PURE__*/function (_Emitter) {
function Clipboard(trigger, options) { function Clipboard(trigger, options) {
var _this; var _this;
clipboard_classCallCheck(this, Clipboard); _classCallCheck(this, Clipboard);
_this = _super.call(this); _this = _super.call(this);
_this.ClipboardActionCut = clipboard_action_cut.bind(_assertThisInitialized(_this)); _this.ClipboardActionCut = clipboard_action_cut.bind(_assertThisInitialized(_this));
@ -361,7 +257,7 @@ var Clipboard = /*#__PURE__*/function (_Emitter) {
*/ */
clipboard_createClass(Clipboard, [{ _createClass(Clipboard, [{
key: "resolveOptions", key: "resolveOptions",
value: function resolveOptions() { value: function resolveOptions() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@ -393,18 +289,25 @@ var Clipboard = /*#__PURE__*/function (_Emitter) {
key: "onClick", key: "onClick",
value: function onClick(e) { value: function onClick(e) {
var trigger = e.delegateTarget || e.currentTarget; var trigger = e.delegateTarget || e.currentTarget;
var selectedText = clipboard_action_default({
action: this.action(trigger),
container: this.container,
target: this.target(trigger),
text: this.text(trigger)
}); // Fires an event based on the copy operation result.
if (this.clipboardActionDefault) { this.emit(selectedText ? 'success' : 'error', {
this.clipboardActionDefault = null; action: this.action,
text: selectedText,
trigger: trigger,
clearSelection: function clearSelection() {
if (trigger) {
trigger.focus();
} }
this.clipboardActionDefault = new clipboard_action_default({ document.activeElement.blur();
action: this.action(trigger), window.getSelection().removeAllRanges();
target: this.target(trigger), }
text: this.text(trigger),
container: this.container,
trigger: trigger,
emitter: this
}); });
} }
/** /**
@ -449,10 +352,6 @@ var Clipboard = /*#__PURE__*/function (_Emitter) {
key: "destroy", key: "destroy",
value: function destroy() { value: function destroy() {
this.listener.destroy(); this.listener.destroy();
if (this.clipboardActionDefault) {
this.clipboardActionDefault = null;
}
} }
}], [{ }], [{
key: "copy", key: "copy",

File diff suppressed because one or more lines are too long

View File

@ -2,135 +2,52 @@ import ClipboardActionCut from './clipboard-action-cut';
import ClipboardActionCopy from './clipboard-action-copy'; import ClipboardActionCopy from './clipboard-action-copy';
/** /**
* Inner class which performs selection from either `text` or `target` * Inner function which performs selection from either `text` or `target`
* properties and then executes copy or cut operations. * properties and then executes copy or cut operations.
*/
class ClipboardActionDefault {
/**
* @param {Object} options * @param {Object} options
*/ */
constructor(options) { const ClipboardActionDefault = (options = {}) => {
this.resolveOptions(options); // Defines base properties passed from constructor.
this.initSelection(); const { action = 'copy', container, target, text } = options;
}
/** // Sets the `action` to be performed which can be either 'copy' or 'cut'.
* Defines base properties passed from constructor. if (action !== 'copy' && action !== 'cut') {
* @param {Object} options
*/
resolveOptions(options = {}) {
this.action = options.action;
this.container = options.container;
this.emitter = options.emitter;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
}
/**
* Decides which selection strategy is going to be applied based
* on the existence of `text` and `target` properties.
*/
initSelection() {
if (this.text) {
this.selectedText = ClipboardActionCopy(this.text, {
container: this.container,
});
} else if (this.target) {
this.selectedText =
this.action === 'cut'
? ClipboardActionCut(this.target)
: ClipboardActionCopy(this.target, {
container: this.container,
});
}
this.handleResult(Boolean(this.selectedText));
}
/**
* Fires an event based on the copy operation result.
* @param {Boolean} succeeded
*/
handleResult(succeeded) {
this.emitter.emit(succeeded ? 'success' : 'error', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this),
});
}
/**
* Moves focus away from `target` and back to the trigger, removes current selection.
*/
clearSelection() {
if (this.trigger) {
this.trigger.focus();
}
document.activeElement.blur();
window.getSelection().removeAllRanges();
}
/**
* Sets the `action` to be performed which can be either 'copy' or 'cut'.
* @param {String} action
*/
set action(action = 'copy') {
this._action = action;
if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "action" value, use either "copy" or "cut"'); throw new Error('Invalid "action" value, use either "copy" or "cut"');
} }
}
/** // Sets the `target` property using an element that will be have its content copied.
* Gets the `action` property.
* @return {String}
*/
get action() {
return this._action;
}
/**
* Sets the `target` property using an element
* that will be have its content copied.
* @param {Element} target
*/
set target(target) {
if (target !== undefined) { if (target !== undefined) {
if (target && typeof target === 'object' && target.nodeType === 1) { if (target && typeof target === 'object' && target.nodeType === 1) {
if (this.action === 'copy' && target.hasAttribute('disabled')) { if (action === 'copy' && target.hasAttribute('disabled')) {
throw new Error( throw new Error(
'Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute' 'Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'
); );
} }
if ( if (
this.action === 'cut' && action === 'cut' &&
(target.hasAttribute('readonly') || target.hasAttribute('disabled')) (target.hasAttribute('readonly') || target.hasAttribute('disabled'))
) { ) {
throw new Error( throw new Error(
'Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes' 'Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'
); );
} }
this._target = target;
} else { } else {
throw new Error('Invalid "target" value, use a valid Element'); throw new Error('Invalid "target" value, use a valid Element');
} }
} }
// Define selection strategy based on `text` property.
if (text) {
return ClipboardActionCopy(text, { container });
} }
/** // Defines which selection strategy based on `target` property.
* Gets the `target` property. if (target) {
* @return {String|HTMLElement} return action === 'cut'
*/ ? ClipboardActionCut(target)
get target() { : ClipboardActionCopy(target, { container });
return this._target;
} }
} };
export default ClipboardActionDefault; export default ClipboardActionDefault;

View File

@ -71,18 +71,25 @@ class Clipboard extends Emitter {
*/ */
onClick(e) { onClick(e) {
const trigger = e.delegateTarget || e.currentTarget; const trigger = e.delegateTarget || e.currentTarget;
const selectedText = ClipboardActionDefault({
if (this.clipboardActionDefault) {
this.clipboardActionDefault = null;
}
this.clipboardActionDefault = new ClipboardActionDefault({
action: this.action(trigger), action: this.action(trigger),
container: this.container,
target: this.target(trigger), target: this.target(trigger),
text: this.text(trigger), text: this.text(trigger),
container: this.container, });
// Fires an event based on the copy operation result.
this.emit(selectedText ? 'success' : 'error', {
action: this.action,
text: selectedText,
trigger, trigger,
emitter: this, clearSelection() {
if (trigger) {
trigger.focus();
}
document.activeElement.blur();
window.getSelection().removeAllRanges();
},
}); });
} }
@ -143,10 +150,6 @@ class Clipboard extends Emitter {
*/ */
destroy() { destroy() {
this.listener.destroy(); this.listener.destroy();
if (this.clipboardActionDefault) {
this.clipboardActionDefault = null;
}
} }
} }

View File

@ -17,7 +17,7 @@ describe('ClipboardActionCopy', () => {
document.body.innerHTML = ''; document.body.innerHTML = '';
}); });
describe.only('#selectText', () => { describe('#selectText', () => {
it('should select its value based on input target', () => { it('should select its value based on input target', () => {
const selectedText = ClipboardActionCopy( const selectedText = ClipboardActionCopy(
document.querySelector('#input'), document.querySelector('#input'),

View File

@ -17,7 +17,7 @@ describe('ClipboardActionCut', () => {
document.body.innerHTML = ''; document.body.innerHTML = '';
}); });
describe.only('#selectText', () => { describe('#selectText', () => {
it('should select its value', () => { it('should select its value', () => {
const selectedText = ClipboardActionCut( const selectedText = ClipboardActionCut(
document.querySelector('#input'), document.querySelector('#input'),

View File

@ -1,4 +1,3 @@
import Emitter from 'tiny-emitter';
import ClipboardActionDefault from '../src/clipboard-action-default'; import ClipboardActionDefault from '../src/clipboard-action-default';
describe('ClipboardActionDefault', () => { describe('ClipboardActionDefault', () => {
@ -20,26 +19,19 @@ describe('ClipboardActionDefault', () => {
describe('#resolveOptions', () => { describe('#resolveOptions', () => {
it('should set base properties', () => { it('should set base properties', () => {
let clip = new ClipboardActionDefault({ const selectedText = ClipboardActionDefault({
emitter: new Emitter(),
container: document.body, container: document.body,
text: 'foo', text: 'foo',
}); });
assert.property(clip, 'action'); assert.equal(selectedText, 'foo');
assert.property(clip, 'container');
assert.property(clip, 'emitter');
assert.property(clip, 'target');
assert.property(clip, 'text');
assert.property(clip, 'trigger');
assert.property(clip, 'selectedText');
}); });
}); });
describe('#set action', () => { describe('#set action', () => {
it('should throw an error since "action" is invalid', (done) => { it('should throw an error since "action" is invalid', (done) => {
try { try {
let clip = new ClipboardActionDefault({ let clip = ClipboardActionDefault({
text: 'foo', text: 'foo',
action: 'paste', action: 'paste',
}); });
@ -56,7 +48,7 @@ describe('ClipboardActionDefault', () => {
describe('#set target', () => { describe('#set target', () => {
it('should throw an error since "target" do not match any element', (done) => { it('should throw an error since "target" do not match any element', (done) => {
try { try {
let clip = new ClipboardActionDefault({ let clip = ClipboardActionDefault({
target: document.querySelector('#foo'), target: document.querySelector('#foo'),
}); });
} catch (e) { } catch (e) {
@ -66,122 +58,23 @@ describe('ClipboardActionDefault', () => {
}); });
}); });
describe('#selectTarget', () => { describe('#selectedText', () => {
it('should select text from editable element', () => { it('should select text from editable element', () => {
let clip = new ClipboardActionDefault({ const selectedText = ClipboardActionDefault({
emitter: new Emitter(),
container: document.body, container: document.body,
target: document.querySelector('#input'), target: document.querySelector('#input'),
}); });
assert.equal(clip.selectedText, clip.target.value); assert.equal(selectedText, 'abc');
}); });
it('should select text from non-editable element', () => { it('should select text from non-editable element', () => {
let clip = new ClipboardActionDefault({ const selectedText = ClipboardActionDefault({
emitter: new Emitter(),
container: document.body, container: document.body,
target: document.querySelector('#paragraph'), target: document.querySelector('#paragraph'),
}); });
assert.equal(clip.selectedText, clip.target.textContent); assert.equal(selectedText, 'abc');
});
});
describe('#copyText', () => {
before(() => {
global.stub = sinon.stub(document, 'execCommand');
});
after(() => {
global.stub.restore();
});
it('should fire a success event on browsers that support copy command', (done) => {
global.stub.returns(true);
let emitter = new Emitter();
emitter.on('success', () => {
done();
});
let clip = new ClipboardActionDefault({
emitter,
target: document.querySelector('#input'),
});
});
it('should fire an error event on browsers that support cut command', (done) => {
let emitter = new Emitter();
emitter.on('error', () => {
done();
});
let clip = new ClipboardActionDefault({
emitter,
target: document.querySelector('#input'),
});
clip.handleResult(false);
});
});
describe('#handleResult', () => {
it('should fire a success event with certain properties', (done) => {
let clip = new ClipboardActionDefault({
emitter: new Emitter(),
container: document.body,
target: document.querySelector('#input'),
});
clip.emitter.on('success', (e) => {
assert.property(e, 'action');
assert.property(e, 'text');
assert.property(e, 'trigger');
assert.property(e, 'clearSelection');
done();
});
clip.handleResult(true);
});
it('should fire a error event with certain properties', (done) => {
let clip = new ClipboardActionDefault({
emitter: new Emitter(),
container: document.body,
target: document.querySelector('#input'),
});
clip.emitter.on('error', (e) => {
assert.property(e, 'action');
assert.property(e, 'trigger');
assert.property(e, 'clearSelection');
done();
});
clip.handleResult(false);
});
});
describe('#clearSelection', () => {
it('should remove focus from target and text selection', () => {
let clip = new ClipboardActionDefault({
emitter: new Emitter(),
container: document.body,
target: document.querySelector('#input'),
});
clip.clearSelection();
let selectedElem = document.activeElement;
let selectedText = window.getSelection().toString();
assert.equal(selectedElem, document.body);
assert.equal(selectedText, '');
}); });
}); });
}); });

View File

@ -1,5 +1,4 @@
import Clipboard from '../src/clipboard'; import Clipboard from '../src/clipboard';
import ClipboardActionDefault from '../src/clipboard-action-default';
describe('Clipboard', () => { describe('Clipboard', () => {
before(() => { before(() => {
@ -75,28 +74,28 @@ describe('Clipboard', () => {
}); });
describe('#onClick', () => { describe('#onClick', () => {
it('should create a new instance of ClipboardActionDefault', () => { it('should create a new instance of ClipboardActionDefault', (done) => {
let clipboard = new Clipboard('.btn'); let clipboard = new Clipboard('.btn');
clipboard.onClick(global.event); clipboard.on('success', () => {
assert.instanceOf( done();
clipboard.clipboardActionDefault,
ClipboardActionDefault
);
}); });
it("should use an event's currentTarget when not equal to target", () => { clipboard.onClick(global.event);
});
it("should use an event's currentTarget when not equal to target", (done) => {
let clipboard = new Clipboard('.btn'); let clipboard = new Clipboard('.btn');
let bubbledEvent = { let bubbledEvent = {
target: global.span, target: global.span,
currentTarget: global.button, currentTarget: global.button,
}; };
clipboard.on('success', () => {
done();
});
clipboard.onClick(bubbledEvent); clipboard.onClick(bubbledEvent);
assert.instanceOf(
clipboard.clipboardActionDefault,
ClipboardActionDefault
);
}); });
it('should throw an exception when target is invalid', (done) => { it('should throw an exception when target is invalid', (done) => {
@ -152,4 +151,41 @@ describe('Clipboard', () => {
assert.equal(clipboard.clipboardAction, null); assert.equal(clipboard.clipboardAction, null);
}); });
}); });
describe('#events', () => {
it('should fire a success event with certain properties', (done) => {
let clipboard = new Clipboard('.btn');
clipboard.on('success', (e) => {
assert.property(e, 'action');
assert.property(e, 'text');
assert.property(e, 'trigger');
assert.property(e, 'clearSelection');
done();
});
clipboard.onClick(global.event);
});
});
describe('#clearSelection', () => {
it('should remove focus from target and text selection', (done) => {
let clipboard = new Clipboard('.btn');
clipboard.on('success', (e) => {
let selectedElem = document.activeElement;
let selectedText = window.getSelection().toString();
e.clearSelection();
assert.equal(selectedElem, document.body);
assert.equal(selectedText, '');
done();
});
clipboard.onClick(global.event);
});
});
}); });

View File

@ -1,8 +1,9 @@
import select from 'select'; import select from 'select';
import command from '../../src/common/command'; import command from '../../src/common/command';
describe('command', () => { describe('#command', () => {
before(() => { before(() => {
global.stub = sinon.stub(document, 'execCommand');
global.input = document.createElement('input'); global.input = document.createElement('input');
global.input.setAttribute('id', 'input'); global.input.setAttribute('id', 'input');
global.input.setAttribute('value', 'abc'); global.input.setAttribute('value', 'abc');
@ -10,26 +11,39 @@ describe('command', () => {
}); });
after(() => { after(() => {
global.stub.restore();
document.body.innerHTML = ''; document.body.innerHTML = '';
}); });
it('should execute cut command', (done) => { it('should execute cut', (done) => {
// Set document direction global.stub.returns(true);
document.documentElement.setAttribute('dir', 'rtl');
select(document.querySelector('#input')); select(document.querySelector('#input'));
assert.isTrue(command('cut')); assert.isTrue(command('cut'));
done(); done();
}); });
it('should execute copy command', (done) => { it('should execute copy', (done) => {
// Set document direction global.stub.returns(true);
document.documentElement.setAttribute('dir', 'rtl');
select(document.querySelector('#input')); select(document.querySelector('#input'));
assert.isTrue(command('copy')); assert.isTrue(command('copy'));
done(); done();
}); });
it('should not execute copy', (done) => {
global.stub.returns(false);
select(document.querySelector('#input'));
assert.isFalse(command('copy'));
done();
});
it('should not execute cut', (done) => {
global.stub.returns(false);
select(document.querySelector('#input'));
assert.isFalse(command('cut'));
done();
});
}); });