Type 'string' is not assignable to type 'Date nest js unit testing - unit-testing

I created a sample project with CRUD using NestJs. I create a User with a randomly generated Id, name, birthdate and email. I need to do unit testing for this create CRUD operation. But I do not know how to test the birthDate. It gives me an error.
This is what I got when I tried to pass the date
User Entity:
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
} from 'typeorm';
#Entity('users')
export class User {
//auto increment
#PrimaryGeneratedColumn('increment')
id: number;
#Column({ nullable: true, default: null })
name: string;
#CreateDateColumn({ nullable: true })
birthDate: Date;
#Column({ type: 'varchar' })
email: string;
}

You're passing a string, but typescript expect Date.
try changing birthDate: '2000.6.7' to birthDate: new Date('2000-06-07').

Related

AWS Amplify GraphQL mutation is not updating a boolean field

I'm playing with the AWS Amplify GraphQL console and I've noticed that updating a boolean field is not working and I'm not sure exactly why. This is also not working from my React Native app. Basically, what I'm trying to do, is at onPress, change the isOnline to true or false (see full code below):
isOnline: !car.isOnline
schema.graphql
type Car #model
#key(name: "byUser", fields: ["userId"])
{
id: ID!
type: String!
latitude: Float
longitude: Float
heading: Float
plate: String
isOnline: Boolean
isActive: Boolean
orders: [Order] #connection(keyName: "byCar", fields: ["id"])
userId: ID!
user: User #connection(fields: ["userId"])
}
mutations.js
export const updateCar = /* GraphQL */ `
mutation UpdateCar(
$input: UpdateCarInput!
$condition: ModelCarConditionInput
) {
updateCar(input: $input, condition: $condition) {
id
type
latitude
longitude
heading
plate
isOnline
isActive
userId
_version
_deleted
_lastChangedAt
createdAt
updatedAt
}
}
`;
index.js
try {
const userData = await Auth.currentAuthenticatedUser();
const input = {
id: userData.attributes.sub,
isOnline: !car.isOnline,
}
const updatedCarData = await API.graphql(
graphqlOperation(
updateCar, {
input
})
)
console.log("Updated car: ", updatedCarData.data.updateCar)
setCar(updatedCarData.data.updateCar);
} catch (e) {
console.error(e);
}
From the app, every time I get the isOnline field set to true, even if I tried setting it to false instead of !car.isOnline.
I also tried creating a new field called isActive which was null initially, I created a mutation on AWS AppSync GraphQL console and was able to set it to false, but then, when trying to set it to true, updating is not working, it's always returning false.
As a note, updating the other fields, for example String fields, is working.
Can you please guide me into this issue?
I was able to solve this issue by:
Running the below command:
amplify update api
Select GraphQL, then Disable Conflict Detection
Last, but not least, run:
amplify push
I haven't found any explanation for this on the Amplify Docs, but if you're running into this issue, make sure to follow the above steps.

How to use single validator class for both resource creation and modification in AdonisJS 5?

