Git Product home page Git Product logo

superdeno's Introduction

Super Deno standing in the rain at night โ€“ stoically facing the dark battle that is software engineering

SuperDeno

HTTP assertions for Deno made easy via superagent.

Current version Current test status SuperDeno docs PRs are welcome SuperDeno issues SuperDeno stars SuperDeno forks SuperDeno license SuperDeno is maintained

SuperDeno latest /x/ version Minimum supported Deno version SuperDeno dependency count SuperDeno dependency outdatedness SuperDeno cached size


Table of Contents

Getting Started

import { superdeno } from "https://deno.land/x/superdeno/mod.ts";
import { opine } from "https://deno.land/x/[email protected]/mod.ts";

const app = opine();

app.get("/user", (req, res) => {
  res.setStatus(200).json({ name: "Deno" });
});

superdeno(app)
  .get("/user")
  .expect("Content-Type", /json/)
  .expect("Content-Length", "15")
  .expect(200)
  .end((err, res) => {
    if (err) throw err;
  });

Looking to test an Oak web server? Check out SuperOak!

About

The motivation of this module is to provide a high-level abstraction for testing HTTP in Deno, while still allowing you to drop down to the lower-level API provided by superagent.

Installation

This is a Deno module available to import direct from this repo and via the Deno Registry.

Before importing, download and install Deno.

You can then import SuperDeno straight into your project:

import { superdeno } from "https://deno.land/x/superdeno/mod.ts";

SuperDeno is also available on nest.land, a package registry for Deno on the Blockchain.

Note: All examples in this README are using the unversioned form of the import URL. In production you should always use the versioned import form such as https://deno.land/x/[email protected]/mod.ts.

Examples

You may pass a url string, http.Server, a request handling function, or an object that implements an app.listen() method (which mirrors the http.serve interface) to superdeno() - if SuperDeno identifies that a server is not already listening for connections, then one is bound to an ephemeral port for you so there is no need to keep track of ports.

SuperDeno works with any Deno test framework. Here's an example with Deno's built-in test framework, note how you can pass done straight to any of the .expect() calls:

Deno.test("GET /user responds with json", async () => {
  await superdeno(app)
    .get("/user")
    .set("Accept", "application/json")
    .expect("Content-Type", /json/)
    .expect(200);
});

Here's an example of SuperDeno working with the Opine web framework:

import { superdeno } from "https://deno.land/x/superdeno/mod.ts";
import { opine } from "https://deno.land/x/[email protected]/mod.ts";
import { expect } from "https://deno.land/x/[email protected]/mod.ts";

const app = opine();

app.get("/", (req, res) => {
  res.send("Hello Deno!");
});

Deno.test("it should support regular expressions", async () => {
  await superdeno(app)
    .get("/")
    .expect("Content-Type", /^application/)
    .catch((err) => {
      expect(err.message).toEqual(
        'expected "Content-Type" matching /^application/, got "text/html; charset=utf-8"'
      );
    });
});

See more examples in the Opine test suite.

Here's an example of SuperDeno working with the Express web framework:

import { superdeno } from "https://deno.land/x/superdeno/mod.ts";
// @deno-types="npm:@types/express@^4.17"
import express from "npm:[email protected]";
import { expect } from "https://deno.land/x/[email protected]/mod.ts";

Deno.test("it should support regular expressions", async () => {
  const app = express();

  app.get("/", (_req, res) => {
    res.send("Hello Deno!");
  });

  await superdeno(app)
    .get("/")
    .expect("Content-Type", /^application/)
    .catch((err) => {
      expect(err.message).toEqual(
        'expected "Content-Type" matching /^application/, got "text/html; charset=utf-8"'
      );
    });
});

See more examples in the Express test suite.

Here's an example of SuperDeno working with the Oak web framework:

import { superdeno } from "https://deno.land/x/superdeno/mod.ts";
import { Application, Router } from "https://deno.land/x/[email protected]/mod.ts";

const router = new Router();
router.get("/", (ctx) => {
  ctx.response.body = "Hello Deno!";
});

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

Deno.test("it should support the Oak framework", () => {
  const controller = new AbortController();
  const { signal } = controller;

  app.addEventListener("listen", async ({ hostname, port, secure }) => {
    const protocol = secure ? "https" : "http";
    const url = `${protocol}://${hostname}:${port}`;

    await superdeno(url)
      .get("/")
      .expect("Hello Deno!", () => {
        controller.abort();
      });
  });

  await app.listen({ port: 0, signal });
});

