Skip to content

Commit

Permalink
feat: add dragDropElems (GAUD-6868) (#468)
Browse files Browse the repository at this point in the history
  • Loading branch information
dlockhart committed Aug 19, 2024
1 parent 8a35e4f commit 9b4aa95
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 63 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,33 @@ it('should click at coordinate', async() => {
});
```

Elements configured using the [Drag & Drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API) can be interacted with using `dragDropElems(sourceElem, destElem)`:

```javascript
import { dragDropElems } from '@brightspace-ui/testing';

it('should drag & drop', async() => {
const rootElem = await fixture(html`
<div>
<div id="source" draggable="true"></div>
<div id="dest"></div>
</div>
`);
// NOTE: destination must have "dragover" and "drop"
// event listeners added for the drag & drop API to function
await dragDropElems(
rootElem.querySelector('#source'),
rootElem.querySelector('#target')
);
// do assertions
});

it('should click at coordinate', async() => {
await clickAt(100, 200);
// do assertions
});
```

### Using the Keyboard

To place focus on an element using the keyboard, use `focusElem(elem)`. Doing so will trigger its `:focus-visible` CSS pseudo-class.
Expand Down
9 changes: 9 additions & 0 deletions src/browser/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ export async function clickElem(elem) {
return clickAt(position.x, position.y);
}

export async function dragDropElems(elem, toElem) {
const fromPosition = getElementPosition(elem);
const toPosition = getElementPosition(toElem);
await sendMouse({ type: 'move', position: [fromPosition.x, fromPosition.y] });
await sendMouse({ type: 'down' });
await sendMouse({ type: 'move', position: [toPosition.x, toPosition.y] });
await sendMouse({ type: 'up' });
}

export async function focusElem(elem) {
await cmdSendKeys({ press: 'Shift' }); // Tab moves focus, Escape causes dismissible things to close
elem.focus({ focusVisible: true });
Expand Down
2 changes: 1 addition & 1 deletion src/browser/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './vdiff.js';

export { assert, aTimeout, defineCE, expect, html, nextFrame, oneDefaultPreventedEvent, oneEvent, waitUntil } from '@open-wc/testing';
export { clickAt, clickElem, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem, setViewport } from './commands.js';
export { clickAt, clickElem, dragDropElems, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem, setViewport } from './commands.js';
export { fixture } from './fixture.js';
export { runConstructor } from './constructor.js';
172 changes: 110 additions & 62 deletions test/browser/commands.test.js
Original file line number Diff line number Diff line change
@@ -1,87 +1,131 @@
import { clickAt, clickElem, expect, fixture, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem, setViewport } from '../../src/browser/index.js';
import { clickAt, clickElem, dragDropElems, expect, fixture, focusElem, hoverAt, hoverElem, sendKeys, sendKeysElem, setViewport } from '../../src/browser/index.js';
import { html } from 'lit';
import { spy } from 'sinon';

describe('commands', () => {

let elem;
const input = html`<input type="text">`;
beforeEach(async() => {
elem = await fixture(input);
});
describe('click/hover', () => {

it('should click on element', async() => {
const clickSpy = spy();
elem.addEventListener('click', clickSpy);
await clickElem(elem);
expect(clickSpy).to.be.calledOnce;
});
let elem;
beforeEach(async() => {
elem = await fixture(html`<button>text</button>`);
});

it('should click at position', async() => {
const clickPos = { x: 0, y: 0 };
function onClick(e) {
clickPos.x = e.clientX;
clickPos.y = e.clientY;
}
window.addEventListener('click', onClick);
await clickAt(200, 300);
expect(clickPos.x).to.equal(200);
expect(clickPos.y).to.equal(300);
window.removeEventListener('click', onClick);
});
it('should click on element', async() => {
const clickSpy = spy();
elem.addEventListener('click', clickSpy);
await clickElem(elem);
expect(clickSpy).to.be.calledOnce;
});

it('should focus on element', async() => {
let focussed = false;
elem.addEventListener('focus', () => focussed = true);
await focusElem(elem);
expect(focussed).to.be.true;
});
it('should click at position', async() => {
const clickPos = { x: 0, y: 0 };
function onClick(e) {
clickPos.x = e.clientX;
clickPos.y = e.clientY;
}
window.addEventListener('click', onClick);
await clickAt(200, 300);
expect(clickPos.x).to.equal(200);
expect(clickPos.y).to.equal(300);
window.removeEventListener('click', onClick);
});

it('should hover over element', async() => {
let hovered = false;
elem.addEventListener('mouseover', () => hovered = true);
elem.addEventListener('mouseout', () => hovered = false);
await hoverElem(elem);
expect(hovered).to.be.true;
});
it('should hover over element', async() => {
let hovered = false;
elem.addEventListener('mouseover', () => hovered = true);
elem.addEventListener('mouseout', () => hovered = false);
await hoverElem(elem);
expect(hovered).to.be.true;
});

it('should hover at position', async() => {
const mousePos = { x: 0, y: 0 };
function onMouseMove(e) {
mousePos.x = e.clientX;
mousePos.y = e.clientY;
}
window.addEventListener('mousemove', onMouseMove);
await hoverAt(50, 100);
expect(mousePos.x).to.equal(50);
expect(mousePos.y).to.equal(100);
window.removeEventListener('mousemove', onMouseMove);
});

it('should hover at position', async() => {
const mousePos = { x: 0, y: 0 };
function onMouseMove(e) {
mousePos.x = e.clientX;
mousePos.y = e.clientY;
}
window.addEventListener('mousemove', onMouseMove);
await hoverAt(50, 100);
expect(mousePos.x).to.equal(50);
expect(mousePos.y).to.equal(100);
window.removeEventListener('mousemove', onMouseMove);
});

it('should send keys to element', async() => {
await sendKeysElem(elem, 'type', 'Hello');
expect(elem.value).to.equal('Hello');
describe('keyboard/focus', async() => {

let elem;
beforeEach(async() => {
elem = await fixture(html`<input type="text">`);
});

it('should focus on element', async() => {
let focussed = false;
elem.addEventListener('focus', () => focussed = true);
await focusElem(elem);
expect(focussed).to.be.true;
});

it('should send keys to element', async() => {
await sendKeysElem(elem, 'type', 'Hello');
expect(elem.value).to.equal('Hello');
});

it('should send keys to browser', async() => {
let key = undefined;
function onKeyDown(e) {
key = e.key;
}
window.addEventListener('keydown', onKeyDown);
await sendKeys('press', 'Escape');
expect(key).to.equal('Escape');
window.removeEventListener('keydown', onKeyDown);
});

});

it('should send keys to browser', async() => {
let key = undefined;
function onKeyDown(e) {
key = e.key;
}
window.addEventListener('keydown', onKeyDown);
await sendKeys('press', 'Escape');
expect(key).to.equal('Escape');
window.removeEventListener('keydown', onKeyDown);
describe('drag & drop', () => {

it('should drag & drop element', (done) => {
fixture(html`<div>
<div id="dest" style="height: 100px; width: 100px;"></div>
<div id="source" draggable="true" style="height: 50px; width: 50px;"></div>
</div>`).then(rootElem => {

let dragSource;
const sourceElem = rootElem.querySelector('#source');
sourceElem.addEventListener('dragstart', e => dragSource = e.target);

const destElem = rootElem.querySelector('#dest');
destElem.addEventListener('dragover', e => e.preventDefault());
destElem.addEventListener('drop', (e) => {
e.preventDefault();
expect(dragSource).to.equal(sourceElem);
done();
});

dragDropElems(sourceElem, destElem);

});
});

});

describe('mouseReset', () => {

const mousePos = { x: 0, y: 0 };
function onMouseMove(e) {
mousePos.x = e.clientX;
mousePos.y = e.clientY;
}

beforeEach(() => {
const buttonTemplate = html`<button>text</button>`;

let elem;
beforeEach(async() => {
elem = await fixture(buttonTemplate);
window.addEventListener('mousemove', onMouseMove);
});

Expand All @@ -99,7 +143,7 @@ describe('commands', () => {
await action(elem);
expect(mousePos.x).to.not.equal(0);
expect(mousePos.y).to.not.equal(0);
await fixture(input);
await fixture(buttonTemplate);
expect(mousePos.x).to.equal(0);
expect(mousePos.y).to.equal(0);
});
Expand All @@ -108,6 +152,10 @@ describe('commands', () => {

describe('viewport', () => {

beforeEach(async() => {
await fixture(html`<div></div>`);
});

it('should set width and height', async() => {
await setViewport({ height: 200, width: 300 });
expect(window.innerHeight).to.equal(200);
Expand Down

0 comments on commit 9b4aa95

Please sign in to comment.