Cypress ReferenceError: input is undefined (Cypress, Cucumber, POM) - cucumber

I'm struggling to find the reason for this:
I'm using Cypress, Cucumber and POM approach.
This is my POM file LoginPage.js
class LoginPage {
get usernameInput() {
return cy.get('input[name="email"]');
}
get passwordInput() {
return cy.get('input[name="password"]');
}
get submitBT() {
return cy.get('button[type="submit"]');
}
loginToCMS() {
cy.visit('https://example.com')
usernameInput.type('admin#admin.com');
}
}
export default new LoginPage
Then I try to call loginToCMS() function in another loginSteps.js file:
import { Given, When, Then, And } from 'cypress-cucumber-preprocessor/steps'
import LoginPage from '../../pages/LoginPage'
Given('user is logged in CMS', () => {
LoginPage.loginToCMS();
})
When run feature file, I get an error: Reference Error: usernameInput is not defined

usernameInput is a function on the LoginPage class, so you have to use this to call it.
class LoginPage {
get usernameInput() {
return cy.get('input[name="email"]');
}
...
loginToCMS() {
cy.visit('https://example.com');
this.usernameInput.type('admin#admin.com');
}
}

Related

TypeError: class is not a constructor (TypeScript)

I'm creating an Node.JS API, using Typescript v4.9.4, and Module Alias v2.2.2
There is a factory that creates the controller SignUp like this:
import { SignUpController } from '#/presentation/controllers'
import { type Controller } from '#/presentation/protocols'
import { makeDbAuthentication, makeDbAddUser } from '#/main/factories/usecases'
import { makeSignUpValidator } from './make-sign-up-validator-factory'
export const makeSignUpController = (): Controller => {
const controller = new SignUpController(makeDbAddUser(), makeSignUpValidator(), makeDbAuthentication())
return controller
}
I have a problem on the makeDbAddUser() that has this code:
import { DbAddUser } from '#/data/usecases'
import { type AddUser } from '#/domain/usecases'
import { UserMongoRepository } from '#/infra/db/mongodb/user-mongo-repository'
import { BcryptAdapter } from '#/infra/cryptography'
export const makeDbAddUser = (): AddUser => {
const salt = 12
const bcryptAdapter = new BcryptAdapter(salt)
const userMongoRepository = new UserMongoRepository()
return new DbAddUser(bcryptAdapter, userMongoRepository, userMongoRepository)
}
The error occurs on the line where new UserMongoRepository() is created.
const userMongoRepository = new db_1.UserMongoRepository();
^
TypeError: db_1.UserMongoRepository is not a constructor
And here is the UserMongoRepository class:
export class UserMongoRepository implements AddUserRepository, LoadUserByEmailRepository, CheckUserByEmailRepository, UpdateAccessTokenRepository {
// eslint-disable-next-line #typescript-eslint/no-useless-constructor
constructor () {}
async add (data: AddUserRepository.Params): Promise<AddUserRepository.Result> {
//code...
}
// other methods
}
To me everything seems fine, I have other classes and factories that I use in the same way. I'm probably missing something on the impor/export maybe? But I dont really know where to start looking anymore.
I already tried adding a constructor, even empty on my Class, but the error persists.
Also, tried the solutions on this thread, about a similar problem. Putting the export { UserMongoRepository } in the end of the file.
As I'm using ModuleAlias to have better import names, I tried without # like so:
import { UserMongoRepository } from '../../../infra/db/mongodb/user-mongo-repository'
But the problem persists.

How to spy on functions outside a component?

// ./index.js
import { Component } from 'react';
export default class Test extends Component {
method () {
console.log('method()');
}
do () {
this.method();
func();
}
render () {
return null;
}
}
export function func () {
console.log('func()');
}
// ./index.test.js
import { shallow } from 'enzyme';
import React from 'react';
import * as Test from './index';
describe('<Test>', () => {
const component = shallow(<Test.default/>),
method_spy = jest.spyOn(component.instance(), 'method'),
func_spy = jest.spyOn(Test, 'func');
test('func()', () => {
component.instance().do();
expect(method_spy).toHaveBeenCalledTimes(1); // passed
expect(func_spy).toHaveBeenCalledTimes(1); // failed
});
});
I want to spy on function outside a component, but It doesn't work well.
I've got a message like Expected mock function to have been called one time, but it was called zero times.
And I don't want to use mock() method instead of spyOn() in the situation.
Is there way to fix it? Thaks you for reading. :D
It doesn't work because this line:
const func_spy = jest.spyOn(Test, 'func');
...is creating a spy on the module export for func...
...but Test.do doesn't call the module export for func, it calls func directly.
There are two options to fix it.
One is to move func into its own module.
Then the module export for it will be imported into index.js and called within Test.do...
...and when the module export for func is wrapped in a spy the spy will get called by Test.do.
The other option is to note that "ES6 modules support cyclic dependencies automatically" so a module can be imported into itself.
If the module is imported into itself then Test.do can call the module export for func:
import { Component } from 'react';
import * as index from './index'; // <= import the module into itself
export default class Test extends Component {
method() {
console.log('method()');
}
do() {
this.method();
index.func(); // <= use the module
}
render() {
return null;
}
}
export function func() {
console.log('func()');
}
...and the spy on the module export for func will be called as expected:
import { shallow } from 'enzyme';
import React from 'react';
import * as Test from './index';
describe('<Test>', () => {
const component = shallow(<Test.default />),
method_spy = jest.spyOn(component.instance(), 'method'),
func_spy = jest.spyOn(Test, 'func');
test('func()', () => {
component.instance().do();
expect(method_spy).toHaveBeenCalledTimes(1); // Success!
expect(func_spy).toHaveBeenCalledTimes(1); // Success!
});
});

