I'm instantiating the service class inside the controller class, and the log method of the service is been used in the controller.
In spec file, I'm adding spy on the log method but the spy is not been called.
Here is my code
test.service.ts
export class TestService {
public log(msg: string): void {
console.log(msg);
}
}
test.controller.ts
import { TestService } from "../service/cart.service";
export class CartController {
private testService: TestService;
constructor() {
this.testService = new TestService();
}
public testFx():void {
this.testService.log("Here is a dummy msg.")
}
}
test.controller.spec.ts
import { TestController } from "./test.controller";
import { TestService } from "./test.service";
describe("Testing controller", () => {
private testController: TestController = new TestController();
private testService: TestService = new TestService();
it ("test function", () => {
spyOn(testService, "log");
testController.testFx();
expect(testService.log).toHaveBeenCalled();
});
})
Error: - Expected spy log to have been called.
Instead of creating a new class instance,
private testController: TestController = new TestController();
private testService: TestService = new TestService();
it ("test function", () => {
spyOn(testService, "log");
you can use escape hatch for it.
Try this:
private testController: TestController = new TestController();
it ("test function", () => {
spyOn(testController["testService"], "log");
Since the private, protected and public are the concept of typescript's syntactic sugar it has nothing to do when code compiles to javascript.
The more explaining answer is here.
Related
I have created an abstract wrapper class around Electron's native BrowserWindow.
It defines two abstract accessors for the BrowserWindow. But whenever I inherit from BaseWindow, the window turns out to be undefined (note comments)!
import { BrowserWindow, BrowserWindowConstructorOptions } from "electron";
abstract class BaseWindow {
public constructor(options?: BrowserWindowConstructorOptions) {
this.setWindow(new BrowserWindow(options));
console.log("From Base", this.getWindow()); // > From Base BrowserWindow { ... }
}
public abstract getWindow(): BrowserWindow;
protected abstract setWindow(newWindow: BrowserWindow): void;
}
class MainWindow extends BaseWindow{
private window!: BrowserWindow;
public override getWindow(): BrowserWindow {
return this.window;
}
protected override setWindow(newWindow: BrowserWindow): void {
this.window = newWindow;
}
public constructor() {
super({
//...
});
console.log("From Main", this.getWindow()); // > From Main undefined
}
}
// Inside ready event
const window = new MainWindow();
console.log("From App", window.getWindow()) // > From App undefined
Am I doing something wrong? Are there any ways of fixing it?
I've been implemented a code, written by https://github.com/krazibit
import { Type } from '#nestjs/common'
import { InjectRepository } from '#nestjs/typeorm'
import * as DataLoader from 'dataloader'
import { keyBy } from 'lodash'
import { Repository } from 'typeorm'
export interface IDataService<T> {
readonly repository: Repository<T>
load: (id: string | number) => Promise<T>
loadMany: (ids: Array<string | number>) => Promise<T[]>
}
type Constructor<I> = new (...args: any[]) => I // Main Point
export function DataService<T>(entity: Constructor<T>): Type<IDataService<T>> {
class DataServiceHost implements IDataService<T> {
#InjectRepository(entity) public readonly repository: Repository<T>
private get primaryColumnName(): string {
return this.repository.metadata.primaryColumns[0]?.propertyName
}
private loader: DataLoader<number | string, T> = new DataLoader(async ids => {
const entities = await this.repository.findByIds(ids as any[])
const entitiesKeyed = keyBy(entities, this.primaryColumnName)
return ids.map(id => entitiesKeyed[id])
})
public async load(id: string | number): Promise<T> {
return this.loader.load(id)
}
public async loadMany(ids: Array<string | number>): Promise<T[]> {
return this.loadMany(ids)
}
}
return DataServiceHost
}
It should be a generic function to extend to services.
But, I'm trying to implement it using:
export class MyService extends IDataService(MyEntity)
But now, I'm trying to use the methods load and loadMany but every time I try to do it, I get an error.
Does someone knows how to do reference to those methods to execute them?
You need to inject repository inside constructor, so:
export function DataService<T>(entity: Constructor<T>): Type<IDataService<T>> {
class DataServiceHost implements IDataService<T> {
constructor(#InjectRepository(entity) public readonly repository: Repository<T>) {}
// ...
}
}
I have a method that connects to an Azure Service Bus Queue and posts messages. I need to Unit test this method. I have created a Mock Interface on the IqueueClient. I am using Moq framework for my unit test.
I am not able assert the test result.
public class WebHookClient : IWebHookClient
{
private readonly ILogger<WebHookClient> _logger;
private readonly IQueueClient _queueClient;
public WebHookClient(IQueueClient queueClient, ILogger<WebHookClient> logger)
{
_logger = logger;
_queueClient = queueClient;
}
public async Task PostAsync(WebHookRequest webHookRequest)
{
try
{
var messageAsText = JsonConvert.SerializeObject(webHookRequest);
var message = new Message(Encoding.UTF8.GetBytes(messageAsText));
await _queueClient.SendAsync(message);
}
catch (Exception ex)
{
}
}
I need to Unit test the above method. So far I have tried the below
public class WebHookClientTests
{
private readonly Mock<IQueueClient> _queueClient;
private readonly IOptions<WebHookOptions> _options;
private readonly Mock<ILogger<WebHookClient>> _logger;
private readonly IWebHookClient _sut;
public WebHookClientTests()
{
_queueClient = new Mock<IQueueClient>();
_logger = new Mock<ILogger<WebHookClient>>();
_sut = new WebHookClient(_queueClient.Object, _logger.Object);
}
[Fact]
public async Task PostAsync_Verify_Message_Was_sent()
{
//Arrange
var webHookRequest = new WebHookRequest();
var messageAsText = JsonConvert.SerializeObject(webHookRequest);
var message = new Message(Encoding.UTF8.GetBytes(messageAsText));
_queueClient.Setup(x => x.SendAsync(It.IsAny<Message>())).Returns(Task.CompletedTask).Verifiable();
//Act
await _sut.PostAsync(webHookRequest);
//Assert
_queueClient.Verify();
}
try with the following:
_queueClient.Verify(x => x.SendAsync(It.IsAny<Message>()), Times.Exactly(1));
I have an abstract class defined statically and an implementation of it retrieved dynamically
Ie
export abstract class Foo {
abstract get();
}
const dynamicClass: typeof Foo = ( function() {
return class Bar {
get: function() {
console.log('get');
}
constructor() {
super();
console.log('cons');
}
}
}();
This is working fine exept one thing : I cannot call the constructor without "cheating"
IE
new Bar() output cannot instantiate abstract class
I have resolved that by doing
// #ts-ignore
new Bar();
But I feel i could do better.
The whole usecase for that is that the funciton that create the class at runtime will act differently based on the system it is (dynamiccally loading extra libraries that i removed for the sake of simplicity)
The easiest thing you can do is to not use an explicit type annotation, let the compiler infer what it will for dynamicClass:
export abstract class Foo {
abstract get(): void;
}
const dynamicClass = (function() {
return class Bar extends Foo {
get() {
console.log('get');
}
constructor() {
super();
console.log('cons');
}
}
})();
new dynamicClass();
Playground Link
If you want to go the explicit route you can use a constructor signature that returns Foo, this should mostly remove the abstarctness of the constructor:
export abstract class Foo {
abstract get(): void;
}
const dynamicClass: new () => Foo = (function() {
return class Bar extends Foo {
get() {
console.log('get');
}
constructor() {
super();
console.log('cons');
}
}
})();
new dynamicClass();
Playground Link
Where can I change the renderer in this code?
import { WINDOW_WIDTH, WINDOW_HEIGHT } from './config'
import Game from './state/Game'
class App extends Phaser.Game {
constructor () {
super(WINDOW_WIDTH, WINDOW_HEIGHT, Phaser.AUTO)
this.state.add('Game', Game)
this.state.start('Game')
}
}
const SimpleGame = new App()
and game is
class Game extends Phaser.State {
constructor() {
super()
this.player = {}
}
}
In the constructor, more specifically in the super call to Phaser.Game's constructor:
class App extends Phaser.Game {
constructor () {
super(WINDOW_WIDTH, WINDOW_HEIGHT, Phaser.CANVAS);
// ...
}
}
Reference: https://photonstorm.github.io/phaser-ce/Phaser.Game.html