See more examples in the Oak test suite.

If you are using the Oak web framework then it is recommended that you use the specialized SuperOak assertions library for reduced bootstrapping.

If you don't need to test the server setup side of your Oak application, or you are making use of the app.handle() method (for example for serverless apps) then you can write slightly less verbose tests for Oak:

import { Application, Router } from "https://deno.land/x/[email protected]/mod.ts";
import { superdeno } from "https://deno.land/x/superdeno/mod.ts";

const router = new Router();

router.get("/", (ctx) => {
  ctx.response.body = "Hello Deno!";
});

const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());

Deno.test(
  "it should support the Oak framework `app.handle` method",
  async () => {
    /**
     * Note that we have to bind `app` to the function otherwise `app.handle`
     * doesn't preserve the `this` context from `app`.
     */
    await superdeno(app.handle.bind(app)).get("/").expect("Hello Deno!");
  }
);

In this case, SuperDeno handles the setup and closing of the server for you, so you can focus on just testing your middleware.

For further examples, see the tests or the supertest examples for inspiration.

Documentation

API

You may use any superagent client (browser) methods and perform assertions in the .end() callback for lower-level needs.

.expect(status[, fn])

Assert response status code.

.expect(status, body[, fn])

Assert response status code and body.

.expect(body[, fn])

Assert response body text with a string, regular expression, or parsed body object.

.expect(field, value[, fn])

Assert header field value with a string or regular expression.

.expect(function(res) {})

Pass a custom assertion function. It'll be given the response object to check. If the check fails, throw an error.

function hasPreviousAndNextKeys(res) {
  if (!("next" in res.parsedBody)) throw new Error("missing next key");
  if (!("prev" in res.parsedBody)) throw new Error("missing prev key");
}

await superdeno(app).get("/").expect(hasPreviousAndNextKeys);

.end(fn)

Perform the request and invoke fn(err, res).

Notes

This is a port of supertest to TypeScript + Deno, which fulfills this motivation currently for Node. This module also includes a XHR sham so superagent client mode can be used directly.

Contributing

Contributing guide


License

This library is a port of supertest whose license and copyrights are available at SUPERTEST_LICENSE in the root of this repository, and covers all files within the source directory which detail that the file is a port.

SuperDeno is licensed under the MIT License.

Icon designed and created by Hannah Morten.

superdeno's People

Contributors

asos-craigmorten avatar c0per avatar cmorten avatar danopia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

superdeno's Issues

`HandlerLike` signature doesn't match actual `server.Handler`. Missing `connInfo`

HandlerLike signature doesn't match actual server.Handler. Missing connInfo

Setup:

  • Deno Version: deno 1.20.6
  • v8 Version: v8 10.0.139.6
  • Typescript Version: 4.6.2
  • SuperDeno Version: 4.8

Details

The actual server.Handler takes a second argument called connInfo that contains information for the http request. See here and quoted:

export type Handler = (
  request: Request,
  connInfo: ConnInfo,
) => Response | Promise<Response>;

But RequestHandlerLike defined in this project doesn't match that. And when actually testing the handler, this project calls the handler with return await app(request); with the connInfo argument missing.

Re-introduce multiple cookie headers in test

It appears the cookie setting code in Opine has regressed cmorten/opine#117 this means we cannot test that setting multiple cookies works as part of the superdeno test suite.

This issue is to track the resolution of the Opine issue and then re-introduce said commented out tests once it is resolved.

SuperDeno does not process headers in the response from Opine

SuperDeno does not process headers from Opine

Setup:

  • Deno Version: deno 1.9.1 (release, x86_64-unknown-linux-gnu)
  • v8 Version: 9.1.269.5
  • Typescript Version: 4.2.2
  • SuperDeno Version: 4.1.0

Details

When: testing the following Opine handler:

handler: (req: Request, res: Response, next: NextFunction) => {
  console.log(res.headers) // shows:  "x-powered-by": "Opine"
  res.json({ data: 'ok' })
}

I want the following test:

  await superdeno(app)
    .get('/')
    .expect(200)
    .then((response) => {
      console.log(response.headers)
    })

to return:

{
   "content-type": "application/json",
   "x-powered-by": "Opine"
}

instead of
{ "content-type": undefined }.

Full response:

