TestCafe: Chaining selectors/functions doesn't seem to work - testing

I'm trying to chain together a Selector, a withText, a find, and another withText in order to find a particular link.
Here's the HTML I'm trying to search through, and I want to select the "Edit" button that's in the div with the text "Reviewers":
<div class="content">
<div class="ui edit-segment--header">Documents
<button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
</div>
<div class="ui segment segment__compact-top">
<div role="list" class="ui bulleted list">
<div role="listitem" class="item"><span>Budget</span></div>
<div role="listitem" class="item"><span>Draw cover sheet</span></div>
<!-- (a few more...) -->
</div>
</div>
</div>
<div class="content">
<div class="ui edit-segment--header">Rules
<button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
</div>
<div class="ui segment segment__compact-top">
<h4 class="ui header">Automatic</h4><span>No rules selected</span>
<h4 class="ui header">Manual</h4><span>No rules selected</span></div>
</div>
<div class="content">
<div class="ui edit-segment--header">Reviewers
<button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
</div>
<div class="ui segment segment__compact-top">
<div role="list" class="ui list">None</div>
</div>
</div>
I'm trying to click this using:
await t.click(Selector("div").withText("Reviewers").find("button").withText("Edit"));
TestCafe ends up finding the "Edit" button that's in the div with the text "Documents" inside and clicking it.
I would expect that Selector("div").withText("Reviewers") would find the specific div with the text Reviewers inside it, and then the .find("button").withText("Edit") would find the only child button (which happens to have the text Edit) inside that. Am I misunderstanding how it should work? Thanks

Your "Edit button" selector (Selector('div').withText('Reviewers').find('button').withText('Edit')) is correct.
I would expect that Selector("div").withText("Reviewers") would find the specific div with the text Reviewers inside it
The main point of your example is that the "Reviewers" (Selector('div').withText('Reviewers')) selector matches two div elements.
To illustrate it I made the following test in the context of your example page:
test.js
import { Selector } from 'testcafe';
fixture `fixture`
.page `http://localhost:8080`;
test('test', async t => {
const divReviewers = Selector('div').withText('Reviewers').addCustomDOMProperties({
outerHTML: el => el.outerHTML
});
await t
.expect(divReviewers.count).eql(2);
console.log('[1] divReviewers.nth(0).outerHTML:\n', await divReviewers.nth(0).outerHTML);
console.log('[2] divReviewers.nth(1).outerHTML:\n', await divReviewers.nth(1).outerHTML);
});
Result
[1] divReviewers.nth(0).outerHTML:
<div class="content">
<div class="ui edit-segment--header">Reviewers
<button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
</div>
<div class="ui segment segment__compact-top">
<div role="list" class="ui list">None</div>
</div>
</div>
[2] divReviewers.nth(1).outerHTML:
<div class="ui edit-segment--header">Reviewers
<button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
</div>
√ test
1 passed (1s)

Related

Vue JS: How to make two Vue Instances to work together on the same page?

I created a recipe website, you can find it here https://hungry-vegetarian.com/.
The tab on the index page is a vue instance. I'm trying to create a search bar that is also a vue instance.
The problem occurs when I try to display searched recipes on the index page. It just shows the search result on top of the search bar.
Ideally, only searched recipes should appear on the tab just like they are now but without any indications on top of the tab like Breakfast, Salad, Bakery, etc.
I don't know how to make two objects work together. For now, they work separately without communicating with each other.
SEARCH
<div id="search">
<div class="main-search">
<h1 class="search-question">What are you in the mood for?</h1>
<div class="search-box">
<input type="text" v-model="searchQuery" class="input-search" placeholder="Bread">
<button class="btn-search"><i class="fa fa-search"></i></button>
</div>
</div>
<div class="container">
<div class="recipe" v-for="post in filteredList">
<div v-if="searchQuery">
<a v-bind:href="post.url" class="recipe-card__card-link" target="_blank">
<img v-bind:src="post.image" alt="" class="recipe-card__image"/>
<div class="recipe-card__text-wrapper">
<h2 class="recipe-card__title">{{post.name}}</h2>
<div class="recipe-card__details-wrapper">
<p class="recipe-card__excerpt">{{post.body}}</p>
<a v-bind:href="post.url" class="recipe-card__read-more">Read more <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
tab
<main id="tab">
<header>
<nav>
<ul>
<div id="arrow">
<span></span>
<span></span>
<span></span>
</div>
<li v-for="(tab, tabName) in tabs" :key="tabName">
<button class="tab" #click="setTabActive(tabName)" :class="{'active': tabName === activeTab}">
<span class="tab-copy">{{ tabName }}</span>
<span class="tab-background">
</span>
</button>
</li>
</ul>
</nav>
</header>
<article>
<div class="container">
<transition name="fade" mode="out-in" appear :duration="500">
<tab-content v-for="(tabContent, t) in tabs" :data="tabContent" :key="'content'+t" v-if="t === activeTab" inline-template>
<div class="content-wrapper">
<div class="recipes" v-for="(recipe, i) in data.recipes" :key="i">
<a v-bind:href="recipe.url" class="recipe-card__card-link"></a>
<img :src="recipe.image" alt="" class="recipe-card__image">
<div class="recipe-card__text-wrapper">
<h2 class="recipe-card__title">{{recipe.name}}</h2>
<div class="recipe-card__details-wrapper">
<p class="recipe-card__excerpt">{{recipe.body}}</p>
<a v-bind:href="recipe.url" class="recipe-card__read-more">Read more <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
</div>
</tab-content>
</transition>
</div>
</article>
</main>
I tried to combine instances search and tab into just one instance tab, but it always gives me a Vue warning:
[Vue warn]: Property or method "searchQuery" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
Also, I feel like I can have just the wrong approach to this problem I am trying to solve. Please, any suggestions are welcome. I am stuck.

