0

Using Selection.each(fn) (see the k6 docs), the callback is passed an index and an Element. Element has a different API than Selection, and within the callback I’d like to use the Selection API on the passed Element so that I can operate on each Selection individually. In jQuery, I’d often do this:

$('li').each(function (index, element) {
  let container = $(element).closest('div.listContainer');
  // now do something with the `container`
});

I’ve tried inside the callback to do things like $(element) or Selection(element) but it errors saying those are undefined. (Kind of stabbing in the dark, since I don’t see in the docs how to do this.)

My code looks like:

mySelection.each((index, element) => {
  // here, I'd like to do element.closest('.someAncestorSelector') if element could be 'wrapped'
})

Is there a way in the jQuery-like Selection API in k6 to do this?

jinglesthula
  • 4,446
  • 4
  • 45
  • 79
  • I found . Does it not do what you want? What exactly is undefined? Please provide the error message. Where does `mySelection` come from? – knittl Sep 13 '22 at 21:21
  • Also note that k6 can not and will not any JavaScript that a real browser might do, so unless the element is part of the HTML document returned from the server, you will not find it. If you must run your tests in a real browser environment, [xk6-browser](https://github.com/grafana/xk6-browser) might be of interest to you – knittl Sep 14 '22 at 05:40
  • @knittl Yes - `.closest()` (and other `Selection` methods) are what I need, but I need them for each item individually. I believe just doing `mySelection.closest()` will only give me the closest element for the selector for a single item in `mySelection`. I need to operate on each of them individually. I've updated the question to better reflect what I'm after. – jinglesthula Sep 14 '22 at 16:24
  • What type is `mySelection`? `each` isn't a native JavaScript query (it's something from jQuery). But `.forEach(…)` or `for (… of …)` are native JasaScript methods/concepts to iterate over collections – knittl Sep 14 '22 at 19:34
  • Ah, sorry - it's a k6 Selection: https://k6.io/docs/javascript-api/k6-html/selection/selection-each/. I've updated the question to clarify. – jinglesthula Sep 14 '22 at 22:37
  • As a side note, I've often been frustrated with jQuery's .each() method passing the raw dom element in rather than a jQuery wrapped version as the 2nd argument, since I always have to re-wrap it in jQuery inside the callback there as well. I can always call .get() if I want the element, and in the case of k6, a Selection object instead of an Element object would be similar - you could always call https://k6.io/docs/javascript-api/k6-html/selection/selection-get/ if you need the Element. shrugs. – jinglesthula Sep 14 '22 at 22:42

1 Answers1

1

From the k6 docs on Selection.closest:

For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. [emphasis mine]

Which means that each is unnecessary and will be performed automatically (returning a new Selection instance with the closest elements).

const closestSelection = mySelection.closest('.someAncestorSelector');
closestSelection.each((index, closestElement) => {
  // now, do something with closestElement.
});

or as a single chain of expressions:

mySelection.closest('.someAncestorSelector')
  .each((index, closestElement) => {
    // now, do something with closestElement.
  });

Btw, even jQuery implicitly handles collections, so your jQuery code could be changed to:

const containers = $('li').closest('div.listContainer');
containers.each(function (index, container) {
  container = $(container);
  // now do something with the `container`
});
knittl
  • 246,190
  • 53
  • 318
  • 364
  • Oh man. I misunderstood both k6 and jQuery - thought they'd both only return one element for the first selected item. Yes, .closest() first and then .each (if needed) is spot on. Thank you! I do wonder if there's a way to do the re-wrapping, but my actual underlying need is resolved. – jinglesthula Sep 15 '22 at 15:50
  • 1
    @jinglesthula depending on what you are doing with "the container", it might even be as simple as `$('li').closest('div.listContainer').addClass('myclass');` – collections in jQuery will implicitly apply such methods to all their elements. – knittl Sep 16 '22 at 06:51