Cypress not picking up html elements - html

I'm trying to get a handle on a simple html <p> tag using the data-cy attribute:
<p data-cy="register">Register</p>
First I mount the component:
it('mounts', () => {
cy.mount(AccountDialogComponent, {
imports: [
HttpClientTestingModule,
ReactiveFormsModule,
AngularMaterialModule,
BrowserAnimationsModule
],
declarations: [ AccountDialogComponent ],
providers: [{provide: AccountService, useValue: accountService}]
})
});
The test I am running for this as follows:
it("text should be 'Register' when user is registering", () => {
cy.get('[data-cy="register"]').should('have.text', 'Register');
});
The test keeps returning a failure:
assertexpected [data-cy="register"] to have text Register, but the
text was ''
After another few seconds, it then returns an Assertion Error:
Timed out retrying after 4000ms: Expected to find element: [data-cy="register"], but never found it.
I can't understand why this isn't working?
I am new to Cypress and this is the first test I am dong since installing Cypress in my Angular app.

I had same problem, this Angular - adding Cypress data-cy attribute sorted it out.
The gist is the Angular framework would not pass on data-cy without it's particular binding,
<p [attr.data-cy]="register">Register</p>
Now, test code will find your element.
BTW Component testing is ok if mount() ok, then it's same syntax for test assertions.

Ok so it seems I was just forgetting that I need to mount the component before each test:
beforeEach(async () => {
cy.mount(AccountDialogComponent, {
imports: [
HttpClientTestingModule,
ReactiveFormsModule,
AngularMaterialModule,
BrowserAnimationsModule
],
declarations: [ AccountDialogComponent ],
providers: [{provide: AccountService, useValue: accountService}]
})
});

Related

angular "Unable to extract routes" when using ng run prerender and generated routes

I am trying to generate routes from json file as I have generic view, which based on json data will create separate view with unique slug also based on this json file there are also sitemaps generated, so its used for two purposes.
generic_pages.json
{
INDUSTRIES: [
{
template: {
title: 'page title',
bannerPath: 'assets/banners/bann.jpg'
},
path: 'industry-name',
...
},
{
template: {
title: 'other page title',
bannerPath: 'assets/banners/other-bann.jpg'
},
path: 'other-industry'
},
....
]
}
and now I am importing this json to routing module, and mapping those routes and pass template to data in following way:
app.routing.module.ts
import * as genericPages from './generic_pages.json';
const industriesPages = genericPages.INDUSTRIES_PAGES.map(page => ({
path: page.path,
loadChildren: () => import('./components/pages/industry-page/industry-page.module').then(m => m.IndustryPageModule),
data: {
title: page.meta.title ? page.meta.title : '',
description: page.meta.description ? page.meta.description : '',
industryTemplate: page.template
}
}));
const routes: Routes = [ ... , ...industriesPages}
#NgModule({
imports: [RouterModule.forRoot(routes, {
initialNavigation: 'enabled',
anchorScrolling: 'enabled',
onSameUrlNavigation: 'reload',
scrollPositionRestoration: 'enabled'
})],
exports: [RouterModule]
})
export class AppRoutingModule { }
and those routes are working properly, when i run ng serve or ng run app:serve-ssr, they are seen and I can access them by URL directly.
The prob exists only when I deploy app, and there is ng run app:prerender, which throws error Unable to extract routes, and on server those routes aren't seen when i want to enter them directly by pasting url (such as domain.com/industry-name) to browser, but when I enter domain.com and click links I can access those routes, and also I noticed when those routes are hardcoded in const routes: Routes = [...] everything is ok, error only occurs when I am mapping and then concatenating to const routes, and also noticed when i erase loadChildren prop from mapping it stops throwing this error.

Error: secretOrPrivateKey must have a value

