Protractor 'toContain' error - protractor

This is my expect:
expect(mandatoryFields[index].getAttribute('class')).toContain('error');
This is the error in console:
Expected['formControl ng-pristine ng-untouched ng-valid ng-empty ng-valid-maxlength error'] to contain 'error'.
Eventhough the class contains ERROR class name, protractor is still throwing error. What could be reason? Any help!!!

Instead of toContain try using toMatch. toContain is used to check whether the required value is present in an array or not. whereas toMatch uses regex for validating the text present in any value.

You could try adding a custom matcher in your beforeEach(), then calling expect(mandatoryFields[index]).toHaveClass('error');
jasmine.addMatchers([
toHaveClass: function () {
return {
compare: function (element, className) {
return {
pass: element.getAttribute('class').then(function (classes) {
return classes.split(' ').indexOf(className) !== -1||classes.split(' ').indexOf(className+"\n") !== -1;
}),
message: "Expected elemenet to have class: "+className
}
},
negativeCompare: function(element, className){
return {
pass: element.getAttribute('class').then(function (classes) {
return classes.split(' ').indexOf(className) !== -1||classes.split(' ').indexOf(className+"\n") === -1;
}),
message: "Expected element not to have class: " + className
}
}
}
}
]);

Related

Vue authorization with Pinia - How do I get my functions to return values and not promises?

