| 'use strict'; |
| require('../common'); |
| const { suite, test } = require('node:test'); |
| |
| suite('input validation', () => { |
| test('throws if condition is not a function', (t) => { |
| t.assert.throws(() => { |
| t.waitFor(5); |
| }, { |
| code: 'ERR_INVALID_ARG_TYPE', |
| message: /The "condition" argument must be of type function/, |
| }); |
| }); |
| |
| test('throws if options is not an object', (t) => { |
| t.assert.throws(() => { |
| t.waitFor(() => {}, null); |
| }, { |
| code: 'ERR_INVALID_ARG_TYPE', |
| message: /The "options" argument must be of type object/, |
| }); |
| }); |
| |
| test('throws if options.interval is not a number', (t) => { |
| t.assert.throws(() => { |
| t.waitFor(() => {}, { interval: 'foo' }); |
| }, { |
| code: 'ERR_INVALID_ARG_TYPE', |
| message: /The "options\.interval" property must be of type number/, |
| }); |
| }); |
| |
| test('throws if options.timeout is not a number', (t) => { |
| t.assert.throws(() => { |
| t.waitFor(() => {}, { timeout: 'foo' }); |
| }, { |
| code: 'ERR_INVALID_ARG_TYPE', |
| message: /The "options\.timeout" property must be of type number/, |
| }); |
| }); |
| }); |
| |
| test('returns the result of the condition function', async (t) => { |
| const result = await t.waitFor(() => { |
| return 42; |
| }); |
| |
| t.assert.strictEqual(result, 42); |
| }); |
| |
| test('returns the result of an async condition function', async (t) => { |
| const result = await t.waitFor(async () => { |
| return 84; |
| }); |
| |
| t.assert.strictEqual(result, 84); |
| }); |
| |
| test('errors if the condition times out', async (t) => { |
| await t.assert.rejects(async () => { |
| await t.waitFor(() => { |
| return new Promise(() => {}); |
| }, { |
| interval: 60_000, |
| timeout: 1, |
| }); |
| }, { |
| message: /waitFor\(\) timed out/, |
| }); |
| }); |
| |
| test('polls until the condition returns successfully', async (t) => { |
| let count = 0; |
| const result = await t.waitFor(() => { |
| ++count; |
| if (count < 4) { |
| throw new Error('resource is not ready yet'); |
| } |
| |
| return 'success'; |
| }, { |
| interval: 1, |
| timeout: 60_000, |
| }); |
| |
| t.assert.strictEqual(result, 'success'); |
| t.assert.strictEqual(count, 4); |
| }); |
| |
| test('sets last failure as error cause on timeouts', async (t) => { |
| const error = new Error('boom'); |
| await t.assert.rejects(async () => { |
| await t.waitFor(() => { |
| return new Promise((_, reject) => { |
| reject(error); |
| }); |
| }); |
| }, (err) => { |
| t.assert.match(err.message, /timed out/); |
| t.assert.strictEqual(err.cause, error); |
| return true; |
| }); |
| }); |
| |
| test('limits polling if condition takes longer than interval', async (t) => { |
| let count = 0; |
| |
| function condition() { |
| count++; |
| return new Promise((resolve) => { |
| setTimeout(() => { |
| resolve('success'); |
| }, 200); |
| }); |
| } |
| |
| const result = await t.waitFor(condition, { |
| interval: 1, |
| timeout: 60_000, |
| }); |
| |
| t.assert.strictEqual(result, 'success'); |
| t.assert.strictEqual(count, 1); |
| }); |