I am using jwt to create token, but when i login via postman I get the error "Error: secretOrPrivateKey must have a value" from my console. I have attached my login code. Please anyone who can help me
exports.login = (req, res, next) => {
User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if (!user) {
return res.status(401).json({
message:
"Auth failed!! either the account does't exist or you entered a wrong account"
});
}
bcrypt.compare(req.body.password, user.password, (err, result) => {
if (err) {
return res.status(401).json({
message: "Auth failed",
token: token
});
}
if (result) {
const token = jwt.sign(
{
email: user.email,
password: user.id
},
process.env.JWT_KEY,
{
expiresIn: "1h"
}
);
res.status(200).json({
message: "Auth granted, welcome!",
token: token
});
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
this is my env.json file
{
"env":{
"MYSQL":"jllgshllWEUJHGHYJkjsfjds90",
"JWT_KEY": "secret"
}
}
It looks like your application can't read the environment variable properly.
I don't know which package you are using to load environment variables but the simplest way is using dotenv package.
After installing it with npm i dotenv, import it as early as possible in your application main file like this:
require("dotenv").config();
Create .env file in your application root folder with this content ( as you see the format is key=value)
MYSQL=jllgshllWEUJHGHYJkjsfjds90
JWT_KEY=secret
Then you can access their values like you already did:
process.env.JWT_KEY
.env file:
Remove the process.env.JWT_SECRET_KEY and do it this way: ${process.env.JWT_SECRET_KEY} wrap it with backtick.
It solved the problem for me.
Had this issue with NestJS when trying to rely on process.env.X. Supposedly #nestjs/config uses dotenv in the background but it doesn't work as expected. I either had to use ConfigService or explicitly configure dotenv in the given files:
jwt.strategy.ts
import * as dotenv from 'dotenv';
dotenv.config();
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
secretOrKey: process.env.JWT_SECRET,
});
}
}
or
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(configService: ConfigService) {
super({
secretOrKey: configService.get<string>('JWT_SECRET'),
});
}
}
auth.module.ts
import * as dotenv from 'dotenv';
dotenv.config();
#Module({
imports: [
JwtModule.register({
secret: process.env.JWT_SECRET,
}),
],
})
or
#Module({
imports: [
JwtModule.registerAsync({
imports: [ConfigModule]
useFactory: async (configService: ConfigService) => {
return {
secret: configService.get<string>('JWT_SECRET'),
};
},
inject: [ConfigService],
}),
],
})
It works for me only if I concatenate it with an empty string like this:
"" + process.env.JWT_KEY
simply remove the process.env.JWT_KEY and replace with "secret key using" ES6 String Literals
${process.env.JWT_SECRET_KEY}
it solves this for me
It was accidentally adding the JWTService as a provider in my AuthModule. That, it seems was overriding the defaults I had set up when registering the JWTModule.
What I had before:
#Module({
imports: [
PassportModule,
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => {
const authConfig = configService.get<AuthenticationConfig>(
PathNames.AUTH,
);
return {
secret: authConfig.accessToken.secret,
signOptions: {
expiresIn: authConfig.accessToken.expiryTime,
},
};
},
}),
],
providers: [
AuthService,
UsersService,
PrismaService,
AuthResolver,
// this was the problem
JwtService,
JWTStrategy,
],
exports: [AuthService],
})
export class AuthModule {}
Are you sure process.env.JWT_KEY has a valid value? I believe it is undefined or null.
Put the require('dotenv').config() at the top of the server.js file
This solved for me
You can try this, it works for me.
"" + process.env.JWT_KEY
I simply removed process.env.JWT_KEY and replace with "secret" and its working fine.
Just add back quotes `` and use the syntax ${process.env.SECRET_KEY} in them.
I also advise you to use the cross-env package, after installing which you can make two files with environment variables .development.env and .production.env
To configure cross-env, just paste this into a package.json "scripts" field:
"start": "cross-env NODE_ENV = production nest start",
"start:dev": "cross-env NODE_ENV = development nest start --watch"
it is for nestjs
To chime in on this, I found this error was being caused by the contents of the key I was trying to use. I regularly use a "password generator" for such strings, and it had given me the following to use:
<B#LCK$^\7(T^fuaQemeR&6s:##AAwe#?T,c'=+kxT?euCP27R/D=uRm893$=^_h^f={c.)MD#[%zg}$K8_D#D-_/tb2?Q>RFr(}H:Fp#{&yNFt#2Y<K\GB28unz
if the above is placed in between back ticks or speech marks it will not be able to be parsed as a string and will therefore cause this error as described above.
As an extra level of de-bugging make sure you first wrap your key in backticks or parenthesis in order to make sure that an un-parsable string isn't the issue.
You can also try and specify an object with a property the path to the configuration file like
require("dotenv").config({path: '/path_to_env_file'});
I also had the same issue I came to realize that the issue was that I didn't include dotenv package
so
import * as dotenv from 'dotenv';
then put dotenv.config() on top before any other implementation
step 1: install dotenv
step 2: import that in app.js:
const dotenv = require("dotenv");
step 3:
dotenv.config(`${process.env.SECRET_KEY}`);
your issue will solve
Check that process.env.JWT_KEY is defined:
console.log(process.env.JWT_KEY)
I have this issue in backend. To solve I create a init.js file, add my config to process.env and require index.js file
const config = require(`<path of config json file>`)
process.env = { ...process.env, ...config }
require('./index')
then get init.js as entry index in webpack
Do not fix this by prepending an emptystring '' + to your JWT or by wrapping it inside of ${process.env.YOUR_JWT}. This resolves the error but doesn't fix the underlying issue.
The problem is actually that dotenv is being invoked after your module code where you try to read from process.env, therefore process.env.ANYTHING_HERE wont have been populated by dotenv yet.
Probably in your entrypoint file (i.e. main.ts you are calling import on app.module before calling into dotenv or nest's wrapper around it.
The comprehensive fix here is to modify main.ts to call require('dotenv').config({ path: './.env' }) or however you bootstrap your env, and to do this before you import any other file. That way, all your imports will have process.env populated with your environment variables before they run.
If you just fix the issue by following the solutions above then you're going to end up setting your secret key to 'undefined' because what you're actually just doing is you're concating empty string with the env variable for your secret before it exists. It solves the error but clearly wont be the secret you wanted from your config file.
It's also not a good idea to fix it this way because you're not solving this issue for your other environment variables either. They still wont be available to your modules where they need them because they're being included after instead of before, and thus you're highly likely to have other issues in your project where your environment variables are undefined elsewhere too.
This message was occured to me only when I was running E2E tests. In my case I had to explicitly set as an secret option to fix it.
this.jwtService.sign(tokenPayload, { secret: `${process.env.JWT_SECRET}` });
In my case using process.env.JWT_SECRET_KEY.replace(/\\n/g, "\n") worked perfectly fine.
I took this reference from how firebase uses keys stored in .env file to parse it. and they use .replace(/\\n/g, "\n") to parse the key.
IN token REPLACE GRAB THE FOLLOWING IN BACKTICKS. THIS SYNTEX WORKED FOR ME TRY THIS.
${process.env.JWT_SECRET_KEY}
Perhaps you use 2 .env files (for development and for production). For example, you use cross-env NODE_ENV=development in package.json file in "start:dev". If it is true, don't forget add
ConfigModule.forRoot({
envFilePath: `.${process.env.NODE_ENV}.env`
}),
to your module file:
#Module({
imports: [
PassportModule,
ConfigModule.forRoot({
envFilePath: `.${process.env.NODE_ENV}.env`
}),
JwtModule.register({
secret: process.env.JWT_KEY,
signOptions: {
expiresIn: '1h'
},
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],
exports: [AuthService]
})
export class AuthModule {}
Then you haven't to add something to file with class JwtStrategy and another.
${process.env.JWT_SECRET_KEY}
it worked for me by placing it in auth.module.ts
Use the code above(image), to overcome your problem.
This error is coming because .env files is not accessible in auth.js.
so dont write process.env.JWT_KEY
instead of this just write a random string in single quotes.
eg: 'iamtheprogrammer'
ERROR:
const token = jwt.sign({_id:user._id}, process.env.SECRET)
CORRECT CODE:
const token = jwt.sign({_id:user._id},'iamtryingtoaddsome')

How to navigate to other page in angular 6?

Im trying to redirect my page from login to another page. Im following this code.
My login component ts file:
import { Router } from '#angular/router';
constructor(private router: Router) {
}
funLogin(mobilenumber){
this.router.navigateByUrl('registration');
}
In my html Im calling this function in a submit btn,
<button class="common-btn btn" (click)="funLogin(mobileNo.value)">Submit</button>
In my app.login.routing file,
export const loginRouting: Routes = [
{
path: '', component: DashboardRootComponent, canActivateChild: [],
children: [
{ path: '', component: DashboardComponent, pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'registration', component: RegistrationComponent },
]
}
]
I have tried with "this.router.navigate" & referredlot of links. But it didnt work. Can anyone please tell me where Im going wrong or if you could give me a workingh sample it would be better.
#sasi.. try like this,
<a routerLink="/registration"><button class="btn btn-success" > Submit </button></a>
Update :
In order to use the routing in your application, you must register the components which allows the angular router to render the view.
We need register our components in App Module or any Feature Module of it (your current working module) in order to route to specific component view.
We can register components in two ways
.forRoot(appRoutes) for app level component registration like
featuteModules(ex. UserManagement) and components which you want register at root level.
.forChild(featureRoutes) for feature modules child components(Ex. UserDelete, UserUpdate).
you can register something like below,
const appRoutes: Routes = [
{ path: 'user', loadChildren: './user/user.module#UserModule' },
{ path: 'heroes', component: HeroListComponent },
];
#NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(
appRoutes
)
],
P.S : In order to navigate from one component to another, you must include the RouterModule in corresponding Module Imports array from #angular/router package.
You can navigate one to another page in Angular in Two ways. (both are same at wrapper level but the implementation from our side bit diff so.)
routerLink directive
routerLink directive gives you absolute path match like navigateByUrl() of Router class.
<a [routerLink]=['/registration']><button class="btn btn-success" > Submit </button></a>
If you use dynamic values to generate the link, you can pass an array of path segments, followed by the params for each segment.
For instance routerLink=['/team', teamId, 'user', userName, {details: true}] means that we want to generate a link to /team/11/user/bob;details=true.
There are some useful points to be remembered when we are using routerLink.
If the first segment begins with /, the router will look up the route
from the root of the app.
If the first segment begins with ./, or doesn't begin with a slash,
the router will instead look in the children of the current activated
route.
And if the first segment begins with ../, the router will go up one
level.
for more info have look here.. routerLink
Router class
We need inject Router class into the component in order to use it's methods.
There more than two methods to navigate like navigate() , navigateByUrl(), and some other.. but we will mostly use these two.
navigate() :
Navigate based on the provided array of commands and a starting point. If no starting route is provided, the navigation is absolute.
this.route.navigate(['/team/113/user/ganesh']);
navigate() command will append the latest string is append to existing URL. We can also parse the queryParams from this method like below,
this.router.navigate(['/team/'], {
queryParams: { userId: this.userId, userName: this.userName }
});
You can get the these values with ActivatedRoute in navigated Component. you can check here more about paramMap, snapshot(no-observable alternative).
navigateByUrl()
Navigate based on the provided URL, which must be absolute.
this.route.navigateByUrl(['/team/113/user/ganesh']);
navigateByUrl() is similar to changing the location bar directly–we are providing the whole new URL.
I am using angular 7 and I solved it in this way into my project.
1.First We need to implement this Modules to our app.module.ts file
import { AppRoutingModule} from './app-routing.module';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
#NgModule({
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
],
})
2.Then Open your.component.html file and then fire a method for navigate where you want to go
<button class="btn btn-primary" (click)="gotoHome()">Home</button>
3.Then Go your.component.ts file for where you want to navigate. And add this code there.
import { Router } from '#angular/router';
export class YourComponentClassName implements OnInit {
constructor(private router: Router) {}
gotoHome(){
this.router.navigate(['/home']); // define your component where you want to go
}
}
4.And lastly want to say be careful to look after your app-routing.module.ts
where you must have that component path where you want to navigate otherwise it will give you error. For my case.
const routes: Routes = [
{ path:'', component:LoginComponent},
{ path: 'home', component:HomeComponent }, // you must add your component here
{ path: '**', component:PageNotFoundComponent }
];
Thanks I think, I share all of the case for this routing section. Happy Coding !!!
navigateByUrl expects an absolute path, so a leading / might take you to the right page
You could also use navigate and don't need the leading / but the syntax is slightly different as it expects an array for the path
https://angular.io/api/router/Router#navigateByUrl
<a class="nav-link mt-1" [routerLink]="['/login']"><i class="fa fa-sign-in"></i> Login</a>