Sometimes I may need to use single validator class for both inserting and updating resources, as opposed to this statement. Otherwise I may have duplicate codes, which inherently goes against DRY principle.
Consider the following case:
Say, I have a products resource in my app, and users of my app can create, update and delete products. Assume that the product model looks something like this:
export default class Product extends BaseModel {
#column({ isPrimary: true })
public id: number
#column()
public code: string
#column()
public title: string
#column()
public description: string
#column()
public price: number
}
Certainly the migration will be very close to the following:
export default class ProductsSchema extends BaseSchema {
protected tableName = 'products'
public async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id').primary()
table.string('code').unique().notNullable() // <= pay attention that this field is unique
table.string('title').notNullable()
table.string('description', 25).notNullable()
table.double('price').notNullable()
})
}
public async down() {
this.schema.dropTable(this.tableName)
}
}
Now users will create a new product. So they will be presented a form, and the validation may look something like:
export default class ProductCreateValidator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
code: schema.string({ trim: true, escape: true }, [
rules.unique({ table: 'products', column: 'code' }),
]), // <= because this field is unique inside the database
title: schema.string({ trim: true, escape: true }, [
rules.alpha({ allow: ['space'] }),
]),
description: schema.string({ trim: true, escape: true }),
price: schema.number(),
})
public cacheKey = this.ctx.routeKey
public messages = {}
}
The fun begins now! If I create separate class for updating products, most the fields will be the same, except code. So I'll have to duplicate the whole class:
export default class ProductUpdateValidator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
code: schema.string({ trim: true, escape: true }, [
// rules.unique({ table: 'products', column: 'code' }),
]), // <= I cannot apply unique rule here - because I won't be able to update anymore
title: schema.string({ trim: true, escape: true }, [
rules.alpha({ allow: ['space'] }),
]),
description: schema.string({ trim: true, escape: true }),
price: schema.number(),
})
public cacheKey = this.ctx.routeKey
public messages = {}
}
What if I want to add 3 more fields? With this current setup, I'd have to go to these two class files and add those fields in both of them. And I'd have to go to both these files if I want to adjust some validation logic. It'd be much easier to maintain if I'd be able to use single class for both create and update actions; and it'd automatically cancel the uniqueness check if the particular field of the product that users trying to update hasn't been changed. How could that even possible?
It's very easy to achieve. We need to drop one validator class and modify the other one like so:
export default class ProductValidator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
code: schema.string({ trim: true, escape: true }, [
rules.unique({
table: 'products',
column: 'code',
whereNot: {
id: this.ctx.request.input('id') || 0 // <= or this may come from route params: this.ctx.params.id
}
}),
]),
title: schema.string({ trim: true, escape: true }, [
rules.alpha({ allow: ['space'] }),
]),
description: schema.string({ trim: true, escape: true }),
price: schema.number(),
})
public cacheKey = this.ctx.routeKey
public messages = {}
}
Let's break this code down:
For inserting new product, the this.ctx.request.input('id') will be undefined, so it'll fallback to 0. So it'll perform SELECT code FROM products WHERE code = ? AND NOT id = ? query with ['<whatever_user_types>', 0]. Since id is the primary key for that table and it cannot be 0, the later condition of the query above will always be TRUE. So the validator will only throw error if the code is found (since the later part is already TRUE). Hence our objective is fulfilled.
For updating existing product, you'll certainly have the ID of the product in hand. Because you're fetching the product from the database, you certainly know its ID. Now put it somewhere of your choice (either inside the update form as <input type="hidden" name="id" value="{{ product.id }}"> or as route param /products/:id/update). Since we have the ID this time around, the this.ctx.request.input('id') (or this.ctx.params.id) will be set. So the query will look like SELECT code FROM products WHERE code = ? AND NOT id = ? query with ['<whatever_user_types>', <product_id>]. This time, the later condition of the query will always be FALSE, so it won't complain if the code matches only with the product we're trying to update and not with any other products. Bingo!
So this is how you can avoid code duplication by utilizing single validator for both create and update actions. Let me know down in comments if you have any other questions.

AWS AppSync only returns 10 items on query on connection

I'm new to AppSync and trying to see how this works and what's the proper way to set this up.
I created schema.graphql looks like below.
type User #model {
id: String!
following: [String]
follower: [String]
journals: [Journal] #connection(name: "UserJournals", sortField: "createdAt")
notifications: [Notification] #connection(name: "UserNotifications", sortField: "createdAt")
}
type Journal #model {
id: ID!
author: User! #connection(name: "UserJournals")
privacy: String!
content: AWSJSON!
loved: [String]
createdAt: String
updatedAt: String
}
and this created queries.js automatically by AppSync.
export const getUser = `query GetUser($id: ID!) {
getUser(id: $id) {
id
following
follower
journals {
items {
id
privacy
content
loved
createdAt
updatedAt
}
nextToken
}
notifications {
items {
id
content
category
link
createdAt
}
nextToken
}
}
}
`;
I noticed that querying getUser only returns 10 journals items and not sure how to set that to more than 10 or proper way to query and add more journals into that 10 items that were queried by getUser.
Since you do not pass the limit argument explicitly in your query, the Request Mapping Template of the journals resolver defaults it to 10 items. If you would like to change this default value, go to your schema page on the AppSync console, navigate to the journals field, found under the Resolvers section of the schema page. This will then show the resolver definition for this field, and you can then update the default value of 10 to anything you like. Alternatively, you can pass this as your query argument.
FYI - This default value is defined in the amplify-cli repo on GitHub and can be found here.

TypeORM: How to set ForeignKey explicitly without having property for loading relations?

