From 7ab36b7ff67ae0fa5a7cd32dc8aa078c21ecfd40 Mon Sep 17 00:00:00 2001
From: Jy <1041207253@qq.com>
Date: Sat, 23 Jan 2021 14:50:51 +0800
Subject: [PATCH 1/2] feat(composable): add a new composable
---
docs/.vuepress/components/timeoutExample.vue | 35 ++++++++
docs/composable/web/timeout.md | 85 +++++++++++++++++++
.../__tests__/web/timeout.spec.ts | 72 ++++++++++++++++
packages/vue-composable/src/web/index.ts | 1 +
packages/vue-composable/src/web/timeout.ts | 43 ++++++++++
5 files changed, 236 insertions(+)
create mode 100644 docs/.vuepress/components/timeoutExample.vue
create mode 100644 docs/composable/web/timeout.md
create mode 100644 packages/vue-composable/__tests__/web/timeout.spec.ts
create mode 100644 packages/vue-composable/src/web/timeout.ts
diff --git a/docs/.vuepress/components/timeoutExample.vue b/docs/.vuepress/components/timeoutExample.vue
new file mode 100644
index 000000000..612ae0c0f
--- /dev/null
+++ b/docs/.vuepress/components/timeoutExample.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
diff --git a/docs/composable/web/timeout.md b/docs/composable/web/timeout.md
new file mode 100644
index 000000000..03dad9c13
--- /dev/null
+++ b/docs/composable/web/timeout.md
@@ -0,0 +1,85 @@
+# Timeout
+
+> The [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout).
+
+## Parameters
+
+```js
+import { useTimeout } from "vue-composable";
+
+useTimeout(fn, delay);
+```
+
+| Parameters | Type | Required | Default | Description |
+| ---------- | ---------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------- |
+| fn | `Function` | `true` | | A function to be executed after the timer expires. |
+| delay | `Number` | `false` | `0 ` | The time, in milliseconds (thousandths of a second), the timer should wait before the specified function is executed. |
+
+## State
+
+The `useTimeout` function exposes the following reactive state:
+
+```js
+import { useTimeout } from "vue-composable";
+
+const { ready } = useTimeout(fn, delay);
+```
+
+| State | Type | Description |
+| ----- | ------------ | ----------- | ---------------------------------------------------------------------------------------------------- |
+| ready | `Ref` | current timeout state:
false - pending
true - called
null - canceled |
+
+## Methods
+
+The `useTimeout` function exposes the following methods:
+
+```js
+import { useTimeout } from "vue-composable";
+
+const { cancel } = useTimeout(fn, delay);
+```
+
+| Signature | Description |
+| --------- | ------------------ |
+| `cancel` | cancel the timeout |
+
+## Example
+
+
+
+### Code
+
+```vue
+
+
+
+
+
+
+
+
+
+```
diff --git a/packages/vue-composable/__tests__/web/timeout.spec.ts b/packages/vue-composable/__tests__/web/timeout.spec.ts
new file mode 100644
index 000000000..d7a605212
--- /dev/null
+++ b/packages/vue-composable/__tests__/web/timeout.spec.ts
@@ -0,0 +1,72 @@
+import { useTimeout } from "../../src";
+import { createVue } from "../utils";
+import { Ref, ref } from "../../src/api";
+
+function sleep(duration: number): Promise {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(true);
+ }, duration);
+ });
+}
+
+describe("timeout", () => {
+ it("should be defined", () => {
+ expect(useTimeout).toBeDefined();
+ });
+
+ it("should call passed function after given amount of time", async () => {
+ let count = 0;
+ useTimeout(() => {
+ count++;
+ }, 1000);
+
+ expect(count).toBe(0);
+ await sleep(1000);
+ expect(count).toBe(1);
+ });
+
+ it("should set ready true after run callback", async () => {
+ const { ready } = useTimeout(() => {}, 1000);
+
+ expect(ready.value).toBe(false);
+ await sleep(1000);
+ expect(ready.value).toBe(true);
+ });
+
+ it("should cancel function call when call cancel function", async () => {
+ let count = 0;
+ const { ready, cancel } = useTimeout(() => {
+ count++;
+ }, 1000);
+
+ expect(ready.value).toBe(false);
+ expect(count).toBe(0);
+
+ cancel();
+
+ await sleep(1000);
+ expect(ready.value).toBe(null);
+ expect(count).toBe(0);
+ });
+
+ it("should cancel on unMounted", async () => {
+ let ready: Ref = ref(false);
+
+ const { mount, destroy } = createVue({
+ template: ``,
+ setup() {
+ ready = useTimeout(() => {}, 1000).ready;
+ },
+ });
+
+ mount();
+
+ expect(ready.value).toBe(false);
+ await sleep(1000);
+ expect(ready.value).toBe(true);
+
+ destroy();
+ expect(ready.value).toBe(null);
+ });
+});
diff --git a/packages/vue-composable/src/web/index.ts b/packages/vue-composable/src/web/index.ts
index 7147045aa..cf304be7c 100644
--- a/packages/vue-composable/src/web/index.ts
+++ b/packages/vue-composable/src/web/index.ts
@@ -11,4 +11,5 @@ export * from "./cssVariables";
export * from "./worker";
export * from "./share";
export * from "./clipboard";
+export * from "./timeout";
export { useWorkerFunction, WebWorkerFunctionOptions } from "./workerFunction";
diff --git a/packages/vue-composable/src/web/timeout.ts b/packages/vue-composable/src/web/timeout.ts
new file mode 100644
index 000000000..358f337b2
--- /dev/null
+++ b/packages/vue-composable/src/web/timeout.ts
@@ -0,0 +1,43 @@
+import { ref, Ref, onUnmounted } from "../api";
+
+interface UseTimeoutReturn {
+ /**
+ * current timeout state:
+ * false - pending
+ * true - called
+ * null - canceled
+ */
+ ready: Ref;
+ /**
+ * cancel the timeout
+ */
+ cancel: () => void;
+}
+/**
+ * @param fn setTimeout callback
+ * @param delay If this parameter is omitted, a value of 0 is used
+ * (https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout)
+ */
+export function useTimeout(
+ fn: () => void,
+ delay: number = 0
+): UseTimeoutReturn {
+ let ready: Ref = ref(false);
+
+ const timeoutId = setTimeout(() => {
+ ready.value = true;
+ fn();
+ }, delay);
+
+ const cancel = () => {
+ ready.value = null;
+ clearTimeout(timeoutId);
+ };
+
+ onUnmounted(cancel);
+
+ return {
+ ready,
+ cancel,
+ };
+}
From 0636f68f6584357014d329ca4501f635da1acaf8 Mon Sep 17 00:00:00 2001
From: pikax
Date: Sat, 23 Jan 2021 08:34:10 +0000
Subject: [PATCH 2/2] chore: update tests to use fake timers
---
.../__tests__/web/timeout.spec.ts | 34 ++++++++++++-------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/packages/vue-composable/__tests__/web/timeout.spec.ts b/packages/vue-composable/__tests__/web/timeout.spec.ts
index d7a605212..7ea1dac93 100644
--- a/packages/vue-composable/__tests__/web/timeout.spec.ts
+++ b/packages/vue-composable/__tests__/web/timeout.spec.ts
@@ -2,15 +2,8 @@ import { useTimeout } from "../../src";
import { createVue } from "../utils";
import { Ref, ref } from "../../src/api";
-function sleep(duration: number): Promise {
- return new Promise((resolve) => {
- setTimeout(() => {
- resolve(true);
- }, duration);
- });
-}
-
describe("timeout", () => {
+ jest.useFakeTimers();
it("should be defined", () => {
expect(useTimeout).toBeDefined();
});
@@ -22,7 +15,11 @@ describe("timeout", () => {
}, 1000);
expect(count).toBe(0);
- await sleep(1000);
+ jest.advanceTimersByTime(900);
+ // should not be resolved
+ expect(count).toBe(0);
+
+ jest.advanceTimersByTime(100);
expect(count).toBe(1);
});
@@ -30,7 +27,7 @@ describe("timeout", () => {
const { ready } = useTimeout(() => {}, 1000);
expect(ready.value).toBe(false);
- await sleep(1000);
+ jest.advanceTimersByTime(1000);
expect(ready.value).toBe(true);
});
@@ -45,7 +42,7 @@ describe("timeout", () => {
cancel();
- await sleep(1000);
+ jest.advanceTimersByTime(1000);
expect(ready.value).toBe(null);
expect(count).toBe(0);
});
@@ -63,10 +60,21 @@ describe("timeout", () => {
mount();
expect(ready.value).toBe(false);
- await sleep(1000);
- expect(ready.value).toBe(true);
+ jest.advanceTimersByTime(500);
+ expect(ready.value).toBe(false);
destroy();
expect(ready.value).toBe(null);
});
+
+ it("should default the delay to 0", () => {
+ let count = 0;
+ useTimeout(() => {
+ count++;
+ });
+
+ expect(count).toBe(0);
+ jest.runOnlyPendingTimers();
+ expect(count).toBe(1);
+ });
});