TSNode + Mocha: Ignore TypeScript errors (make compiler emit on errors and make TSNode execute emitted code) - node.js

In the below code, although function test2 in invalid, it should not affect to testing of function test1:
export function test1(): boolean {
return true;
}
export function test2(): number {
return "1";
}
Test:
import { assert as Assert } from "chai";
import { test1 } from "./example";
describe("Example", (): void => {
it("Example", (): void => {
Assert.isTrue(test1());
});
});
However Mocha, executed by TSNode will fail:
TSError: ⨯ Unable to compile TypeScript:
Source/ProjectBuilder/example.ts(6,3): error TS2322: Type '"1"' is not assignable to type 'number'.
Possible to force TSNode to complete above test? TypeScript has option noEmitOnError...
My mocharc.yaml:
extension:
- ts
spec: "**/*.test.ts"
require:
- ts-node/register
- tsconfig-paths/register
Why I need it
According the Clean Architecture, "Business rules must not depends on anything, and it must be testable". But even if business rules does not depend on views, controllers, etc., we can not test it if some errors in views, controllers, etc. exists.
When I modify business logic in my application, all that depend on it becomes invalid. Assume that in my entity in business logic type User { name: string; age: number } has been changed to type User { fullName: string; age: string; }. All that depend on business logic (view, controllers, presenters, etc.) becomes invalid - I need to correct it too according updated to business logic.
// In business rules:
type User = {
ID: number;
fullName: string;
age: string; // in past - number
}
// In controller:
class UserProfileController {
// ...
// All what comes from input field is string ↓
private onClickChangeUserAge(inputtedUserAge: string) {
// This expression obeys to previous version of business rules!
this.targetUser.age = Number(inputtedUserAge);
// TypeScript will emit type error, when I try to test business rules,
// however business rules does not depend on controller.
}
}
However, in big application, this corrections could takes days, weeks and months. How we can get the feedback proves that at least business logic works properly and we are in right way?

It would not make sense for you to ask Typescript to disregard types. What you are describing is akin to asking for a calculator that confirms that 2 + 2 = 5, only temporarily, because eventually you will ask for 2 + 3 = 5 but that might take a very long time.
The assumption in your question is that number and string are sufficiently compatible that your business logic will be sound regardless of whether test2 returns 1 or "1". This is not true: By way of example, 1 + 1 == 2, "1" + 1 == "11", and "1" - 1 == 0. Depending on which of those applies to your case, disregarding types may allow you to test your business logic, or may give you false confidence in a broken system. I would venture that in general the data types count as part of the business logic you're trying to verify--what would the data model count as, if not business logic?
Instead, what you are describing is a gradual migration during which the business rules ensure that test2 returns string | number. By describing the migration accurately in the type system, you may be able to confirm that the business logic applies correctly--if that is true across your migration--and also provide a type that you can apply only from certain modules and call sites that can be tightened up as you finish the migration.

type User = {
ID: number;
fullName: string;
age: string | number
}
You can specify both types to make migration easier and not use //#ts-ignore everywhere.
This will add proper suggestions everywhere like:

Related

DDD : Business Logic which need infra layer access should be in application service layer, domain service or domain objects?

