Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/total-typescript/shoehorn
Work seamlessly with partial mocks in TypeScript.
https://github.com/total-typescript/shoehorn
mock testing typescript
Last synced: 3 months ago
JSON representation
Work seamlessly with partial mocks in TypeScript.
- Host: GitHub
- URL: https://github.com/total-typescript/shoehorn
- Owner: total-typescript
- License: mit
- Created: 2023-03-03T15:17:24.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-02-26T15:26:54.000Z (8 months ago)
- Last Synced: 2024-05-17T04:43:59.947Z (6 months ago)
- Topics: mock, testing, typescript
- Language: TypeScript
- Homepage: https://totaltypescript.com
- Size: 92.8 KB
- Stars: 429
- Watchers: 3
- Forks: 10
- Open Issues: 2
-
Metadata Files:
- Readme: rEaDMe.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# `shoehorn`
```
npm i @total-typescript/shoehorn
````shoehorn` (meaning "to force something into a space") lets you **pass partial data in tests** while keeping TypeScript happy.
### Problem
Using 'as' in tests feels bad.
```ts
type Request = {
body: {
id: string;
};
// Imagine oodles of other properties...
};it("Should get the user", () => {
// Even though we only care about body.id for
// this test, we need to pass in the whole Request
// object
getUser({
body: {
id: "123",
},
} as Request);
});
```- You're trained not to use it
- You need to _manually_ specify the type you want to assert to
- For testing with incorrect data, you need to 'double-as' (`as unknown as User`)### Solution
`shoehorn` gives you some first-class primitives for _safely_ providing incomplete data to tests.
```ts
import { fromPartial } from "@total-typescript/shoehorn";it("Should get the user", () => {
getUser(
fromPartial({
body: {
id: "123",
},
}),
);
});
```### But isn't passing partial data to tests bad?
Yes, in general. Having to pass huge objects to tests is a sign that your types are too loose. Ideally, every function should only specify the data it needs.
Unfortunately, we live in the real world. There are many cases where `shoehorn` is the best choice:
- **Legacy codebases**: If you're working on a large codebase, you might not have the time to refactor everything to be perfect.
- **Third-party libraries**: If you're using a third-party library, you might not be able to alter the types without needless wrapper functions.## API
For each example below, imagine that the following types are defined:
```ts
type Request = {
body: {
id: string;
};
// Imagine oodles of other properties...
};// The function we're testing
const requiresRequest = (request: Request) => {};
```### `fromPartial`
Lets you pass a deep partial to a slot expecting a type.
```ts
import { fromPartial } from "@total-typescript/shoehorn";requiresRequest(
fromPartial({
body: {
id: "123",
},
}),
);
```It'll fail if you pass a type that doesn't match the one expected:
```ts
// Type "1234123" has no properties in common
// with type 'PartialObjectDeep'
requiresRequest(fromPartial("1234123"));
```### `fromAny`
Lets you pass anything to a slot, while still giving you autocomplete on the original type:
```ts
import { fromAny } from "@total-typescript/shoehorn";requiresRequest(
fromAny({
body: {
id: 124123,
},
}),
);
```It WILL NOT FAIL if you pass something that doesn't match.
```ts
// All good!
requiresRequest(fromAny("1234123"));
```### `fromExact`
A convenience method for forcing you to pass all the properties of a type. Useful for when you want to swap in and out of `fromPartial`/`fromAny`:
```ts
import { fromExact } from "@total-typescript/shoehorn";requiresRequest(
// Will fail! We're not passing all the oodles of
// properties of Request
fromExact({
body: {
id: 124123,
},
}),
);
```