Can't set up routing to a named outlet in Angular

I have three named router outlets as shown below.
...
<router-outlet name="menus"><router-outlet>
<router-outlet><router-outlet>
<router-outlet name="footer"><router-outlet>
...
In the markup I want to route the first one, menus, to a component with certain submenu junk in it as shown in the docs.
<ul *ngFor="let main of menus;"
routerLink="[{outlets:{menus:[{{main.link}}]}}]"
class="nav-items">{{main.header}}
The error I'm getting says that:
Error: Cannot match any routes. URL Segment: '%5B%7Boutlets:%7Bmenus:%5Bsubmenu1%5D%7D%7D%5D'
Am at a loss what's wrong with the syntax. Googling my fingernails off but haven't found a simple and crude example of a routerLink version showing how to point a route in a named outlet.
Edit: Based on the comments and samples, I need to reformulate the code being used, still with the same error. In the markup:
<ul *ngFor="let main of menus;"
(click)="pullMenu(main.link)"
class="nav-items">{{main.header}}
Then, in TS:
constructor(private router: Router, private route: ActivatedRoute) { }
pullSubmenu(input) {
console.log(input);
this.router.navigate(
[{ outlets: { menus: [input] } }],
{ relativeTo: this.route });
}
Now, I'm getting the following error (submenu1 is the name of configured path).
Error: Cannot match any routes. URL Segment: 'submenu1'
My routing is set up in the module like this.
const routes: Routes = [
{ path: "submenu1", component: Submenu1Component },
{ path: "submenu2", component: Submenu2Component }
];
#NgModule({
declarations: [
AppComponent,
NavbarComponent,
MainAreaComponent,
Submenu1Component,
Submenu2Component
],
imports: [
BrowserModule,
RouterModule.forRoot(routes)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
You need to use the evaluated version [routerLink]:
<ul *ngFor="let main of menus;"
[routerLink]="[{outlets:{menus:[{{main.link}}]}}]"
class="nav-items">{{main.header}}
As an alternative you can emulate the routerLink. Here is the gist of what it does:
#HostListener('click')
onClick(): boolean {
const extras = {
skipLocationChange: attrBoolValue(this.skipLocationChange),
replaceUrl: attrBoolValue(this.replaceUrl),
};
this.router.navigateByUrl(this.urlTree, extras);
return true;
}
So, here is the setup using navigate instead of navigateByUrl:
#Component({
template: `
<ul *ngFor="let main of menus;" (click)="[{outlets:{menus:[{{main.link}}]}}])"
class="nav-items">{{main.header}}
`
...
class MyComponent {
constructor(router: Router, route: ActivatedRoute) {}
navigate(commands) {
this.router.navigate(commands, {relativeTo: this.route})
You can't use unevaluated version of routerLink because it reads commands as a string and if you have outletsin the commands strings don't work. See Navigation to secondary route URL for routerLink attribute to understand why.

JSON pipe in Angular 2 is not working

When I try to pipe my data by JSON pipe I get the following error in the console:
Unhandled Promise rejection: Template parse errors:
The pipe 'json' could not be found (...
What am I doing wrong?
Most likely you forgot about importing CommonModule:
import { CommonModule } from '#angular/common';
#NgModule({
...
imports: [ CommonModule ]
...
})
As noted in the comments, do this in the module where you're using the json pipe.
In my case CommonModule was added, but the component was not part of declaration of any module
(I was creating component dynamically by using ContainerRef)
Your parent Module of the component should be like this.
import {NgModule} from '#angular/core';
import {AuditTrailFilterComponent} from './components/audit-trail-filter/audit-trail-filter.component';
import {CommonModule} from '#angular/common'; <-- This is important !!!!
#NgModule({
imports: [
CommonModule, <-- This is important !!!!
],
declarations: [AuditTrailFilterComponent],
exports: [
AuditTrailFilterComponent
]
})
export class AuditTrailModule {
}
This can also occur if you declare your component in a Lazy module and try to add the component to a route that hasn't caused that module to be loaded.
eg. I just had this error with:
children: [
{
path: 'editor',
loadChildren: () => from(import(/* webpackChunkName: "editor" */ '../editor/editor.module').then(m => m.EditorModule))
},
{
path: 'multi-preview',
component: MultiPreviewerComponent // declared in Editor.module (lazy loaded)
}
]
For me,
I had to add it on the under the providers in the app.module.ts
#NgModule({
providers: [
{ provide: JsonPipe }, <-- This is important !!!!