I'm working on front end authorization with Vue and Pinia. My goal is to fetch a list of permissions belonging to the current user into my component file and then check if the User has the permission to see certain aspects of my component.
The problem arises when I use v-if to call my methods and check whether the user has the required permission. My function values are never returned and it always defaults to true.
This is what my auth.js file looks like:
export const useAuthStore = defineStore({
id: "authentication",
state: () => ({
...,
...,
userPermissions: fetchUserPerm(), //!!!
)},
const fetchUserPerm = async () => {
const res = await axios.get("api/users/me");
// My Laravel back end returns a User object with a Role property
which contains a list of all the permissions tied to this user:
return res.data.role.permissions;
};
And this is code contained within the component that I want to fetch the permissions to:
<script>
import router from "../../../router";
import axios from "axios";
import Modal from "../../UI/Modal.vue";
import { useAuthStore } from "../../../stores/auth";
export default {
setup() {
const authStore = useAuthStore();
return { authStore };
},
data() {
return {
...,
...,
userPermissions: this.authStore.userPermissions,
filteredPermissions: null,
};
},
I tried the following in "methods" and "computed" within my component:
methods:{
async checkUserPermFn(value) {
this.userPermissions = await this.userPermissions;
this.filteredPermissions = this.userPermissions.filter((permission) => {
return permission.name.includes(value);
});
console.log(this.filteredPermissions); //CORRECTLY LOGS AFTER FILTERING:
Proxy { <target>: [], <handler>: {…} }
<target>: Array []
return this.filteredPermissions.length > 0; //Gets ignored
},
}
computed:{
async checkPermission() {
this.userPermissions = await this.userPermissions;
console.log(this.userPermissions,"computed"); //CORRECTLY LOGS :
Proxy { <target>: (22) […], <handler>: {…} }
target>: Array(22)
this.filteredPermissions = this.userPermissions.filter(
(permission) => {
return permission.name.includes('permission.name');
}
);
console.log(this.filteredPermissions,"computed"); // CORRECTLY LOGS AFTER FILTERING:
Proxy { <target>: [], <handler>: {…} }
<target>: Array []
console.log(this.filteredPermissions.length)// CORRECTLY LOGS 0
return this.filteredPermissions.length > 0;
},
},
Now in my component I try check what gets returned from my methods and why does it still render them:
<div v-if="checkUserPermFn(value)"><p>Hi!</p></div>
This div is still shown even though the method should return false, and when I console log what my method returns I just get a promise:
Promise { <state>: "pending" }
​
<state>: "fulfilled"
Doing the same thing but with the computed method:
<div v-if="checkUserPermFn(value)"><p>Hi!</p></div>
The div is shown again even though the method should return false, and when I console log what my computed method returns I get a promise again but this time it contains the correct value too:
Promise { <state>: "fulfilled", <value>: false }
​
<state>: "fulfilled"
What am I missing here? I tried resolving promises but that only works within the method, when I try to return the resolved value I get a promise again. Thanks everyone!

Custom Select() with parameter

UPDATE
As of #NGXS v3.1, they finally introduced arguments into #Selector().
https://www.ngxs.io/concepts/select#lazy-selectors
Examples from the DOCS
First, you define the #Selector "pandas"
#State<string[]>({
name: 'animals',
defaults: []
})
#Injectable()
export class ZooState {
#Selector()
static pandas(state: string[]) {
return (type: string) => {
return state.filter(s => s.indexOf('panda') > -1).filter(s => s.indexOf(type) > -1);
};
}
}
Then you just call it in your '.ts' file
import { Store } from '#ngxs/store';
import { map } from 'rxjs/operators';
#Component({ ... })
export class ZooComponent {
babyPandas$: Observable<string[]>;
constructor(private store: Store) {
this.babyPandas$ = this.store
.select(ZooState.pandas)
.pipe(map(filterFn => filterFn('baby')));
}
}
* From Old Post *
I am trying to create a custom #Select () to be able to drill down a particular tree and return the values dynamically. Getting either undefined or it's not making it (executing)
user.component.ts
const location = 'new york'
#Select(state => UserState.getUserLocationSlots(state, location)) slots$;
user.state.ts
#Selector()
static getUserLocationSlots(state: UserStateModel, location: any) {
console.log(state);
console.log(location); // <-- expecting 'new york', but getting undefined
}
You can achieve this by using crateSelector function from #ngxs/store
In your .state.ts file:
static getLocationSlots(location: string) {
return createSelector([UserState], (state: string[) => {
// logic for filtering your data
// eg.: state.filter(element => element == location)
})
}
In your .component.ts file:
#Select(UserState.getLocationSlots('new york')) slots$: Observable<any>
You can also check here for more details
I don't think it is possible to pass parameter to #Selector() decorated functions in ngxs v2. It would be nice though.
A ticket exist for this feature request.
Also, I think you are not using #Selector() correctly. I should be something like (hence, cannot pass parameters):
#Select(UserState.getUserLocationSlots) slots$
Refer to the docs.
Note: I am not an expert in ngxs...this is just based on what I understand now.
This is achievable in NGXS v2 & v3. Copied from my comment in the discussion on dynamic selectors here
We can achieve this at the moment using a pattern often used for redux
selectors...
The #Selector decorator can be written so that it returns a function
with the desired parameter. This enables the desired dynamic selector
arguments as well as late resolution of the selected state. For
Example:
#State<UserStateModel>( ... )
export class UserState {
#Selector()
getFilteredUsersFn(userStateModel: UserStateModel) {
return (filter: string) =>
userStateModel.users.filter((user) => user.indexOf(filter) >= 0);
}
}
And then the component would contain:
#Component({...})
export class AppComponent {
#Select(UserState.getFilteredUsersFn)
filteredUsersFn$: Observable<(filter: string) => User[]>;
get currentFilteredUsers$() {
return this.filteredUsersFn$
.pipe(map(filterFn => filterFn('myFilter')));
}
}
To pass parameters you can have the select return a function, it isn't elegant, however it works.
For example the select statement would look like:
#Selector()
static getItemByIdFn(state: { [id: number]: Entity }) {
return (id: number) => {
return state[id];
};
}
then in the component:
this.store.select(MyState.getItemByIdFn)
.pipe(map(mapByIdFn) => mayByIdFn(1)) // using the returned function
.subscribe(...);
Note the map, which is where you pass your id to the returned function. Here you can place whatever parameters you would like.
Hope this helps :)!

How to fix a Wait condition error?

I have a browser.wait() in an E2E test which is invoking a function defined in protractor.config.js file. When running the test, I get the following error:
Failed: Wait condition must be a promise-like object, function, or a Condition object
FYI - the function defined in protractor.config.js contains an If-condition which I need for two cases. When I remove the If-condition, the test runs fine. The function returns a: deferred.promise
What does this exactly means and how to fix it? Have been searching, but unfortunately can't anything related to it.
Function in protractor.config.js:
checkMail: function(user, subjectSent) {
const deferred = protractor.promise.defer();
var usermail;
var mailsubject;
var count = 0;
mailListener.on("mail", function(mail, seqno, attributes) {
var mailuid = attributes.uid;
var toMailbox = '[Gmail]/All Mail';
var i = ++count;
user = mail.to[0].address;
mailsubject = mail.subject;
if (i > 2) {
mailListener.stop();
return;
}
deferred.fulfill(mail);
});
if ((user === usermail) && (subjectSent === mailsubject)) {
return deferred.promise;
}
}
E2E it-function:
it("It should do xxxxxxx", (done) => {
browser.wait(browser.params.checkMail('user_email#yyyyy.com', 'Email subject'))
.then((email) => {
expect(email['subject']).toEqual("Email subject");
expect(email['headers'].to).toEqual( 'user_email#yyyyy.com' );
});
done();
});

protractor - try catch - error handling

I am looking for an element and if the element is not present, I want to give a decent error message saying "element not present"; but it comes out of the block and throwing a message like element not found for the xpath.
Below is the code I have tried but I'm still getting the same error.
For example a=protractor and if the value is present, it says text prevails - protractor; and in case it is not there, instead of saying element not present/error occurs it says "no element found element(by.xpath("//div[#title='"protractor"']")) followed by a big error message.
How to resolve this?
this.gridverify = function (a) {
browser.sleep(10000);
try {
var elm = element(by.xpath("//div[#title='" + a + "']"));
if (elm.isPresent) {
elm.getText().then(function (x) {
console.log("text Prevails: " + x);
})
}
else {
console.log('element not present');
}
}
catch (err) {
console.log('error occured');
}
}
Try:
browser.wait(until.presenceOf(element(by.className("user-thumb"))),5000,'Element not present');
browser.wait(until.presenceOf(element(Add Locator here)),wait time,'Add Message you want to print in case element not found');
This might resolve your problem.
Consider digging more deeply into promises. Your code has a lot of errors. http://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/promise.html
this.gridverify = function (a) {
browser.sleep(10000); // Why this needed? Can you update to .wait() ?
var elm = element(by.xpath("//div[#title='" + a + "']"));
elm.isPresent().then(present => {
if (present) {
elm.getText().then(function (x) {
console.log("text Prevails: " + x);
})
} else {
console.log('element not present');
}
}, err => {
console.log('error occured', err);
})
}
Your try/catch won't work as you expecting in async code.

How to get Meteor.Call to return value for template?

I've tried to understand this post regarding this concept, however, I'm failing to get it. I have the following simple setup:
/server/test.js
Meteor.methods({
abc: function() {
var result = {};
result.foo = "Hello ";
result.bar = "World!";
return result;
}
});
/client/myapp.js
var q = Meteor.call('abc');
console.log(q);
This structure returns to the console undefined.
If I change the myapp.js file to:
Meteor.call('abc', function(err, data) {
!err ? console.log(data) : console.log(err);
}
I receive the Object in my console.
Ideally this is what I'd like to be able to do, but it doesn't work, stating in the console: Cannot read property 'greeting' of undefined
/client/myapp.js
var q = Meteor.call('abc');
Template.hello.greeting = function() {
return q.foo;
}
Any help in passing the data from the server object into the template would be greatly appreciated. I'm still learning JavaScript & Meteor.
Thanks!
From the Meteor.call documentation:
On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method. That is because the client doesn't have fibers, so there is not actually any way it can block on the remote execution of a method.
So, you'll want to do it like this:
Meteor.call('abc', function(err, data) {
if (err)
console.log(err);
Session.set('q', data);
});
Template.hello.greeting = function() {
return Session.get('q').foo;
};
This will reactively update the template once the data is available.
This happens because Npm.require has Async behavior. That's the reason that you have to write a callback for Meteor.call.
But there is a solution, just use install(mrt add npm) and you'll get a function named Meteor.sync(//...) with this you can do both games: sync and async in your Meteor.call().
Reference: http://www.sitepoint.com/create-a-meteor-app-using-npm-module/
You can get the return value of a Meteor method for use in a template by using a reactive variable. Check out the working demonstration on Meteorpad
I went for a ghetto solution. But, it works for me, which is what matters, to me. Below is my code, which, in concept, I think, solves OP's problem.
In the client's main.js:
Meteor.setInterval(function() {
confirmLogin();
}, 5000);
This runs the confirmLogin() function every five seconds.
The confirmLogin function (in the client's main.js):
function confirmLogin() {
Meteor.call('loggedIn', function (error, result) {
Session.set("loggedIn", result);
});
}
The loggedIn method (in the server's main.js):
loggedIn: function () {
var toReturn = false;
var userDetails = Meteor.user();
if (typeof userDetails["services"] !== "undefined") {
if (typeof userDetails["services"]["facebook"] != "undefined") {
toReturn = true;
}
}
return toReturn;
},
The relevant helper:
loggedIn: function () {
return Session.get("loggedIn");
}