Skip to content

Commit

Permalink
Use the Node.js test runner API and remove the dev dependency `test-d…
Browse files Browse the repository at this point in the history
…irector`.
  • Loading branch information
jaydenseric committed Aug 27, 2023
1 parent f24d71b commit 3b7f034
Show file tree
Hide file tree
Showing 9 changed files with 638 additions and 713 deletions.
80 changes: 40 additions & 40 deletions GraphQLUpload.test.mjs
@@ -1,26 +1,26 @@
// @ts-check

import { doesNotThrow, throws } from "node:assert";
import { describe, it } from "node:test";

import { parseValue } from "graphql";

import GraphQLUpload from "./GraphQLUpload.mjs";
import Upload from "./Upload.mjs";

/**
* Adds `GraphQLUpload` tests.
* @param {import("test-director").default} tests Test director.
*/
export default (tests) => {
tests.add("`GraphQLUpload` scalar `parseValue` with a valid value.", () => {
doesNotThrow(() => {
GraphQLUpload.parseValue(new Upload());
describe(
"GraphQL scalar `GraphQLUpload`.",
{
concurrency: true,
},
() => {
it("Method `parseValue`, value valid.", () => {
doesNotThrow(() => {
GraphQLUpload.parseValue(new Upload());
});
});
});

tests.add(
"`GraphQLUpload` scalar `parseValue` with an invalid value.",
() => {
it("Method `parseValue`, value invalid.", () => {
throws(
() => {
GraphQLUpload.parseValue(true);
Expand All @@ -30,33 +30,33 @@ export default (tests) => {
message: "Upload value invalid.",
},
);
},
);
});

tests.add("`GraphQLUpload` scalar `parseLiteral`.", () => {
throws(
() => {
// The dummy value is irrelevant.
GraphQLUpload.parseLiteral(parseValue('""'));
},
{
name: "GraphQLError",
message: "Upload literal unsupported.",
locations: [{ line: 1, column: 1 }],
},
);
});
it("Method `parseLiteral`.", () => {
throws(
() => {
// The dummy value is irrelevant.
GraphQLUpload.parseLiteral(parseValue('""'));
},
{
name: "GraphQLError",
message: "Upload literal unsupported.",
locations: [{ line: 1, column: 1 }],
},
);
});

tests.add("`GraphQLUpload` scalar `serialize`.", () => {
throws(
() => {
// The dummy value is irrelevant.
GraphQLUpload.serialize("");
},
{
name: "GraphQLError",
message: "Upload serialization unsupported.",
},
);
});
};
it("Method `serialize`.", () => {
throws(
() => {
// The dummy value is irrelevant.
GraphQLUpload.serialize("");
},
{
name: "GraphQLError",
message: "Upload serialization unsupported.",
},
);
});
},
);
79 changes: 41 additions & 38 deletions Upload.test.mjs
@@ -1,59 +1,62 @@
// @ts-check

import { ok, rejects, strictEqual } from "node:assert";
import { describe, it } from "node:test";

import Upload from "./Upload.mjs";

/**
* Adds `Upload` tests.
* @param {import("test-director").default} tests Test director.
*/
export default (tests) => {
tests.add("`Upload` class resolving a file.", async () => {
const upload = new Upload();
describe(
"Class `Upload`.",
{
concurrency: true,
},
() => {
it("Resolving a file.", async () => {
const upload = new Upload();

ok(upload.promise instanceof Promise);
strictEqual(typeof upload.resolve, "function");
ok(upload.promise instanceof Promise);
strictEqual(typeof upload.resolve, "function");

/** @type {any} */
const file = {};
/** @type {any} */
const file = {};

upload.resolve(file);
upload.resolve(file);

const resolved = await upload.promise;
const resolved = await upload.promise;

strictEqual(resolved, file);
strictEqual(upload.file, file);
});
strictEqual(resolved, file);
strictEqual(upload.file, file);
});

tests.add("`Upload` class with a handled rejection.", async () => {
const upload = new Upload();
it("Handled rejection.", async () => {
const upload = new Upload();

ok(upload.promise instanceof Promise);
strictEqual(typeof upload.reject, "function");
ok(upload.promise instanceof Promise);
strictEqual(typeof upload.reject, "function");

const error = new Error("Message.");
const error = new Error("Message.");

upload.reject(error);
upload.reject(error);

// This is the safe way to check the promise status, see:
// https://github.com/nodejs/node/issues/31392#issuecomment-575451230
await rejects(Promise.race([upload.promise, Promise.resolve()]), error);
});
// This is the safe way to check the promise status, see:
// https://github.com/nodejs/node/issues/31392#issuecomment-575451230
await rejects(Promise.race([upload.promise, Promise.resolve()]), error);
});

tests.add("`Upload` class with an unhandled rejection.", async () => {
const upload = new Upload();
it("Unhandled rejection.", async () => {
const upload = new Upload();

ok(upload.promise instanceof Promise);
strictEqual(typeof upload.reject, "function");
ok(upload.promise instanceof Promise);
strictEqual(typeof upload.reject, "function");

const error = new Error("Message.");
const error = new Error("Message.");

upload.reject(error);
upload.reject(error);

// Node.js CLI flag `--unhandled-rejections=throw` must be used when these
// tests are run with Node.js v14 (it’s unnecessary for Node.js v15+) or the
// process won’t exit with an error if the unhandled rejection is’t silenced
// as intended.
});
};
// Node.js CLI flag `--unhandled-rejections=throw` must be used when these
// tests are run with Node.js v14 (it’s unnecessary for Node.js v15+) or
// the process won’t exit with an error if the unhandled rejection is’t
// silenced as intended.
});
},
);
1 change: 1 addition & 0 deletions changelog.md
Expand Up @@ -8,6 +8,7 @@
- Updated dev dependencies, some of which require newer Node.js versions than previously supported.
- Refactored tests to use the standard `AbortController`, `fetch`, `File`, and `FormData` APIs available in modern Node.js and removed the dev dependencies [`node-abort-controller`](https://npm.im/node-abort-controller) and [`node-fetch`](https://npm.im/node-fetch).
- Replaced the test utility function `streamToString` with the function `text` from `node:stream/consumers` that’s available in modern Node.js.
- Use the Node.js test runner API and remove the dev dependency [`test-director`](https://npm.im/test-director).

### Patch

Expand Down
120 changes: 57 additions & 63 deletions graphqlUploadExpress.test.mjs
Expand Up @@ -4,6 +4,7 @@ import "./test/polyfillFile.mjs";

import { deepStrictEqual, ok, strictEqual } from "node:assert";
import { createServer } from "node:http";
import { describe, it } from "node:test";

import express from "express";
import createError from "http-errors";
Expand All @@ -12,14 +13,13 @@ import graphqlUploadExpress from "./graphqlUploadExpress.mjs";
import processRequest from "./processRequest.mjs";
import listen from "./test/listen.mjs";

/**
* Adds `graphqlUploadExpress` tests.
* @param {import("test-director").default} tests Test director.
*/
export default (tests) => {
tests.add(
"`graphqlUploadExpress` with a non multipart request.",
async () => {
describe(
"Function `graphqlUploadExpress`.",
{
concurrency: true,
},
() => {
it("Non multipart request.", async () => {
let processRequestRan = false;

const app = express().use(
Expand All @@ -39,48 +39,48 @@ export default (tests) => {
} finally {
close();
}
},
);

tests.add("`graphqlUploadExpress` with a multipart request.", async () => {
/**
* @type {{
* variables: {
* file: import("./Upload.mjs").default,
* },
* } | undefined}
*/
let requestBody;

const app = express()
.use(graphqlUploadExpress())
.use((request, response, next) => {
requestBody = request.body;
next();
});

const { port, close } = await listen(createServer(app));

try {
const body = new FormData();

body.append("operations", JSON.stringify({ variables: { file: null } }));
body.append("map", JSON.stringify({ 1: ["variables.file"] }));
body.append("1", new File(["a"], "a.txt", { type: "text/plain" }));

await fetch(`http://localhost:${port}`, { method: "POST", body });

ok(requestBody);
ok(requestBody.variables);
ok(requestBody.variables.file);
} finally {
close();
}
});

tests.add(
"`graphqlUploadExpress` with a multipart request and option `processRequest`.",
async () => {
});

it("Multipart request.", async () => {
/**
* @type {{
* variables: {
* file: import("./Upload.mjs").default,
* },
* } | undefined}
*/
let requestBody;

const app = express()
.use(graphqlUploadExpress())
.use((request, response, next) => {
requestBody = request.body;
next();
});

const { port, close } = await listen(createServer(app));

try {
const body = new FormData();

body.append(
"operations",
JSON.stringify({ variables: { file: null } }),
);
body.append("map", JSON.stringify({ 1: ["variables.file"] }));
body.append("1", new File(["a"], "a.txt", { type: "text/plain" }));

await fetch(`http://localhost:${port}`, { method: "POST", body });

ok(requestBody);
ok(requestBody.variables);
ok(requestBody.variables.file);
} finally {
close();
}
});

it("Multipart request and option `processRequest`.", async () => {
let processRequestRan = false;

/**
Expand Down Expand Up @@ -127,12 +127,9 @@ export default (tests) => {
} finally {
close();
}
},
);
});

tests.add(
"`graphqlUploadExpress` with a multipart request and option `processRequest` throwing an exposed HTTP error.",
async () => {
it("Multipart request and option `processRequest` throwing an exposed HTTP error.", async () => {
let expressError;
let requestCompleted;
let responseStatusCode;
Expand Down Expand Up @@ -201,12 +198,9 @@ export default (tests) => {
} finally {
close();
}
},
);
});

tests.add(
"`graphqlUploadExpress` with a multipart request following middleware throwing an error.",
async () => {
it("Multipart request following middleware throwing an error.", async () => {
let expressError;
let requestCompleted;

Expand Down Expand Up @@ -268,6 +262,6 @@ export default (tests) => {
} finally {
close();
}
},
);
};
});
},
);

0 comments on commit 3b7f034

Please sign in to comment.