Mock window.location.reload with sinon - vue.js

I'm writting tests with sinon for a section of Vue code that performs a reload with window.location.reload();.
The code works correctly, but the test is failing with an error Error: Not implemented: navigation (except hash changes)
If I delete that line of code, the tests don't crash.
How can I write a sinon test that runs correctly through that line of code?
I'm not sure if I need to stub that line, although I'm not sure how could I do it for a property.
Any ideas?

Consider onbeforeunload which throws an error and prevents an actual page reloading, and assert.throws catching the error. Something like this:
describe("#location.reload", () => {
it("works well", () => {
window.onbeforeunload = () => {
throw new Error();
};
assert.throws(location.reload);
});
});

Related

Aurelia-testing: Failed to execute 'replaceChild' on 'Node': parameter 1 is not of type 'Node'

I am using for the first time the aurelia-testing package to test my HTML code.
I seem to have followed the docs to set up my test as follows:
describe('Contextual Menu HTML View test suite', function () {
let component: ComponentTester;
beforeEach(function () {
component = StageComponent
.withResources('../../src/components/modal/contextual-menu')
.inView('<contextual-menu is-active.two-way="activateMenu"></contextual-menu>')
.boundTo({ activateMenu: false });
});
it('should not add the is-active class to the root element', async function () {
await component.create(bootstrap);
const rootElement = await waitForDocumentElement('.qa-contextual-menu');
expect(rootElement.classList.contains('is-active')).toBe(false);
});
afterEach(function () {
component.dispose();
});
});
I tried using just bind instead of two-way but that fails too.
I tried both with a document.querySelector and with waitForDocumentElement, both cases fail, but anyways I assume the error comes from earlier.
I am getting an error and I am not sure why. Could you put on the tracks to identify the root cause of the following:
TypeError: Failed to execute 'replaceChild' on 'Node': parameter 1 is not of type 'Node'.
at Object.convert (/Users/lemoustachiste/work/lm-frontend/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/generated/Node.js:573:11)
at HTMLDivElement.replaceChild (/Users/lemoustachiste/work/lm-frontend/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/generated/Node.js:292:31)
at NodeJsDom.replaceNode (/Users/lemoustachiste/work/lm-frontend/node_modules/aurelia-pal-nodejs/dist/nodejs-dom.js:95:29)
at makeElementIntoAnchor (/Users/lemoustachiste/work/lm-frontend/node_modules/aurelia-templating/dist/commonjs/aurelia-templating.js:2432:19)
at applyInstructions (/Users/lemoustachiste/work/lm-frontend/node_modules/aurelia-templating/dist/commonjs/aurelia-templating.js:2479:17)
at ViewFactory.create (/Users/lemoustachiste/work/lm-frontend/node_modules/aurelia-templating/dist/commonjs/aurelia-templating.js:2707:7)
at TemplatingEngine.enhance (/Users/lemoustachiste/work/lm-frontend/node_modules/aurelia-templating/dist/commonjs/aurelia-templating.js:5290:24)
at /Users/lemoustachiste/work/lm-frontend/node_modules/aurelia-framework/dist/commonjs/aurelia-framework.js:176:28
at new Promise (<anonymous>)
at Aurelia.enhance (/Users/lemoustachiste/work/lm-frontend/node_modules/aurelia-framework/dist/commonjs/aurelia-framework.js:174:12)
Thanks a lot
I am not a jest user. So I simply used the scaffolded TS jest skeleton app from aurelia-cli (au new jest-skeleton --unattended --select typescript,jest,vscode). And found that to be working.
It seems the you are missing the following configuration in your jest.config.js.
testEnvironment: "node",
After only adding that, the tests started working.

How to disable the "Global error handler detected" warning in vue test utils

