I have this Angular web application I want to run e2e tests on a mocked out REST API. I can stub out my network requests to my REST API easy enough, but the authentication is using a third-party provider (Cognito using Amplify).
Now I want to stub out the Angular service that wraps the authentication.
In Angular I have
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
some methods
isSignedIn(): Observable<boolean> {
...
}
}
I want to stub the isSignedIn()
-method. My first attempt looks something like this:
import {AuthenticationService} from "../../src/app/authentication.service";
import {BehaviorSubject} from "rxjs";
context('albums', () => {
it('get albums', () => {
cy.stub(AuthenticationService,'isSignedIn').returns(new BehaviorSubject(true));
}
}
Cypress/Chrome then complains it cannot find AuthenticationService on that location. How do I solve this?
Replace a function, record its usage and control its behavior.
The Cypress setup in an Angular workspace is easy to do because of the available Cypress schematic library. The @briebug/cypress-schematic project adds Cypress to your workspace and configures the angular.
There are several ways in Cypress to use JSON files for mocking data. Cypress uses so-called fixtures for that. By default, it will generate a fixtures folder where you can store your JSON mock files.
I basically agree what has been said. Cypress is a framework independent ui testing tool. Unlike Jasmin/Jest that can work with angular/react to mock services, it works differently.
With that being said, it has problems aka need certain work arounds executing tests cross domain when involving OIDC, OAuth authentication flows.
Maybe you can try looking into cookies / sessionStorages before and after successful login under chrome devtools, if you can get past the authentication flow:
cy.window().then(window => {
window.sessionStorage.setItem(key, value);
})
There are a few issues with your test
1 - Cypress itself is not executed within the browser, it is a wrapper application that commands the browser. It uses JS language, but on the wrapper not withing the browser. It can send JS commands to the browser though, as I will explain below.
2 - the AuthenticationService
class in your cypress test is different from the one used by angular... for two reasons:
3 - even if AuthenticationService
was the same scope as the angular one, it would still be incorrect... what you need is the instance of this class from within Angular's scope/zone.
Worry not, Cypress allows you to reach into the Browser's scope with its Window function:
cy.window()
.then((window) => { // the window here is the browser's
window['console'].log('Hi there from Cypress scope'); // this will appear in the console window within cypress
})
});
And we could provide a reference to the service from within angular's scope to the browser's window. For example, from using your AppComponent like this
export class AppComponent {
constructor(..., authenticationService: AuthenticationService) {
window['authenticationService'] = authenticationService;
}
}
and using cypress's Window function to get the browser's window
object, your test could then stub the service:
cy.window().then((window) => {
const serviceFromAngularScope = window['authenticationService'];
cy.stub(serviceFromAngularScope,'isSignedIn').returns(new BehaviorSubject(true));
});
Hopefully this gets you started
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With