Skip to content

Commit

Permalink
feat: initial implementation of freezeTime and freezeTimeAwait
Browse files Browse the repository at this point in the history
  • Loading branch information
eturino committed Nov 5, 2019
1 parent d40ad7b commit c4df449
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 21 deletions.
28 changes: 26 additions & 2 deletions README.md
Expand Up @@ -9,15 +9,39 @@

[Github repo here](https://github.com/plandek-utils/ts-time-utils)

small utils for managing Time, supported by Dayjs. It is intended to be used in tests.
small utils for managing Time, supported by `Dayjs`. It is intended to be used in tests.

## Installation

`yarn add @plandek-utils/time-utils` or `npm install @plandek-utils/time-utils`.

## Dependencies

it requires [`timekeeper`](https://www.npmjs.com/package/timekeeper) and [`Dayjs`](https://www.npmjs.com/package/dayjs)

## Usage

TBD.
we get 2 functions:

- `freezeTime(time, fn)`: freezes time to the given one, executes the given function, and resets the time before returning the result of that execution.
- `freezeTimeAwait(time, asyncFn)`: same as `freezeTime()` but expects an async function, and it waits for its return before resetting the time

```typescript
// assume now is "2019-03-21T12:21:13.000Z"

function renderTime() {
const d = new Date()
console.log(d.toISOString())
}

renderTime() // => logs "2019-03-21T12:21:13.000Z"

const time = new Date("2018-01-02T13:14:15.123Z")
const res = freezeTime(time, () => { renderTime(); return 'blah' }) // => logs "2018-01-02T13:14:15.123Z"
console.log(res) // => logs 'blah' (freezeTime() returns the result of the passed function)

renderTime() // => logs "2019-03-21T12:21:13.010Z" (time is unfrozen, let's say that a 10ms have passed)
```

## Development, Commits, versioning and publishing

Expand Down
5 changes: 4 additions & 1 deletion package.json
Expand Up @@ -49,7 +49,10 @@
"engines": {
"node": ">=10.0"
},
"dependencies": {},
"dependencies": {
"dayjs": "^1.8.16",
"timekeeper": "^2.2.0"
},
"devDependencies": {
"@bitjson/npm-scripts-info": "^1.0.0",
"@types/inquirer": "^6.5.0",
Expand Down
43 changes: 43 additions & 0 deletions src/__tests__/index.spec.ts
@@ -0,0 +1,43 @@
import dayjs from "dayjs";
import { freezeTime, freezeTimeAwait } from "..";

function nowString() {
const d = new Date();
return d.toISOString();
}

function dayjsNow() {
return dayjs(new Date());
}

const now = dayjsNow().subtract(1, "week");

[
{ time: now, title: "works with Dayjs" },
{ time: now.toDate(), title: "works with Date" }
].forEach(({ time, title }) => {
describe(title, () => {
describe("freezeTime()", () => {
it("executes the given expect inside of the function", () => {
freezeTime(time, () => {
expect(nowString()).toEqual(time.toISOString());
});
expect.assertions(1);
});
});

describe("freezeTimeAwait()", () => {
async function doShit(): Promise<string> {
return Promise.resolve(dayjsNow().toISOString());
}

it("executes the given expect inside of the function", async () => {
await freezeTimeAwait(time, async () => {
const res = await doShit();
expect(res).toEqual(time.toISOString());
});
expect.assertions(1);
});
});
});
});
59 changes: 58 additions & 1 deletion src/index.ts
@@ -1 +1,58 @@
export * from "./lib/my-lib";
import { Dayjs, isDayjs } from "dayjs";
import timekeeper from "timekeeper";

/**
* @internal
*/
function getDate(time: Dayjs | Date) {
return isDayjs(time) ? time.toDate() : time;
}

/**
* Executes the given function, freezing the time first to the given `time`, and resetting the function execution (uses `timekeeper`)
*
* ```typescript
* // assume now is "2019-03-21T12:21:13.000Z"
*
* function renderTime() {
* const d = new Date()
* console.log(d.toISOString())
* }
*
* renderTime() // => logs "2019-03-21T12:21:13.000Z"
*
* const time = new Date("2018-01-02T13:14:15.123Z")
* const res = freezeTime(time, () => { renderTime(); return 'blah' }) // => logs "2018-01-02T13:14:15.123Z"
* console.log(res) // => logs 'blah' (freezeTime() returns the result of the passed function)
*
* renderTime() // => logs "2019-03-21T12:21:13.010Z" (time is unfrozen, let's say that a 10ms have passed)
* ```
*
* @param time the time that will be the new "now"
* @param fn function to execute, on which the time will be frozen as `time`
*/
export function freezeTime<T>(time: Dayjs | Date, fn: () => T): T {
timekeeper.freeze(getDate(time));
const result = fn();
timekeeper.reset();
return result;
}

/**
* same as `freezeTime()` but it expects an async function. It will await for the function's return and return it before resetting the time
*
* TODO: this needs concurrency testing
*
* @param time the time that will be the new "now"
* @param fn async function to execute, on which the time will be frozen as `time`
* @see freezeTime
*/
export async function freezeTimeAwait<T>(
time: Dayjs | Date,
fn: () => Promise<T>
): Promise<T> {
timekeeper.freeze(getDate(time));
const result = await fn();
timekeeper.reset();
return result;
}
12 changes: 0 additions & 12 deletions src/lib/__tests__/my-lib.spec.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/lib/my-lib.ts

This file was deleted.

Empty file removed src/types/.keep
Empty file.
10 changes: 10 additions & 0 deletions yarn.lock
Expand Up @@ -1489,6 +1489,11 @@ dateformat@^3.0.0:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==

dayjs@^1.8.16:
version "1.8.16"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.16.tgz#2a3771de537255191b947957af2fd90012e71e64"
integrity sha512-XPmqzWz/EJiaRHjBqSJ2s6hE/BUoCIHKgdS2QPtTQtKcS9E4/Qn0WomoH1lXanWCzri+g7zPcuNV4aTZ8PMORQ==

debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
Expand Down Expand Up @@ -5623,6 +5628,11 @@ through@2, "through@>=2.2.7 <3", through@^2.3.6:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=

timekeeper@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/timekeeper/-/timekeeper-2.2.0.tgz#9645731fce9e3280a18614a57a9d1b72af3ca368"
integrity sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A==

tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
Expand Down

0 comments on commit c4df449

Please sign in to comment.