Response {
  req: Test {
    _query: [],
    method: "GET",
    url: "http://127.0.0.1:38097/",
    header: {},
    _header: {},
    _callbacks: { "$end": [ [Function] ], "$abort": [ [Function] ] },
    app: [Function: app] {
      emit: [Function],
      ... (other methods)
      request: ServerRequest { app: [Circular] },
      response: Response { app: [Circular] },
      cache: {},
      engines: {},
      settings: {
        "x-powered-by": true,
        etag: "weak",
        "etag fn": [Function: generateETag],
        "query parser": "extended",
        "query parser fn": [Function: parseExtendedQueryString],
        "subdomain offset": 2,
        "trust proxy": false,
        "trust proxy fn": [Function: trustNone],
        view: [Function: View],
        views: "<my dir>/views",
        "jsonp callback name": "callback",
        "view cache": true
      },
      locals: { settings: [Object] },
      mountpath: "/",
      _router: [Function: router] {
        params: [Object],
        _params: [Array],
        caseSensitive: false,
        mergeParams: undefined,
        strict: false,
        stack: [Array]
      }
    },
    _maxRedirects: 0,
    _endCalled: true,
    _callback: [Function],
    xhr: XMLHttpRequestSham {
      id: "1",
      origin: "http://127.0.0.1:38097",
      onreadystatechange: [Function],
      readyState: 4,
      responseText: '{"data":"ok"}',
      responseType: "",
      response: '{"data":"ok"}',
      status: 200,
      statusCode: 200,
      statusText: "OK",
      aborted: false,
      options: {
        requestHeaders: [Object],
        method: "GET",
        url: "http://127.0.0.1:38097/",
        username: undefined,
        password: undefined,
        requestBody: null
      },
      controller: AbortController {},
      getAllResponseHeaders: [Function],
      getResponseHeader: [Function]
    },
    _fullfilledPromise: Promise { [Circular] }
  },
  xhr: XMLHttpRequestSham {
    id: "1",
    origin: "http://127.0.0.1:38097",
    onreadystatechange: [Function],
    readyState: 4,
    responseText: '{"data":"ok"}',
    responseType: "",
    response: '{"data":"ok"}',
    status: 200,
    statusCode: 200,
    statusText: "OK",
    aborted: false,
    options: {
      requestHeaders: {},
      method: "GET",
      url: "http://127.0.0.1:38097/",
      username: undefined,
      password: undefined,
      requestBody: null
    },
    controller: AbortController {},
    getAllResponseHeaders: [Function],
    getResponseHeader: [Function]
  },
  text: '{"data":"ok"}',
  statusText: "OK",
  statusCode: 200,
  status: 200,
  statusType: 2,
  info: false,
  ok: true,
  redirect: false,
  clientError: false,
  serverError: false,
  error: false,
  created: false,
  accepted: false,
  noContent: false,
  badRequest: false,
  unauthorized: false,
  notAcceptable: false,
  forbidden: false,
  notFound: false,
  unprocessableEntity: false,
  headers: { "content-type": undefined },
  header: { "content-type": undefined },
  type: "",
  links: {},
  body: null
}

Couldn't make `multipart/form-data` requests with oak.

Issue

Setup:

  • Deno Version: 1.15.3 (release, x86_64-apple-darwin)
  • v8 Version: 9.5.172.19
  • Typescript Version: 4.4.2
  • SuperDeno Version: 4.6.0
  • Oak Version: v9.0.1

Details

I'm using oak server. I tried the following code to test a multipart/form-data endpoint, didn't seem to work.
Both superoak and superdeno seemed not to work properly.

await req
    .post(url)
    .field('form_key', 'form_value')
    .attach('form_key2', 'path_to_file', 'filename');

I can only receive an empty body text/plain request.
I've also tried using superagent with jspm. Still not working. Maybe its because nodejs package having some bugs on deno by jspm.

[BUG] res.header vs res.headers typescript issues

Issue

Setup:

  • Deno Version: deno 1.5.4 (bc79d55, release, x86_64-apple-darwin)
  • v8 Version: v8 8.8.278.2
  • Typescript Version: typescript 4.0.5
  • SuperDeno Version: 2.4.0

Header(s) properties on res object parameter in .expect() seem off.

Details

In the latest version (and previous ones!) there appears to be res.header and res.headers properties on the res object provided to the callback of the .expect() API.

Both appear to have issues with the typings, resulting in needing (res as any) like workarounds.

