Open ithacasnowman opened 5 years ago
What are you trying to test with highlighting text? It'll be easier to determine a fix if we understand what you're trying to do.
My application keeps a record of highlighted text. I'm trying to test that that works correctly.
We've gotten this question several times. We don't have a specific API implemented to handle highlighting text. We do have a generic cy.trigger()
where you can trigger any event, so it is theoretically possible to test many of what you'd need, but would require intimate knowledge of how your application works and what events it triggers.
I will update this issue to reflect request for this feature. This issue should now track:
This feature also requires work that's already in progress for our Native Events issue: https://github.com/cypress-io/cypress/issues/311
Related comment from @tnrich on wanting ability to highlight text with cy.type('{meta}a')
:
I would specifically like a way to trigger the exact same thing as a user-invoked "meta+a" on any element. That might happen to select text in some instances, or select everything in the page if not inside an input/textarea, or it might do something totally different if there are hotkeys listening to that specific keypress.
@Bkucera Would this situation be covered in the Native Events work currently?
This would have to be a new command entirely, and isn't planned for the native events release. However we do plan to support text selection in the future
In the meantime, you can try this:
cy.get('p.mytext')
.trigger('mousedown')
.then(($el) => {
const el = $el[0]
const document = el.ownerDocument
const range = document.createRange()
range.selectNodeContents(el)
document.getSelection().removeAllRanges(range)
document.getSelection().addRange(range)
})
.trigger('mouseup')
cy.document().trigger('selectionchange')
@Bkucera why this line cy.document().trigger('selectionchange')
is needed? Btw, great solution!
Here are a couple of commands that are working for my team, using Cypress to test a Slate based editor: https://gist.github.com/erquhart/37bf2d938ab594058e0572ed17d3837a
Includes the ability to naively select based on text matching:
cy.get('p').setSelection('foo')
Or set both the start and end points of the selection:
cy.get('p').setSelection('foo', 'baz')
Also setCursorBefore/After
with the same text matching interface, plus some other lower level commands.
@vctormb it's what the browser fires if you were to select text manually, but it won't make a difference if your app code doesn't listen for it
FYI, I couldn't get the gist above working with input
or textarea
's and it looks like its due to lack of support: https://developer.mozilla.org/en-US/docs/Web/API/Window/getSelection#Related_objects (it also wasn't working in Chrome 80 for me), so I created a fork of the gist with a different path for those elements:
https://gist.github.com/samtsai/5cf901ba61fd8d44c8dd7eaa728cac49
@erquhart Thanks you so much !!! The highlighting works !!!
I feel maybe this can be made into an official way of highlighting text instead of just being labelled as a workaround !!! hehe
Yeah I used this Gist successfully on a selection-heavy project test suite and encountered no real issue, I'd be fine if this was the code used for official support despite its potential limitations, it's still better than no support
Glad it worked for you! It's super naive, Eg., duplicates of the targeted string can trip it up easily. We've avoided this by not using duplicate strings in our tests (they're generally short strings anyway). Probably not a viable candidate for a first class solution, but a good stopgap.
For anyone running into issues w/ the gist, our implementation has evolved a bit and may work better. You'll just have to dig a bit in the source file to find the relevant code. Here's the source as of today: https://github.com/netlify/netlify-cms/blob/a4b7481a99f58b9abe85ab5712d27593cde20096/cypress/support/commands.js#L180
@erquhart Thanks a lot! You saved us hours of work.
I really recommend you to create a separate package with all selection related commands so people can just install it via npm in the future and use it directly. I'd be the first one to star it!
For future readers: if @erquhart solution is not working for you, try to trigger a 'selectstart' after the triggered 'mousedown' in the 'selection' command. That seems to fake better a real mouse interaction. In my case i had a popup that is triggered when text was selected.
@jennifer-shehane how can we move this issue forward?
If the previous workarounds didn't work for some people (like me), you could try cy.realPress(["Shift", "ArrowLeft"]);
from https://github.com/dmtrKovalenko/cypress-real-events
@erquhart What a great solution and many thanks for sharing. I have similar issues starting out testing my own rich text editor app and this saved me a lot of time.
Any other suggestions for handling selecting text inside iframe ?
@erquhart thanks for your solution!! Here's a simple fork to select anything within a Node. No need to change Cypress.command
or anything, just a simple fixed utility function.
/**
* Returns an `Array` with all `#text` nodes in a Node.
* @param {Node} target root node
* @returns {Node[]} the requested nodes
*/
function getTextNodes(target) {
if (target.nodeType === 3) {
return [target];
}
let nodes = [];
const doc = target.ownerDocument;
const win = doc.defaultView;
const walk = doc.createTreeWalker(target, win.NodeFilter.SHOW_TEXT, null);
let node;
while (node = walk.nextNode()) {
if (node.nodeType === 3) {
nodes = [...nodes, node];
}
}
return nodes;
}
/**
* Select all the text of the first textNode of a given element.
* @param {Node} target target element
*/
export default function selectText(target) {
const textNodes = getTextNodes(target);
const [startNode, endNode] = [...textNodes.slice(0,1), ...textNodes.slice(-1)];
console.log(startNode,endNode)
const doc = target.ownerDocument;
const win = doc.defaultView;
const range = new win.Range();
range.setStart(startNode , 0);
range.setEnd(endNode, endNode.textContent.length);
win.getSelection().removeAllRanges();
win.getSelection().addRange(range);
}
cypress/fixtures/selectText.js
and paste the above codecypress/integration/FILE.spec.js
use import selectText from '../fixtures/selectText'
it('selects all text in a Node', 90 => {
cy.get('SELECTOR').then((target) => {
selectText($target[0]);
// now do something with all that selected text
expect(target[0].ownerDocument.getSelection().toString().length).to.be.above(0);
})
})
Last but not least: have fun!
If the previous workarounds didn't work for some people (like me), you could try
cy.realPress(["Shift", "ArrowLeft"]);
from https://github.com/dmtrKovalenko/cypress-real-events
This worked like a charm! Thanks @NZhlebinkov
I want to select and highlight span all the elements present under the
<div class="section-text">
<span sid="0" ost="0">S</span>
<span sid="0" ost="1">a</span>
<span sid="0" ost="2">n</span>
<span sid="0" ost="3">t</span>
<span sid="0" ost="4">a</span>
Cypress.Commands.add('selectText', function(text) {
cy.contains(text).then(($el) => {
const el = $el[0];
const document = el.ownerDocument;
const range = document.createRange();
range.selectNodeContents(el);
const fullText = el.textContent || "";
const startIndex = fullText.indexOf(text);
const endIndex = startIndex + text.length;
if (startIndex !== -1 && endIndex !== -1) {
range.setStart(el.firstChild, startIndex);
range.setEnd(el.firstChild, endIndex);
const selection = document.getSelection();
selection.removeAllRanges();
selection.addRange(range);
$el.trigger('mouseup');
cy.document().trigger('selectionchange');
} else {
throw new Error(`The text "${text}" was not found in the element`);
}
});
});
Current behavior:
I'm having a hard time creating a text selection. Things I've tried:
document.createRange()
andwindow.getSelection()
cy.trigger
to simulate a cursor drag over the paragraph.dblclick
on the paragraph.Desired behavior:
Test highlighting text.
Steps to reproduce:
I can provide sample code for the approaches I tried, but I'll hold off for now in case there's a completely different known way of doing this.
Versions
Cypress 3.1.1, Chrome 70.0.3538.102