Using static in page object (Cypress) - javascript

Looking through various examples of implementing e2e tests on Cypress, I came across the fact that many people use the method of creating a new object, instead of using static. Why do they do this? Why not use static for page-object methods, because we don't change any data in the class itself and, accordingly, don't communicate to this, and we don't need to have multiple instances of the same page (or I don't see a scenario for using this). I understand that Selenium uses page factory and because of this it is necessary to create a new object, but I did not find an analogy in Cypress.
Example of creating a new object:
import { BasePage } from './BasePageClass'
import { navMenu } from './NavigationMenuClass';
import { queryPage } from './QueryPageClass';
export class MainPage extends BasePage {
constructor() {
super();
this.mainElement = 'body > .banner';
}
verifyElements() {
super.verifyElements();
cy.get(this.mainElement).find('.container h1').should('be.visible');
}
switchToQueryingPage() {
navMenu.switchToQueryingPage();
queryPage.verifyElements();
}
};
export const mainPage = new MainPage();
Example using static:
import { BasePage } from './BasePageClass'
import { navMenu } from './NavigationMenuClass';
import { queryPage } from './QueryPageClass';
export default class MainPage extends BasePage {
static mainElement = 'body > .banner';
constructor() {
super();
}
static verifyElements() {
super.verifyElements();
cy.get(MainPage.mainElement).find('.container h1').should('be.visible');
}
static switchToQueryingPage() {
navMenu.switchToQueryingPage();
queryPage.verifyElements();
}
};

Here is an example of a composition of commands my seniors have taught me to use. I have a function buyProduct, but it requires several steps and I have made them in different commands that can be used in different cases:
it('buyProductAsCustomer', ()=>{
cy.login(customer)
cy.shopFe_openProductByName(product.name)
cy.shopFe_addProductToCart()
cy.shopFe_openCheckoutFromCart()
cy.shopFe_selectPaymentMethod("payWithCreditCardMethod")
cy.shopFe_fillCheckoutFormAsCustomer(customer)
cy.shopFe_checkoutPageGetOrderData()
cy.shopFe_submitCheckoutForm()
cy.shopFe_completePaymentWithCreditCard()
});
it('buyProductAsGuest', ()=>{
cy.shopFe_openProductByName(product.name)
cy.shopFe_addProductToCart()
cy.shopFe_openCheckoutFromCart()
cy.shopFe_selectPaymentMethod("payWithCashMethod")
cy.shopFe_fillCheckoutFormAsGuest(guest)
cy.shopFe_checkoutPageGetOrderData()
cy.shopFe_submitCheckoutForm()
cy.shopFe_completePaymentWithCreditCard()
});
These 2 cases can be done in command with several variables, but in time those variables tend to increase tenfold. Thus we separate them into smaller repeatable parts that can be combined in different ways.

Related

Why would you need to null coalesce a static member initialization?

I'm looking through the Mixpanel for React Native example project and they're initializing a singleton like this:
import {Mixpanel} from 'mixpanel-react-native';
import {token as MixpanelToken} from './app.json';
export default class MixpanelManager {
static sharedInstance = MixpanelManager.sharedInstance || new MixpanelManager();
constructor() {
this.configMixpanel();
}
configMixpanel = async () => {
this.mixpanel = await Mixpanel.init(MixpanelToken);
}
}
I've never seen a singleton handled quite this way. What's the circumstance where MixpanelManager.sharedInstance will already be set when this class gets declared?

Hacking the import statement to extend an inherited class

In a library that I wish to extend without modifying its code, several classes inherit from the same imported one. That is in this BaseClass I would need to overwrite a specific method.
In the library (written in TypeScript) :
import { BaseClass } from './base_class';
export class ClassA extends BaseClass {}
import { BaseClass } from './base_class';
export class ClassB extends BaseClass {}
…
In the external extension I wish to write :
import { BaseClass } from 'library';
export class ExtendedBaseClass extends BaseClass {
oneMethod() {
const data = BaseClass.prototype.oneMethod.call(this);
// make additional things with data
return data;
}
}
Is there a way for this new ExtendedBaseClass to become the parent of all ClassXs ? At least in a new extended and re-exported version of them without the need to copy their internal code.
Is there a way for this new ExtendedBaseClass to become the parent of all ClassXs?
No.
An alternative might be to replace the one method directly on the base class:
import { BaseClass } from 'library';
const oneMethod = BaseClass.prototype.oneMethod;
Object.defineProperty(BaseClass.prototype, 'oneMethod', {
value() {
const data = oneMethod.call(this);
// make additional things with data
return data;
},
});
There's no way to do exactly what you're asking, but you could achieve the same result by extending each class individually.
ExtendedClassA extends ClassA {
oneMethod() {
// call a shared method if you need to reuse
}
}
// ExtendedClassB, etc

Reusing code across React component

