VueJS event callback spy doesn't work - javascript

I have a VueJS component text-editor that I call as such in my tests:
import Vue from 'vue';
import TextEditor from '../src/TextEditor.vue';
import expect, {spyOn} from 'expect';
describe("<text-editor>", (done) => {
beforeEach(() => {
this.vm = new Vue({
data: { hi: { text: "hi" } },
template: '<div><text-editor ref="texteditor" v-model="hi" #hide="hidecb"></text-editor></div>',
components: { 'text-editor': TextEditor },
methods: {
hidecb: function() {
console.log('hide');
}
}
}).$mount();
});
it("should call the #hide callback", (done) => {
let spy = spyOn(this.vm, 'hidecb');
// This call will trigger an this.$emit('hide') in the component
this.vm.$refs.texteditor.save();
Vue.nextTick(() => {
expect(spy).toHaveBeenCalled();
done();
});
});
});
Weird thing is, method hidecb does get called and I see "hide" on the console. But the spy will fail with the following error:
Error: spy was not called (undefined:29)
I checked and the callback is indeed called before nextTick. I should also point out that I am using Webpack, expectjs and karma.
Would someone be able to point out why the spy doesn't work?

Related

Cannot read values from file in fixture folder, getting error as "TypeError Cannot read properties of undefined (reading 'data')"

I'm trying to use fixtures to hold data for different tests, specifically user credentials. This is an example of the code. I'm getting 'Cannot read properties of undefined (reading 'data')'. I tried to google search , I found Cypress fixtures - Cannot read properties of undefined (reading 'data')
I used closure variable technique as reccomended in that post , yet I got reference error of unable to reference data.Please help me.I know cypress.config can be used but I want to keep that for global configs
Json(credentials.json):
{
"username":"*****",
"password":"*****"
}
Code:
import { LoginPage } from "./pageobject/login_page"
describe('Test Scenario', () => {
before(function () {
cy
.fixture('credentials').then(function (data) {
this.data = data
})
})
it('Simple login', () => {
cy.visit(Cypress.env('url'))
var loginpage = new LoginPage()
loginpage.EnterUsername(this.data.username)
loginpage.clickonSubmit()
loginpage.EnterPassword(this.data.password)
loginpage.clickonSubmit()
Cypress
.on('uncaught:exception', (err, runnable) => {
return false;
});
cy.
wait(10000)
cy.
get('span[id="user"]').should('have.text', this.data.username , 'User Login Unsuccessfully')
});
});
There's a few things need adjusting
use function () {} syntax in the it() block
use beforeEach() and alias to load the fixture, because data on this can be cleared (especially after login)
move uncaught:exception catcher to the top of the block
don't cy.wait(), instead add timeout to next command
.should() only has two parameters in this case, so use .and() to test the 2nd text
import { LoginPage } from './pageobject/login_page';
describe('Test Scenario', () => {
beforeEach(function () {
cy.fixture('credentials').as('data')
})
it('Simple login', function() {
Cypress.on('uncaught:exception', (err, runnable) => {
return false;
});
cy.visit(Cypress.env('url'));
var loginpage = new LoginPage();
loginpage.EnterUsername(this.data.username);
loginpage.clickonSubmit();
loginpage.EnterPassword(this.data.password);
loginpage.clickonSubmit();
cy.get('span[id="user"]', {timout:10_000})
.should('have.text', this.data.username)
.and('have.text', 'User Login Unsuccessfully')
})
})
I suspect it's because you are using an arrow function instead of a regular function, you cannot access the this object with an arrow function.
Cypress docs
If you store and access the fixture data using this test context
object, make sure to use function () { ... } callbacks. Otherwise the
test engine will NOT have this pointing at the test context.
change it to this:
it('Simple login', function() {
...
});

Apollo MockedProvider testing issues (my rendered component keeps disappearing)

