Enzyme/Jest static method mock not running - javascript

I'm trying to test out an imported static method, that ought be run on button click. Here is the component, on which the test ought be run:
const NextButton = (props: ISubmitButtonProps) => (
<button
onClick={Service.goToNext}
className="col-2 submit"
type="submit"
disabled={props.submitting}>
Next
</button>
);
export default NextButton;
Now, I want to test whether the method goToNext is actually being run.
For that I've used an example from here and have added a mock looking fine, like this:
const goToNextMock = jest.fn();
jest.mock('Services/service', () => ({
default: class {
public static goToNext() {
goToNextMock(); //the jest.fn from above
}
}
})
);
And later wrote the test for it, simply simulating the click event, and then checking if the jest.fn() was run:
it('should call goToNext on button click', () => {
//button is set before as shallow(<NextButton submitting={false}/>);
button.simulate('click');
expect(goToNext).toHaveBeenCalled();
})
The problem is, reasons unknown, the test does not persist. Giving me a
Expected mock function to have been called.
EDIT: Same result would occur when attempting to mock it this way (mind the additional preventDefault()
it('should call goToNextReport on button click', () => {
const mock = jest.fn();
Service.goToNext = mock.bind(Service);
button.simulate('click', { preventDefault() {} });
expect(mock).toHaveBeenCalled();
})
I'm fairly new to JEST and js testing. It seems the mock was done properly, yet still I can't get the method to be checked.
Any ideas on the subject?
All help would be amazing!
EDIT: The issue was also submitted to the JEST github channel: https://github.com/facebook/jest/issues/8695

Try this:
jest.mock('Services/service', () => ({
goToNext: jest.fn()
}));

Related

jasmine unit-testing: Can't trigger change event in custom angular dropdown component

I am working on unit-testing with jasmine and karma an angular component. In the template-component a custom dropdown component is used:
<div class="my-modal-body">
<form [formGroup]="form" class="form-horizontal">
<div class="padding-dropdown">
<my-form-wrapper
label="Dateiformat"
labelClass="col-lg-4 two-col-label-size"
inputClass="col-lg-8 two-col-input-size"
>
<my-dropdown
[items]="exportOptionen"
formControlName="dateiTyp"
(selectedChange)="exportFileChange($event)"
>
</my-dropdown>
</my-form-wrapper>
</div>
In my testing I try to test the value change, but can't get it working. However I try to set the value, the exportFileChange is not triggered.
And I know that the component is correct, because it's already in production. So it has to be the test that errors.
Here is my test:
it('dateiTyp auswahl excel', waitForAsync(() => {
spyOn(component, 'exportFileChange');
dateiTyp.setValue('Excel');
component.dateiTyp.setValue('Excel', { emitEvent: true });
fixture.detectChanges();
fixture.whenStable().then(
() => {
expect(component.exportFileChange).toHaveBeenCalled();
let exDiv = fixture.debugElement.query(By.css("#excelExportDiv"));
expect(exDiv).not.toBeNull();
}
);
}));
When changing the selection the exportFileChange(event) method should be called and in the template an div appears. The exportFileChange-Method in the component just changes an boolean.
I tested changing the boolean in the test and that worked, but the event still wasn't triggered.
Here are the most relevant parts of the setup:
describe('ExportModalComponent', () => {
[...]
let dateiTyp: jasmine.SpyObj<FormControl>;
let dateiTypChange: Subject<string>;
[...]
beforeEach( waitForAsync(() => {
[...]
dateiTyp = jasmine.createSpyObj('dateiTyp', ['value', 'setValue']);
formGroup.get.withArgs('dateiTyp').and.returnValue(dateiTyp);
dateiTypChange = new Subject();
Object.defineProperty(dateiTyp, 'valueChanges', { value: dateiTypChange });
[...]
and my-dropdown.component.d.ts:
export declare class myDropdownComponent implements ControlValueAccessor, OnInit, OnChanges
{ [...] }
I can change the ExportModal-template or the ExportModal-component but I can't change the implementation or use of myDropdownComponent.
I am grateful for every help!
Thanks!
This is not a complete answer but it should help you.
This is a good read. In these kind of situations, I just use triggerEventHandler on the DebugElement.
Something like this:
it('should do abc', () => {
// get a handle on the debugElement
const myDropDown = fixture.debugElement.query(By.css('my-dropdown'));
// the first argument is the name of the event you would like to trigger
// and the 2nd argument of type object (or anything) is the $event you want to mock for the calling function
myDropDown.triggerEventHandler('selectedChange', { /* mock $event here */});
// continue with tests
});
I am not entirely sure how your components are wired but that's the best way I have found to raise custom events for custom components.

Cypress not intercepting request with render function vue

I'm trying to do a pretty simple intercept in Cypress using a Vue's application. My component has a setup method using render function as such:
setup() {
useInfiniteLoading({ runner: ... })
}
Then on my tests I do the following:
describe("List todo resource", () => {
it("Checks it loads more todos when scrolling to the bottom", function () {
cy.intercept('/todo').as('getTodos');
cy.visit("/todos");
cy.wait("#getTodos").then(({response}) => {
console.log(response);
})
})
})
When running the test I see that the intercept is not stubbing the response.
As you can see from the image the request makes a request to my actual server running locally and the response is stubed. The weird part is that in a previous test I have:
it("Checks the todo list gets updated when clicking on to resolve it (from true to false)", function () {
cy.visit("/todos");
const resolved = false;
const shouldHaveClass = resolved
? "mdi-checkbox-marked-outline"
: "mdi-checkbox-blank-outline";
cy.intercept("GET", "todo", {
fixture: "resources/todo/list.todo.json",
}).as("getTodos");
cy.intercept("PUT", "todo", {
body: { data: { ...this.updateTodoFixture.data, resolved } },
}).as("updateTodo");
cy.get(".todo-list-item__resolve")
.first()
.each((btn) => {
btn.click();
});
cy.get(".todo-list-item__resolve")
.first()
.should("satisfy", ($el) => {
const classList = Array.from($el[0].classList);
return classList.includes(shouldHaveClass);
});
});
And the response is stubbed using intercept as you can see from the previous screenshot. Is it possible that the previous test is affecting the next test? I have tried taking a look into "Intercept too soon" but no luck on trying to apply the fix described in the page.
Any idea on what could be causing the stub not to happen?

in cypress, intercept in test doesn't work

I'm starting to use cypress and I wanted to do 2 test. One to verify what is displayed if my api return 'false' and one to what is on screen if my api return 'true'.
I tried to do a simple test like this one :
context('contextTest', () => {
before(() => {
cy.waitLoading();
});
beforeEach(() => {});
it('false test', function() {
cy.intercept('POST', '**/test/alreadySent', {
fixture: 'test/alreadySent-false.json',
}).as('alreadySent');
cy.wait('#alreadySent');
cy.get('[data-cy=alreadysent-button]');
});
});
But the intercept doesn't work and it always return the true api call.
What is strange is, if I just put the code in my before(), all work fine as expected.
context('contextTest', () => {
before(() => {
cy.intercept('POST', '**/test/alreadySent', {
fixture: 'test/alreadySent-false.json',
}).as('alreadySent');
cy.waitLoading();
});
beforeEach(() => {});
it('false test', function() {
cy.wait('#alreadySent');
cy.get('[data-cy=alreadysent-button]');
});
});
But I need to change the intercept for the next test so I wanted to set the intercept on this test exclusively.
Is it possible, why is my first code doesn't seem to work?
Or should I write my next test on another file and it is a bad practice to do this kind of verification on the same file?
Since it works when the intercept is moved up in the command order, it seems that cy.waitLoading() triggers the POST and not cy.get('[data-cy=alreadysent-button]').
The intercept must always be set up before the trigger (page visit or button click).
But the intercept varies between tests, so instead of before() I would try setting up a helper function that is called at the top of each test.
const loadAndIntercept = (apiResult) => {
const apiFixture = apiResult ? 'test/alreadySent-true.json' : 'test/alreadySent-false.json';
cy.intercept('POST', '**/test/alreadySent', { fixture: apiFixture }).as('alreadySent');
cy.waitLoading();
})
it('false test', function() {
loadAndIntercept(false);
cy.wait('#alreadySent');
cy.get('[data-cy=alreadysent-button]');
});
it('true test', function() {
loadAndIntercept(true);
cy.wait('#alreadySent');
cy.get('[data-cy=alreadysent-button]');
});
This should work since intercepts are cleared between tests. Ref docs - intercept
Note: all intercepts are automatically cleared before every test.

Jest: Testing API Methods from Intercom

I am having trouble understanding what the testing flow would be for testing functions which use functions loaded from a JavaScript library from Intercom.
My method looks like this:
export const generateButton = (handleOnClick) => {
case "moo":
return <button onClick={() => Intercom('show')}>Sign Up</button>
default:
return 'moo'
The error I get when running this is:
ReferenceError: Intercom is not defined
So I figured it out, I needed to add a new file and point jest set up on package.json to it like so (the file added is mockObject)
"setupFiles": [
"./config/jest/setupJest.js",
"./config/jest/mockObject.js"
],
then in the file itself has this in it
global.Intercom = () => {
console.log('Intercom called')
}
If I understand what you're trying to do then create a dummyFunction to replace Intercom in your tests. Something like this...
const Intercom = jest.fn();
describe('button click', () => {
it('Intercom is called correctly', () => {
// whatever component contains the button should be mounted
const wrapper = mount(<YourComponentHere />);
// you may need to add a class to target the specific button
wrapper.find('button').simulate('click');
expect(dummyFunction).toHaveBeenCalledWith('show');
expect(dummyFunction).toHaveBeenCalledTimes(1);
});
});

Jest: Trying to mock nested functions and redirects in jest, but no avail

We are using a javascript framework(Not react) to render the ui.
main.js
function logout(){
someObj.lock($('#container'), 'Logging out', true);
document.location = app.context + `/${appName}/signout.action?name=${appName}`;
}
function action(event){
switch(event.target){
case 'user:logout':
logout();
break;
case 'user:application':
document.location = app.context + "/";
break;
}
}
module.exports = {
action: action,
logout: logout
}
main.js along with another js file renders a navbar and a dropdown. My intention is to check whether title, dropdown in the navbar is rendered. Also I
am testing whether the browser redirect takes place in the right way.
action method takes an event object and based on its type, either performs signout('user:logout') or redirects to application page('user:application').
tests/main.js
import main from '../main';
describe("some title", () => {
it("some behavior", () => {
let event = {
target: 'user:logout'
}
let app = {
context: ''
}
let appName = 'Some app';
main.logout = jest.fn();
someObj = jest.fn();
someObj.lock = jest.fn();
document.location.assign = jest.fn();
main.action(event);
expect(main.logout).toHaveBeenCalled();
expect(document.location.assign).toBeCalledWith(app.context + `/${appName}/signout.action?name=${appName}`);
})
});
In the test file, I am trying to mock logout function. However it is executing someObj.lock function. someObj is not availabe to tests/main.js
and I am mocking it as well. I'm not sure whether I have to use spyOn instead. I'm using document.location.assign to test for browser redirects.
This test is not working and the terminal is displaying TypeError: Could not parse "/application name/signout.action?name=application name" as URL.
I have spent an entire day testing this feature but to no avail. I need some advice on the best way to test this feature.
Links explored: Intercept navigation change with jest.js (or how to override and restore location.href)
jest documentation

Categories

Resources