UNPKG

@eggjs/supertest

Version:

SuperAgent driven library for testing HTTP servers

322 lines 23.3 kB
import { inspect } from 'node:util'; import { STATUS_CODES } from 'node:http'; import { Server as HttpsServer } from 'node:tls'; import { deepStrictEqual } from 'node:assert'; import { Request } from 'superagent'; import { AssertError } from './error/AssertError.js'; export class Test extends Request { app; _server; _asserts = []; /** * Initialize a new `Test` with the given `app`, * request `method` and `path`. */ constructor(app, method, path) { super(method.toUpperCase(), path); this.redirects(0); this.buffer(); this.app = app; this.url = typeof app === 'string' ? app + path : this.serverAddress(app, path); } /** * Returns a URL, extracted from a server. * * @return {String} URL address * @private */ serverAddress(app, path) { const addr = app.address(); if (!addr) { this._server = app.listen(0); } const port = app.address().port; const protocol = (app instanceof HttpsServer || this._server instanceof HttpsServer) ? 'https' : 'http'; return `${protocol}://127.0.0.1:${port}${path}`; } /** * Expectations: * * ```js * .expect(200) * .expect(200, fn) * .expect(200, body) * .expect('Some body') * .expect('Some body', fn) * .expect(['json array body', { key: 'val' }]) * .expect('Content-Type', 'application/json') * .expect('Content-Type', 'application/json', fn) * .expect(fn) * .expect([200, 404]) * ``` * * @return {Test} The current Test instance for chaining. */ expect(a, b, c) { // callback if (typeof a === 'function') { // .expect(fn) this._asserts.push(wrapAssertFn(a)); return this; } if (typeof b === 'function') { // .expect('Some body', fn) this.end(b); } if (typeof c === 'function') { // .expect('Content-Type', 'application/json', fn) this.end(c); } // status if (typeof a === 'number') { this._asserts.push(wrapAssertFn(this._assertStatus.bind(this, a))); // body if (typeof b !== 'function' && arguments.length > 1) { // .expect(200, 'body') // .expect(200, null) // .expect(200, 9999999) this._asserts.push(wrapAssertFn(this._assertBody.bind(this, b))); } return this; } // multiple statuses if (Array.isArray(a) && a.length > 0 && a.every(val => typeof val === 'number')) { // .expect([200, 300]) this._asserts.push(wrapAssertFn(this._assertStatusArray.bind(this, a))); return this; } // header field if (typeof b === 'string' || typeof b === 'number' || b instanceof RegExp) { // .expect('Content-Type', 'application/json') // .expect('Content-Type', /json/) this._asserts.push(wrapAssertFn(this._assertHeader.bind(this, { name: String(a), value: b }))); return this; } // body // .expect('body') // .expect(['json array body', { key: 'val' }]) // .expect(/foo/) this._asserts.push(wrapAssertFn(this._assertBody.bind(this, a))); return this; } /** * UnExpectations: * * .unexpectHeader('Content-Type') * .unexpectHeader('Content-Type', fn) */ unexpectHeader(name, fn) { if (typeof fn === 'function') { this.end(fn); } // header if (typeof name === 'string') { this._asserts.push(this._unexpectHeader.bind(this, name)); } return this; } /** * Expectations: * * .expectHeader('Content-Type') * .expectHeader('Content-Type', fn) */ expectHeader(name, fn) { if (typeof fn === 'function') { this.end(fn); } // header if (typeof name === 'string') { this._asserts.push(this._expectHeader.bind(this, name)); } return this; } _unexpectHeader(name, res) { const actual = res.headers[name.toLowerCase()]; if (actual) { return new AssertError('unexpected "' + name + '" header field, got "' + actual + '"', name, actual); } } _expectHeader(name, res) { const actual = res.headers[name.toLowerCase()]; if (!actual) { return new AssertError('expected "' + name + '" header field', name, actual); } } /** * Defer invoking superagent's `.end()` until * the server is listening. */ end(fn) { const server = this._server; super.end((err, res) => { const localAssert = () => { this.assert(err, res, fn); }; if (server && '_handle' in server && server._handle) { return server.close(localAssert); } localAssert(); }); return this; } /** * Perform assertions and invoke `fn(err, res)`. */ assert(resError, res, fn) { let errorObj; // check for unexpected network errors or server not running/reachable errors // when there is no response and superagent sends back a System Error // do not check further for other asserts, if any, in such case // https://nodejs.org/api/errors.html#errors_common_system_errors const sysErrors = { ECONNREFUSED: 'Connection refused', ECONNRESET: 'Connection reset by peer', EPIPE: 'Broken pipe', ETIMEDOUT: 'Operation timed out', }; if (!res && resError) { if (resError instanceof Error && resError.syscall === 'connect' && resError.code && sysErrors[resError.code]) { errorObj = new Error(resError.code + ': ' + sysErrors[resError.code]); } else { errorObj = resError; } } // asserts for (let i = 0; i < this._asserts.length && !errorObj; i += 1) { errorObj = this._assertFunction(this._asserts[i], res); } // set unexpected superagent error if no other error has occurred. if (!errorObj && resError instanceof Error && (!res || resError.status !== res.status)) { errorObj = resError; } fn.call(this, errorObj || null, res); } /** * Perform assertions on a response body and return an Error upon failure. */ _assertBody(body, res) { const isRegexp = body instanceof RegExp; // parsed if (typeof body === 'object' && !isRegexp) { try { deepStrictEqual(body, res.body); } catch (err) { const a = inspect(body); const b = inspect(res.body); return new AssertError('expected ' + a + ' response body, got ' + b, body, res.body, { cause: err }); } } else if (body !== res.text) { // string const a = inspect(body); const b = inspect(res.text); // regexp if (isRegexp) { if (!body.test(res.text)) { return new AssertError('expected body ' + b + ' to match ' + body, body, res.body); } } else { return new AssertError('expected ' + a + ' response body, got ' + b, body, res.body); } } } /** * Perform assertions on a response header and return an Error upon failure. */ _assertHeader(header, res) { const field = header.name; const actual = res.header[field.toLowerCase()]; const fieldExpected = header.value; if (typeof actual === 'undefined') { return new AssertError('expected "' + field + '" header field', header, actual); } // This check handles header values that may be a String or single element Array if ((Array.isArray(actual) && actual.toString() === fieldExpected) || fieldExpected === actual) { return; } if (fieldExpected instanceof RegExp) { if (!fieldExpected.test(actual)) { return new AssertError('expected "' + field + '" matching ' + fieldExpected + ', got "' + actual + '"', header, actual); } } else { return new AssertError('expected "' + field + '" of "' + fieldExpected + '", got "' + actual + '"', header, actual); } } /** * Perform assertions on the response status and return an Error upon failure. */ _assertStatus(status, res) { if (res.status !== status) { const a = STATUS_CODES[status]; const b = STATUS_CODES[res.status]; return new AssertError('expected ' + status + ' "' + a + '", got ' + res.status + ' "' + b + '"', status, res.status); } } /** * Perform assertions on the response status and return an Error upon failure. */ _assertStatusArray(statusArray, res) { if (!statusArray.includes(res.status)) { const b = STATUS_CODES[res.status]; const expectedList = statusArray.join(', '); return new AssertError('expected one of "' + expectedList + '", got ' + res.status + ' "' + b + '"', statusArray, res.status); } } /** * Performs an assertion by calling a function and return an Error upon failure. */ _assertFunction(fn, res) { let err; try { err = fn(res); } catch (e) { err = e; } if (err instanceof Error) { return err; } } } /** * Wraps an assert function into another. * The wrapper function edit the stack trace of any assertion error, prepending a more useful stack to it. * * @param {Function} assertFn * @return {Function} wrapped assert function */ function wrapAssertFn(assertFn) { const savedStack = new Error().stack.split('\n').slice(3); return (res) => { let badStack; let err; try { err = assertFn(res); } catch (e) { err = e; } if (err instanceof Error && err.stack) { badStack = err.stack.replace(err.message, '').split('\n').slice(1); err.stack = [err.toString()] .concat(savedStack) .concat('----') .concat(badStack) .join('\n'); } return err; }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDcEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxJQUFJLFdBQVcsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUVqRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzlDLE9BQU8sRUFBRSxPQUFPLEVBQWlCLE1BQU0sWUFBWSxDQUFDO0FBQ3BELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQVlyRCxNQUFNLE9BQU8sSUFBSyxTQUFRLE9BQU87SUFDL0IsR0FBRyxDQUFrQjtJQUNyQixPQUFPLENBQVM7SUFDaEIsUUFBUSxHQUFxQixFQUFFLENBQUM7SUFFaEM7OztPQUdHO0lBQ0gsWUFBWSxHQUFvQixFQUFFLE1BQWMsRUFBRSxJQUFZO1FBQzVELEtBQUssQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFbEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDZCxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNmLElBQUksQ0FBQyxHQUFHLEdBQUcsT0FBTyxHQUFHLEtBQUssUUFBUTtZQUNoQyxDQUFDLENBQUMsR0FBRyxHQUFHLElBQUk7WUFDWixDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ08sYUFBYSxDQUFDLEdBQVcsRUFBRSxJQUFZO1FBQy9DLE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztR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