Disclaimer; I'm a bit new to react-testing-library (been using an admittedly older version of Enzyme) and the Apollo Query/MockedProvider components (been using the client via a JS service object), so this may be a stupid question...
I have a component that receives a list of countries for which I am trying to write tests. What I would like to do is something like:
import React from 'react';
import { MockedProvider } from '#apollo/react-testing';
import { render, act } from '#testing-library/react';
import wait from 'waait';
import Countries, { countryQuery } from './Countries';
import { isTerminating } from 'apollo-link/lib/linkUtils';
const mockCountryName = 'sample country';
const mocks = [
{
request: {
query: countryQuery,
vairables: {},
},
result: {
data: {
countries: [{ name: mockCountryName }],
},
},
},
];
describe('when working with the countries component', () => {
describe('and the component is loading', () => {
let component;
beforeAll(async (done) => {
await act(async () => {
component = render(
<MockedProvider mocks={[]}>
<Countries />
</MockedProvider>
);
});
done();
});
it('should have a title', () => {
expect(component.getByText('Countries Component')).not.toBeUndefined();
});
it('should have a loading status', () => {
expect(component.getByText('Loading...')).not.toBeUndefined();
});
});
});
When this runs, the second test (about loading status) fails as it looks like the component is only a body tag at that point. I tried changing beforeAll to beforeEach, but that just produced a component that had an Error indicator. I put some console.log statements in my component, and this is what they are showing me:
console.log src/components/Countries.js:45
Loading is: true
console.log src/components/Countries.js:46
Error is: undefined
console.log src/components/Countries.js:45
Loading is: false
console.log src/components/Countries.js:46
Error is: Error: Network error: No more mocked responses for the query: {
countries {
name
phone
__typename
}
}
, variables: {}
I'm wondering if it does not like the empty array passed in as the mocks property for the MockedProvider. But every example I've seen does it that way, so...
As an experiment, I added a second set of test to the spec file to see if it was just a weird timing issue with the component that was causing the issue. Here's the second test:
describe('and the component has data', () => {
let component;
beforeAll(async (done) => {
await act(async () => {
component = render(
<MockedProvider mocks={mocks} addTypename={false}>
<Countries />
</MockedProvider>
);
await wait(0);
});
done();
});
it('should have a title', () => {
expect(component.getByText('Countries Component')).not.toBeUndefined();
});
it('should have a loading status', () => {
expect(component.getByText(mockCountryName)).not.toBeUndefined();
});
});
This has the same problem; the first test works (if I reorder the test, the one that first always works) but the second one fails, and the component seems to be an empty body tag.
Is there a way to make this type of test structure work? I don't like the idea of having to put everything into a single test, let alone the setup code for the component.
Thanks!
I'm not sure if it's the best approach, but I think I found a workaround.
First, the empty array/loading issue was not an issue; I traced everything back to testing-library resetting/re-rendering the component between tests.
Here's what I did:
describe('and the component is loading', () => {
let component, pageTitle, loadingMessage;
beforeAll(async (done) => {
await act(async () => {
component = render(
<MockedProvider mocks={[]}>
<Countries />
</MockedProvider>
);
pageTitle = component.getByText(mockPageTitle);
loadingMessage = component.getByText(mockLoadingMessage);
});
done();
});
it('should have a title', () => {
expect(pageTitle).not.toBeUndefined();
});
it('should have a loading status', () => {
expect(loadingMessage).not.toBeUndefined();
});
});
Instead of trying to call component.getTextBy in each test, I moved them into the beforeAll, and assigned the output to variables. Each test uses the variables for their tests. I also wrote a test for my Routes component, and I was still able to call fireEvent.click() on the components.
I would be very interested in any feedback from anyone who has a more experience with testing-library on this. It seems better than what I had, but I want to make sure it's really the best approach.
Thanks.

unable to use $off and passing parameters in eventbus in Vue