tests fail when injecting a class with decorator

This is likely an environment issue on my end, but I'm having problems testing injected classes that use decorators.
Am hoping someone can see what I'm missing.
Note: that when I run the code, it runs fine. The error only occurs when running jest tests. I have a full test suite that works fine. The test in question that fails passes when I remove the decorator annotation and no longer have the class extend EventEmitter.
I also use ts-node to run the code. I use ts-node ./node_modules/.bin/jest src/event-emitter-inversify/__tests__/event-emitter-inversify.test.ts
I'm not sure why the tests fail and the run succeeds.
I consistently see the error TypeError: Cannot read property 'constructor' of null in my tests.
Here is the setup.
event-emitter-inversify.ts
import 'reflect-metadata';
import { EventEmitter } from 'events';
import { ContainerModule, decorate, injectable, interfaces } from 'inversify';
decorate(injectable(), EventEmitter);
#injectable()
export class EventEmitterChild extends EventEmitter {
constructor() {
super();
}
greet() {
console.log('hello world.');
}
}
export const EventEmitterModule = new ContainerModule(
(bind: interfaces.Bind) => {
bind<EventEmitterChild>('EventEmitterChild').to(EventEmitterChild).inSingletonScope();
}
);
event-emitter-inversify-dependent.ts
import { inject, injectable } from 'inversify';
import { EventEmitterChild } from './event-emitter-inversify';
#injectable()
export class EventEmitterDependent {
constructor(#inject('EventEmitterChild') private readonly _eventEmitterChild: EventEmitterChild) {
}
run() {
this._eventEmitterChild.greet();
}
}
run.ts (this runs fine!)
import { Container } from 'inversify';
import { EventEmitterChild, EventEmitterModule } from './event-emiiter-inversify';
import { EventEmitterDependent } from './event-emitter-inversify-dependent';
const referenceContainer = new Container();
referenceContainer.load(EventEmitterModule);
const eventEmitterChild = referenceContainer.get<EventEmitterChild>('EventEmitterChild');
eventEmitterChild.greet();
const eventEmitterDependent = referenceContainer.get<EventEmitterDependent>('EventEmitterDependent');
eventEmitterDependent.run();
event-emitter-inversify.test.ts (this fails)
import { Container } from 'inversify';
import { EventEmitterChild, EventEmitterModule } from '../event-emitter-inversify';
describe('EventEmitter test', () => {
const container: Container = new Container();
beforeAll(async () => {
container.load(EventEmitterModule);
});
test('get EventEmitterChild from container', () => {
const eventEmitterChild = container.get<EventEmitterChild>('EventEmitterChild');
expect(eventEmitterChild).toBeDefined();
});
});
I run the test with:
ts-node ./node_modules/.bin/jest src/event-emitter-inversify/__tests__/event-emitter-inversify.test.ts
And it fails with:
TypeError: Cannot read property 'constructor' of null
stacktrace
at getClassPropsAsTargets (node_modules/inversify/lib/planning/reflection_utils.js:82:75)
at getClassPropsAsTargets (node_modules/inversify/lib/planning/reflection_utils.js:84:27)
at getClassPropsAsTargets (node_modules/inversify/lib/planning/reflection_utils.js:84:27)
at getTargets (node_modules/inversify/lib/planning/reflection_utils.js:28:27)
at Object.getDependencies (node_modules/inversify/lib/planning/reflection_utils.js:12:19)
at node_modules/inversify/lib/planning/planner.js:106:51
at Array.forEach (<anonymous>)
at _createSubRequests (node_modules/inversify/lib/planning/planner.js:94:20)
at Object.plan (node_modules/inversify/lib/planning/planner.js:136:9)
at node_modules/inversify/lib/container/container.js:318:37
Any ideas of what I'm missing or doing wrong?

refactored geb login spec to module resulting in "not initialized" error

