How to click all matching elements in Webdriver? - webdriver-io

How do you click all elements that match a selector, instead of just the first one?
elems = browser.elements '.item-checkbox'
console.log elems
for elem in elems
# neither of these work
browser.click elem
elem.click()
{ state: 'success',
sessionId: '66fe2543-7b28-40e7-8bbb-d7da7d2af928',
hCode: 1564933402,
value:
[ { ELEMENT: '702' },
{ ELEMENT: '703' },
{ ELEMENT: '704' },
{ ELEMENT: '705' },
{ ELEMENT: '706' },
{ ELEMENT: '707' } ],
class: 'org.openqa.selenium.remote.Response',
status: 0 }

http://webdriver.io/api/protocol/elementIdClick.html
res.value.forEach(function(elem) {
browser.elementIdClick(elem.Element, function(err, res) {
})
})
https://github.com/webdriverio/webdriverio/issues/273

Related

vue3 nested search filter

Please help to return filteredList() based on comparing for similarity input search with key 'info': array.
It always says its undefined.
export default {
data() {
return {
search: "",
postList: [
{
title: "hello",
info: ["one", "two", "three", "four"],
},
{
title: "goodbye",
info: ["five", "six"],
},
],
};
},
computed: {
filteredList() {
return this.postList.filter((item) => {
return item.info.includes(this.search);
});
},
},
};
</script>

Get tiptap-vuetify to work with "Mentions" in a Vue Nuxt app