Bind a click event to a :title in Vue

So I'm trying to bind the click event so it only runs when the actually href title is clicked on. here is my code.
<collapse :multiple-active="false">
<div v-for="(campaign, index) in allCampaigns" :key="index">
<collapse-item :title="campaign.campaign_name" #click.native.prevent="grabClientFacebookData(campaign.id)">
<div v-if="spinner == true" style="text-align: center"><img src="../../../../img/spinner.gif"></div>
<div v-if="search == true">
<vue-good-table
:columns="columns"
:rows="tableData"
styleClass="vgt-table striped bordered"/>
<highcharts :options="chartOptions"></highcharts>
</div>
</collapse-item>
</div>
</collapse>
And here is the parent element:
<div class="card card-plain">
<div role="tab" id="headingOne" class="card-header">
<a data-toggle="collapse"
data-parent="#accordion"
:href="`#${itemId}`"
#click.prevent="activate"
:aria-expanded="active"
:aria-controls="`content-${itemId}`">
<slot name="title" #click.prevent="grabClientFacebookData(campaign.id)">
{{title}}
</slot>
<i class="now-ui-icons arrows-1_minimal-down"></i>
</a>
</div>
<collapse-transition :duration="animationDuration">
<div v-show="active"
:id="`content-${itemId}`"
role="tabpanel"
:aria-labelledby="title"
class="collapsed">
<div class="card-body">
<slot></slot>
</div>
</div>
</collapse-transition>
I am fairly new to vue and was wondering if it's possible. My problem is that the click event shoots whenever any port of the collapse is clicked, not just the title.
have you tried wrapping {{title}} in a span with the event bound to that? i.e.
<span #click.prevent="grabClientFacebookData(campaign.id)">{{title}}</span>

How to remove the html element using $http.delete in VueJS

