So I am writing few test cases. I have one class as follows.
export default class DateProcessor {
requestHandler = (req, res) => {
//code
}
}
Now I am writing one unit test to see if the typeof DateProcessor is class
import {default as processor} from './getDatesProcessor';
describe('Date Processor', () => {
it('should be a class', () => {
expect(typeof processor).toBe('class');
})
});
But the test case is failing because I am getting the type as a function and not a class.
I want to know if this is the expected behavior or I am not doing something right.
The answer to your question is: yes, it is expected behavior
Explanation:
In JavaScript, there's no such thing as class. The class keyword is just a syntax which makes it easier to create prototypes according to best practices. In fact, all those classes are actually functions. You can check it using typeof keyword which will return function when applied to a class. Also, this is also possible in JavaScript:
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
class Student extends Person {
constructor(name, studies) {
super(name);
this.studies = studies;
}
getStudies() {
return this.studies;
}
}
const s = new Student('John', 'Maths');
console.log(s.getName(), s.getStudies());
More on classes in JS, here
Before JavaScript had classes, you had to emulate classes using functions (with some special syntax new/this).
export default class DateProcessor {
requestHandler = (req, res) => {
//code
}
}
Your code is (roughly) equivalent to:
export default function DateProcessor() {
this.requestHandler = (req, res) => {
}
}
Even though there's a dedicated class keyword these days, they're still implemented as functions that must be called with the new keyword, therefore typeof still regards them as functions.
It's worth reading the MDN docs for typeof to see that there aren't many possible return values.
Related
I have a class with method performing login
LoginPage.js
class loginPage {
fillCredentials(username, password) {
cy.get('[id=username]').type(username);
cy.get('[id=password]').type(password);
return this;
}
clickLogin() {
cy.contains("Login").click();
}
}
export default loginPage;
I have another spec file for testing:
login.spec.js
import {fillCredentials,clickLogin} from '../../support/PageObjects/loginPage'
describe('User Onboarding Emails', () => {
it('Verification email', () => {
cy.visit('/')
fillCredentials('username','password')
clickLogin()
});
});
However, it is giving an error of
(0 , _loginPage.fillCredentials) is not a function
I know its a wrong way of calling a method. Is there any way I can use the methods without creating an instance of class to access methods
You can do so if you make the methods static
class loginPage {
static fillCredentials(username, password) {
cy.get('[id=username]').type(username);
cy.get('[id=password]').type(password);
//return this; // you can't return "this" because there is no this for static methods
}
static clickLogin() {
cy.contains("Login").click();
}
}
export default loginPage;
import {fillCredentials,clickLogin} from '../../support/PageObjects/loginPage'
describe('User Onboarding Emails', () => {
it('Verification email', () => {
cy.visit('/')
fillCredentials('username','password')
clickLogin()
});
});
With static methods you lose this which refers to the class instance, and therefore lose the ability to chain methods,
import {fillCredentials,clickLogin} from '../../support/PageObjects/loginPage'
describe('User Onboarding Emails', () => {
it('Verification email', () => {
cy.visit('/')
fillCredentials('username','password').clickLogin() // can't do this with static
});
});
As functions instead of a class, this is the pattern
// LoginPage.js
export const fillCredentials = (username, password) => {
cy.get('[id=username]').type(username);
cy.get('[id=password]').type(password);
return this;
}
export const clickLogin = () => {
cy.contains("Login").click();
}
// login.spec (same as you have above)
import { fillCredentials, clickLogin } from '../../support/PageObjects/loginPage'
describe('User Onboarding Emails', () => {
it('Verification email', () => {
cy.visit('/')
fillCredentials('username','password')
clickLogin()
});
})
Be wary of encapsulating test code in page objects, it can lead to over-complicated code.
For example, if you now want to test what happens if password is not entered, you can't use fillCredentials because you can't omit the password parameter. So do you add a fillCredentialsWithoutPassword function? Do you modify fillCredentials to test if password is undefined?
So, what's going on is that you are mixing up the module structure with is defined by Closures with the class-instance pattern.
For this scenario (which is class-instance) the functions are NOT part of the object itself, but of it's PROTOTYPE.
So in order to get that function you should access it's prototype.
//create a class (class syntax and this one is pretty much the same)
function xx (){}
//this is what class syntax makes to create a method for the class
xx.prototype.theFunctionIwant = function (){}
//create an instance
var example = new xx()
//this is how you can spy that function in the test
xx.prototype.theFunctionIwant
//ƒ (){}
Try it out : )
The other answers given will work and solve your exact question, but I fear that making the functions static is an anti-pattern for the Page Object Model. Check out this article on how to set up a POM for Cypress. I would highly encourage you to instantiate the class, similar to below.
//LoginPage.js
export class LoginPage { ... }
//login.spec.js
import { LoginPage } from '../../support/PageObjects/loginPage';
describe('User Onboarding Emails', () => {
it('Verification email', () => {
const loginPage = new LoginPage()
cy.visit('/')
loginPage.fillCredentials('username','password')
loginPage.clickLogin()
});
});
You could also use a beforeEach() block to instantiate the variable before each test.
describe('User Onboarding Emails', () => {
let loginPage: LoginPage;
beforeEach(() => {
loginPage = new LoginPage();
});
it('Verification email', () => {
...
});
})
As an aside, it is usually preferred to name classes beginning with an uppercase (LoginPage vs. loginPage). When naming a class this way, you can easily differentiate the class vs. the instantiated variable.
I have two classes, A and B. What I am trying to do is to pass data from A to B after receiving a message from sockets.
This is simplified look of how classes are defined:
class A:
export default class A {
client;
callbacks;
constructor() {
this.callbacks = {
open: () => this.client.logger.debug('open'),
close: () => this.client.logger.debug('closed'),
message: (data) => {this.client.logger.log(data)}, //I want to pass this data object to class B
};
this.client = new Spot(constants.apiKey, constants.apiSecret, {
baseURL: constants.baseURL,
wsURL: constants.wsURL,
});
this.client.userData(listenKey, this.callbacks);
}
}
I already have a property of A in class definition of B:
export default class B {
account;
constructor() {
this.account = new A();
}
}
What would be a correct/standard way to connect these two so I get a 'data' object from class A every time the socket message callback from class A is triggered?
I am a bit new with JS, but on iOS we would use a delegation pattern, with a protocol, that says:
class A will have a delegate property.
A delegate (class B) must implement a protocol (in this case it would be a requirement to implement method called didReceiveMessage(data).
After that, when a message is received in class A, we would just do(in socket message callback shown above) something like this.delegate.didReceiveMessage(data).
Protocol usage here is not important generally, but it is a plus, cause from A class, we can only access didReceiveData(data) method trough a delegate property, and nothing else (other properties / methods of class B are not visible). At least that is how it works in Swift/Obj-C. I just mentioned it, cause I am curious is this how it is done in JS too.
I guess there is some similar mechanism in Javascript, or some more standard/better way to achieve this kind of data sending between objects?
on iOS we would use a delegation pattern, with a protocol
You can do it exactly as you described:
export default class A {
client;
delegate;
constructor(delegate) {
this.delegate = delegate;
this.client = new Spot(constants.apiKey, constants.apiSecret, {
baseURL: constants.baseURL,
wsURL: constants.wsURL,
});
const callbacks = {
open: () => this.client.logger.debug('open'),
close: () => this.client.logger.debug('closed'),
message: (data) => this.delegate.didReceiveMessage(data),
};
this.client.userData(listenKey, callbacks);
}
}
export default class B {
account;
constructor() {
this.account = new A(this);
}
didReceiveMessage(data) {
console.log(data); // or whatever
}
}
There is no interface (protocol) declaration that would tell A which properties and methods it may access on the passed delegate, but the contract exists of course. You should document it in prose. (Or use TypeScript).
Notice also how your class A interacts with the Spot client, it uses very much the same pattern of passing an object with event handler methods.
A simpler pattern in JavaScript, if you just need a single method in your protocol, is to pass a callable function only:
export default class A {
client;
constructor(onMessage) {
this.client = new Spot(constants.apiKey, constants.apiSecret, {
baseURL: constants.baseURL,
wsURL: constants.wsURL,
});
this.client.userData(listenKey, {
open: () => this.client.logger.debug('open'),
close: () => this.client.logger.debug('closed'),
message: onMessage,
});
}
}
export default class B {
account;
constructor() {
this.account = new A(this.didReceiveMessage.bind(this));
// or inline:
this.account = new A(data => {
console.log(data); // or whatever
});
}
didReceiveMessage(data) {
console.log(data); // or whatever
}
}
I am not an expert on NodeJs, but you can use something like an emitter plugin.
In javascript, it would look like this:
function A() {
Emitter(this);
this.action = function() {
console.log("something happened");
this.emit("action", { prop: "value" });
};
}
function B(a_instance) {
// subscribe to "action" event
a.on("action", function(data) {
console.log(data.prop); // "value"
});
};
var myA = new A();
var myB = new B(myA);
myA.action();
Hello I am curious about the working of the decorator in Typescript for binding 'this' to functions in Typescript.
function autoBind(
target:any,
methodName:String,
descriptor:PropertyDescriptor
){
console.log("Calling Decorator");
const originalMethod = descriptor.value;
const adjustableDescriptor: PropertyDescriptor = {
configurable : true,
get(){
console.log("Calling get");
const boundFn = originalMethod.bind(this);
return boundFn;
}
}
return adjustableDescriptor;
}
class ProjectInput {
constructor(){
this.configure();
}
#autoBind
private submitHandler(event: Event){
console.log("Calling submit handler");
event.preventDefault();
console.log("Submitting data ...");
console.log(this.titleInputElement.value);
}
private configure() {
this.element.addEventListener("submit",this.submitHandler);
}
}
const projInput = new ProjectInput();
What I did :
I created a Class ProjectInput and in the constructor i am calling the configure method so that i can add EventListeners and handle user submit data and for binding 'this' so that it reference the right object.
I created a Decorator in typescript that will call automatically as soon as the class declared
Everything is fine but I want to know the behind the scenes of the decorator how it binds the this to the function.
I came here, hoping I'd get a more thorough answer than what I'd be able to find, but at least it encouraged me to dig a little further.
Taken directly from React & Autobinding:
Autobind Decorator is an NPM package which binds methods of a class to the correct instance of this, even when the methods are detached. The package uses #autobind before methods to bind this to the correct reference to the component's context.
import autobind from 'autobind-decorator'
class MyComponent extends React.Component {
constructor() {
/* ... */
}
#autobind
addTask(task) {
/* ... */
this.setState({ task });
}
#autobind
myMethod2(task) {
/* ... */
this._anotherBindedMethod(task);
}
render() {
return (
/* ... */
)
}
}
his seems like a simple solution, but I'd rather not have to add a line above each individual method inside each of my React components. Not to worry, Autobind Decorator is smart enough to let us bind all methods inside a component class at once. Like so:
import autobind from 'autobind-decorator'
#autobind
class MyComponent extends React.Component {
constructor() {
/* ... */
}
addTask(task) {
/* ... */
this.setState({ task });
}
/* ... */
}
And just like that, this issue is resolved.
Anyway, hope that helps. Reading it a couple times, helped me. Cheers.
Be careful cause in your code getter returns a new function each time is called and this can potentially lead to memory leaks. This happen cause .bind returns a new function.
So for example if you do .addEventListener('click', this.submitHandler) you're adding a new function each time. .removeEventListener('click', this.submitHandler) will not remove nothing cause will not match any listener
You can easily test this is truth like this
const projectInput = new ProjectInput();
projectInput.submitHandler === projectInput.submitHandler; // false
So an easy fix to your code could be this one
function autobindFunction(
target:any,
methodName:String,
descriptor:PropertyDescriptor
){
console.log("Calling Decorator");
if(typeof descriptor.value !== 'function') {throw new TypeError("cannot decorate prop that is not a function")}
const bound = descriptor.value
const adjustableDescriptor: PropertyDescriptor = {
configurable : true,
value: function (...args: any[]) {
return bound.apply(this, args)
}
}
return adjustableDescriptor;
}
class Test {
#autobindFunction
hi() {
console.log("asd")
}
}
const a = new Test()
console.log(a.hi === a.hi) // true
In this way the reference of the function is stable and the function will be always the same
I want to build a class that can compose multiple objects and use any of their interfaces.
Class A can use any of the interfaces of Class B and C
B can use any of the interfaces of C
C can use any of the interfaces of B
I have the above functionality written in JavaScript and I was wondering what's the best and correct way to achieve the same using TypeScript:
import { findLast, isFunction } from "lodash";
class Composite {
constructor(behavior) {
this.behaviors = [];
if (behavior) {
this.add(behavior);
}
}
add(behavior) {
behavior.setClient(this);
this.behaviors.push(behavior);
return this;
}
getMethod(method) {
const b = findLast(this.behaviors, (behavior) =>
isFunction(behavior[method])
);
return b[method].bind(b);
}
}
class Behavior1 {
foo() {
console.log("B1: foo");
}
foo2() {
console.log("B1: foo2");
this.getMethod("bar")();
}
setClient(client) {
this.client = client;
}
getMethod(method) {
return this.client.getMethod(method);
}
}
class Behavior2 {
foo() {
console.log("B2: foo");
this.getMethod("foo2")();
}
bar() {
console.log("B2: bar");
}
setClient(client) {
this.client = client;
}
getMethod(method) {
return this.client.getMethod(method).bind(this);
}
}
const c = new Composite();
c.add(new Behavior1());
c.add(new Behavior2());
c.getMethod("foo")();
c.getMethod("bar")();
// Output:
// B2: foo
// B1: foo2
// B2: bar
// B2: bar
Link to codesandbox: https://codesandbox.io/s/zen-poitras-56f4e?file=/src/index.js
You can review my other answer to see some of the issues and concerns with the previous approach. Here I've created a completely different version from the ground up. There is less code repetition and less tight coupling between the classes.
Behaviors no longer call methods directly and no longer store a reference to the client. Instead, they receive the client (or any object which call get and call methods) as an argument of their register method.
We define any object which can lookup and call methods as a MethodAccessor
interface MethodAccessor {
getMethod(name: string): () => void;
safeCallMethod(name: string): boolean;
}
We define any object that provides behaviors through a register method as a BehaviorWrapper. These objects can call functions from other objects by calling getMethod or safeCallMethod on the helper argument.
type KeyedBehaviors = Record<string, () => void>;
interface BehaviorWrapper {
register(helper: MethodAccessor): KeyedBehaviors;
}
A behavior which does not need instance variables could be a pure function rather than a class.
const functionBehavior = {
register(composite: MethodAccessor) {
return {
foo: () => console.log("B1: foo"),
foo2: () => {
console.log("B1: foo2");
composite.safeCallMethod("bar");
}
};
}
};
Class behaviors can make use of instance variables in their methods.
class ClassBehavior {
name: string;
constructor(name: string) {
this.name = name;
}
bar = () => {
console.log(`Hello, my name is ${this.name}`);
};
register() {
return {
bar: this.bar
};
}
}
There is some redundancy here when defining a method like bar separately rather than inline as an arrow function within the return object. The reason that I am having the methods come from register rather than using all class methods is so that I can have stricter typing on them. You could have methods in your class which do require args and as long as they aren't part of the register returned object then it's not a problem.
Our class Composite now stores its behaviors in a keyed object rather than an array. Newly added behaviors of the same name will overwrite older ones. Our getMethod is typed such that it always returns a method, and will throw an Error if none was found. I've added a new method safeCallMethod to call a method by name. If a method was found, it calls it and returns true. If no method was found, it catches the error and returns false.
class Composite implements MethodAccessor {
behaviors: KeyedBehaviors = {};
constructor(behavior?: BehaviorWrapper) {
if (behavior) {
this.add(behavior);
}
}
// add all behaviors from a behavior class instance
add(behavior: BehaviorWrapper): this {
this.behaviors = {
...this.behaviors,
...behavior.register(this)
};
return this;
}
// lookup a method by name and return it
// throws error on not found
getMethod(method: string): () => void {
const b = this.behaviors[method];
if (!b) {
throw new Error(`behavior ${method} not found`);
}
return b;
}
// calls a method by name, if it exists
// returns true if called or false if not found
safeCallMethod(method: string): boolean {
try {
this.getMethod(method)();
return true;
} catch (e) {
return false;
}
}
}
There's a lot that's not ideal about your setup. I might post a separate answer with an alternate setup, but for now I just want to show you how to convert your code to typescript.
Keep in mind that typescript errors exist to help you prevent runtime errors, and there are some genuine potential runtime errors that we need to avoid. If a Behavior calls getMethod before calling setClient to set this.client that will be a fatal error. If you try to call the returned method from getMethod on a Composite or a Behavior where the name didn't match a method that's another fatal error. And so on.
You choose to handle certain situations by throwing an Error with the expectation that it will be caught later on. Here I am preferring to "fail gracefully" and just do nothing or return undefined if we can't do what we want. The optional chaining ?. helps.
When defining an interface for a function argument, it's best to keep it to the minimum necessities and not require any extraneous properties.
The only thing that a Behavior requires of its Client is a getMethod method.
interface CanGetMethod {
getMethod(name: string): MaybeMethod;
}
We use the union of undefined and a void function in a few places, so I am saving it to an alias name for convenience.
type MaybeMethod = (() => void) | undefined;
The Composite calls setClient on its behaviors, so they must implement this interface.
interface CanSetClient {
setClient(client: CanGetMethod): void;
}
It also expects that its methods take zero arguments, but we can't really declare this with the current setup. It is possible to add a string index to a class, but that would conflict with our getMethod and setClient arguments which do require arguments.
One of the typescript errors that you get a bunch is `Cannot invoke an object which is possibly 'undefined', so I created a helper method to wrap a function call.
const maybeCall = (method: MaybeMethod): void => {
if (method) {
method();
}
};
In typescript, classes need to declare the types for their properties. Composite gets an array of behaviors behaviors: CanSetClient[]; while the behaviors get a client client?: CanGetMethod;. Note that the client must be typed as optional because it is not present when calling new().
After that, it's mostly just a matter of annotating argument and return types.
I have declared the interfaces that each class implements, ie. class Behavior1 implements CanGetMethod, CanSetClient, but this is not required. Any object fits the interface CanGetMethod if it has a getMethod property with the right types, whether it explicitly declares CanGetMethod in its type or not.
class Composite implements CanGetMethod {
behaviors: CanSetClient[];
constructor(behavior?: CanSetClient) {
this.behaviors = [];
if (behavior) {
this.add(behavior);
}
}
add(behavior: CanSetClient): this {
behavior.setClient(this);
this.behaviors.push(behavior);
return this;
}
getMethod(method: string): MaybeMethod {
const b = findLast(this.behaviors, (behavior) =>
isFunction(behavior[method])
);
return b ? b[method].bind(b) : undefined;
}
}
class Behavior1 implements CanGetMethod, CanSetClient {
client?: CanGetMethod;
foo() {
console.log("B1: foo");
}
foo2() {
console.log("B1: foo2");
maybeCall(this.getMethod("bar"));
}
setClient(client: CanGetMethod): void {
this.client = client;
}
getMethod(method: string): MaybeMethod {
return this.client?.getMethod(method);
}
}
class Behavior2 implements CanGetMethod, CanSetClient {
client?: CanGetMethod;
foo() {
console.log("B2: foo");
maybeCall(this.getMethod("foo2"));
}
bar() {
console.log("B2: bar");
}
setClient(client: CanGetMethod) {
this.client = client;
}
getMethod(method: string): MaybeMethod {
return this.client?.getMethod(method)?.bind(this);
}
}
const c = new Composite();
c.add(new Behavior1());
c.add(new Behavior2());
maybeCall(c.getMethod("foo"));
maybeCall(c.getMethod("bar"));
I see patterns which make use of a singleton pattern using ES6 classes and I am wondering why I would use them as opposed to just instantiating the class at the bottom of the file and exporting the instance. Is there some kind of negative drawback to doing this? For example:
ES6 Exporting Instance:
import Constants from '../constants';
class _API {
constructor() {
this.url = Constants.API_URL;
}
getCities() {
return fetch(this.url, { method: 'get' })
.then(response => response.json());
}
}
const API = new _API();
export default API;
Usage:
import API from './services/api-service'
What is the difference from using the following Singleton pattern? Are there any reasons for using one from the other? Im actually more curious to know if the first example I gave can have issues that I am not aware of.
Singleton Pattern:
import Constants from '../constants';
let instance = null;
class API {
constructor() {
if(!instance){
instance = this;
}
this.url = Constants.API_URL;
return instance;
}
getCities() {
return fetch(this.url, { method: 'get' })
.then(response => response.json());
}
}
export default API;
Usage:
import API from './services/api-service';
let api = new API()
I would recommend neither. This is totally overcomplicated. If you only need one object, do not use the class syntax! Just go for
import Constants from '../constants';
export default {
url: Constants.API_URL,
getCities() {
return fetch(this.url, { method: 'get' }).then(response => response.json());
}
};
import API from './services/api-service'
or even simpler
import Constants from '../constants';
export const url = Constants.API_URL;
export function getCities() {
return fetch(url, { method: 'get' }).then(response => response.json());
}
import * as API from './services/api-service'
The difference is if you want to test things.
Say you have api.spec.js test file. And that your API thingy has one dependency, like those Constants.
Specifically, constructor in both your versions takes one parameter, your Constants import.
So your constructor looks like this:
class API {
constructor(constants) {
this.API_URL = constants.API_URL;
}
...
}
// single-instance method first
import API from './api';
describe('Single Instance', () => {
it('should take Constants as parameter', () => {
const mockConstants = {
API_URL: "fake_url"
}
const api = new API(mockConstants); // all good, you provided mock here.
});
});
Now, with exporting instance, there's no mocking.
import API from './api';
describe('Singleton', () => {
it('should let us mock the constants somehow', () => {
const mockConstants = {
API_URL: "fake_url"
}
// erm... now what?
});
});
With instantiated object exported, you can't (easily and sanely) change its behavior.
Both are different ways.
Exporting a class like as below
const APIobj = new _API();
export default APIobj; //shortcut=> export new _API()
and then importing like as below in multiple files would point to same instance and a way of creating Singleton pattern.
import APIobj from './services/api-service'
Whereas the other way of exporting the class directly is not singleton as in the file where we are importing we need to new up the class and this will create a separate instance for each newing up
Exporting class only:
export default API;
Importing class and newing up
import API from './services/api-service';
let api = new API()
Another reason to use Singleton Pattern is in some frameworks (like Polymer 1.0) you can't use export syntax.
That's why second option (Singleton pattern) is more useful, for me.
Hope it helps.
Maybe I'm late, because this question is written in 2018, but it still appear in the top of result page when search for js singleton class and I think that it still not have the right answer even if the others ways works. but don't create a class instance.
And this is my way to create a JS singleton class:
class TestClass {
static getInstance(dev = true) {
if (!TestClass.instance) {
console.log('Creating new instance');
Object.defineProperty(TestClass, 'instance', {
value: new TestClass(dev),
writable : false,
enumerable : true,
configurable : false
});
} else {
console.log('Instance already exist');
}
return TestClass.instance;
}
random;
constructor() {
this.random = Math.floor(Math.random() * 99999);
}
}
const instance1 = TestClass.getInstance();
console.log(`The value of random var of instance1 is: ${instance1.random}`);
const instance2 = TestClass.getInstance();
console.log(`The value of random var of instance2 is: ${instance2.random}`);
And this is the result of execution of this code.
Creating new instance
The value of random var of instance1 is: 14929
Instance already exist
The value of random var of instance2 is: 14929
Hope this can help someone