I have a bunch of components with methods like these
class Header extends Component {
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
I'd like to move this duplicate code to a function such as
function toggleBodyClass(className, e) {
e.preventDefault();
document.body.classList.toggle('sidebar-mobile-show');
}
Then refactor the functions above like so
sidebarMinimize(e) {
toggleBodyClass('sidebar-minimized', e);
}
In the past, I would have used a mixin, but the React docs now discourage their use.
Should I just put this function in a regular JavaScript module and import it in the component modules, or is there a particular React construct for reusing code across components?
You could make a High Order Component with those functions as so:
import React, { Component } from 'react';
export default function(ComposedComponent) {
return class ExampleHOC extends Component {
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
render()
return <ComposedComponent { ...this.props } />;
}
}
}
Then take whatever component you wish to augment with those properties by wrapping them in the HOC:
ExampleHOC(Header);
Should I just put this function in a regular JavaScript module and import it in the component modules
Yes. That would be a pretty standard way to share code between JavaScript files. I don't believe you need to or should do anything React-related to achieve this.
However, it is important to understand that you shouldn't directly interact with the DOM ever from a React component. Thanks #ShubhamKhatri for the heads up.
In my opinion, you are correct in putting the function in a regular JavaScript module and import it in the component modules.
Since a typical answer OOP answer would be to create another class extending React.Component adding that function. Then extend that class so every component you create will have that function but React doesn't want that.
One thing to verify that you are correct is in this pattern I believe.
https://reactjs.org/docs/composition-vs-inheritance.html
inherence solve your problem , create new class that extends Component and extend from your new class to share functionality and reduce the code
class SuperComponent extends Component
{
sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
---------------------------------------------------------------------
class Home extends SuperComponent
{
someMethod()
{
this.sidebarMinimize();
}
}
class Main extends SuperComponent
{
someMethod()
{
this.sidebarToggle();
}
}
Other Solution
create utils class and use it in your component
class UIUtiles
{
static sidebarToggle(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-hidden');
}
static sidebarMinimize(e) {
e.preventDefault();
document.body.classList.toggle('sidebar-minimized');
}
}
class Home extends SuperComponent {
someMethod(e) {
UIUtiles.sidebarToggle(e);
UIUtiles.sidebarMinimize(e);
}
}

Node.js v6.2.0 class extends is not a function error?

So I'm trying to extend a class in node js and the compiler keeps returning the following error:
TypeError: Class extends value #<Object> is not a function or null
I checked that I was exporting the class correctly and I am, any ideas? I'll post my code below:
/handler/venue.js:
var VenueViews = require('../views/venue'); // If I remove this the error will dissapear (as expected)
class Venue {
constructor(data) {
this.setDataHere = data;
}
main () {
var View = new VenueViews(); // This doesn't run
}
}
module.exports = Venue;
/views/venue.js:
var Venue = require('../handlers/venue');
console.log (Venue) // This returns {} ???
class VenueViews extends Venue {
constructor() {
super();
}
}
module.exports = VenueViews;
I know that node supports these es6 features, so I'm unsure why they aren't working?
Edit:
I'm not sure if this is suppose to happen but, when I log my Venue require it returns an empty object {}.
console.log (Venue) // This returns {} ???
So it turns out I had a circular reference in my code, where I was importing the class that was extending, into the class that itself was extending (tongue twister :P).
The obvious fix was to simply remove the extends reference and find another way of doing what I was trying to achieve. In my case it was passing the Venue class properties down into the VenueViews constructor.
E.g var x = VenueViews(this)
In my instance, it was the same issue as #James111 was experiencing (circular import) due to a factory pattern I was trying to set up in Typescript. My fix was to do move the code into files, similar to the following:
// ./src/interface.ts
import { ConcreteClass } from './concrete';
export interface BaseInterface {
someFunction(): any;
}
export class Factory {
static build(): BaseInterface {
return new ConcreteClass();
}
}
// ./src/base.ts
import { BaseInterface } from './interface';
class BaseClass implements BaseInterface {
someFunction(): any {
return true;
}
}
// ./src/concrete.ts
import { BaseClass } from './base';
export class ConcreteClass extends BaseClass {
someFunction(): any {
return false;
}
}
I had faced similar issue, after checking all the workaround finally issue got resolved by deleting the node_modules folder and run npm i.

Splitting up class definition in ES 6 / Harmony

Suppose I have a class in one big file like this:
export default class {
constructor () {}
methodA () {}
methodB () {}
methodC () {}
}
And I want to break up the class definition so that methodA, methodB, and methodC are each defined in their own separate files. Is this possible?
You should be able to, as class is supposed to just be syntax sugar for the usual prototype workflow:
import methodOne from 'methodOne'
import methodTwo from 'methodTwo'
class MyClass {
constructor() {
}
}
Object.assign(MyClass.prototype, {methodOne, methodTwo})
export default MyClass
#elclanrs gave a correct answer, but I would modify it to allow for the use of this. I also think this is more readable.
import methodOne from 'methodOne'
import methodTwo from 'methodTwo'
class MyClass {
constructor() {
this.methodOne = methodOne.bind(this)
this.methodTwo = methodTwo.bind(this)
}
}
export default MyClass
Tip: although if your class is so large that it warrants being split into multiple files, a better solution might be to split up the class into multiple classes.

Categories