I am new to writing geb specs for funcational testing and appreciate your help with this issue. I am also new to Groovy, and the "Not Initialized" error might be to do with basic inexperience in that. I am trying to build a module to log me in automatically, at which point I can proceed with further tests, but I receive a geb.error.ModuleInstanceNotInitializedException. Previously, not using a module, I was able to log in to my page using only a spec. I was refactoring this to a module approach based on the answer on rcgeorge23's response here:
How to refactor common Geb test sequences.
The spec:
import spock.lang.Unroll
class FlowSpecs extends GebReportingSpec {
#Unroll
def "setup Spec"() {
given:
to QUserPage
when:
authModule.signIn("mwalle","password")
then:
assert { $("span", "class":"login-text z-label")[3].text() == "mwalle" }
}
the page:
package pages.app
import geb.Page
import AuthModule
class QUserPage extends Page {
static url = "/qsystem/quser"
static at = { title == "QSystem" }
static content = {
authModule { module AuthModule }
}
}
and the module:
import geb.Module
class AuthModule extends Module {
def idUser = js."zk.Widget.\$('\$usr').uuid" + "-real"
def idPass = js."zk.Widget.\$('\$pwd').uuid"
static content = {
loginUser { $("input", id:idUser) }
loginPass { $("input", id:idPass) }
loginButton { $("button",class:"login-button z-button")[0] }
}
void signIn(String username = "mwalle", String password = "password") {
loginUser.value(user)
loginPass.value(pass)
loginButton.click()
}
}
The full error is:
geb.error.ModuleInstanceNotInitializedException: Instance of module class AuthModule has not been initialized. Please pass it to Navigable.module() or Navigator.module() before using it.
at geb.Module.uninitializedException(Module.groovy:757)
at geb.Module.getJs(Module.groovy:96)
at AuthModule.<init>(AuthModule.groovy:5)
at geb.navigator.AbstractNavigator.module(AbstractNavigator.groovy:356)
at geb.content.NavigableSupport.module(NavigableSupport.groovy:207)
at geb.content.PageContentTemplateFactoryDelegate.module(PageContentTemplateFactoryDelegate.groovy:31)
at pages.app.QUserPage._clinit__closure2$_closure3(QUserPage.groovy:12)
at pages.app.QUserPage._clinit__closure2$_closure3(QUserPage.groovy)
at geb.content.PageContentTemplate.invokeFactory(PageContentTemplate.groovy:97)
at geb.content.PageContentTemplate.create_closure1(PageContentTemplate.groovy:59)
at geb.content.PageContentTemplate.create_closure1(PageContentTemplate.groovy)
at geb.content.PageContentTemplate.create(PageContentTemplate.groovy:82)
at geb.content.PageContentTemplate.get(PageContentTemplate.groovy:54)
at geb.content.DefaultPageContentSupport.getContent(DefaultPageContentSupport.groovy:42)
at geb.content.PageContentSupport.propertyMissing(PageContentSupport.groovy:39)
at geb.Page.propertyMissing(Page.groovy:112)
at geb.Browser.propertyMissing(Browser.groovy:216)
at geb.spock.GebSpec.propertyMissing(GebSpec.groovy:60)
at FlowSpecs.setup Spec(FlowSpecs.groovy:23)
The problem are these lines
def idUser = js."zk.Widget.\$('\$usr').uuid" + "-real"
def idPass = js."zk.Widget.\$('\$pwd').uuid"
js needs an initialized navigator, as you can see with at geb.Module.getJs(Module.groovy:96)
I would strongly advise to use another selector (css or otherwise) if you can instead of using javascript to lookup the id. If you cannot then move the lookup code into the content block.
static content = {
loginUser { $("input", id: js."zk.Widget.\$('\$usr').uuid" + "-real") }
loginPass { $("input", id: js."zk.Widget.\$('\$pwd').uuid") }
loginButton { $("button",class:"login-button z-button")[0] }
}

Get path of required module in NodeJS

I have 2 classes, one that extends from the other. I need to have a method that can be called from extending classes but resolves the path to reflect whatever directory the extending class module is in.
/main.js
class Main {
getTemplate () {
return readFileSync(__dirname + './template.ejs')
}
}
/some/path/module.js (also contains /some/path/template.ejs)
class Module extends Main {
}
In main code
const m = new Module()
m.getTemplate() // /some/path/template.ejs
The above doesn't work since __dirname doesn't reflect the 'module.js' path.
I've played around with require.resolve but I am not sure how I can use this from within the module.
/main.js
class Main {
constructor(dirname) {
this.dirname = dirname;
}
getTemplate () {
return readFileSync(this.dirname + './template.ejs')
}
}
/some/path/module.js (also contains /some/path/template.ejs)
class Module extends Main {
constructor() {
super(__dirname);
}
}
Ok. I've got a working alas hokey solution.
class Main {
constructor () {
try {
throw new Error()
} catch(e) {
const m = e.stack.match(/at new \w+ \(([^:]+)/)
this.dirname = path.dirname(m[1])
}
}
getTemplate () {
return readFileSync(this.dirname + '/template.ejs')
}
}
class Module extends Main {
}

Resources