Testing an angular 2 component but it seems to be swallowing a promise. I've set up an inner expect that should always fail (expect false to be true) but it doesn't throw an exception and causes the test to pass. Any thoughts?
Using ng2 rc1
test
import { it, ddescribe, expect, inject, async, beforeEachProviders } from '#angular/core/testing';
import { provide } from '#angular/core';
import {
TestComponentBuilder,
ComponentFixture
} from '#angular/compiler/testing';
import { Http, BaseRequestOptions } from '#angular/http';
import { LoginComponent } from './..';
import { MockBackend } from '#angular/http/testing';
import { UserService } from '../../';
ddescribe('LoginThing', () => {
it('should wrap content', async(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
console.log('Ready to run test');
return tcb.createAsync(LoginComponent)
.then((fixture: ComponentFixture<LoginComponent>) => {
console.log(fixture);
fixture.detectChanges();
var compiled = fixture.debugElement.nativeElement;
expect(compiled).toContainText('stuff');
expect(false).toBe(true);
});
})));
});
karma testing shim
/*global jasmine, __karma__, window*/
Error.stackTraceLimit = Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
__karma__.loaded = function () {
};
var distPath = '/base/.test/';
var appPath = distPath + 'app/';
function isJsFile(path) {
return path.slice(-3) == '.js';
}
function isSpecFile(path) {
return path.slice(-8) == '.spec.js';
}
function isAppFile(path) {
return isJsFile(path) && (path.substr(0, appPath.length) == appPath);
}
var allSpecFiles = Object.keys(window.__karma__.files)
.filter(isSpecFile)
.filter(isAppFile);
// Load our SystemJS configuration.
System.config({
baseURL: distPath,
});
System.import('system.config.js').then(function(e) {
// Load and configure the TestComponentBuilder.
return Promise.all([
System.import('#angular/core/testing'),
System.import('#angular/platform-browser-dynamic/testing')
]).then(function (providers) {
var testing = providers[0];
var testingBrowser = providers[1];
testing.setBaseTestProviders(
testingBrowser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
testingBrowser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS
);
});
}).then(function() {
return Promise.all(
allSpecFiles.map(function (moduleName) {
return System.import(moduleName);
}));
}).then(__karma__.start, __karma__.error);
Related
I'm trying to write a test for a utility function in our project, which uses the formatDuration module from date-fns/formatDuration. Can anyone help me creating a mock for this module with Jest and be able to test if formatDuration was called with expected arguments?
This is my current setup:
// ../utilites/date.ts
import formatDuration from "date-fns/formatDuration";
import subSeconds from "date-fns/subSeconds";
import intervalToDuration from "date-fns/intervalToDuration";
export const createDurationFromSeconds = (seconds: number) => {
const end = new Date();
const start = subSeconds(end, seconds);
return intervalToDuration({ start, end });
};
type FunctionArgs = Parameters<typeof formatDuration>;
export const formatDurationHelper = (
duration: FunctionArgs[0],
options?: FunctionArgs[1]
) => {
//...do something with options.format
return formatDuration(duration, options);
};
// ../utilites/date.test.ts
import formatDuration from "date-fns/formatDuration";
import { formatDurationHelper, createDurationFromSeconds } from "./date";
jest.mock("date-fns/formatDuration", () => {
return {
__esModule: true,
default: jest.fn()
};
});
describe("formatDurationWithLocale", () => {
it("created mocked formatDuration", () => {
expect(jest.isMockFunction(formatDuration)).toBe(true); // <- this test is successful
});
it("does something with options.format", () => {
const duration = createDurationFromSeconds(1);
formatDurationHelper(duration, {
format: ["seconds"]
});
expect(formatDuration).toHaveBeenCalled(); // <- this test is unsuccessful
expect(formatDuration).toHaveBeenCalledWith(duration, { // <- this test is unsuccessful
format: ["seconds"]
});
});
});
expect(jest.isMockFunction(formatDuration)).toBe(true) is successful, but the others fail...
Thanks in advance!
I am running a cypress test and would like to import a mongodb module so I can mock some data in my e2e tests.
Here is my test:
import { MongoMemoryServer } from 'mongodb-memory-server';
import db from '../../src/server/db/datasource';
const createDb = async () => {
const server = await MongoMemoryServer.create();
try {
db.setOptions({ url: server.getUri() });
await db.initialize();
} catch (err) {
throw err;
}
return db;
};
describe('The main search bar functions as it should', () => {
beforeEach(async () => {
await createDb();
});
it('Should return the correct results when a user types in the input field', () => {
// my test here...
});
});
The part that is failing is the import { MongoMemoryServer } from 'mongodb-memory-server';
if I comment this line out and re-run the test I get the following error require is not defined
I think what is happening is my tests are not running in a node environment, although happy to be challenged on that. I have tried to look up this issue but have not found anything helpful on resolving it.
Not sure if it helps but below is my cypress config:
import 'dotenv-defaults/config';
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
on('before:browser:launch', (browser, launchOptions) => {
if (browser.name === 'chrome') {
launchOptions.args.push('--proxy-bypass-list=<-loopback>');
launchOptions.args.push('--disable-dev-shm-usage');
launchOptions.args.push('--disable-gpu');
launchOptions.args.push('--no-sandbox');
return launchOptions;
}
});
on('task', {
log(message) {
console.log(message);
return null;
},
});
return config;
},
baseUrl: `http://localhost:${process.env.PORT || 3000}`,
video: false,
screenshotOnRunFailure: false,
modifyObstructiveCode: false,
chromeWebSecurity: false,
experimentalSessionAndOrigin: true,
experimentalSourceRewriting: true,
},
env: process.env,
});
Would love some help to point me in the right direction as am a bit lost atm... thanks
I want to write a unit test for a controller in NestJS which uses the service. Service uses an entity and typeorm to getting data from postgres.
controller.spec.ts
import { Test, TestingModule } from '#nestjs/testing';
import { EmissionsWeldingController } from '../EmissionsWelding.controller';
describe('EmissionsWeldingController', () => {
let controller: EmissionsWeldingController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [EmissionsWeldingController],
}).compile();
controller = module.get<EmissionsWeldingController>(EmissionsWeldingController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
It failed with an error: Nest can't resolve dependencies of the EmissionsWeldingController (?). Please make sure that the argument EmissionsWeldingService at index [0] is available in the RootTestModule context.
When I define my service and entity
import { Test, TestingModule } from '#nestjs/testing';
import { TypeOrmModule } from '#nestjs/typeorm';
import { EmissionsWeldingController } from '../EmissionsWelding.controller';
import { Mark, Substance, WorkType, WorkSpecification, InputField, SummaryValue } from '../EmissionsWelding.entity';
import { EmissionsWeldingService } from '../EmissionsWelding.service';
describe('EmissionsWeldingController', () => {
let controller: EmissionsWeldingController;
let service: EmissionsWeldingService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [TypeOrmModule.forFeature([Mark, Substance, WorkType, WorkSpecification, InputField, SummaryValue])],
controllers: [EmissionsWeldingController],
providers: [EmissionsWeldingService],
}).compile();
controller = module.get<EmissionsWeldingController>(EmissionsWeldingController);
service = module.get<EmissionsWeldingService>(EmissionsWeldingService);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
It's failing with an error: Nest can't resolve dependencies of the MarkRepository (?). Please make sure that the argument Connection at index [0] is available in the TypeOrmModule context.
How should I define providers and entities without getting above error?
service.ts
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { GetResultDto } from './dto/GetResult.dto';
import { InputField, Mark, Substance, SummaryValue, WorkSpecification, WorkType } from './EmissionsWelding.entity';
#Injectable()
export class EmissionsWeldingService {
constructor(
#InjectRepository(Mark)
private markRepository: Repository<Mark>,
#InjectRepository(Substance)
private substanceRepository: Repository<Substance>,
#InjectRepository(WorkSpecification)
private workSpecificationRepository: Repository<WorkSpecification>,
#InjectRepository(WorkType)
private workTypeRepository: Repository<WorkType>,
#InjectRepository(InputField)
private inputFieldRepository: Repository<InputField>,
#InjectRepository(SummaryValue)
private summaryValueRepository: Repository<SummaryValue>,
) {}
async getMarks(work_type_id: number, work_specification_id: number): Promise<Mark[]> {
return await this.markRepository.find({ where: { work_type_id, work_specification_id } });
}
async getSubstances(): Promise<Substance[]> {
return await this.substanceRepository.find();
}
async getWorkSpecifications(): Promise<WorkSpecification[]> {
return await this.workSpecificationRepository.find();
}
async getWorkTypes(): Promise<WorkType[]> {
return await this.workTypeRepository.find();
}
async getInputFields(): Promise<WorkType[]> {
return await this.inputFieldRepository.find();
}
async getSummaryValues(mark_id: number, substance_id: number): Promise<SummaryValue[]> {
return await this.summaryValueRepository.find({ where: { mark_id, substance_id } });
}
async getResult(body: GetResultDto): Promise<GetResultDto[]> {
const result = [];
const { mark_id, input_fields_values } = body;
const substances = await this.getSubstances();
let currentSummaryValue;
for (let i = 0; i <= substances.length - 1; i++) {
currentSummaryValue = await this.getSummaryValues(mark_id, i + 1);
result.push({
code: substances[i].code,
name: substances[i].name,
year:
((input_fields_values.year * currentSummaryValue[0].value) / 10 ** 6) *
(1 - (input_fields_values.clean ? input_fields_values.clean : 0)),
second:
((currentSummaryValue[0].value * input_fields_values.hour) / 3600) *
(1 - (input_fields_values.clean ? input_fields_values.clean : 0)),
});
}
return result;
}
}
controller.ts
import { Body, Controller, Get, Post, Query } from '#nestjs/common';
import { ApiTags } from '#nestjs/swagger';
import { GetResultDto } from './dto/GetResult.dto';
import { EmissionsWeldingService } from './EmissionsWelding.service';
#ApiTags('EmissionsWelding')
#Controller('EmissionsWelding')
export class EmissionsWeldingController {
constructor(private emissionsWeldingService: EmissionsWeldingService) {}
#Get('getMarks')
getMarks(#Query('work_type_id') work_type_id: number, #Query('work_specification_id') work_specification_id: number) {
return this.emissionsWeldingService.getMarks(work_type_id, work_specification_id);
}
#Get('getSubstances')
getSubstances() {
return this.emissionsWeldingService.getSubstances();
}
#Get('getWorkSpecifications')
getWorkSpecifications() {
return this.emissionsWeldingService.getWorkSpecifications();
}
#Get('getWorkTypes')
getWorkTypes() {
return this.emissionsWeldingService.getWorkTypes();
}
#Get('getInputFields')
getInputFields() {
return this.emissionsWeldingService.getInputFields();
}
#Post('getResult')
getResult(#Body() body: GetResultDto) {
return this.emissionsWeldingService.getResult(body);
}
}
You need to provide a mock for every repository that is injected into your service.
This answer provides the necessary detail: https://stackoverflow.com/a/55366343/588734
describe('EmissionsWeldingController', () => {
let controller: EmissionsWeldingController;
let service: EmissionsWeldingService;
let markRepositoryMock: MockType<Repository<Mark>>;
// repeat for every repository let __RepositoryMock: MockType<Repository<__>>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [EmissionsWeldingController],
providers: [
EmissionsWeldingService,
{
provide: getRepositoryToken(Mark),
useValue: jest.fn(() => ({
findOne: jest.fn(entity => entity),
// provide a mock for each function you are calling
}))
},
// repeat for every mock
],
}).compile();
controller = module.get<EmissionsWeldingController>(EmissionsWeldingController);
service = module.get<EmissionsWeldingService>(EmissionsWeldingService);
markRepositoryMock = module.get(getRepositoryToken(Mark));
// repeat for every mock repository
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
I am not sure I how to write unit test case file for guard in nestjs. I have below Role.guard.ts file. I have to create Role.guard.spec.ts file. can somebody help please?
import { Injectable, CanActivate, ExecutionContext, Logger } from '#nestjs/common';
import { Reflector } from '#nestjs/core';
import { ROLES_KEY } from './roles.decorator';
import { Role } from './role.enum';
#Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
const { user } = context.switchToHttp().getRequest();
if (!user.role) {
Logger.error('User does not have a role set');
return false;
}
if (user.role === Role.Admin) {
return true;
}
if (!Array.isArray(requiredRoles) || !requiredRoles.length) {
// No #Roles() decorator set, deny access as not admin
return false;
}
if (requiredRoles.includes(Role.All)) {
return true;
}
return requiredRoles.includes(user.role);
}
}
I wrote below code but coverage issue is coming.
import { createMock } from '#golevelup/ts-jest';
import { ExecutionContext } from "#nestjs/common";
import { Reflector } from "#nestjs/core";
import { RolesGuard } from "./roles.guard";
describe('RolesGuard', () => {
let guard: RolesGuard;
let reflector: Reflector;
beforeEach(() => {
reflector = new Reflector();
guard = new RolesGuard(reflector);
});
it('should be defined', () => {
expect(guard).toBeDefined();
});
it('should return false if user does not exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
const context = createMock<ExecutionContext>();
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(false);
})
})
below lines are not getting covered.
if (user.role === Role.Admin) {
return true;
}
if (!Array.isArray(requiredRoles) || !requiredRoles.length) {
// No #Roles() decorator set, deny access as not admin
return false;
}
if (requiredRoles.includes(Role.All)) {
return true;
}
return requiredRoles.includes(user.role);
Edit 1:-
Below test cases are covering my some part of code.
it('should return true if user exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
const context = createMock<ExecutionContext>({
switchToHttp: () => ({
getRequest: () => ({
user: {
role:'admin'
}
}),
}),
});
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(true);
})
it('should return false if user does not exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
const context = createMock<ExecutionContext>({
switchToHttp: () => ({
getRequest: () => ({
user: {
role:'user'
}
}),
}),
});
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(false);
})
But below code still not getting covered.
if (requiredRoles.includes(Role.All)) {
return true;
}
return requiredRoles.includes(user.role);
}
Can sombody help me on the same?
Looks like you need to be able to craft the payload appropriately such that your code is hit. There are a variety of ways to do this but, in a "Nest"-y way, we can try something like what the docs tell us. Notice in that link that the provided testing utilities make this a lot easier to mock.
import { createMock } from '#golevelup/ts-jest';
import { ExecutionContext } from "#nestjs/common";
import { Reflector } from "#nestjs/core";
import { RolesGuard } from "./roles.guard";
describe('RolesGuard', () => {
let guard: RolesGuard;
let reflector: Reflector
beforeEach(async () => {
reflector = new Reflector();
guard = new RolesGuard(reflector);
});
it('should be defined', () => {
expect(guard).toBeDefined();
});
it('should return false if user does not exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
const context = createMock<ExecutionContext>();
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(false);
})
it('should return false if user does exist', () => {
reflector.getAllAndOverride = jest.fn().mockReturnValue(true);
// Mock the "class" type of this so we can get what we want.
// We want to tell it to return an object where role is defined.
const context = createMock<ExecutionContext>({
switchToHttp: () => ({
getRequest: () => ({
user: { role: { /* enter your data here */ }
}),
}),
});
const canActivate = guard.canActivate(context);
expect(canActivate).toBe(false);
})
})
From here your context is successfully hydrated with whatever you want and the second test should start showing up as covering your other code branches. You can now edit the role attribute to look however you want. Notice also in the above beforeEach call you should be able to switch to using testing modules instead. This is not exhaustive though, you'll likely need to add additional test cases to cover your other branches. If you follow as I've done here, that should be relatively trivial.
Does what I've done here make sense? By crafting a custom payload to the object, the roles attribute is present, allowing the test to evaluate other cases. I got my override from the createMock function directly from the docs for golevelup.
I am trying to make stores which can be accessed by Screens. File structure:
index.ios.js
/app/index.js
/app/store/database.js
/app/store/userStore.js
index.ios.js :
import { AppRegistry } from 'react-native';
import App from './app/index';
AppRegistry.registerComponent('AwesomeProject', () => App);
/app/index.js :
import React, { Component} from 'react';
import {
Text,
View,
} from 'react-native';
import userStore from './store/userStore';
import ViewBackground from './components/ViewBackground';
class App extends Component {
constructor(props){
super(props);
this.isLoggedIn = true;
}
componentDidMount() {
this.fetchUsers().done();
}
async fetchUsers(){
console.log('Before User Fetch');
var result = await userStore.getAllUsers();
console.log('After User Fetch');
}
render() {
if(this.isLoggedIn){
return this.loggedInView();
}else{
return this.loggedOutView();
}
}
loggedInView(){
return <ViewBackground>
</ViewBackground>
}
loggedOutView(){
return <View>
<Text>Hi, This is logged Out view </Text>
</View>
}
}
export default App;
/app/store/userStore.js :
import React from 'react';
import database from './database';
class UserStore{
async getAllUsers(){
let query = {
type: 'SELECT',
sql: 'SELECT * FROM Users',
vals: [],
}
let queries = [query];
console.log('in store before');
let dbResult = await database.runQuery(queries);
console.log('in store after');
return dbResult;
}
}
const userStore = new UserStore;
export default userStore;
/app/store/database.js :
'use strict';
import React from 'react';
import SQLite from 'react-native-sqlite-storage';
SQLite.enablePromise(true);
var database_name = "test.db";
var database_version = "1.0";
var database_displayname = "Test";
var database_size = 1024 * 1024 * 10;
class Database {
constructor(){
SQLite.openDatabase(database_name, database_version, database_displayname, database_size).then(this.dbOpenSuccess).catch(this.dbOpenError);
}
dbOpenSuccess(dbInstance){
this.conn = dbInstance;
}
dbOpenError(err) {
}
getConnection() {
return this.conn;
}
setUpDatabase(){
let queries = [
'CREATE TABLE IF NOT EXISTS Users (user_id INTEGER PRIMARY KEY, f_name VARCHAR(64), l_name VARCHAR(64), email_id VARCHAR(128), mobile VARCHAR(10))'
];
this.conn.transaction( tx => {
queries.map( q => {
tx.executeSql(q, [], res => {}, err => {});
});
});
}
async runQuery(queries) {
await this.conn.transaction(tx => {
return Promise.all(queries.map(async (q) => {
try {
let results = null;
switch(q.type){
case 'SELECT':
results = await tx.executeSql(q.sql, q.vals);
console.log('Query', q, 'Executed. results:', results);
break;
}
} catch(err) {
console.log('Something went wrong while executing query', q, 'error is', err);
}
}));
});
return false;
}
closeDatabase(){
this.conn.close().then(this.dbCloseSuccess).catch(this.dbCloseError);
}
dbCloseSuccess(res) {
}
dbCloseError(err){
}
}
const dbInstance = new Database();
dbInstance.setUpDatabase();
export default dbInstance;
In /app/index.js I am trying to fetch users from userStore.js which will call database.js to retrieve the users from database. I want to pause execution when I fetch users from database, so tried async/await. I used console.log() to check whether execution paused. None of async/await is working. I am getting response after all console.log is done.
I want it to wait until I receive data from database.
You need to wrap it in a Promise, then resolve the result when sql execution is done.
for example
async () => {
return new Promise((resolve, reject) => {
db.transaction(tx => {
tx.executeSql('SELECT * FROM users;', [], (tx, results) => {
const { rows } = results;
let users = [];
for (let i = 0; i < rows.length; i++) {
users.push({
...rows.item(i),
});
}
resolve(users);
});
});
});
}
let SQLite = require('react-native-sqlite-storage');
const DB = SQLite.openDatabase({name:'test.db',createFromLocation:'~sqlitedb.db'});
class Database{
db;
constructor(db){
this.db =db;
}
executeSql = (sql,params=[])=>new Promise((resolve , reject)=>{
this.db.transaction((trans)=>{
trans.executeSql(sql,params,(db,results)=>{
resolve(results);
},
(error)=>{
reject(error);
});
});
});
}
export default (new Database(DB));
use
import Database from 'database';
try
{
results = await DB.excuteSql("SQL",['params']);
}
catch(e)
{
}
The following worked for me:
import { openDatabase } from 'react-native-sqlite-storage'
const db = openDatabase({
name: 'app.db',
location: 'default',
})
export default function App() {
useEffect(() => {
db.then((db) => {
db.transaction((tx) => {
tx.executeSql('SELECT this from that', [])
})
})
/* Rest of the component... */
}
openDatabase returns a Promise, on resolving which we get the actual db on which we can run db.transaction().
You could use the async/await syntax too, but that would be a lot of encapsulation, and so .then() is always cleaner.
This is different from the "expo-sqlite" package, because db = openDatabase('app.db') does not return a Promise there. Instead, you can run db.transaction() directly.
just add this lines
import {enablePromise, openDatabase } from 'react-native-sqlite-storage';
enablePromise(true)
I follow this way to do DB operations
export const fetchUsers = async () => {
return new Promise((resolve, reject) => {
db.transaction(txn => {
txn.executeSql('SELECT * FROM "Users";', [], (tx, res) => (
resolve(res.rows.raw())
))
})
})
}
rows.raw() will return the data as object
(async()=>{
data= await fetchUsers()
})()