For an attribute which need to be validated, lets say for an entity we have country field as VO
This country field needs to be validated to be alpha-3 code as per some business logic required by domain expert.
NOTE:
*We need to persist this country data as it can have other values also and possible in future there can be addition, updating and deleting of the country persisted data.
This is just one example using country code which may rarely change, there can be other fields which needs to be validated from persistence like validating some quantity with wrt data in persistence and it won't be efficient to store them in memory or prefetching them all.
Another valid example can be user creation with unique and valid domain email check, which will need uniqueness check from persistence
*
Case 1.
Doing validation in application layer:
If we call repository countryRepo.getCountryByCountryAlpha3Code() in application layer and then if the value is correct and valid part of system we can then pass the createValidEntity() and if not then can throw the error directly in application layer use-case.
Issue:
This validation will be repeated in multiple use-case if same validation need to be checked in other use-cases if its application layer concern
Here the business logic is now a part of application service layer
Case 2
Validating the country code in its value object class or domain service in Domain Layer
Doing this will keep business logic inside domain layer and also won't violate DRY principle.
import { ValueObject } from '#shared/core/domain/ValueObject';
import { Result } from '#shared/core/Result';
import { Utils } from '#shared/utils/Utils';
interface CountryAlpha3CodeProps {
value: string;
}
export class CountryAlpha3Code extends ValueObject<CountryAlpha3CodeProps> {
// Case Insensitive String. Only printable ASCII allowed. (Non-printable characters like: Carriage returns, Tabs, Line breaks, etc are not allowed)
get value(): string {
return this.props.value;
}
private constructor(props: CountryAlpha3CodeProps) {
super(props);
}
public static create(value: string): Result<CountryAlpha3Code> {
return Result.ok<CountryAlpha3Code>(new CountryAlpha3Code({ value: value }));
}
}
Is it good to call the repository from inside domain layer (Service
or VO (not recommended) ) then dependency flow will change?
If we trigger event how to make it synchronous?
What are some better ways to solve this?
export default class UseCaseClass implements IUseCaseInterface {
constructor(private readonly _repo: IRepo, private readonly countryCodeRepo: ICountryCodeRepo) {}
async execute(request: dto): Promise<dtoResponse> {
const someOtherKeyorError = KeyEntity.create(request.someOtherDtoKey);
const countryOrError = CountryAlpha3Code.create(request.country);
const dtoResult = Result.combine([
someOtherKeyorError, countryOrError
]);
if (dtoResult.isFailure) {
return left(Result.fail<void>(dtoResult.error)) as dtoResponse;
}
try {
// -> Here we are just calling the repo
const isValidCountryCode = await this.countryCodeRepo.getCountryCodeByAlpha2Code(countryOrError.getValue()); // return boolean value
if (!isValidCountryCode) {
return left(new ValidCountryCodeError.CountryCodeNotValid(countryOrError.getValue())) as dtoResponse;
}
const dataOrError = MyEntity.create({...request,
key: someOtherKeyorError.city.getValue(),
country: countryOrError.getValue(),
});
const commandResult = await this._repo.save(dataOrError.getValue());
return right(Result.ok<any>(commandResult));
} catch (err: any) {
return left(new AppError.UnexpectedError(err)) as dtoResponse;
}
}
}
In above application layer,
this part of code :
const isValidCountryCode = await this.countryCodeRepo.getCountryCodeByAlpha2Code(countryOrError.getValue()); // return boolean value
if (!isValidCountryCode) {
return left(new ValidCountryCodeError.CountryCodeNotValid(countryOrError.getValue())) as dtoResponse;
}
it it right to call the countryCodeRepo and fetch result or this part should be moved to domain service and then check the validity of the countryCode VO?
UPDATE:
After exploring I found this article by Vladimir Khorikov which seems close to what I was looking, he is following
As per his thoughts some domain logic leakage is fine, but I feel it will still keep the value object validation in invalid state if some other use case call without knowing that persistence check is necessary for that particular VO/entity creation.
I am still confused for the right approach
In my opinion, the conversion from String to ValueObject does not belong to the Business Logic at all. The Business Logic has a public contract that is invoked from the outside (API layer or presentation layer maybe). The contract should already expect Value Objects, not raw strings. Therefore, whoever is calling the business logic has to figure out how to obtain those Value Objects.
Regarding the implementation of the Country Code value object, I would question if it is really necessary to load the country codes from the database. The list of country codes very rarely changes. The way I've solved this in the past is simply hardcoding the list of country codes inside the value object itself.
Sample code in pseudo-C#, but you should get the point:
public class CountryCode : ValueObject
{
// Static definitions to be used in code like:
// var myCountry = CountryCode.France;
public static readonly CountryCode France = new CountryCode("FRA");
public static readonly CountryCode China = new CountryCode("CHN");
[...]
public static AllCountries = new [] {
France, China, ...
}
public string ThreeLetterCode { get; }
private CountryCode(string threeLetterCountryCode)
{
ThreeLetterCode = threeLetterCountryCode;
}
public static CountryCode Parse(string code)
{
[...] handle nulls, empties, etc
var exists = AllCountries.FirstOrDefault(c=>c.ThreeLetterCode==code);
if(exists == null)
// throw error
return exists;
}
}
Following this approach, you can make a very useful and developer-friendly CountryCode value object. In my actual solution, I had both the 2 and 3-letter codes and display names in English only for logging purposes (for presentation purposes, the presentation layer can look up the translation based on the code).
If loading the country codes from the DB is valuable for your scenario, it's still very likely that the list changes very rarely, so you could for example load a static list in the value object itself at application start up and then refresh it periodically if the application runs for very long.

