Method or how-to set values needed to be considered logged-in.
Is your feature request related to a problem? Please describe. No
Describe the solution you'd like A Clear way to set the expected values needed by the library to be 'logged in' for automated scenarios.
Cypress is worked with specific Auth Providers that likely have client-side libraries for auth. They are working together to provide automation solutions. Would love to see support for cypress and other programmatic authentication added to this project.
Programmatic Authentication with Cypress
Here in the cypress realworld-app you can see the custom login commands they've written against 3 providers.
Real World App - Auth Examples
Given i know how to authorize with my own provider programmatically, I need to know how to set the values with angular-auth-oidc-client like in the Real World samples above.
This would allow us to bypass redirects completely, for testing purposes because we would set the needed storage items before the first url request was made.
I just found this issue again and I just want to spend some thoughts on that. If we introduce a method to configure the lib at runtime we have the problem of first: Having two ways of configuring the lib. This leads to inconsistenc when working with the lib and second: People misuse this for runtime configuration which is not what this should be used with. Can you think of any way to provide like a method of configuring but making sure people do not misuse this to change their config at runtime?
hi @FabianGosebrink, was this related to the other issue we were discussing Lazy load ? I'm confused with your reply in regards to being able to use cypress with angular-auth-oidc-client.
Hey @wolfpackt99, thanks for your answer and sorry about not being clear in my expressions. Causing confusion was not my intention.
So iirc you need a method to pass a config to the lib at runtime because cypress needs this. if this is correct, then we would introduce a door where users can configure the lib at runtime. We could document it that it should only being used for testing, but I am 100% sure the method will be misused. Also configuring the lib at the start - like it is now - and at runtime adding or changing the configuration would lead to inconsistency in the app and the lib, what configurations are currently running.
I hope I got this more clear now, sorry for not being precises in the first place. Please let me know if I am wrong and/or your thoughts on this. Thanks!
I had two needs;
- dynamic changing of auth urls/documents (https://github.com/damienbod/angular-auth-oidc-client/issues/1284)
- ability to use cypress for testing (this issue)
This issue #1255 was just about being able to set auth information programmatically.
So perhaps I want to use a rest api to get all the values needed (access token, refresh token, etc) then be able to just have instructions for this library to save that in a manner where angular-auth-oidc-client would know we are logged in. I would configure the library to use localStorage, then take my values from a script and write them to the localStorage in a manner that the library would know I am logged in.
Please see these examples where cypress worked with 3 major providers and were able to provide samples: https://github.com/cypress-io/cypress-realworld-app/tree/develop/cypress/support/auth-provider-commands
I would set everything in storage before opening the app to the url, then the library would treat me as logged in.
Hey @wolfpackt99 , thanks for your quick reply. Ah, so you do not need a way to configure the lib at runtime, but a method to store the information manually to set the lib into the state that it is authenticated, correct?
this ticket is just about being able to set the correct values into session or storage so when I load the app, angular-auth-oidc-client behaves like i am logged in.
see this file: https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/support/auth-provider-commands/okta.ts
In this example, they are fetching the tokens via http call, setting them in storage they way okta likes, then load the app. The app then just thinks you are logged in.
Knowing how to set the variables for angular-auth-oidc-client would allow us to use cypress for automated testing.
Hey @wolfpackt99, thanks for your message. The example you are providing is accessing the local storage directly and setting the data in the format the lib accepts. Nothing prevents you from doing that right now already. However, I like the idea of providing a method to set the data or at least pass the tokens and the lib transforms the tokens in the way it can read it. But I really see the danger of misusage of that feature. People will get their tokens on their own and set it to the lib. The lib has to work without having control over where the data comes from. Thinking about a way to resolve this...
I would think since those big three providers worked with cypress to give examples, it would be ok for the same here. I've tried with this library to set some of the same values but have not had luck. it seems there are a lot of extra values that are beyond just the token that I don't understand.
have a look at the official write-ups on cypress for the providers: https://docs.cypress.io/guides/testing-strategies/auth0-authentication (starting point, there are others there too).
We do not provide a method for this yet. Basically, you do not need the whole refresh cycle, is that correct? Can you provide a sample where the method provided by us is missing so that we can build what you require? Can be a test, can be an app...anything that we can make sure we build the thing you need to run cypress tests with this lib.
i need to be able to call my provider programitcally, like this sample, then use the values obtained to set items in storage so angular-auth-oidc-client knows im logged in already.
cy.request({
method: "POST",
url: `https://<my-provider-url>/oauth/token`,
body: {
grant_type: "password",
username,
password,
audience,
scope,
client_id,
client_secret,
},
}).then(({ body }) => {
const usertoken: any = jwt.decode(body.id_token);
const authorizationData_profile = usertoken;
const authorizationResult_profile = {
"id_token": "<idtoken>"
...
};
window.localStorage.setItem("authorizationData_profile",authorizationData_profile);
window.localStorage.setItem("authorizationResult_profile", JSON.stringify(aothorizationResult_profile));
...other items for storage???
log.snapshot("after");
log.end();
});
//tell cypress to open website, website and library know im authenticated already.
cy.visit("/");
I just took a quick look and I think all you need to do is setting an authresult and all we need to do is exposing a method for you to do so. I will talk to @damienbod, and then we can expose a method for doing this. Maybe a few config parameters are needed as well, but it will get specifically when we get to the implementation.
@wolfpackt99 sorry for being later for the party, I am here to write an issue with cypress that mostly works.
But for you case here is some code that should work:
Cypress.Commands.add('login', (username: string, password: string) => {
cy.session([username, password], () => {
cy.visit('/');
cy.keycloakLogin(username, password);
cy.get(entityItemSelector).should('be.visible'); // wait for something in the GUI that says you are logged in
});
});
Cypress.Commands.add('keycloakLogin', (username: string, password: string) => {
cy.clickOnLoginItem();
cy.get('#username').type(username);
cy.get('#password').type(password);
cy.get('#kc-login').click({ force: true });
});
Hope this helps, don't hesitate if you have questions
Any updates on this? Thanks
I just took a quick look and I think all you need to do is setting an authresult and all we need to do is exposing a method for you to do so. I will talk to @damienbod, and then we can expose a method for doing this. Maybe a few config parameters are needed as well, but it will get specifically when we get to the implementation.
Any news on exposing the method for setting the authentication state?
Same I need set values for login, I previously called a post to log in.
@wolfpackt99 sorry for being later for the party, I am here to write an issue with cypress that mostly works.
But for you case here is some code that should work:
Cypress.Commands.add('login', (username: string, password: string) => { cy.session([username, password], () => { cy.visit('/'); cy.keycloakLogin(username, password); cy.get(entityItemSelector).should('be.visible'); // wait for something in the GUI that says you are logged in }); }); Cypress.Commands.add('keycloakLogin', (username: string, password: string) => { cy.clickOnLoginItem(); cy.get('#username').type(username); cy.get('#password').type(password); cy.get('#kc-login').click({ force: true }); });Hope this helps, don't hesitate if you have questions
I have tried to log in by clicking on the page and adding username and password but when I click on the login button it stops
I have solved it by doing the normal login with a cypress command. I leave an example: the important thing is to use cy.origin
But being able to add it manually would be nice since the login flow would be faster
My env:
env: {
URL: 'http://localhost:4200',
EMAIL: 'xxx',
PASSWORD: 'xxx'
}
Cypress.Commands.add('login', (url, email, password) => {
cy.session('appLogin', () => {
cy.clearData();
cy.visit(url);
cy.origin('https://login.microsoftonline.com',
{args: [email, password]},
([email, password]) => {
cy.get('#otherTile').then(($element) => {
if ($element.length !== 0) {
$element.click();
cy.log('Elemento encontrado');
}
});
cy.get('input[type=\'email\']').click({force: true});
cy.get('input[type=\'email\']').type(email);
cy.get('input[type=\'submit\']').click({force: true});
cy.get('input[name=\'passwd\']').type(password);
cy.get('input[type=\'submit\']').click({force: true});
cy.get('[type="checkbox"]').check()
cy.get('input[type=\'submit\']').click({force: true});
});
cy.wait(3000);
cy.visit(url);
});
});
describe('TestFormComponent', () => {
beforeEach(() => {
cy.login(Cypress.env('URL'), Cypress.env('EMAIL'), Cypress.env('PASSWORD'));
cy.wait(3000);
cy.visit(Cypress.env('URL'));
});
xit('should disable yearSubscriptionInput date', () => {
cy.get('[formControlName="yearEffect"]').type('2020');
cy.get('[formControlName="yearSubscription"]').should('be.empty');
cy.get('[formControlName="yearSubscription"]').should('be.disabled');
cy.get('[formControlName="yearEffect"]').should('have.value', '2020');
});
});
@pookdeveloper The whole reason we would like a method to set authentication state programatically is because we do not want to redirect and write cypress commands for a third-party providers, as these sites are not managed by us and changes will break our code.
Having an exposed method that we can use to set the state ourselves, allows us to even set a mocked authentication state for testing purposes.