Skip to content

Commit

Permalink
Merge branch 'master' into pr-389
Browse files Browse the repository at this point in the history
# Conflicts:
#	package.json
  • Loading branch information
jaydenseric committed Oct 1, 2024
2 parents c7d394b + 69b9c85 commit 6375ebd
Show file tree
Hide file tree
Showing 11 changed files with 643 additions and 721 deletions.
80 changes: 40 additions & 40 deletions GraphQLUpload.test.mjs
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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.
});
},
);
3 changes: 2 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

### Major

- Updated Node.js support to `^18.15.0 || >=20.4.0`.
- Updated Node.js support to `^18.18.0 || ^20.9.0 || >=22.0.0`.
- 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).

### Minor

Expand Down
120 changes: 57 additions & 63 deletions graphqlUploadExpress.test.mjs
Original file line number Diff line number Diff line change
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();
}
},
);
};
});
},
);
Loading

0 comments on commit 6375ebd

Please sign in to comment.