so my problem is that I can't seem to make use of the "Mentions" functionality of tiptap inside a vuetify-nuxt project.
The original example can be found here
More useful info:
Example implementation from the tiptap github here
Similar question asked and not answered fully here
Similar question asked in the vuetify integration library here
To do that I'm trying to combine documentation examples.
I guess it goes wrong around the time I try to use "tippy", which is the css library used to display the popup that actually lists users to pick from (after the #), but I can't seem to understand the real issue.
So when I type # the keydown/up event listeners are functioning, but the tippy seems to not bind the popup successfully (it's not displayed), and the following error occurs:
Editor.vue?6cd8:204 Uncaught TypeError: Cannot read property '0' of undefined
at VueComponent.enterHandler (Editor.vue?6cd8:204)
at onKeyDown (Editor.vue?6cd8:175)
at Plugin.handleKeyDown (extensions.esm.js?f23d:788)
at eval (index.es.js?f904:3298)
at EditorView.someProp (index.es.js?f904:4766)
at editHandlers.keydown (index.es.js?f904:3298)
This is my tippy.js nuxt plugin:
import Vue from "vue";
import VueTippy, { TippyComponent } from "vue-tippy";
Vue.use(VueTippy, {
interactive: true,
theme: "light",
animateFill: false,
arrow: true,
arrowType: "round",
placement: "bottom",
trigger: "click",
// appendTo: () => document.getElementById("app")
});
Vue.component("tippy", TippyComponent);
This is the component in which I'm trying to show the editor and the suggestions/mentiosn functionality:
<template>
<div>
<div class="popup">
aaaa
</div>
<editor-menu-bar v-slot="{ commands }" :editor="editor">
<div class="menubar">
<v-btn class="menubar__button" #click="commands.mention({ id: 1, label: 'Fred Kühn' })">
<v-icon left>#</v-icon>
<span>Mention</span>
</v-btn>
</div>
</editor-menu-bar>
<tiptap-vuetify v-model="localValue" :extensions="extensions" :native-extensions="nativeExtensions" :toolbar-attributes="{ color: 'grey' }" #init="onInit" />
</div>
</template>
<script>
// import the component and the necessary extensions
import {
TiptapVuetify,
Heading,
Bold,
Italic,
Strike,
Underline,
Code,
CodeBlock,
Image,
Paragraph,
BulletList,
OrderedList,
ListItem,
Link,
Blockquote,
HardBreak,
HorizontalRule,
History,
} from "tiptap-vuetify";
// TESTING
import { EditorMenuBar, Editor } from "tiptap";
import { Mention } from "tiptap-extensions";
import tippy, { sticky } from "tippy.js";
export default {
components: { TiptapVuetify, EditorMenuBar },
props: {
value: {
type: String,
default: "",
},
},
data: () => ({
editor: null,
extensions: null,
nativeExtensions: null,
// TESTING
query: null,
suggestionRange: null,
filteredUsers: [],
navigatedUserIndex: 0,
insertMention: () => {},
popup: null,
}),
computed: {
localValue: {
get() {
return this.value;
},
set(value) {
this.$emit("input", value);
},
},
// TESTING
hasResults() {
return this.filteredUsers.length;
},
showSuggestions() {
return this.query || this.hasResults;
},
},
created() {
this.extensions = [
History,
Blockquote,
Link,
Underline,
Strike,
Italic,
ListItem,
BulletList,
OrderedList,
[
Heading,
{
options: {
levels: [1, 2, 3],
},
},
],
Bold,
Link,
Code,
CodeBlock,
Image,
HorizontalRule,
Paragraph,
HardBreak,
];
this.nativeExtensions = [
// https://github.com/ueberdosis/tiptap/blob/main/examples/Components/Routes/Suggestions/index.vue
new Mention({
// a list of all suggested items
items: async () => {
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
return [
{ id: 1, name: "Sven Adlung" },
{ id: 2, name: "Patrick Baber" },
{ id: 3, name: "Nick Hirche" },
{ id: 4, name: "Philip Isik" },
{ id: 5, name: "Timo Isik" },
{ id: 6, name: "Philipp Kühn" },
{ id: 7, name: "Hans Pagel" },
{ id: 8, name: "Sebastian Schrama" },
];
},
// When # is pressed, we enter here
onEnter: ({ items, query, range, command, virtualNode }) => {
this.query = query; // the field that the # queries? currently empty
this.filteredUsers = items;
this.suggestionRange = range;
this.renderPopup(virtualNode); // render popup - failing
this.insertMention = command; // this is saved to be able to call it from within the popup
},
// probably when value after # is changed
onChange: ({ items, query, range, virtualNode }) => {
this.query = query;
this.filteredUsers = items;
this.suggestionRange = range;
this.navigatedUserIndex = 0;
this.renderPopup(virtualNode);
},
// mention canceled
onExit: () => {
// reset all saved values
this.query = null;
this.filteredUsers = [];
this.suggestionRange = null;
this.navigatedUserIndex = 0;
this.destroyPopup();
},
// any key down during mention typing
onKeyDown: ({ event }) => {
if (event.key === "ArrowUp") {
this.upHandler();
return true;
}
if (event.key === "ArrowDown") {
this.downHandler();
return true;
}
if (event.key === "Enter") {
this.enterHandler();
return true;
}
return false;
},
// there may be built-in filtering, not sure
onFilter: async (items, query) => {
await console.log("on filter");
},
}),
];
},
methods: {
// TESTING
// navigate to the previous item
// if it's the first item, navigate to the last one
upHandler() {
this.navigatedUserIndex =
(this.navigatedUserIndex + this.filteredUsers.length - 1) %
this.filteredUsers.length;
},
// navigate to the next item
// if it's the last item, navigate to the first one
downHandler() {
this.navigatedUserIndex =
(this.navigatedUserIndex + 1) % this.filteredUsers.length;
},
enterHandler() {
const user = this.filteredUsers[this.navigatedUserIndex];
if (user) {
this.selectUser(user);
}
},
// we have to replace our suggestion text with a mention
// so it's important to pass also the position of your suggestion text
selectUser(user) {
this.insertMention({
range: this.suggestionRange,
attrs: {
id: user.id,
label: user.name,
},
});
this.editor.focus();
},
renderPopup(node) {
if (this.popup) {
return;
}
// ref: https://atomiks.github.io/tippyjs/v6/all-props/
this.popup = tippy(".page", {
getReferenceClientRect: node.getBoundingClientRect, // input location
appendTo: () => document.body, // must be issue
interactive: true,
sticky: true, // make sure position of tippy is updated when content changes
plugins: [sticky],
content: this.$refs.suggestions,
trigger: "mouseenter", // manual
showOnCreate: true,
theme: "dark",
placement: "top-start",
inertia: true,
duration: [400, 200],
});
},
destroyPopup() {
if (this.popup) {
this.popup[0].destroy();
this.popup = null;
}
},
beforeDestroy() {
this.destroyPopup();
},
/**
* NOTE: destructure the editor!
*/
onInit({ editor }) {
this.editor = editor;
},
},
};
</script>
How can I get the "suggestions" item display in the aforementioned setting?

Render function partly working, how can i fix this?

My render function doesn't work like expecting, i tried a few things, but i cannot understand why it isn't working. Can someone help me out ?
As you can see below it does create the UL element but not the LI element, same goes for both conditions.
render: function (createElement) {
var list;
if (this.items.length > 0) {
list = createElement(
'ul',
{
class: {
'v7-modal-list': true
}
},
this.items.map(function (item) {
return createElement(
'li',
createElement(
'label',
[
createElement(
'span',
item.name
),
createElement(
'input',
{
attrs: {
type: "checkbox"
}
}
)
]
)
)
})
)
} else {
list = createElement(
'ul',
{
class: {
'v7-modal-list': true
}
},
createElement(
'li',
{
class: {
"v7-modal-empty-list": true
}
},
"Empty list"
)
)
}
return createElement(
'div', [
createElement(
'h4',
{
class: {
"v7-modal-title-4": true
}
},
this.name
),
list
]
)
}
Output:
<div><h4 class="v7-modal-title-4">Log::</h4><ul class="v7-modal-list"></ul></div>
createElement arguments: (nodeName, attributes, elements) as described https://v2.vuejs.org/v2/guide/render-function.html#createElement-Arguments.
Elements must be array (or string if text node is used). It may be array in array as it will be flattened. So this code must work:
list = createElement(
'ul',
{
class: {
'v7-modal-list': true
}
},
[createElement(
'li',
{
class: "v7-modal-empty-list"
},
"Empty list"
)]
)
Commented out code is correct.

Vue.js dynamic component render "Failed to resolve directive"

Currently I have solved things in an other way, but I am still curious why this is not working.
I'm trying to render a transition with a template with 2 directives, but it seems it tries to resolve the attrs/props from an other scope, but I can't see why at this point. Perhaps I just made a stupid mistake.
This gives me the error:
"[Vue warn]: Failed to resolve directive: ..." for both bind and text
<script>
import Step from './Step';
export default {
data() {
return {
pointer: 0,
steps: [],
}
},
render(createElement) {
this.steps = this.$slots.default
.filter(vnode => vnode.tag && vnode.tag.indexOf(Step.name) > -1);
this.pointer = this.steps[0].key;
return createElement('div',
{},
[
createElement('transition',
{},
[
createElement('template', {
directives: [
{name: 'bind', arg: 'key', value: 'pointer'},
{name: 'text', value: 'step'},
],
})
]
)
]);
},
computed: {
step() {
return _.find(this.steps, step => step.key === this.pointer);
}
},
methods: {
next() {
++this.pointer;
}
}
}
</script>

Map on a set is not triggered if an item is updated

gun 0.8.7, Node.js-to-Node.js, no browser.
Nodes are successfully created and added to the tasks set
const Gun = require('gun');
const _ = require('lodash');
require( "gun/lib/path" );
const gun = new Gun({peers:['http://localhost:8080/gun', 'http://localhost:8081/gun']});
const watchers = [
{
id: '123',
type: 'skeleton',
stat: {
num: 0
}
},
{
id: '456',
type: 'snowmann',
stat: {
num: 0
}
},
{
id: '789',
type: 'moose',
stat: {
num: 0
},
}
];
const tasks = gun.get('tasks');
_.forEach(watchers, function (watcher) {
let task = gun.get(`watcher/${watcher.id}`).put(watcher);
tasks.set(task);
});
There are results of the .map evaluation
a2task { _:
{ '#': 'watcher/123',
'>': { id: 1506959623558, type: 1506959623558, stat: 1506959623558 } },
id: '123',
type: 'skeleton',
stat: { '#': 'j8acunbf70NblJptwXWa' } }
task { _:
{ '#': 'watcher/456',
'>':
{ id: 1506959623579.002,
type: 1506959623579.002,
stat: 1506959623579.002 } },
id: '456',
type: 'snowmann',
stat: { '#': 'j8acunbv03sor9v0NeHs7cITj' } }
task { _:
{ '#': 'watcher/789',
'>':
{ id: 1506959623581.002,
type: 1506959623581.002,
stat: 1506959623581.002 } },
id: '789',
type: 'moose',
stat: { '#': 'j8acunbx03sorM0hWZdQz0IyL' } }
on a listener side
const Gun = require('gun');
const gun = new Gun({peers:['http://localhost:8080/gun']});
const tasks = gun.get('tasks');
tasks.map().val(function (task) {
console.log('task', task);
});
But there are no results if one of the properties updated:
_.forEach(watchers, function (watcher) {
gun.get(`watcher/${watcher.id}`).put({
stat: {
num: 1
}
});
Why?
Here is the code to play with https://github.com/sergibondarenko/shared-schedule
It gets no update because you're not mapping that level. 'stat' is already a property that is an object so you get no change.
tasks.map().map().val(function (task_stat) {
console.log('task stat', task_stat);
});