How to encapsulate 'Role' functionality into page model to log in only once - testcafe

Currently we are using testcafe to implement our test cases, and we'd like to encapsulate some page models for reusing purpose. In testcafe there is a 'Role' functionality that we want to leverage in our 'log_in' function so that we could log in only once in each test suite. The page model code is like below:
app.js
async _login(url, userName, password) {
const userRole = Role(url, async (t) => {
await t
.typeText(this.user, userName)
.typeText(this.password, password)
.click(this.signIn)
.expect(this.home.exists)
.ok("The file icon should exist after logging on");
}, { preserveUrl: true });
await t.useRole(userRole);
}
async login1stApp() {
await this._login(config.firstUrl, config.user, config.password)
}
async login2ndApp() {
await this._login(config.secondUrl, config.user, config.password,
)
}
And in the test code, we will simply reference this page model and execute login function in beforeEach hook:
test.js
fixture`check ui`.beforeEach(async (t) => {
await app.login1stApp();
});
test(`test a`, async (t) => {
...
});
test(`test b`, async (t) => {
....
});
It seems that the 'Role' does not take effect. Instead of logging in only once, testcafe will log in for each test case every time.
Is there any solution to make the 'Role' work based on current implementation? Thanks!

You need to rewrite your page model class so that the t.useRole(role) method call is placed in the beforeEach hook.
So, the fixed page model implementation will look as follows:
import { Role, t } from 'testcafe';
class App {
constructor() {
this._login1AppRole = Role('https://example.com', async (t) => {
await t.wait(1000);
}, { preserveUrl: true });
}
async login1stApp() {
await t.useRole(this._login1AppRole);
}
}
export default new App();

Related

Add a new column and also index it using knex?

I have a simple knext migration to add a new column:
import * as Knex from "knex";
export async function up(knex: Knex): Promise<void> {
await knex.schema.alterTable("bins", (table) => {
table.bigInteger("parent_lsn").defaultTo(null).after("lsn").index();
});
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.alterTable("bins", (table) => {
table.dropColumns("parent_lsn");
});
}
I tried adding the .index() in there, but it's not seeming to reflect as an indexed column in the database. Not sure where I'm going wrong here?

React Admin - Redirecting to a page after login

