Angular 2 Unit Test. Test Route with login screen and hidden menu component - angular-ui-router

I have to realise Angular 2 unit Test on routes and I fail with errors.
My application start with that content within app.component.html
<app-top-menu></app-top-menu>
<router-outlet></router-outlet>
I have those routes:
const appRoutes: Routes = [
{path: 'login', component: LoginComponent},
{path: 'home', component: HomeComponent, canActivate: [AuthGuard]},
{path: 'Second', component: SecondComponent, canActivate: [AuthGuard]},
{path: 'Third', component: ThirdComponent, canActivate: [AuthGuard]},
{path: 'Fourth', component: FourthComponent, canActivate: [AuthGuard]},
{path: '', redirectTo: '/login', pathMatch: 'full'},
{path: '**', component: PageNotFoundComponent}
];
When you acccess the application you're first redirected toward a login page for authentification.
All other page can only be accessed if logged.
Within app.component.html we first have app-top-menu before router-outlet.
The component app-top-menu is hidden and appear only once the user is logged.
This tricked has been made to hide the app-top-menu component from login page.
When we log in login component we do that action to display the component app-top-menu
this.globalEventsManager.showNavBar(true);
Everyting works fine when I run ng serve - I use angular cli.
The UI is working very well.
But when I run ng test I get a first error in app.component
AppComponent should create the app
Failed: Template parse errors:
'router-outlet' is not a known element:
1. If 'router-outlet' is an Angular component, then verify that it is part of this module.
2. If 'router-outlet' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message. ("<app-top-menu></app-top-menu>
[ERROR ->]<router-outlet></router-outlet>"): AppComponent#1:0
then a second within SecondComponent about routerLink.
Failed: Uncaught (in promise): Error: Template parse errors:
Can't bind to 'routerLink' since it isn't a known property of 'a'. ("
<h1>Home</h1>
<p>You're logged in with JWT!!</p>
<p><a [ERROR ->][routerLink]="['/login']">Logout</a></p>
</div>"): SecondComponent#3:10
Error: Template parse errors:
Can't bind to 'routerLink' since it isn't a known property of 'a'. ("
Here is the content of my app.component.spec.ts
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
TopMenuComponent
]
});
TestBed.compileComponents();
});
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
How can I mock the router and test routes.
Also the app-top-menu is involved as it appears/disappear according to login.
Thanks for your help.

Related

vue-meta / Inertia: Title is 'undefined' between page rendering

I'm using Vue 2.6.12, Laravel and Inertia.
When using vue-meta to alter the meta title it displays 'undefined' for a split second when loading any page.
Im using Inertia, so the routing is on Laravels side and uses Inertia to pass the Vue component name and data to the frontend.
//app.js
new Vue({
metaInfo: {
titleTemplate: 'Inertia: %s'
},
render: h => h(App, {
props: {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: name => require(`./Pages/${name}`).default,
},
}),
}).$mount(el)
//Index.vue
export default {
metaInfo: {
title: 'User list'
}
}
It generally works, but it seems to stop working while Inertia requests are being processed / recieved / sent.
How do I prevent this?
what I understood that you want to load and manipulate metadata of the html page.
This cannot be manipulated unless you create a slot in the header, or place a prop so that each time you pass parameters to it it changes, with a layout.!
the most ideal thing would be that you use it inside the router:
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: {
title: 'Home Page - Example App',
metaTags: [
{
name: 'description',
content: 'The home page of our example app.'
},
{
property: 'og:description',
content: 'The home page of our example app.'
}
]
}
}
i dont expert in english.! will it really help
enter link description here

Laravel Vue VueRouter history mode

I'm building an e-commerce project with laravel, vue and vue router
I want to use vue router with history mode but it cause me trouble.
Here is my code
new Vue({
el: '#app',
router: new VueRouter({
mode: 'history',
routes
})
});
Here is my route in web.php which have locale middleware
Route::group(['prefix' => '{locale}', 'where' => ['locale' => '[a-zA-Z]{2}'], 'middleware' => 'setlocale'], function () {
Route::view('/{path?}', ('layouts.app'))->where('path', '.*');
});
Here is my route with vue router
export const routes = [
{
path: '/',
component: require('./components/Page/HomePage').default,
},
{
path: '/product',
component: require('./components/Page/Product/ProductPage').default,
},
];
I need my url to be
http://localhost/en
instead of (with the hashtag)
http://localhost/en#/
After using history mode, i successfully remove the hashtag. But, the router link of other will remove my locale in my url
http://localhost/product
I don't know what to do now with it.
Please help~ Thanks.
Update 19 Mar 2020
You need to set the base value to tell Vue Router what the base URL of your application is. In your case you can set it dynamically using the locale value.
For example, in your Blade template you could have the following script to set the locale value on the JavaScript window object:
<script>
window._locale = "{{ app()->getLocale() }}";
</script>
And then you can set the base value to the locale when creating your router:
router: new VueRouter({
mode: 'history',
base: `/${window._locale}/`,
routes
})
Very simple way is too Accept the locale in Vue router too. So your route would be like this:
export const routes = [
{
path: '/:locale',
children: [
{
path: '',
component: require('./components/Page/HomePage').default,
},
{
path: 'product',
component: require('./components/Page/Product/ProductPage').default,
},
]
}
];
just be sure for children route dont put '/' in begining because its remove locale