How can I set an entity type within a dto [NestJS]?

I don't even think I've got a proper question so I apologize greatly.
I am consuming a 3rd party API and to update or create records, one of the fields is the entity type.
For example, here is my CreateOrganizationDTO:
export class CreateOrganizationDto {
#ApiProperty({
description: "The entity type. Only 'organization' is allowed.",
example: "organization",
})
#IsNotEmpty()
readonly #type: string; <-- this
...
I'm not sure how to properly handle the # character. I've tried different versions of '#type' or ['#type']. Clearly, neither are correct. I'm also not sure how to send that data through my service. For example:
// MyService.ts
const {name, #type, active} = updateOrganizationDto;
organization.name = name;
organization.#type = #type; <-- not going to work :(
organization.active = active;
...
What is the proper way to "escape" this # throughout my application? Thank you for any suggestions!

TS: Cannot invoke an expression whose type lacks a call signature when defined dynamically, but it works

I'm still quite new to typescript, so please be gentle with me if I'm doing something with no sense for this technology!
The problem that I'm trying to solve is having a dynamic way to define how my application errors should be structured, but leaving to the users the faculty to enrich the messages.
So I tried to create this logic in a module that could be extended easily from the application, but I'm currently facing the problem:
Error:(35, 18) TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'ErrorMessage' has no compatible call signatures.
What I thought it was a good idea (but please tell me if I'm wrong), was to use a register and a map to have the possibility to extend this mapping every time I want. So I created my ErrorMessage interface to be like the following:
export interface ErrorMessage {
actionMessage: string;
actionSubject: string;
originalErrorMessage?: string;
toString: () => string;
}
and a register for these, called ErrorResponseRegister, as it follows:
export enum defaultErrors {
ExceptionA = 'ExceptionA',
ExceptionB = 'ExceptionB',
}
export class ErrorResponseRegister {
private mapping: Map<string, ErrorMessage>;
constructor() {
this.mapping = new Map()
.set(defaultErrors.ExceptionA, exceptionAErrorMessage)
.set(defaultErrors.ExceptionB, exceptionBErrorMessage);
}
}
So at the end, every ErrorMessage function should look like:
export function exceptionAErrorMessage(originalErrorMessage?: string): ErrorMessage {
return {
enrichment1: "Something happened",
enrichment2: "in the application core",
originalErrorMessage: originalErrorMessage,
toString(): string {
return `${this.enrichment1} ${this.enrichment2}. Original error message: ${originalErrorMessage}`;
},
};
}
Please note I haven't used classes for this ones, as it doesn't really need to be instantiated
and I can have a bunch of them where the toString() method can vary. I just want to enforce the errors should have an enrichment1 and enrichment2 that highlight the problem in a better way for not-technical people.
So, now, back to code. When I'm trying to use the exceptionAErrorMessage statically, I can't see any problem:
console.log(exceptionAErrorMessage(originalErrorMessage).toString())
But when I try dynamically, using the map defined in the ErrorResponseRegister, something weird happens:
// In ErrorResponseRegister
public buildFor(errorType: string, originalErrorMessage?: string): Error {
const errorMessageBuilder = this.mapping.get(errorType);
if (errorMessageBuilder) {
return errorMessageBuilder(originalErrorMessage).toString();
}
return "undefined - do something else";
}
The code works as expected, the error returned is in the right format, so the toString function is executed correctly.
BUT, the following error appears in the IDE:
Error:(32, 18) TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'ErrorMessage' has no compatible call signatures.
The line that causes the problem is
errorMessageBuilder(originalPosErrorMessage).toString()
Can someone help me to understand what I'm doing wrong?
It looks like your problem is you've mistyped mapping... it doesn't hold ErrorMessage values; it holds (x?: string)=>ErrorMessage values:
private mapping: Map<string, (x?: string) => ErrorMessage>;
What's unfortunate is that you initialize this variable via new Map().set(...) instead of the using an iterable constructor argument.
The former returns a Map<any, any> which is trivially assignable to mapping despite the mistyping. That is, you ran smack into this known issue where the standard library's typings for the no-argument Map constructor signature produces Map<any, any> which suppresses all kinds of otherwise useful error messages. Perhaps that will be fixed one day, but for now I'd suggest instead that you use the iterable constructor argument, whose type signature declaration will infer reasonable types for the keys/values:
constructor() {
this.mapping = new Map([
[defaultErrors.ExceptionA, exceptionAErrorMessage],
[defaultErrors.ExceptionB, exceptionBErrorMessage]
]); // inferred as Map<defaultErrors, (orig?: string)=>ErrorMessage>
}
If you had done so, it would have flagged the assignment as an error with your original typing for mapping (e.g., Type 'Map<defaultErrors, (originalErrorMessage?: string | undefined) => ErrorMessage>' is not assignable to type 'Map<string, ErrorMessage>'.) Oh well!
Once you make those changes, things should behave more reasonably for you. Hope that helps; good luck!
Link to code

Defining Spock mock behaviors

I am writing my first Spock test and read the docs on mocking interactions, but am still not seeing the "forest through the trees" on a few items.
I have a class, MyRealm, that performs authentication for my app. It has two dependencies, AuthService and ShiroAdapter. The former I'd like to mock and the latter I want to leave as-is (if at all possible). This is because the AuthService actually makes a backend connection to LDAP, so I want to mock it. But the ShiroAdapter just defines several utility methods that convert my objects into Apache Shiro security objects (principals, permissions, etc.). So it can be left un-mocked (methinks).
class MyRealmSpec extends Specification {
MyRealm realm
def setup() {
AuthService authService = Mock(AuthService)
// configure 'authService' mock <-- ?????
ShiroAdapter shiroAdapter = new ShiroAdapter()
realm = new MyRealm(authService: authService,
shiroAdapter: shiroAdapter)
}
def "authenticate throws ShiroException whenever auth fails"() {
when:
realm.authenticate('invalid_username', 'invalid_password')
then:
Throwable throwable = thrown()
ShiroException.isAssignableFrom(throwable)
}
}
I believe I'm very close, but am struggling to configure the mock to behave the way I want it to for the test. The Spock docs (linked above) only seem to document how to verify the number of times a mock method is called. I'm not interested in that here.
Here, MyRealm#authenticate(String,String) calls AuthService#doAuth(String,String) under the hood. So I need my mock AuthService instance to simply either return false (indicating failed auth) or to throw an ServiceFaulException if something unexpected happened.
Any ideas how I can accomplish this?
You are very close, an easy, short-hand way to check a thrown exception type is to put the Exception class in parenthesis. Ex:
def "authenticate throws ShiroException whenever auth fails"() {
when:
realm.authenticate('invalid_username', 'invalid_password')
then:
thrown(ShiroException)
}
You also need to mock the LDAP service call itself and simulate an exception or a failed login. The mock operations go in the then clause of your test.
def "authenticate throws ShiroException whenever auth fails"() {
setup:
String invalidUserName = 'invalid_username'
String invalidPassword = 'invalid_password'
when:
realm.authenticate(invalidUserName, invalidPassword)
then:
1 * authService.doAuth(invalidUserName, invalidPassword) >> returnClosure
thrown(ShiroException)
where:
returnClosure << [{throw new ShiroException()}, { false }]
}
Note that you will need to have the arguments on the mock statements match or use wild card matching.
To match on any String you can use the underscore syntax:
1 * authService.doAuth(_, _) >> false
There are a few different behavior objects you might be interested in.
Stub - You only define what gets returned
MyObject obj = Stub{method >> null}
Mocks - You define what gets returned and/or how many times a method is called
MyObject obj = Mock {1..3 methodCall >> false}
Spies - It creates your object but you can override specific methods as a mock (and your overrides can still make calls to the original code)
MyObject obj = Spy {methodCall >> false}
obj.otherMethodCall() // Calls code like normal
obj.methodCall() // Returns false like we told it to
It sounds like you need a stub, but you could use a mock without any issue. I mention spy, because it's a life-saver if your object ever is self dependent (in the future).
def "authenticate throws ShiroException whenever auth fails"() {
given:
AuthService authService = Stub(AuthService)
authService.doAuth(_,_) >> expectedError
MyRealm realm = new MyRealm(
authService: authService,
shiroAdapter: new ShiroAdapter())
when:
realm.authenticate("just enough to get", "to the doAuth method")
then:
thrown(ShiroException)
where:
expectedError << [ShiroException, /*other exceptions this method has to test*/]
}
The data/logic separation isn't needed, but it's a good approach for making tests more flexible and maintainable. Although in this case it's not really needed since you only have one exception to throw.
I would actually separate your failed authentication and exception-ed authentication tests. They're looking at fundamentally different behaviors and the test logic to test both situations is somewhat different. In the interest of maintainability/flexibility, it's in your interest to avoid testing too much (or too little) with each test.
def "authenticate throws ShiroException whenever auth fails"() {
given:
AuthService authService = Stub(AuthService)
authService.doAuth(_,_) >> { args ->
return args[0] == good && args[1] == good
}
MyRealm realm = new MyRealm(
authService: authService,
shiroAdapter: new ShiroAdapter())
expect:
realm.authenticate(username, password) == expectedAuthentication
where:
userName | password | expectedAuthentication
bad | good | false
bad | bad | false
good | good | true
}
Note on the above test, this tests...
The mock's computation for a return value (testing the test)
Any code that happens between calling authenticate and doAuth()
Hopefully that's what you intend. If there's nothing in .authenticate()'s logic that could break (it has complexity on par with a getter or setter method), this test is mostly a waste of time. The only way that logic could break is if something went wrong in the JVM (which is completely outside the responsibility of this test), or someone made a change sometime in the future (ok, even under the huge assumption that .authenticate() contains unbreakably basic logic the test has some value). My rambling off-topic point (terribly sorry); make sure to keep the what & why of your tests in mind. It will help you prioritize test cases and while working out the best ways to organize/separate test logic.

Allowing multiple AssertionErrors before failing a test

Is there a conventional way to attempt a group of asserts to always be evaluated before failing the test?
Let's say my test assesses the presence of some names on a page:
var pageContent = 'dummy page content';
//.include(haystack, needle, [message])
//Asserts that haystack includes needle.
assert.include(pageContent, 'Alice');
assert.include(pageContent, 'Bob');
assert.include(pageContent, 'John');
Now, if Alice is missing, the test would fail with a single error:
>AssertionError: expected 'dummy page content' to contain 'Alice'
However I want to be notified that all three names are missing since in this case failing one condition does not prevent from evaluating others.
Rather than writing a wrapper method that aggregates the would-be output of these checks and throws a single error, I was hoping there would third-party library that "specializes" in this sort of thing or perhaps in-built functionality I'm overlooking.
I can offer two approaches.
The first one, mentioned by #Peter Lyons, relies on converting multiple assertions into a single assertion on multiple values. To keep the assertion error message useful, it's best to assert on the list of names:
var expected = ['Alice', 'Bob', 'John'];
var found = expected.filter(function(name) {
return pageContent.indexOf(name) >= 0;
}
// assuming Node's require('assert')
assert.deepEqual(found, expected);
// Example error message:
// AssertionError: ["Alice","Bob","John"] deepEqual ["Alice"]
The second approach uses "parameterised test". I'll assume you are using BDD-style for specifying test cases in my code.
describe('some page', function() {
for (var name in ['Alice', 'Bob', 'John'])
itContainsString(name);
function itContainsString(name) {
it('contains "' + name + '"', function() {
var pageContent = 'dummy page content';
assert.include(pageContent, 'Alice');
});
}
}
var found = ['Alice', 'Bob', 'John'].map(function (name) {
return pageContent.indexOf(name) >= 0;
});
assert.include(found, true);
If I may opine that your desire for a wrapper library for fuzzy asserting sounds misguided. Your fuzzy rules and heuristics about what is a "soft" vs "hard" assertion failure seem like a much less sensible alternative than good old programming using the existing assertion paradigm. It's testing. It's supposed to be straightforward and easy to reason about.
Keep in mind you can always take logic such as the above and wrap it in a function called includesOne(pageContent, needles) so it is conveniently reusable across tests.
Another approach to validating multiple assertions and getting feedback from all of them, regardless of which one fails first, is to use a Node.js module I wrote and published called multi-assert. Now, before we continue, I want to point out that, in your specific use case, if you're really only asserting 3 names, then I think Miroslav's answer is quite sufficient. As long as it serves your needs for quickly determining what broke and what to do to fix it, then you should continue on with that solution, and there's no need for additional dependencies in your project.
But the areas where I've run into major difficulties, or needed to spend more time debugging test failures or help others do the same, is when we've asserted properties of a really large object or array. For instance, when using deepEqual, I've personally run into cases where the error message can be quite complex, confusing, and unreadable in both HTML reports as well as the logs.
With the multi-assert module, the error messages are transparently displayed and specific to what we want to measure. For example, we can do something like this:
// import { multiAssert } from 'multi-assert';
const { assert } = require('chai');
const { multiAssert } = require('multi-assert');
describe('Page Content Tests', () => {
it('should contain Alice, Bob, and John somewhere in the content', () => {
var pageContent = 'dummy page content';
//.include(haystack, needle, [message])
//Asserts that haystack includes needle.
multiAssert([
() => assert.include(pageContent, 'Alice'),
() => assert.include(pageContent, 'Bob'),
() => assert.include(pageContent, 'John')
]);
});
});
And by running these tests, with "dummy page content", we're going to see the following error messages reported back to us with full transparency:
Page Content Tests
1) should contain Alice, Bob, and John somewhere in the content
0 passing (7ms)
1 failing
1) Page Content Tests
should contain Alice, Bob, and John somewhere in the content:
AssertionError:
MultipleAssertionError: expected 'dummy page content' to include 'Alice'
at /Users/user123/Dev/page-content-example/test/page-content.spec.js:13:20
at /Users/user123/Dev/page-content-example/node_modules/multi-assert/src/multi-assert.js:10:13
at Array.forEach (<anonymous>)
MultipleAssertionError: expected 'dummy page content' to include 'Bob'
at /Users/user123/Dev/page-content-example/test/page-content.spec.js:14:20
at /Users/user123/Dev/page-content-example/node_modules/multi-assert/src/multi-assert.js:10:13
at Array.forEach (<anonymous>)
MultipleAssertionError: expected 'dummy page content' to include 'John'
at /Users/user123/Dev/page-content-example/test/page-content.spec.js:15:20
at /Users/user123/Dev/page-content-example/node_modules/multi-assert/src/multi-assert.js:10:13
at Array.forEach (<anonymous>)
at multiAssert (node_modules/multi-assert/src/multi-assert.js:19:15)
at Context.<anonymous> (test/page-content.spec.js:12:5)
at processImmediate (node:internal/timers:466:21)
I want to also note that the multi-assert module also works with other testing frameworks; it's not just limited to Mocha and Chai; however, it's worth noting that Jasmine has been evaluating soft assertions by default for quite some time due to the nature of how their test runner and assertion library are more tightly integrated. If switching to Jasmine is not an easy or desired solution, and if existing assertion methods alone don't provide the desired level of feedback, then you can see the simplicity in wrapping up existing assertions in a multiAssert function call in order to achieve this transparency in your test cases. Hoping this helps!

Resources