I don't want to create a property for loading relation into it (as shown in all the examples). The only thing I need is to have an explicit foreign key property so that the migration will be able to create appropriate constraints for it in the database. The closest decorator to the one I need is #RelationId but it still requires the presence of a property of the relational class.
For clarity let's take the example from the documentation:
#Entity()
export class Post {
#ManyToOne(type => Category)
category: Category;
#RelationId((post: Post) => post.category) // it still requires the presence of the `category` proeprty
categoryId: number;
}
I don't need the category property here. I want to have the categoryId property and mark it as foreign key to Category.Id. It should look like this:
#Entity()
export class Post {
#ForeignKey((category: Category) => category.Id) // it's a foreign key to Category.Id
categoryId: number;
}
Is it possible?
"I need is to have an explicit foreign key property"...
No, you could not. TypeOrm will automatically create foreign key property when you use #ManyToOne decorator. Just combine #ManyToOne and #JoinColumn decorators together like this:
#ManyToOne(type => Category)
#JoinColumn({ name: 'custom_field_name_if_you_want' })
category: Category;
Maybe you can create and write your own migration and use it like this :
const queryRunner = connection.createQueryRunner();
await queryRunner.createTable(new Table({
name: "question",
columns: [
{
name: "id",
type: "int",
isPrimary: true
},
{
name: "name",
type: "varchar",
}
]
}), true);
await queryRunner.createTable(new Table({
name: "answer",
columns: [
{
name: "id",
type: "int",
isPrimary: true
},
{
name: "name",
type: "varchar",
},
{
name: "questionId",
isUnique: connection.driver instanceof CockroachDriver, // CockroachDB requires UNIQUE constraints on referenced columns
type: "int",
}
]
}), true);
// clear sqls in memory to avoid removing tables when down queries executed.
queryRunner.clearSqlMemory();
const foreignKey = new TableForeignKey({
columnNames: ["questionId"],
referencedColumnNames: ["id"],
referencedTableName: "question",
onDelete: "CASCADE"
});
await queryRunner.createForeignKey("answer", foreignKey);
This code snippet is extracted from the functional test of type orm and you can use it to create your own constraint on the database I think.
It's actually possible to do so:
#Entity()
export class Post {
// this will add categoryId
#ManyToOne(type => Category)
category: Category;
// and you can use this for accessing post.categoryId
// only column you mark with #Column decorator will be mapped to a database column
// Ref: https://typeorm.io/#/entities
categoryId: number;
}
The added categoryId won't be mapped to column and will then be use for setting explicitly the id or for accessing its value as in:
post.categoryId = 1;
// or
const id = post.categoryId
Check with these two places Auth module(JwtModule.register()) and JWT strategy(super({...})). Make sure you have secret /secretOrKey is set to the same key. In my case "secret: process.env.JWT_SECRET_KEY" & "secretOrKey: process.env.JWT_SECRET_KEY"
I have encountered the same problem recently.
I still use the Entity but only with the primary key value of the referenced entity.
i.e. I do not query the database for the referenced entity.
Suppose your category entity looks like this:
#Entity()
export class Category{
#PrimaryGeneratedColumn()
id: number;
// ... other stuff
}
Now using your codes as example.
Dircely assigning relation using a foreign key value would be like.
// You wish to assign category #12 to a certain post
post.category = { id: 12 } as Category

Testing MongooseJs Validations

Does anyone know how to test Mongoose Validations?
Example, I have the following Schema (as an example):
var UserAccount = new Schema({
user_name : { type: String, required: true, lowercase: true, trim: true, index: { unique: true }, validate: [ validateEmail, "Email is not a valid email."] },
password : { type: String, required: true },
date_created : { type: Date, required: true, default: Date.now }
});
The validateEmail method is defined as such:
// Email Validator
function validateEmail (val) {
return /^[a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test(val);
}
I want to test the validations. The end result is that I want to be able to test the validations and depending on those things happening I can then write other tests which test the interactions between those pieces of code. Example: User attempts to sign up with the same username as one that is taken (email already in use). I need a test that I can actually intercept or see that the validation is working WITHOUT hitting the DB. I do NOT want to hit Mongo during these tests. These should be UNIT tests NOT integration tests. :)
Thanks!
I had the same problem recently.
First off I would recommend testing the validators on their own. Just move them to a separate file and export the validation functions that you have.
This easily allows your models to be split into separate files because you can share these validators across different models.
Here is an example of testing the validators on their own:
// validators.js
exports.validatePresenceOf = function(value){ ... }
exports.validateEmail = function(value){ ... }
Here is a sample test for this (using mocha+should):
// validators.tests.js
var validator = require('./validators')
// Example test
describe("validateEmail", function(){
it("should return false when invalid email", function(){
validator.validateEmail("asdsa").should.equal(false)
})
})
Now for the harder part :)
To test your models being valid without accessing the database there is a validate function that can be called directly on your model.
Here is an example of how I currently do it:
describe("validating user", function(){
it("should have errors when email is invalid", function(){
var user = new User();
user.email = "bad email!!"
user.validate(function(err){
err.errors.email.type.should.equal("Email is invalid")
})
})
it("should have no errors when email is valid", function(){
var user = new User();
user.email = "test123#email.com"
user.validate(function(err){
assert.equal(err, null)
})
})
})
The validator callback gets an error object back that looks something like this:
{ message: 'Validation failed',
name: 'ValidationError',
errors:
{ email:
{ message: 'Validator "Email is invalid" failed for path email',
name: 'ValidatorError',
path: 'email',
type: 'Email is invalid'
}
}
}
I'm still new to nodeJS and mongoose but this is how I'm testing my models + validators and it seems to be working out pretty well so far.
You should use validate() method as a promise and test it with a tool that makes asserts for async stuff (ex: Chai as Promised).
First of all, require a promise library and switch out to the promise provider (for example Q):
mongoose.Promise = require('q').Promise;
Afterwards just, use asserts about promises:
it('should show errors on wrong email', function() {
user = new UserModel({
email: 'wrong email adress'
});
return expect(user.validate()).to.be.rejected;
});
it('should not show errors on valid email adress', function() {
user = new UserModel({
email: 'test#test.io'
});
return expect(user.validate()).to.be.fulfilled;
});