On refresh vuejs template is not working and I get just json Data, Vuejs and Laravel

I have a route where when I refresh the page I get only the JSON info for that page. (only on refresh F5). The rest of the routes are ok. I am not sure what I am doing wrong.
web.php
Route::get('/persons', 'MyController#index');
Route::post('/record/{personId?}', 'MyController#create'); // this is the one that don't work on refresh
Route::get('/record/{id}', 'MyController#getRecord');
Route::delete('/record/{id}', 'MyController#destroy');
Route::get('/lookups', 'LkpController#index');
Route::post('/validate', 'MyController#getValidation');
//Routes for VueJs
Route::get('/{any}', function () {
return view('welcome');
})->where('any','^(?!api).*$')->name('home');
router.js
const routes = [
{
path: "/",
name: "Home",
component: Home,
meta: { requiresAuth: true }
},
{
path: "/record",
name: "Record",
component: Record,
meta: { requiresAuth: true }
},
{
path: "/record/:id",
name: "View Record",
component: require ('./components/AddPerson').default,
meta: { requiresAuth: true }
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
The problem is that you are putting all your routes in web.php, and you have the same routes for your Vue SPA as your Laravel application.
You should put your API routes in your web/api.php file that way they will be automatically prefixed with the 'api' route.
The route that is returning JSON data is not the one you pointed out, it is the next one:
Route::get('/record/{id}', 'MyController#getRecord'); // this is the one that don't work on refresh
This is because your Vue router is pointing to the exact same route:
{
path: "/record/:id",
name: "View Record",
component: require ('./components/AddPerson').default,
meta: { requiresAuth: true }
}
Both routes point to yourwebsite.com/record/{id}, but on refresh you make a brand new request to your Laravel application, that means your not in your Vue application anymore and your browser will load whatever Laravel will tell them first, in this case it will be the first route in the routes/web.php file:
Route::get('/record/{id}', 'MyController#getRecord');
Edit: This is how you should do it if you cannot use API routes due to authentication:
You must make sure that your don't have duplicate routes between your Vue router and your Laravel routes, you can just prefix them with something that makes sense to you.
Route::prefix('prefix')->group(function () {
Route::get('/persons', 'MyController#index');
Route::post('/record/{personId?}', 'MyController#create');
Route::get('/record/{id}', 'MyController#getRecord');
Route::delete('/record/{id}', 'MyController#destroy');
Route::get('/lookups', 'LkpController#index');
Route::post('/validate', 'MyController#getValidation');
});
//Routes for VueJs
Route::get('/{any}', function () {
return view('welcome');
})->where('any','^(?!api).*$')->name('home');
In this example, the route you are having trouble with will now be prefixed with 'prefix' yourwebsite.com/prefix/record/{id}, you can change it to whatever you need it to be.

vuetify shows blank page on firefox after setup

I've follwed this tutorial setting up my vuetify project: https://www.youtube.com/watch?v=FbEW3xAmhKs
I did the follwing:
vue create vuetify-test -> I chose "manually" -> Babel, Router, linter -> history router (yes) -> Eslint only with error prevention
thats it. After that I ran "npm run serve" and when I click the localhost...-link I get a blank page. with the developer tools in firefox I can see that all tags are at the top in one line. What am I doing wrong??
//router.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
})

Laravel + Vue router - Best practice for slugs

I have a laravel + vue app. I've created a vue spa application for a particular page called shop. In this shop, I have 3 sub pages which is about, products and contact.
routes.php
Route::get('/shop/{slug}/{vue_capture?}', 'ShopController#show')->where('vue_capture', '[\/\w\.-]*');
vue-router.js
export const routes = [
{ path: '/', component: Home, name: 'home',
children: [
{
path: '/',
name: 'about',
component: About
},
{
path: '/products',
name: 'products',
component: Product
},
{
path: '/contact',
name: 'contact',
component: Contact
}
]
},
];
So for example I go to domain.com/shop/joe-shop, what is the best practice to extract the slug and use it in my vue application so I can make http requests with slug parameter to server? Thank you
note: I'm also using vuex state management in my app
var slug = window.location.pathname.replace(/^\/shop\/([^\/]+)(?:\/.*)?/i,'$1');
Note:
With your current set-up, you would need to set the base property in your vue-router config to behave properly.
new Router({
base: window.location.pathname.replace(/^(\/shop\/[^\/]+).*/i,'$1'),
mode: 'history',
routes: ...
})

Resources