mirror of
https://github.com/gravitational/teleport.git
synced 2026-11-02 14:59:53 +08:00
* Lint the web files but not node_modules or vendored files. * Add license headers to web files that were missing it. * Add missing licenses.
174 lines
5.4 KiB
TypeScript
174 lines
5.4 KiB
TypeScript
/**
|
|
* Copyright 2023 Gravitational, Inc
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import { renderHook, act } from '@testing-library/react-hooks';
|
|
|
|
import { useAsync, CanceledError } from './useAsync';
|
|
|
|
test('run returns a promise which resolves with the attempt data', async () => {
|
|
const returnValue = Symbol();
|
|
const { result, waitForNextUpdate } = renderHook(() =>
|
|
useAsync(() => Promise.resolve(returnValue))
|
|
);
|
|
|
|
let [, run] = result.current;
|
|
let promise: Promise<[symbol, Error]>;
|
|
act(() => {
|
|
promise = run();
|
|
});
|
|
await waitForNextUpdate();
|
|
|
|
await expect(promise).resolves.toEqual([returnValue, null]);
|
|
});
|
|
|
|
test('run resolves the promise to an error and does not update the state on unmount when the callback returns a resolved promise', async () => {
|
|
const { result, unmount } = renderHook(() =>
|
|
useAsync(() => Promise.resolve(Symbol()))
|
|
);
|
|
|
|
let [, run] = result.current;
|
|
let promise: Promise<[symbol, Error]>;
|
|
act(() => {
|
|
promise = run();
|
|
});
|
|
unmount();
|
|
|
|
await expect(promise).resolves.toEqual([null, new CanceledError()]);
|
|
const [attempt] = result.current;
|
|
expect(attempt.status).toBe('processing');
|
|
});
|
|
|
|
test('run resolves the promise to an error and does not update the state on unmount when the callback returns a rejected promise', async () => {
|
|
const { result, unmount } = renderHook(() =>
|
|
useAsync(() => Promise.reject(new Error('oops')))
|
|
);
|
|
|
|
let [, run] = result.current;
|
|
let promise: Promise<[symbol, Error]>;
|
|
act(() => {
|
|
promise = run();
|
|
});
|
|
unmount();
|
|
|
|
await expect(promise).resolves.toEqual([null, new CanceledError()]);
|
|
const [attempt] = result.current;
|
|
expect(attempt.status).toBe('processing');
|
|
});
|
|
|
|
test('run resolves the promise to an error after being re-run when the callback returns a resolved promise', async () => {
|
|
const { result, waitForNextUpdate } = renderHook(() =>
|
|
useAsync((count: number) => Promise.resolve(count))
|
|
);
|
|
|
|
let [, run] = result.current;
|
|
let firstRunPromise: Promise<[number, Error]>;
|
|
act(() => {
|
|
firstRunPromise = run(1);
|
|
});
|
|
|
|
act(() => {
|
|
run(2);
|
|
});
|
|
await waitForNextUpdate();
|
|
|
|
await expect(firstRunPromise).resolves.toEqual([null, new CanceledError()]);
|
|
});
|
|
|
|
test('run does not update state after being re-run when the callback returns a resolved promise', async () => {
|
|
let resolveFirstPromise, resolveSecondPromise;
|
|
const firstPromise = new Promise(resolve => {
|
|
resolveFirstPromise = resolve;
|
|
});
|
|
const secondPromise = new Promise(resolve => {
|
|
resolveSecondPromise = resolve;
|
|
});
|
|
|
|
const { result } = renderHook(() =>
|
|
// Passing a promise lets us control when the callback resolves.
|
|
useAsync((promise: Promise<unknown>) => promise)
|
|
);
|
|
|
|
let [, run] = result.current;
|
|
await act(async () => {
|
|
// Start two runs, one after the other.
|
|
const firstRunPromise = run(firstPromise);
|
|
const secondRunPromise = run(secondPromise);
|
|
|
|
// Once the first promise resolves, it should see that another one was started. The first
|
|
// promise should return early with an error.
|
|
resolveFirstPromise();
|
|
await firstRunPromise;
|
|
|
|
const attemptAfterFirstPromise = result.current[0];
|
|
expect(attemptAfterFirstPromise.status).toBe('processing');
|
|
|
|
resolveSecondPromise();
|
|
await secondRunPromise;
|
|
});
|
|
});
|
|
|
|
test('run resolves the promise to an error after being re-run when the callback returns a rejected promise', async () => {
|
|
const { result, waitForNextUpdate } = renderHook(() =>
|
|
useAsync((count: number) => Promise.reject(new Error(`oops ${count}`)))
|
|
);
|
|
|
|
let [, run] = result.current;
|
|
let firstRunPromise: Promise<[number, Error]>;
|
|
act(() => {
|
|
firstRunPromise = run(1);
|
|
});
|
|
|
|
act(() => {
|
|
run(2);
|
|
});
|
|
await waitForNextUpdate();
|
|
|
|
await expect(firstRunPromise).resolves.toEqual([null, new CanceledError()]);
|
|
});
|
|
|
|
test('run does not update state after being re-run when the callback returns a rejected promise', async () => {
|
|
let rejectFirstPromise, rejectSecondPromise;
|
|
const firstPromise = new Promise((resolve, reject) => {
|
|
rejectFirstPromise = reject;
|
|
});
|
|
const secondPromise = new Promise((resolve, reject) => {
|
|
rejectSecondPromise = reject;
|
|
});
|
|
|
|
const { result } = renderHook(() =>
|
|
// Passing a promise lets us control when the callback resolves.
|
|
useAsync((promise: Promise<unknown>) => promise)
|
|
);
|
|
|
|
let [, run] = result.current;
|
|
await act(async () => {
|
|
// Start two runs, one after the other.
|
|
const firstRunPromise = run(firstPromise);
|
|
const secondRunPromise = run(secondPromise);
|
|
|
|
// Once the first promise resolves, it should see that another one was started. The first
|
|
// promise should return early with an error.
|
|
rejectFirstPromise();
|
|
await firstRunPromise;
|
|
|
|
const attemptAfterFirstPromise = result.current[0];
|
|
expect(attemptAfterFirstPromise.status).toBe('processing');
|
|
|
|
rejectSecondPromise();
|
|
await secondRunPromise;
|
|
});
|
|
});
|