I have a react admin application with a customRoutes, as well as resources (say /users). One of my custom route is a private page (say /private), which I protect with the useAuthenticated() hook:
export default () => {
useAuthenticated();
return (<Card>
<Title title="Private Page" />
<CardContent>
This is a private page.
</CardContent>
</Card>)
}
When I browse this private page and I'm not authenticated, I'm entering an authentication process as it should be (I'm using OIDC). This process is triggered by the checkAuth() method of the authProvider. But when the process is completed, I'm redirected to the /users resource and not the /private page. Is there a way to tell the authProvider that I want to be redirected to the private page?
Thanks - C
I have not done this myself, but I imagine you can use your redirect path as an argument in the useAuthenticated() call. https://marmelab.com/react-admin/Authentication.html#useauthenticated-hook
export default () => {
useAuthenticated({ redirectPath: '/privatepage' });
return (
<Card>
<Title title="Private Page" />
<CardContent>
This is a private page.
</CardContent>
</Card>
)
}
From there you should be able to use that arg/parameter in your checkAuth method.
tl;dr In your login().then() aspect, do a redirect('/myDefaultUrl')
I had the same challenge as you, I think. After looking into the ReactAdmin code a bit I was unable to find a way to do it in any 'official' way. I did see something quite interesting in the useAuthProvider() hook.
The AuthProvider object maintained by RA seems to have a variable with a couple properties initialized with some defaults.
import { useContext } from 'react';
import { AuthProvider } from '../types';
import AuthContext from './AuthContext';
export const defaultAuthParams = {
loginUrl: '/login',
afterLoginUrl: '/',
};
/**
* Get the authProvider stored in the context
*/
const useAuthProvider = (): AuthProvider => useContext(AuthContext);
export default useAuthProvider;
Specifically the afterLoginUrl property looked interesting. I attempted to override that property in my authProvider but didn't have any luck.
What I ended up doing was this. In my invocation of the login (from useLogin()), when the authProvider.login resolves, I return back the user along with their profile (I use Cognito so it is a CognitoUser instance). In my user I have configured an attribute for where the user should go after login. I then simply use the redirect hook (from useRedirect) to then direct the user to that URL.
Here is my login from my AuthProvider:
const authProvider = {
login: (params) => {
if (params instanceof CognitoUser) {
return params;
}
if (params.error) {
return Promise.reject(params.error);
}
return new Promise((resolve, reject) => {
Auth.signIn(params.username,params.password).then(cognitoUser => {
if (cognitoUser.challengeName === 'NEW_PASSWORD_REQUIRED') {
reject({ code: 'NewPasswordRequired', cognitoUser: cognitoUser })
} else {
setAndStoreUserProfile(cognitoUser);
resolve(cognitoUser);
}
}, function(err) {
reject(err);
});
});
},
....
Then in my Login form, I do this:
raLogin(formData)
.then((cognitoUser) => {
console.log("User logged in. Result:", cognitoUser);
clearTransitionState();
redirect('/profile');
})
.catch(error => {
if (error.code && error.code === 'PasswordResetRequiredException') {
transition(PHASE.RESET_ACCOUNT, {username: formData.username });
} else if (error.code && error.code === 'NewPasswordRequired') {
transition(PHASE.NEW_PASSWORD, { cognitoUser: error.cognitoUser });
} else {
processAuthError(error);
}
});

Object users in Observable Angular 8

I created a service and I try call API method (HTTP GET) and I put my data in Observable, I don't understand why I don't see all data(object) from API GET.
angular-component.ts
public allUsers$: Observable<User[]>;
constructor(private usersService: UsersService) { }
ngOnInit() {
this.allUsers$ = this.getAllUsers();
console.log(this.allUsers$)
}
private getAllUsers(): Observable<User[]> {
return this.usersService.getUsers();
}
In console I have this message:
users.service.ts
public getUsers(): Observable<User[]> {
return this.apiService.get(this.type) as Observable<User[]>;
}
api.service.ts
public get(url: string): Observable<any> {
return this.http.get(environment.apiUrl + `/${url}`);
}
nodejs-route.js
app.get("/", async (req, res) => {
const getAllUsers = await User.find().populate("orders.order_id");
res.status(200).send(getAllUsers);
});
Always keep in mind that an Observable does nothing.
As the lead RxJS developer, Ben Lesh, once said:
Observables themselves are enert. They don't stream anything or do
anything. They are templates for streaming/actions/observations that
will be set up on a subscription.
And there are two basic ways to subscribe:
With an async pipe.
Using the subscribe method.
The async pipe in a template AUTOMATICALLY subscribes and unsubscribes for you.
So in your template, you'd have something like this:
<div class="card"
*ngIf="allUsers$ | async as users">
Then you will be able to access users in your template, such as in an *ngFor.
However, using an async pipe makes it a bit more difficult to access the data in your component code. So you can NOT just do this to see your data:
console.log(this.allUsers$)
All that will give you is information on the Observable, as you saw.
The other option is to subscribe in your component:
sub: Subscription
users: User[]
ngOnInit() {
this.sub = this.getAllUsers().subscribe(
users => {
this.users = users;
console.log(users);
);
}
The subscribe() method returns a Subscription that you can then use to manually unsubscribe.
You will then have an array of users User[], NOT an Observable<User[]> as your component property. Your template can then bind to this array.
The first technique (async pipe) is normally the recommended approach.

How do I load a WASM module in a Vue component without initializing the module every time?

I have created a Rust library of type cdylib using
cargo web build --target=wasm32-unknown-unknown
I use a modified version of the "rust-wasm-loader" NPM package to build and load the WASM file. rust-wasm-loader uses this as a way to use the Rust code:
const wasm = require('./main.rs')
wasm.initialize().then(module => {
// Use your module here
const doub = module.cwrap('doub', 'number', ['number'])
console.log(doub(21))
})
I do not want to initialize the module every time I want to use the code. How do I load the module and use it like a library?
Since the loading of WebAssembly is asynchronous and may actually take some time for large modules, you need to handle the state when the module is not loaded, and then let the rest of the application know when the WebAssembly module is loaded.
You do not say how you are handling state in your Vue application, but if you are e.g. using Vuex you can do something like this:
const doubPlugin = store => {
wasm.initialize().then(module => {
const doub = module.cwrap('doub', 'number', ['number'])
store.subscribe((mutation, state) => {
if (mutation.type === 'DOUB_REQUEST') {
store.commit('DOUB_RESULT', doub(mutation.payload))
}
})
store.commit('DOUB_READY')
})
}
const store = new Vuex.Store({
state,
mutations,
plugins: [doubPlugin]
})
I've done a similar thing in an Elm/WebAssembly application (relevant JavaScript), so if you want to see how this can be applied in practice you can check that out.
Making a wrapper JS module that performs initialization and re-exports the promise seems like the most straightforward approach.
// main.js
module.exports = require("./main.rs").initialize().then(module => {
return {
doub: module.cwrap('doub', 'number', ['number'])
};
});
Then anything can do
require("./main.js").then(api => {
console.log(api.doub(21));
});
and will always get the same module. Or alternatively you could invert the async part and do
// main.js
const api = require("./main.rs").initialize().then(module => {
return {
doub: module.cwrap('doub', 'number', ['number'])
};
});
exports.doub = async function (val) {
return (await api).doub(val);
};
Then users of your module could do
const api = require("./main.js");
api.doub(21).then(result => {
console.log(result);
});
I created a class to wrap the WebAssembly loading and created a cwrap for every function:
class mkLib {
ready = false
_mod = require("./main.rs").initialize().then(module => {
this._mod = module
this.doub = module.cwrap('doub', 'number', ['number'])
this.ready = true
})
}
export default mkLib
In the Vue component's data there is a variable for the new class and in watch I wait for a change in the ready property:
data () {
return {
mod: new mkLib,
ready: false
}
},
watch: {
'mod.ready': function () {
this.ready = true
// now this.mod.FUNC(PARAMS) can be used
console.log(this.mod.doub(20))
}
}

javascript nested async calls

My script has a function that login the user as follows:
class myClient {
SignIn() {
this._userManager.signinRedirect();
this._userManager.processSigninResponse().then(function (response) {
manager._userManager.getUser().then(function (user) {
manager._loggedUser = user;
});
})
}
}
As you can see, there are two nested promises. The user is only logged into the system once the inner most promise is resolved (i.e.: manager._loggedUser = user)
Now, I would like my class to expose just two methods: SignIn() [as described above] and GetUserInfo():
GetUserInfo() {
// ...
return this._loggedUser;
};
So that anyone using my class would just need to follow these steps in order to get the logged in user profile:
create the object
call the signin method
get the user info
How can i 'synchronize' the 2nd and the 3rd step, in order to ensure that the _loggedUser is not null after calling the signin() method first and the GetUserInfo() after?
It should be flattened to avoid 'callback hell' (one of the reasons why promises are used) - unless there are reasons to not do that (i.e. when response is used in nested promises). And it should return a promise.
SignIn() {
this._userManager.signinRedirect();
return this._userManager.processSigninResponse().then(function (response) {
return manager._userManager.getUser();
})
.then(function (user) {
manager._loggedUser = user;
});
}
Considering that GetUserInfo relies on SignIn results, promises should be utilized when using them together.
obj.SignIn().then(() => {
const info = obj.GetUserInfo();
...
});