how to use params in meteor mongo query with react router - mongodb

I cannot get my id parameter to show up in the createContainer block.
class Host extends Component {
render() {
return (
<div>
{console.log(this.props.routeParams.hostId)} //works great
</div>
)
}
}
export default createContainer(() => {
Meteor.subscribe('hosts');
return {
hosts: Hosts.findOne({_id: this.props.routeParams.hostId}), //returns undefined
};
}, Host);
I want to do a query by id here, but the parameters are only available in the class itself. Not in the create container block.
How do I get my parameter to show up in createContainer?

Scope of 'this' might cause a problem. Maybe defining the param outside of the return method might work. Can you give this a try
export default createContainer(({routeParams}) => {
const id = routeParams.hostId;
Meteor.subscribe('hosts');
return {
hosts: Hosts.findOne({_id: id}),
};
}, Host);

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!

Google analytics user property react-ga4

I'm using react-ga4.
I wonder how i could send user properties using this library and set it up in the google analytics panel as I think that i'm doing something wrong.
This is how i initialize ReactGA4
ReactGA.initialize(
[
{
trackingId: id,
gaOptions: {
role: userRole,
}
},
]
)
any suggestion?
It depends what user properties that you want to send. You can send custom user properties that not reserved by Google.
For example, I want to send account_verified with boolean value and name with string value in user property.
You can use ReactGA.gtag(...args) in this library, and then you can use it directly or put it into utils/analytics.js and wrap it to export function with parameter, so you can use it whenever it needs.
import ReactGA from "react-ga4";
ReactGA.gtag("set", "user_properties", {
account_verified: true,
});
ReactGA.gtag("set", "user_properties", {
name: "John",
});
or
import ReactGA from "react-ga4";
export const setAccountProperty = (value: boolean) => {
ReactGA.gtag("set", "user_properties", {
account_verified: value,
});
};
export const setNameProperty = (value: string) => {
ReactGA.gtag("set", "user_properties", {
name: value,
});
};
After that, you can check in your Google Analytics in DebugView directly to ensure your user properties works well.

How to call a customhelper in CodeCeptjs?