In main.js i created the eventBus
Vue.prototype.$eventHub = new Vue()
And in component1
this.$eventHub.$emit('logged-in')
In component2, i tried this
beforeMount () {
this.$eventHub.$on('logged-in', function () {
console.log("logged in")
})
},
beforeDestroy() {
this.$eventHub.$off('logged-in')
}
It is not printing any thing in the console. If i remove this.$eventHub.$off('logged-in') it is working fine, but it is executing number of times that$emit is executed. What am i doing wrong here? why $off is not working?
Unable to pass the parameters as well
trying to send message using $emit
this.$eventHub.$emit('logged-in', "some message")
in $on
this.$eventHub.$on('logged-in', this.testEvent)
The test event method looks
testEvent (params) {
console.log(params)
}
The params shows undefined.
But if i do this, it is working fine
this.$eventHub.$on('logged-in', (params) => {
console.log(params)
})
How can i pass parameters to the method?
You should pass a reference to $off
beforeMount () {
this.$eventHub.$on('logged-in', this.onEventHandler)
},
beforeDestroy() {
this.$eventHub.$off('logged-in', this.onEventHandler)
},
methods: {
onEventHandler () {
console.log("logged in")
}
}

Sinon.spy fails with imported method

I have of couple JS modules, let's say A and B. In module A, I have a method which depends on another method imported from module B. Now how do I test with sinon.spy, whether the method from A triggers the method from B?
//ModuleA.js
import{ methodFromB } from "ModuleB.js";
function methodFromA (){
methodFromB();
}
export{
methodFromA
}
//ModuleB.js
function methodFromB (){
//doSomething
}
ModuleA.Spec.js
import sinon from 'sinon';
import { assert,expect } from "chai";
import * as modB from "ModuleB.js";
import { methodA } from '../js/ModuleA.js';
describe("ModuleA.js", function() {
beforeEach(function() {
stubmethod = sinon.stub(modB, "methodB").returns("success");
});
after(function() {
});
describe("#methodA", function() {
it("Should call the method methodB", function() {
expect(methodA()).to.deep.equal('success');
expect(stubmethod.calledOnce).to.equal(true);
});
});
});
After trying to stub methodB, i get the error "expected undefined to deeply equal 'success'".
Thanks in advance.
you should mock module B, and expect it to.have.been.called instead of spy from methodFromA
You stub the wrong function from module B. It is supposed to be methodFromB not methodB based on your source file.
describe("ModuleA.js", function () {
beforeEach(function () {
stubmethod = sinon.stub(modB, "methodFromB").returns("success"); // change to methodFromB
});
after(function () {
stubmethod.restore(); // don't forget to restore
});
describe("#methodA", function () {
it("Should call the method methodB", function () {
expect(methodA()).to.deep.equal('success');
expect(stubmethod.calledOnce).to.equal(true);
});
});
});

Aurelia. Testing. TypeError: config.addPipelineStep is not a function

I use default Aurelia's sceleton-esnext updated to last version .
I added this line to App (
Example from doc. Customizing the Navigation Pipeline)
config.addPipelineStep('authorize', AuthorizeStep);
After this I catch error running 'gulp test'
Chrome 52.0.2743 (Linux 0.0.0) the App module contains a router property FAILED
TypeError: config.addPipelineStep is not a function
Test
it('contains a router property', () => {
expect(sut.router).toBeDefined();
});
Test is going well without line.
I just came across this issue. To fix, you just need to add an empty method into your RouterStub:
class RouterStub {
configure(handler) {
handler(this);
}
map(routes) {
this.routes = routes;
}
addPipelineStep(stepName, stepClass) {
}
}
then in your test:
describe('the App module', () => {
var app;
var mockedRouter;
beforeEach(() => {
mockedRouter = new RouterStub();
app = new App();
app.configureRouter(mockedRouter, mockedRouter);
});
it('contains a router property', () => {
expect(app.router).toBeDefined();
});
});
If you're trying to test the pipeline step you'll need to mock the router itself and test the actual logic, but if you just want your tests to run (i.e. be defined, check the router title etc), this will work.

Categories

Resources