I use $http.delete in a VueJS project to remove the users from a page. When I click on delete icon the user is delete it from the database but on the front end the html for that user is still on page. Will disappear if I refresh the page.
This whole HTML(down) is a user from a list of users, from a database. I tried wrapping the whole HTML with another div and use inside a v-if directive, but in this case will not show me any user.
So how can I remove the html element too, when I delete the user, without refreshing the page?
If there is another way to delete a user from database, beside this $http.delete, fell free to show it to me.
HTML
<template>
<div>
<div class="card visitor-wrapper">
<div class="row">
<div class="col-md-2">
<div class="checkbox checkbox-success">
<input type="checkbox" id="select-1">
<label for="select-1" style="width: 50px;"><img src="../../assets/icons/visitors-icon.svg" alt=""></label>
</div>
<i class="fa fa-user-o fa-2x" aria-hidden="true"></i>
</div>
<div class="col-md-3">
<p class="visitor-name">{{user.firstName}}</p>
<span class="visitor-email">{{user.userType}}</span>
</div>
<div class="col-md-2">
<p class="visitor-other-detail">{{user.rid}}</p>
</div>
<div class="col-md-2">
<p class="visitor-other-detail">{{user.departmentId}}</p>
</div>
<div class="col-md-2">
<p class="visitor-other-detail">{{createdDate(user.createdDate)}}</p>
</div>
<div class="col-md-1 divider-left">
<div class="edit-icon">
<router-link :to="'/users/edit-user/'+user.rid"><a data-toggle="tooltip" data-placement="top" title="Edit Employee"><i class="ti-pencil-alt" aria-hidden="true"></i></a></router-link>
</div>
<div class="trash-icon">
<a data-toggle="tooltip" data-placement="top" title="Delete Employee" #click="removeUser(user.rid)"><i class="ti-trash" aria-hidden="true"></i></a>
</div>
</div>
</div>
</div>
</div>
</template>
JS
export default {
props: ['user'],
methods: {
removeUser(item) {
this.$http.delete('/user/' + item)
.then((response) => {
console.log('response', response);
});
}
}
}
Set a v-if on the element that you want to have removed.
In your data you can have an attribute like; userIsActive or something which defaults to true. If your ajax call is a success you can set it to false which will make the element disappear with the v-if.
removeUser(item) {
this.$http.delete('/user/' + item)
.then((response) => {
this.userIsActive = false;
console.log('response', response);
});
}
Of course there are dozens of variations on how to do this but this might help you out.
you can use v-html for remove html text and only show text..
<p v-html="items"></p>

Hide html elements in vuejs2

I want to hide html elements during the initial load, by clicking a button or link i will show those html elements. I can't find a solution to hide or show the element in vuejs2 version. I can able to see few options in vuejs but i am not sure how to use those methods. Below is my component code in that i want to hide the html element(id) "Message".
<template>
<div class="row">
<div class="col-lg-12">
<label class="checkbox checkbox-inline no_indent">
<input type="checkbox" value="">Show stats
</label>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="panel-group">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">List Values</h3>
</div>
<div class="panel-body">
<button type="button" id="btn1" class="btn btn-warning btn-md" v-on:click="showWorkflow">Test 1</button>
<button type="button" id="btn2" class="btn btn-danger btn-md" v-on:click="showWorkflow">Test 2</button>
<button type="button" id="btn3" class="btn btn-info btn-md" v-on:click="showWorkflow">Test 3</button>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div id="Message">Hello i am here</div>
</div>
</template>
<script>
export default {
name: 'jobs',
methods: {
showWorkflow: function (e) {
console.log(e.target.id)
}
}
}
</script>
In Vue, you use the v-if directive to conditionally render elements.
You could also use the v-show directive if you wanted to just toggle the CSS display property.
See the section in the docs on Conditional Rendering for more info.
In your specific case, make showWorkflow a data property initially set to false.
Use this as the argument for a v-if directive on the content that you want to initially hide.
Then, when you want to show the content, set showWorkflow to true:
new Vue({
el: '#app',
data() {
return {
showWorkflow: false,
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<div v-if="showWorkflow">
Here is the workflow
</div>
<button #click="showWorkflow = true">Show Workflow</button>
</div>
Here is the documentation on conditional rendering in Vue

showing previous slide with using show/hide code

I have simple manual text slider with using show/hide code. every thing is ok but when i click previous slide button, current text will be hide but previous one won't show. why it doesn't show ?!
this is my html code:
<div class="hand_1" id="hand_1">
<img id="hand_img_1" src="myimage1.png" width="176.25" height="332.25" />
<div class="hand_text_1">
<h2>header</h2>
<p>paragraph 1</p>
<div class="connect-links">
<a id="next_icon_1" href="#" ></a>
</div>
</div>
</div>
<div class="hand_2" id="hand_2" style="display:none;">
<img id="hand_img_2" src="myimage2.png" width="176.25" height="332.25" />
<div class="hand_text_2">
<h2>header 2</h2>
<p>paragraph 2</p>
<div class="connect-links">
<a id="next_icon_2" href="#"></a>
<a id="previous_icon_2" href="#"></a>
</div>
</div>
</div>
and this is my javascript:
$(document).ready(function(){
$('#next_icon_1').on("click", function(){
$('#hand_img_1').fadeOut('fast');
$('.hand_text_1').fadeOut('fast');
$('.hand_2').fadeIn('fast');
});
$('#previous_icon_2').on("click", function(){
$('#hand_img_2').fadeOut('fast');
$('.hand_text_2').fadeOut('fast');
$('.hand_1').fadeIn('fast');
});
});