I have the following Backbone module called router (router.js)
define(["app/facilities/messenger"], function (messenger)
{
return Backbone.Router.extend({
routes: {
"*hash": "onHashChange"
},
onHashChange: function (hash) {
messenger.publish("navigate", hash);
console.log("Publish navigate");
},
start: function () {
Backbone.history.start();
}
});
});
Then I run another module called application (application.js) as follows:
define(["app/facilities/contentManager","app/facilities/router"], function (contentManager, router)
{
return
{
run: function () {
contentManager.start();
router = router || new router();
router.start();
}
}
});
And I get the following error:
Uncaught TypeError: Object function (){ return parent.apply(this, arguments); } has no method 'start' (application line 6)
Any ideas why my router doesn't have a start() function? It's clear to me that it should.
Try changing this line:
router = router || new router();
to
router = new router();
I suspect that because router always returns as an object your code never tries to run new router() and is trying to call .start() on an unintialised object.
If you're trying to avoid calling new router() multiple times by using that conditional then perhaps return the already initialised router from your module. That way if it gets called again RequireJS will just return you the initialised router and not another instance.
Related
So I have this function inside my Vue Component:
function openLink(event: Event, url: string, type: string) {
switch (type) {
case 'onetype':
case 'twotype':
event.preventDefault()
openURLInBrowser(url, '_blank');
break
}
}
I am writing my unit test with Vitest. I can easily test, if openLink have been called:
const wrapper = shallowMount(MyLinks, {
propsData: {
myLinks: linkDataStructure
}
})
const a = wrapper.find('a');
const openLink= vi.spyOn(wrapper.vm, 'openLink')
await a.trigger('click');
expect(openLink).toHaveBeenCalled()
This works great. Now I need to test the case, if type is onetype, the method openURLInBrowser is called. So basically the switchcase inside the openLink function.
If I use following, I get: openURLInBrowser does not exist.
const openLink= vi.spyOn(wrapper.vm, 'openURLInBrowser')
How can I access this method inside the function to test it?
Note: The function openURLInBrowser is imported from a openURLInBrowser.ts-File.
I am fairly new to Vue.js and am currently working on a project. I currently have some constants declared in setup(), lets call one of the constant "c", and I want to get them from within mounted(). I realized that I can still console.log(this.c) within mounted() to get the constant printed out but when I try to console.log(this.c) within a function in mounted() I can no longer get it and I get an error Uncaught (in promise) TypeError: Cannot read properties of undefined.
Why is this so? And what work arounds are there?
Example:
setup() {
const c = ref(1)
},
mounted() {
console.log(this.c) // prints 1 on console
function doesSomething() {
console.log(this.c) // TypeError: Cannot read properties of undefined
...
}
}
The function doSomething in the mounted hook should be declared with an arrow function instead, since function declaration has its own this binding:
mounted() {
console.log(this.c)
const doesSomething = () => {
console.log(this.c) // Ok
}
}
mounted is an option in the options api which is different than the composition api using the setup hook, you could use onMounted hook in setup to replace mounted option:
import {onMounted} from 'vue';
setup(){
let c='some content'
onMounted(()=>{
console.log(c)// don't use this keyword
})
}
I have set up chartApp as my application like so:
const chartApp = {
data(){
...
},
methods:{
async init() {
//await async menthod
}
}
}
const app = Vue.createApp(chartApp).mount('#app');
app.init();
Which works.
I can go into the browser console, type app. and see the init function
I'm wanting to register a component. I've tried to set the app like this:
const chartApp = {
data(){
...
},
methods:{
async init() {
//await async menthod
}
}
}
const app = Vue.createApp(chartApp);
app.component('my-component', {
template:'<div>hello</div>'
});
app.mount('#app');
app.init();
But I receive an error stating
app.init is not a function
this time when I look at my browser console, and type app. ...I see an option to mount / unmount, but not init function.
I thought, maybe the app had failed to mount, so I tried:
app.mount('#app')
in the console but received the following warning:
App has already been mounted.
How am I able to register a component please? VueJs3 version is 3.2.16.
In the 1st case you are calling your init method on the result of the mount function.
But in the second case on the result of createApp....which is a very different object
Do this:
const app = Vue.createApp(chartApp);
app.component('my-component', {
template:'<div>hello</div>'
});
const mountedApp = app.mount('#app');
mountedApp.init();
In my component , I have a method which will execute a router.push()
import router from "#/router";
// ...
export default {
// ...
methods: {
closeAlert: function() {
if (this.msgTypeContactForm == "success") {
router.push("/home");
} else {
return;
}
},
// ....
}
}
I want to test it...
I wrote the following specs..
it("should ... go to home page", async () => {
// given
const $route = {
name: "home"
},
options = {
...
mocks: {
$route
}
};
wrapper = mount(ContactForm, options);
const closeBtn = wrapper.find(".v-alert__dismissible");
closeBtn.trigger("click");
await wrapper.vm.$nextTick();
expect(alert.attributes().style).toBe("display: none;")
// router path '/home' to be called ?
});
1 - I get an error
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: could not overwrite property $route, this is usually caused by a plugin that has added the property asa read-only value
2 - How I should write the expect() to be sure that this /home route has been called
thanks for feedback
You are doing something that happens to work, but I believe is wrong, and also is causing you problems to test the router. You're importing the router in your component:
import router from "#/router";
Then calling its push right away:
router.push("/home");
I don't know how exactly you're installing the router, but usually you do something like:
new Vue({
router,
store,
i18n,
}).$mount('#app');
To install Vue plugins. I bet you're already doing this (in fact, is this mechanism that expose $route to your component). In the example, a vuex store and a reference to vue-i18n are also being installed.
This will expose a $router member in all your components. Instead of importing the router and calling its push directly, you could call it from this as $router:
this.$router.push("/home");
Now, thise makes testing easier, because you can pass a fake router to your component, when testing, via the mocks property, just as you're doing with $route already:
const push = jest.fn();
const $router = {
push: jest.fn(),
}
...
mocks: {
$route,
$router,
}
And then, in your test, you assert against push having been called:
expect(push).toHaveBeenCalledWith('/the-desired-path');
Assuming that you have setup the pre-requisities correctly and similar to this
Just use
it("should ... go to home page", async () => {
const $route = {
name: "home"
}
...
// router path '/home' to be called ?
expect(wrapper.vm.$route.name).toBe($route.name)
});
In my component shoppingCart.vue file I'm calling a simple method:
saveCart : _.debounce(() => {
console.log('hi');
}, 2000),
But I get the Error: Uncaught ReferenceError: _ is not defined.
Now gets the fun part. If I change the function for example to:
saveCart(){
console.log(_.random(0, 5));
}
Everything works perfekt and I get for example: 4. To make it even more interesting, I have some other components that are using _.debounce for example searching for Users:
findUsers: _.debounce(
function (term)
{
let vm = this;
axios.get('/search', { params: { user: term }})
.then(response => {
vm.updateResult(response.data);
});
}
,500),
And it works perfect.
So here are some background informations for you. I think I have a guess where the problem is but I'm not sure:
I'm using Laravel and I'm import Lodash through bootstrap.js with
window._ = require('lodash');
My component shoppingCart.vue is being called by Buying.vue.
Buying.vue is called by
export default new VueRouter({
mode: 'history',
routes: [
{
path: '/:user/:title',
component: require('./views/buying/Buying'),
},
],
});
Maybe the problem is somewhere because of vue router? But I tried to make a jsfiddle http://jsfiddle.net/gnu5gq3k/, but my example works in this case... In my real life project test2 creates the problem...
What could be the problem? What kind of informations do you need to understand my problem better?
Edit
I must be doing some easy mistake that I cannot see: I changed the code to:
debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
},
saveCart: this.debounce(() => {
// All the taxing stuff you do
console.log('blubb');
}, 250),
And I cannot call my own function!
Uncaught TypeError: this.debounce is not a function
at Object
What am I doing wrong?
Error: Uncaught ReferenceError: _ is not defined.
In shoppingCart.vue do import _ from 'lodash';:
<script>
import _ from 'lodash';
export default {
// ...
}
</script>
Uncaught TypeError: this.debounce is not a function
at Object
You can't use this while constructing an object (the object is not created yet). You can use it in functions because that code is not executed right away.
window.a = "I'm window's a";
var myObj = {
a: 1,
b: this.a
};
console.log(myObj); // {a: 1, b: "I'm window's a"}
My solution is a workaround:
mounted(){
let that = this;
let savingCart = _.debounce(() => {
that.saveCart();
}, 1000);
window.events.$on('savingCart', savingCart);
}
This works fine