I'm creating async tests using vue-test-utils and jest using the approach described here:
https://vue-test-utils.vuejs.org/guides/#what-about-nexttick
where you set Vue.config.errorHandler = done like shown below
test('Then we are shown events in EventCreate component', done => {
Vue.config.errorHandler = done
This is working and when an error is thrown in a promise handler in a component my tests will fail. However I'm getting this warning.
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:1421
[vue-test-utils]: Global error handler detected (Vue.config.errorHandler).
Vue Test Utils sets a custom error handler to throw errors thrown by instances. If you want this behavior in your tests, you must remove the global error handler.
I don't want to spam my test output with this warning. Is there a way to disable it?
This is how I did
beforeEach(() => {
jest.spyOn(console, 'error');
console.error.mockImplementation(() => 'some error');
});
afterEach(() => {
console.error.mockRestore();
});

Accumulate all JS warnings and errors during test runs in TestCafe

I would like to be able to access all JS warnings and errors from the Browser Console during test runs. With the "-e" (skip JS errors) flag disabled, the test stops at the first error, so clearly it is looking for them. With this flag enabled, I would like to be able to see which errors (and ideally warnings) fired during test runs.
I've tried using the ClientFunction and window.onerror methods. I've also tried the -r 'reports' flag -- I only see TestCafe errors, not JS errors from the page under test. I've tried "Accessing Console Messages" from https://devexpress.github.io/testcafe/documentation/test-api/accessing-console-messages.html but this only gives messaging thrown by console.log, etc ("Note that this method returns only messages posted via the console.error, console.warn, console.log and console.info methods. Messages output by the browser (like when an unhandled exception occurs on the page) will not be returned.")
const installErrorHandler = ClientFunction(() => {
window.onerror = error => {
console.log("ERROR::::::");
console.log(error);
};
});
Over in the Clojure space, when using the Etaoin webdriver implementation (on Chrome or Phantom.js), at any point simply performing a
(get-logs driver)
returns
{:level :warning,
:message "1,2,3,4 anonymous (:1)",
:timestamp 1511449388366,
:source nil,
:datetime #inst "2017-11-23T15:03:08.366-00:00"}
....
....
Including any 'unhandled exceptions'.
Can I not do this in TestCafe?
Probably your example with window.onerror does not work because it executes later that error occurs. I suggest you extract the error handler into a separate *.js file and inject it using the new testcafe feature: Inject Scripts into Tested Pages.
Look at the following example:
script to inject (log-errors.js):
window.unhandledErrors = [];
window.onerror = (message, source, lineno, colno, error) => {
window.unhandledErrors.push({ message, source, lineno, colno, error });
}
test:
import { Selector } from 'testcafe';
fixture('Log errors')
.page('http://example.com')
.afterEach(async t => {
const errors = await t.eval(() => window.unhandledErrors);
console.log(errors);
});
test('test', async t => {
//...
});
Run tests by the following command:
testcafe chrome test.js -e --cs=./scripts/log-errors.js
Note that Script Injection feature is available since 1.4.0 version.

Why does an expectation in $nextTick never fail?

I need to use $nextTick in order to test some parts of my program. Somehow, it breaks my tests and make them success all the time - even when they should fail.
A minimal test sample would look like this:
import App from "./App";
import { shallowMount } from "#vue/test-utils";
it("should fail", () => {
const wrapper = shallowMount(App);
wrapper.vm.$nextTick(() => {
expect(1).toBe(3);
done();
});
});
You can find a sandbox example here
If you open the console, you should find the following error messages:
[Vue warn]: Error in nextTick: "Error: expect(received).toBe(expected)
Error: expect(received).toBe(expected)
Why does the test success? Why are the errors ignored? How do I use $nextTick properly if note like so?
In order to wait until Vue.js has finished updating the DOM after a
data change, you can use Vue.nextTick(callback) immediately after the
data is changed. The callback will be called after the DOM has been
updated.
I can not see any trigger that change DOM in your test. And you missed done argument in test callback
For example in the following this is wrapper.find('button').trigger('click')
it('fetches async when a button is clicked', (done) => {
const wrapper = shallowMount(Foo)
wrapper.find('button').trigger('click')
wrapper.vm.$nextTick(() => {
expect(wrapper.vm.value).toBe('value')
done()
})
})

mocha programmatically set vue error handler

I find myself writing this at the start of pretty much all of my unit tests in mocha:
it('should do something', (done) => {
Vue.config.errorHandler = done;
// do something aynchronous
});
By default, Vue catches all errors itself and logs them to the console, so mocha can't see them. This code makes sure that thrown errors fail the tests.
Is there a way with mocha to do this without having to start every single async test with this line of code? If I have to write / use a plugin, that's fine.
Try:
Vue.config.errorHandler = function (err, vm, info) {
throw err
}
in your test entry.