I believe the bug lies in the line:

type ExpectChecker = (res: Response) => any;

Which should read:

type ExpectChecker = (res: IResponse) => any;

In order to use the superagent response object, and not the Deno Response object. The whole thing needs a look at though as the real shape of the res object doesn't quite match the IReponse object either... so this should be fixed up as well!


Ideally it should conform to, and be typed as, either:

Or... a combination of the above if there is no / sensible overlaps in expected types for named properties.

The Response object has properties:

{
  headers: Headers;
  ok: boolean;
  redirected: boolean;
  status: number;
  statusText: string;
  trailer: Promise<Headers>;
  type: ResponseType;
  url: string;
  body: ReadableStream<Uint8Array> | null;
  bodyUsed: boolean;
}

And the superagent response looks like:

{
  text: string;
  body: string;
  header: { [key: string]: string };
  type: string;
  charset: string;
  status: number;
  type: number;
  info: number;
  ok: number;
  clientError: number;
  serverError: number;
  error: number;
  accepted: number;
  noContent: number;
  badRequest: number;
  unauthorized: number;
  notAcceptable: number;
  notFound: number;
  forbidden: number;
  ...
}

Expected "Hello World" response body, got "HTTP/1.1 20"

Issue

I get this error when I'm asserting a response body. For some reason it asserts with a raw HTTP response:

