I just joined a front team and I am asked to do some tests of the application,
I need to check that my Not Found page appears only if the user does not enter a correct url.
I know there is MemoryRouter if our application routing use react router but my team does not use it:
<MemoryRouter initialEntries={["/random"]}>
<Routes />
</MemoryRouter>
this is the component that manages the routing:
const routes = {
path: "",
children: [
{
path: "/",
load: () => import(/* webpackChunkName: 'home' */ "./home")
},
{
path: "/login",
load: () => import(/* webpackChunkName: 'login' */ "./login")
},
{
path: "/delivery",
load: () => import(/* webpackChunkName: 'delivery' */ "./delivery")
},
{
path: "/offers",
load: () => import(/* webpackChunkName: 'delivery' */ "./offers")
},
// Wildcard routes, e.g. { path: '(.*)', ... } (must go last)
{
path: "(.*)",
load: () => import(/* webpackChunkName: 'not-found' */ "./not-found")
}
],
async action({ next }) {
const route = await next();
return route;
}
};
**export default routes:**
So I still tried with MemoryRouter but it does not work:
import React from "react";
import { mount } from "enzyme";
import { MemoryRouter } from "react-router";
import { Route } from "react-router-dom";
import NotFoundPage from "../routes/not-found/NotFound";
import Routes from "../routes/index";
describe("testing NotFoundPage", () => {
it("should go to 404 page", () => {
const component = mount(
<MemoryRouter initialEntries={["/random"]}>
<Routes />
</MemoryRouter>
);
expect(component.find(NotFoundPage)).toHaveLength(1);
});
});
Related
i created 2 view one login.vue and register.vue and i impoetred them in the index.js inside the router folder but when i try to route to certain paden all the route show a # like the pages dont exist
my index .js inside the router folder
import { createRouter, createWebHashHistory } from 'vue-router'
import Login from '../views/Login.vue'
import Home from '../views/Home.vue'
import Register from '../views/Register.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/register',
name: 'Register',
component: () => import(/* webpackChunkName: "about" */
'../views/Register.vue')
},
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "about" */
'../views/Login.vue')
},
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
Vue 3 import all js files for all vue components on first load project.
i want vue to import only required files.
for example if i open contact page vue 3 should import only contact.js file.
Right now it is import all those files
<link href="/js/contact.js" rel="prefetch">
<link href="/js/forgot.js" rel="prefetch">
<link href="/js/signin.js" rel="prefetch">
<link href="/js/signup.js" rel="prefetch">
<link href="/js/app.js" rel="preload" as="script">
<link href="/js/chunk-vendors.js" rel="preload" as="script">
These my index router file :
import { createRouter, createWebHistory } from "vue-router";
import Home from "../views/Home.vue";
import store from "../store";
import {authConstants} from "../_constants";
const routes = [
{
path: "/",
name: "Home",
component:()=>Home,
},
{
path: "/contact",
name: "contact",
component: () => import(/* webpackChunkName: "contact" */ "../views/contact.vue"),
},
{
path: "/signin",
name: "signin",
component: () => import(/* webpackChunkName: "signin" */ "../components/auth/signin.vue"),
},
{
path: "/signup",
name: "signup",
component: () => import(/* webpackChunkName: "signup" */ "../components/auth/signup.vue"),
},
{
path: "/recoverpassword",
name: "recoverPassword",
component: () => import(/* webpackChunkName: "forgot" */ "../components/auth/recoverPassword.vue"),
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
scrollBehavior() {
// document.getElementById("app").scrollIntoView();
},
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters[authConstants.GET_USER_DATA]) {
next({ name: 'signin' })
} else {
next() // go to wherever I'm going
}
} else {
next() // does not require auth, make sure to always call next()!
}
})
export default router;
and thanks for help in advanced.
You should disable preloading/prefetching in vue.config.js:
module.exports =
{
chainWebpack: config =>
{
config.plugins.delete('prefetch'); // for async routes
config.plugins.delete('preload'); // for CSS
return config;
}
};
I have some issues with Vue 3 and Vuex.
I'm trying to redirect users when logged in in my Vuex file, but it's not working as expected.
It's not returning any errors, it's changing a link, but not redirected to another page.
My action looks like this;
actions: {
async login(commit: any, payload: any ) {
const cookie_token = useCookies();
API.post('/login', {
email: payload.email.value,
password: payload.password.value
})
.then((response: any) => {
notif.success('Welcome back, ' + response.data.player.name)
cookie.set('user', response.data)
commit.commit('loginSuccess', response.data)
router.push({
name: 'index',
})
}).catch((e) => (
console.log(e.message)
)
)
}
},
And the router is getting files where routes are defined.
And here is my full router file:
import {
createRouter as createClientRouter,
createWebHistory,
} from 'vue-router'
import * as NProgress from 'nprogress'
// import routes from 'pages-generated'
import type { RouteRecordRaw } from "vue-router";
// Then we can define our routes
const routes: RouteRecordRaw[] = [
// This is a simple route
{
component: () => import("/#src/pages/index.vue"),
name: "index",
path: "/",
props: true,
},
{
component: () => import("/#src/pages/auth.vue"),
path: "/auth",
props: true,
children: [
{
component: () => import("/#src/pages/auth/login.vue"),
name: "auth-login",
path: "login-1",
props: true,
},
{
component: () => import("/#src/pages/auth/login.vue"),
name: "auth-signup",
path: "singup",
props: true,
},
],
},
{
component: () => import("/#src/pages/[...all].vue"),
name: "404",
path: "/:all(.*)",
props: true,
},
];
export function createRouter() {
const router = createClientRouter({
history: createWebHistory(),
routes,
})
/**
* Handle NProgress display on-page changes
*/
router.beforeEach(() => {
NProgress.start()
})
router.afterEach(() => {
NProgress.done()
})
return router
}
export default createRouter()
Have in mind that it's working on other files, and I can see that router is triggered here, but not chaning a page, only on vuex is not working. If it's not working, why there is no error?
You're creating more than one instance of Vue Router. You should export the same router instance, not a function creating a new instance each time it gets called.
The following code will likely yield the desired outcome:
import {
createRouter,
createWebHistory,
} from 'vue-router'
import * as NProgress from 'nprogress'
import type { RouteRecordRaw } from "vue-router";
const routes: RouteRecordRaw[] = [
// your routes here...
];
let router;
export function useRouter() {
if (!router) {
router = createRouter({
history: createWebHistory(),
routes,
})
router.beforeEach(() => {
NProgress.start()
})
router.afterEach(() => {
NProgress.done()
})
}
return router
}
I'm placing the router instance in the outer scope, so you always get the same instance when calling useRouter().
Consume it using:
import { useRouter } from '../path/to/router'
const router = useRouter();
I am using vue and firebase.
I want to add the redirect method using vue-router.
In my vue-router code, I have meta: { requiresAuth: true } in the multiple pages for the middleware.
My vue-router redirect method is, if jwt token is not stored in the local storage, the url redirects to /login.
I am using firebase, so I think the user account token is stored in the local storage when the user logs in.
So if my vuex code is correct, my vue-router code supposed to work properly.
Now, if I login as a user, the url doesn't change. But if I enter the
specific user's dashboard page, the redirect is working.
Why doesn't the url change when I log in?
import Vue from 'vue'
import VueRouter from 'vue-router'
//import Home from '../views/Home.vue'
import Dashboard from '../views/Dashboard.vue'
import OrdersMobile from '../views/OrdersMobile.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: () => import(/* webpackChunkName: "about" */ '../selfonboarding/Home.vue')
},
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "about" */ '../components/Login.vue')
},
{
path: '/dashboard/',
name: 'Dashboard',
component: Dashboard,
meta: { requiresAuth: true },
children: [
{
path: 'products/:id',
name: 'Products',
component: () => import(/* webpackChunkName: "about" */ '../views/Products.vue')
},
{
path: 'working-hours/:id',
name: 'WorkingHours',
component: () => import(/* webpackChunkName: "about" */ '../views/WorkingHours.vue')
},
// {
// path: 'pictures/:id',
// name: 'Pictures',
// component: Pictures,
// },
{
path: 'orders/:id',
name: 'Orders',
component: () => import(/* webpackChunkName: "about" */ '../views/Orders.vue')
},
{
path: 'orders.s/:id',
name: 'OrdersMobile',
component: OrdersMobile,
children: [
{
path: 'processed',
name: 'Processed',
component: () => import(/* webpackChunkName: "about" */ '../views/Processed.vue')
}
]
},
{
path: 'information/:id',
name: 'Information',
component: () => import(/* webpackChunkName: "about" */ '../views/Information.vue')
},
{
path: 'information.s/:id',
name: 'InformationMobile',
component: () => import(/* webpackChunkName: "about" */ '../views/InformationMobile.vue')
},
]
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
})
router.beforeEach((to, from, next) => {
if(to.matched.some(record => record.meta.requiresAuth)) {
if (localStorage.getItem('jwt') == null) {
next({
path: '/login',
params: { nextUrl: to.fullPath }
})
}
} else {
next()
}
})
export default router
vuex code
../store/user.js
import 'firebase/firebase-auth'
import fireApp from '#/plugins/firebase'
import router from '../../router'
const firebase = require("firebase");
require("firebase/firestore");
const db = firebase.firestore();
const state = {
currentUser: null
}
const getters = {
currentUser: state => state.currentUser
}
const mutations = {
userStatus: (state, user) => {
user === null ? state.currentUser = null : state.currentUser = user.email
}
}
const actions = {
signIn: async ({ commit }, user) => {
try {
const userData = await fireApp.auth().signInWithEmailAndPassword(
user.email,
user.password
);
// Get the user id (from the user object I guess)
const userId = fireApp.auth().currentUser.uid;
// or maybe through const userId = fireApp.auth().currentUser.uid;
const proUserDocRef = db.collection('ProUser').doc(userId);
proUserDocRef.get().then((doc) => {
if(doc.exists && doc.data().status === true) {
router.push({name:'Products',params:{id: userId}}).catch(err => {})
} else if(doc.exists && doc.data().status === false){
router.push({name:'Welcome',params:{id: userId}}).catch(err => {})
} else {
alert('You are not registered as a pro user.')
}
})
}
catch(error) {
const errorCode = error.code
const errorMesage = error.message
if(errorCode === 'auth/wrong-password') {
alert('wrong password')
} else {
alert(errorMesage)
}
}
},
signOut: async({ commit }) => {
try {
await fireApp.auth().signOut()
}
catch(error) {
alert(`error sign out, ${error}`)
}
commit('userStatus', null)
}
}
export default {
state,
mutations,
getters,
actions
}
The beforeEach navigation guard is missing a next() call when the route requires authentication and you are logged in:
router.beforeEach((to, from, next) => {
if(to.matched.some(record => record.meta.requiresAuth)) {
if (localStorage.getItem('jwt') == null) {
next({
path: '/login',
params: { nextUrl: to.fullPath }
})
} else {
next(); // Add this ✅
}
} else {
next()
}
})
I added
const token = await firebase.auth().currentUser.getIdToken(true)
localStorage.setItem('jwt', token)
in user.js actions section.
Then, I could make it.
I couldn't set the jwt token in the local storage.
So I did when I log in to the website.
Also I was missing to add next().
I'm trying to achieve something like the following router structure in plain route objects.
const Demo = () => (
<Router history={hashHistory}>
<Route path="/" component={App}>
<Route path="fade" component={FadeDemo}>
<IndexRoute component={Lorem} />
<Route path="demo-1" component={Lorem} />
<Route path="demo-2" component={Lorem} />
<Route path="demo-3" component={Lorem} />
</Route>
My app router looks like this:
export const createRoutes = (store) => ({
path: '/',
component: CoreLayout,
indexRoute: Home,
childRoutes: [
CounterRoute(store)
]
})
So I want to add the FadeDemo transition container from the former JSX as a route without a path on my latter example. Is that possible?
EDIT:
That's my updated route index file, now I get can't match the '/counter' location:
import CoreLayout from '../layouts/CoreLayout/CoreLayout'
import Home from './Home'
import CounterRoute from './Counter'
import TransitionWrapper from './TransitionWrapper'
export const createRoutes = (store) => ({
path: '/',
component: CoreLayout,
indexRoute: Home,
childRoutes: [{
//path: 'fade',
component: TransitionWrapper,
childRoutes: [
CounterRoute(store)
]
}]
})
counter app index:
import { injectReducer } from '../../store/reducers'
export default (store) => ({
path: 'counter',
/* Async getComponent is only invoked when route matches */
getComponent (nextState, cb) {
/* Webpack - use 'require.ensure' to create a split point
and embed an async module loader (jsonp) when bundling */
require.ensure([], (require) => {
/* Webpack - use require callback to define
dependencies for bundling */
const Counter = require('./containers/CounterContainer').default
const reducer = require('./modules/counter').default
/* Add the reducer to the store on key 'counter' */
injectReducer(store, { key: 'counter', reducer })
/* Return getComponent */
cb(null, Counter)
/* Webpack named bundle */
}, 'counter')
}
})
TransitionWrapper
import React from 'react'
import { Link } from 'react-router'
import { RouteTransition } from 'react-router-transition'
const TransitionWrapper = (props) => (
<div>
<RouteTransition
component={"div"}
className="transition-wrapper"
pathname={this.props.location.pathname}
{...props.preset}
>
{this.props.children}
</RouteTransition>
</div>
)
export default TransitionWrapper
Here is described how you can achieve it.
export const createRoutes = (store) => ({
path: '/',
component: CoreLayout,
indexRoute: Home,
childRoutes: [
{
component: FadeDemo,
childRoutes: [
{
path: 'demo-1',
component: Lorem
},
{
path: 'demo-2',
component: Lorem
}
// ...
]
},
]
})