How to call a method defined in customhelper?
MycustomHelper
const { Helper } = codeceptjs;
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const expect = chai.expect;
class MyHelper extends Helper {
async JavaScriptclick(LocatorVale) {
await browser.waitForAngularEnabled(true);
browser.executeScript("arguments[0].click();", element(by.xpath(LocatorVale)));
}
}
module.exports = MyHelper;
Code.js
helpers: {
MyHelper: {
require: './myhelper_helper.js',
},
Stepfile.js
Scenario('Add a new user group', (I, MyHelper) => {
MyHelper.JavaScriptclick(‘.badged-button.mat-raised-button.mat-primar')
});
If I execute the above code, I get the below error
Add a new user group:
Object of type MyHelper is not defined in container
Please help me to resolve this issue. I need to click on a button, but I.click is not able to locate the button. So I had to use javascriptclick in this case. However I.executescript is also not working. Hence I need to use native protractor commands as it works only this way.
There are no need to call helper by it's name.
All methods are added in actor (I) object
As said in documentation:
Methods of Helper class will be available in tests in I object. This abstracts test scenarios from the implementation and allows easily switching between backends.
https://codecept.io/helpers/#extending-codeceptjs-with-custom-helopers
So, in test:
Scenario('Add a new user group', (I) => {
I.JavaScriptclick(‘.badged-button.mat-raised-button.mat-primar')
});

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 :)!

What's the correct Protractor's syntax for Page Objects?

I've come across different types of syntax for Protractor's Page Objects and I was wondering, what's their background and which way is suggested.
This is the official PageObject syntax from Protractor's tutorial. I like it the most, because it's clear and readable:
use strict;
var AngularHomepage = function() {
var nameInput = element(by.model('yourName'));
var greeting = element(by.binding('yourName'));
this.get = function() {
browser.get('http://www.angularjs.org');
};
this.setName = function(name) {
nameInput.sendKeys(name);
};
this.getGreeting = function() {
return greeting.getText();
};
};
module.exports = AngularHomepage;
However, I've also found this kind:
'use strict';
var AngularPage = function () {
browser.get('http://www.angularjs.org');
};
AngularPage.prototype = Object.create({}, {
todoText: { get: function () { return element(by.model('todoText')); }},
addButton: { get: function () { return element(by.css('[value="add"]')); }},
yourName: { get: function () { return element(by.model('yourName')); }},
greeting: { get: function () { return element(by.binding('yourName')).getText(); }},
todoList: { get: function () { return element.all(by.repeater('todo in todos')); }},
typeName: { value: function (keys) { return this.yourName.sendKeys(keys); }} ,
todoAt: { value: function (idx) { return this.todoList.get(idx).getText(); }},
addTodo: { value: function (todo) {
this.todoText.sendKeys(todo);
this.addButton.click();
}}
});
module.exports = AngularPage;
What are the pros/cons of those two approaches (apart from readability)? Is the second one up-to-date? I've seen that WebdriverIO uses that format.
I've also heard from one guy on Gitter that the first entry is inefficient. Can someone explain to me why?
Page Object Model framework becomes popular mainly because of:
Less code duplicate
Easy to maintain for long
High readability
So, generally we develop test framework(pom) for our convenience based on testing scope and needs by following suitable framework(pom) patterns. There are NO such rules which says that, strictly we should follow any framework.
NOTE: Framework is, to make our task easy, result oriented and effective
In your case, 1st one looks good and easy. And it does not leads to confusion or conflict while in maintenance phase of it.
Example: 1st case-> element locator's declaration happens at top of each page. It would be easy to change in case any element locator changed in future.
Whereas in 2nd case, locators declared in block level(scatter across the page). It would be a time taking process to identify and change the locators if required in future.
So, Choose which one you feel comfortable based on above points.
I prefer to use ES6 class syntax (http://es6-features.org/#ClassDefinition). Here, i prepared some simple example how i work with page objects using ES6 classes and some helpful tricks.
var Page = require('../Page')
var Fragment = require('../Fragment')
class LoginPage extends Page {
constructor() {
super('/login');
this.emailField = $('input.email');
this.passwordField = $('input.password');
this.submitButton = $('button.login');
this.restorePasswordButton = $('button.restore');
}
login(username, password) {
this.email.sendKeys(username);
this.passwordField.sendKeys(password);
this.submit.click();
}
restorePassword(email) {
this.restorePasswordButton.click();
new RestorePasswordModalWindow().submitEmail(email);
}
}
class RestorePasswordModalWindow extends Fragment {
constructor() {
//Passing element that will be used as this.fragment;
super($('div.modal'));
}
submitEmail(email) {
//This how you can use methods from super class, just example - it is not perfect.
this.waitUntilAppear(2000, 'Popup should appear before manipulating');
//I love to use fragments, because they provides small and reusable parts of page.
this.fragment.$('input.email').sendKeys(email);
this.fragment.$('button.submit')click();
this.waitUntilDisappear(2000, 'Popup should disappear before manipulating');
}
}
module.exports = LoginPage;
// Page.js
class Page {
constructor(url){
//this will be part of page to add to base URL.
this.url = url;
}
open() {
//getting baseURL from params object in config.
browser.get(browser.params.baseURL + this.url);
return this; // this will allow chaining methods.
}
}
module.exports = Page;
// Fragment.js
class Fragment {
constructor(fragment) {
this.fragment = fragment;
}
//Example of some general methods for all fragments. Notice that default method parameters will work only in node.js 6.x
waitUntilAppear(timeout=5000, message) {
browser.wait(this.EC.visibilityOf(this.fragment), timeout, message);
}
waitUntilDisappear(timeout=5000, message) {
browser.wait(this.EC.invisibilityOf(this.fragment), timeout, message);
}
}
module.exports = Fragment;
// Then in your test:
let loginPage = new LoginPage().open(); //chaining in action - getting LoginPage instance in return.
loginPage.restorePassword('batman#gmail.com'); // all logic is hidden in Fragment object
loginPage.login('superman#gmail.com')