res.format(obj) > should send text by default
Error: expected "Hello World" response body, got "HTTP/1.1 20"
    at error (https://deno.land/x/[email protected]/src/test.ts:637:15)
    at Test.#assertBody (https://deno.land/x/[email protected]/src/test.ts:535:16)
    at Test.#assertFunction (https://deno.land/x/[email protected]/src/test.ts:617:13)
    at Test.#assert (https://deno.land/x/[email protected]/src/test.ts:480:35)
    at https://deno.land/x/[email protected]/src/test.ts:455:23
    at async close (https://deno.land/x/[email protected]/src/close.ts:48:46)

failures:

        res.format(obj) > should send text by default

test result: FAILED. 121 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (4184ms)

Setup:

deno 1.12.0 (release, x86_64-unknown-linux-gnu)
v8 9.2.230.14
typescript 4.3.2

  • SuperDeno Version: 4.4.0

Details

import { describe, it, run } from 'https://deno.land/x/[email protected]/mod.ts'
import { App, Handler, AppConstructor, Request, Response } from 'https://deno.land/x/tinyhttp/mod.ts'

const runServer = (h: Handler) => {
  const app = new App()

  app.use(h)

  const request = superdeno(app.attach)

  return request
}


it('should send text by default', async () => {
    const request = runServer((req, res) => {
      formatResponse(req, res, () => {})({
        text: (req: Request) => req.respond({ body: `Hello World` })
      }).end()
    })

    await request.get('/').expect(200).expect('Hello World')
  })

Can this be used with `express`?

Issue

Really a question, but with Opine being in maintenance mode, I tried the recommendation of using express on Deno.

I tried using superdeno to test routes, but when I run the test, the tests fails and then just hangs the process.

Steps to reproduce:

Run this using deno test:

// @deno-types="npm:@types/express@^4.17"
import express from "npm:[email protected]";
import { superdeno } from "https://deno.land/x/[email protected]/mod.ts";

const app = express();

app.get("/", (_req, res) => res.json("hello express"));

Deno.test("mod", async () => {
  await superdeno(app).get("/").expect("hello express").end();
});

I also tried using npm:supertest but that doesn't seem to work with npm:express on Deno either ๐Ÿคท .

I guess am not sure what the expectation is (pun unintended) for testing express apps on top of deno. Should I be spinning the app up and down in tests, and then manually calling with fetch?

Setup:

deno 1.31.1 (release, x86_64-unknown-linux-gnu)
v8 11.0.226.13
typescript 4.9.4

SuperDeno Version: 4.8.0

Details

Besides Opine being in maintenance mode, the hard impetus for trying out express on Deno was because my tests started to fail using superdeno and opine together. The tests seem to run, but then an error is thrown after each file is executed by Deno:

error: TypeError: core.runMicrotasks is not a function
    core.runMicrotasks();
         ^
    at processTicksAndRejections (https://deno.land/[email protected]/node/_next_tick.ts:62:10)
    at https://deno.land/[email protected]/node/process.ts:312:7

With some digging, it seems that opine is importing theses deps from std, and those deps are using an api removed in later versions of deno, which is causing an error to be thrown on beforeunload.

Don't know if this should be an issue on opine, but it seems opine cannot be used inside of Deno.test.

Error: Request has been terminated for native http server

Issue

Setup:

  • Deno Version: 1.15.2
  • v8 Version: 9.5.172.19
  • Typescript Version: 4.4.2
  • SuperDeno Version: 4.6.0

Details

import { superdeno } from 'https://deno.land/x/[email protected]/mod.ts'
import { it, run } from 'https://deno.land/x/[email protected]/mod.ts'
import { App } from 'https://denopkg.com/deno-libs/tinyhttp@new-std-http/mod.ts'

it('simple test', async () => {
  const app = new App()

  const request = superdeno(app._server!) // or `app.handler`, it doesn't work either way

  await request.get('/').expect(404, 'Not Found')
})

run()

Error message:

Error: Request has been terminated
Possible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.
    at Test.Request.crossDomainError (https://jspm.dev/npm:[email protected]!cjs:674:13)
    at XMLHttpRequestSham.xhr.onreadystatechange (https://jspm.dev/npm:[email protected]!cjs:777:19)
    at XMLHttpRequestSham.xhrReceive (https://deno.land/x/[email protected]/src/xhrSham.js:115:29)
    at https://deno.land/x/[email protected]/src/xhrSham.js:62:21
    at Object.xhr.onreadystatechange (https://deno.land/x/[email protected]/src/xhrSham.js:211:7)
    at XMLHttpRequestSham.xhrSend (https://deno.land/x/[email protected]/src/xhrSham.js:335:20)
    at async XMLHttpRequestSham.send (https://deno.land/x/[email protected]/src/xhrSham.js:61:7)

Question: testing if header doesn't exist

Issue

Setup:

deno 1.12.0 (release, x86_64-unknown-linux-gnu)
v8 9.2.230.14
typescript 4.3.2

  • SuperDeno Version: 4.4.0

Details

At the moment this:

import { superdeno } from 'https://deno.land/x/[email protected]/mod.ts'
import { App } from 'https://deno.land/x/tinyhttp/mod.ts'
import { describe, it, expect, run } from 'https://deno.land/x/[email protected]/mod.ts'

describe('App settings', () => {
it('when disabled should not send anything', async () => {

const app = new App({ settings: { xPoweredBy: false } })

    app.use((_req, res) => void res.send('hi'))

    const request = superdeno(app.attach)

    await request.get('/').expect('X-Powered-By', null)

})
})

run()

results in this:

Error: expected "X-Powered-By" header field
    at Test.#assertHeader (https://deno.land/x/[email protected]/src/test.ts:562:14)
    at Test.#assertFunction (https://deno.land/x/[email protected]/src/test.ts:617:13)
    at Test.#assert (https://deno.land/x/[email protected]/src/test.ts:480:35)
    at https://deno.land/x/[email protected]/src/test.ts:455:23
    at async close (https://deno.land/x/[email protected]/src/close.ts:48:46)

failures:

        App settings > xPoweredBy > when disabled should not send anything

test result: FAILED. 101 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (2657ms)

What's the proper way to test for absence of a header?

Getting async leaking error when testing opine v2

Issue: Getting async leaking error when testing opine v2

Setup:

  • Deno Version: 1.16.4
  • v8 Version: 9.7.16.15
  • Typescript Version: 4.4.2
  • SuperDeno Version: 4.7.1

Details

When running a simple test with [email protected] Deno Test Assertions return AssertionError: Test case is leaking async ops. - there are no async's in the example code which is pasted below.

server.ts

import { opine } from 'https://deno.land/x/[email protected]/mod.ts'


export function build() {

 const app = opine();

  app.get('/', function (req, res) {
    res.send('Hello World')
  })

  return app
}

test.ts

import {superdeno} from 'https://deno.land/x/[email protected]/mod.ts'
import { build } from './server.ts'
const app = build()

Deno.test('hello world', () => {
  superdeno(app)
    .get('/')
    .expect(200)
})

Run

deno test -A --unstable test.ts

Output

running 1 test from file:///workspace/deno-playground/test.ts
test hello world ... FAILED (12ms)

failures:

hello world
AssertionError: Test case is leaking async ops.
Before:
  - dispatched: 0
  - completed: 0
After:
  - dispatched: 2
  - completed: 1
Ops:
  op_net_accept:
    Before:
      - dispatched: 0
      - completed: 0
    After:
      - dispatched: 1
      - completed: 0

Make sure to await all promises returned from Deno APIs before
finishing test case.
    at assert (deno:runtime/js/06_util.js:41:13)
    at asyncOpSanitizer (deno:runtime/js/40_testing.js:128:7)
    at async resourceSanitizer (deno:runtime/js/40_testing.js:144:7)
    at async Object.exitSanitizer [as fn] (deno:runtime/js/40_testing.js:176:9)
    at async runTest (deno:runtime/js/40_testing.js:381:7)
    at async Object.runTests (deno:runtime/js/40_testing.js:494:22)

failures:

        hello world

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (147ms)

error: Test failed

[BUG] Error thrown on empty body responses (e.g. 304)

Issue

Setup:

  • Deno Version: 1.3.1
  • v8 Version: 8.6.334
  • Typescript Version: 3.9.7
  • SuperDeno Version: 2.2.0

Seeing 304 Not Modified responses with empty (no) body result in an error thrown by SuperDeno.

error: Uncaught Error: Request has been terminated
Possible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.
    at Test.Request.crossDomainError (https://dev.jspm.io/npm:[email protected]/lib/client.dew.js:680:15)
    at XMLHttpRequestSham.xhr.onreadystatechange (https://dev.jspm.io/npm:[email protected]/lib/client.dew.js:783:21)
    at XMLHttpRequestSham.xhrReceive (https://deno.land/x/[email protected]/src/xhrSham.js:105:29)
    at XMLHttpRequestSham.send (https://deno.land/x/[email protected]/src/xhrSham.js:64:12)

Details

Adding some logs in the xhrSham we can see that (xhrSham.js:293:34):

...

window._xhrSham.promises[self.id] = fetch(options.url, {
  method: options.method,
  headers: options.requestHeaders,
  body,
  signal: this.controller.signal,
  mode: "cors",
});

// Wait on the response, and then read the buffer.
response = await window._xhrSham.promises[self.id];

...

const buf = await response.arrayBuffer();
parsedResponse = decoder.decode(buf); // BOOM!

...

Is throwing:

err: TypeError: Cannot use 'in' operator to search for 'buffer' in null
    at TextDecoder.decode (/Users/runner/work/deno/deno/op_crates/web/08_text_encoding.js:445:18)
    at XMLHttpRequestSham.xhrSend (https://deno.land/x/[email protected]/src/xhrSham.js:293:34)
    at async XMLHttpRequestSham.send (https://deno.land/x/[email protected]/src/xhrSham.js:51:7)

This doesn't occur in Deno 1.3.0, so assume introduced by one of the changes to Deno core in 1.3.1, see the release notes: https://github.com/denoland/deno/releases/tag/v1.3.1

08_text_encoding line ref: https://github.com/denoland/deno/blob/master/op_crates/web/08_text_encoding.js#L445

Reproducing we can see we get the error with:

const decoder = new TextDecoder("utf-8");
const buf = null;
const decoded = decoder.decode(buf as any);

It would seem that response.arrayBuffer() in Deno 1.3.0 returned "" for a null body whereas no it returns null which causes the error in the decoder as it has no null protection.

We can protect against this in SuperDeno by adding our own null check around the decoder.

4xx response body is null

Issue

Setup:

  • deno 1.0.5
  • v8 8.4.300
  • typescript 3.9.2

4xx response body is null, even though there is a response body.

Details

I want to test the custom response body, but there is nothing in res body.

By the way, when responding 4xx, superdeno also throws error which is different from supertest, which is annoying.

4xx and 5xx response missing body and text

Issue

Setup:

  • deno 1.0.5
  • v8 8.4.300
  • typescript 3.9.2

When server response 4xx or 5xx, superdeno's response doesn't have body or text, so there is no way to test the HTTP body part.

import {
  Application,
} from "https://deno.land/x/ako/mod.ts";
import { superdeno } from "https://deno.land/x/[email protected]/mod.ts";
import { describe, it } from "https://deno.land/x/[email protected]/test/utils.ts";

describe("ctx.onerror(err)", () => {
  it("should respond", async () => {
    const app = new Application();

    app.use((ctx, next) => {
      ctx.body = "something else";

      ctx.throw(418, "boom");
    });

    const res = await superdeno(app.listen())
      .head("/")
      .expect(418)
      .expect("Content-Length", "4")
      .expect("Content-Type", "text/plain; charset=utf-8");
    console.log(res);

    // res.body is null
    // res.text is null
  });
});

curl:

curl -i  127.0.0.1:5000
HTTP/1.1 418 I'm a teapot
content-length: 4
content-type: text/plain; charset=utf-8

boom% 

Attach is possibly not sending the actual file to the app

Issue

Setup:

  • Deno Version: 1.18.0
  • v8 Version: 9.8.177.6
  • Typescript Version: 4.5.2
  • SuperDeno Version: 4.8.0

Details

When using the .attach method on a request.post the body.value.read(), appears to be returning undefined for files. I am not sure what the reason for this might be, I have created a test-case showcasing the problem and can create a PR for the same if required. test case file

Support new [email protected]/http API

Issue

Setup:

  • Deno Version: 1.14.0
  • v8 Version: 9.4.146.15
  • Typescript Version: 4.4.2
  • SuperDeno Version: 4.4

Details

With new std/http superdeno doesn't work anymore. superdeno should support new API and deprecate the old one

Submitting a payload with a get request results in request termination error

image

Issue

Submitting a payload with a get request results in request termination error

Setup:

  • Deno Version: 1.1.3
  • v8 Version: 8.5.216
  • Typescript Version: 3.9.2
  • SuperDeno Version: 1.5.1

Please replace this line with a short description of the issue.

Details

        await superdeno("http://localhost:8080/api")
        .get("/endpoint/")
        .send({
            "name": "asset X",
            "thingType": "truck-asset-type"
        })
       .expect(200);

results in the error above. It seems like superdeno doesn't support sending payloads with a get request?

Submitting a payload with a GET request is appropriate in this case as there'll be no side effect to the API. The body is essentially a DSL to help filter the response.

How does superdeno intercept redirects?

Is there a way to test for redirects?

When I do something along the lines of:

    await superdeno(testApiUrl)
    .post('/api/to/endpoint/that/triggers/a/redirect')
    .expect((response, error) => {
       assertEquals(response.status, 302);
        assertEquals(response.headers.includes('location: http://google.com/'), true);
    });

This errors out and insists that the final state is 200, not 302.

I've noticed that the response.headers capture those of the final destination page rather than the actual API redirect state. Is there a way to go one step before the final destination URL?

I have also tried

    await superdeno(testApiUrl)
    .post('/api/to/endpoint/that/triggers/a/redirect')
    .expect(302)
    .expect((response, error) => {
        assertEquals(response.headers.includes('location: http://google.com/'), true);
    });

but to no effect.

Thanks heaps (again great library).

[CHORE] Use Deno's inspect instead of one from NPM

Issue

I noticed that an NPM library was being used to provide node's util functionality, which brings in a total of 16 NPM packages. (22 vs 6 going by the badges that were just added ๐Ÿ˜„ )

It seems like this import is easily avoided by leveraging Deno's std library.

Details

After searching the codebase I determined that the util import from NPM was only being used to polyfill util.inspect() for error messages. I've prepared a patchset that removes the util NPM package in favor of Deno.inspect: main...danopia:use-deno-inspect

Going by the test suite, the only difference I observed was that Deno.inspect uses different quoting rules than the util.inspect from NPM. So I had to adjust some quotes in the test suite. I suppose it's possible that consumers are testing for exact messages too but overall the change doesn't seem very disruptive to me.

I also have a mutually exclusive patchset that uses Deno's /std/node polyfile for util.inspect but it doesn't seem to give anything over using Deno.inspect directly. Here it is anyway: main...danopia:use-std-util

I'm prepared to open a PR with either patchset if this looks agreeable.

Here's the before / after of the package dependency tree:

Screenshot 2021-02-10 at 20 21 54
Screenshot 2021-02-10 at 21 00 57

Release 1.5 causing an error on download

Issue

image

Setup:

  • Deno Version: 1.1.2
  • v8 Version: 8.5.216
  • Typescript Version: 3.9.2
  • SuperDeno Version: 1.5.0

I got the error in the screenshot above on first run (I upgraded from 1.2.1 to 1.5.0). There are actually two (first being a warning re the module implicitly referencing Deno master) and the second being the main blocker:

error: TS2305 [ERROR]: Module '"./_utils"' has no exported member 'normalizeEncoding'.
import { notImplemented, normalizeEncoding } from "./_utils.ts";

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.