2021-12-17 00:17:02 +00:00
|
|
|
import {execa} from "execa";
|
2021-04-20 18:48:48 +00:00
|
|
|
import restana from "restana";
|
2022-12-09 11:46:05 +00:00
|
|
|
import {join, dirname} from "node:path";
|
|
|
|
import {readFileSync, mkdtempSync} from "node:fs";
|
|
|
|
import {writeFile, readFile, rm} from "node:fs/promises";
|
|
|
|
import {fileURLToPath} from "node:url";
|
|
|
|
import {tmpdir} from "node:os";
|
2023-06-17 21:51:04 +00:00
|
|
|
import {env} from "node:process";
|
2024-05-23 21:53:45 +00:00
|
|
|
import type {Server} from "node:http";
|
|
|
|
import type {Service, Protocol} from "restana";
|
2019-01-19 19:05:26 +00:00
|
|
|
|
2023-09-04 23:00:06 +00:00
|
|
|
const testFile = fileURLToPath(new URL("fixtures/npm-test/package.json", import.meta.url));
|
|
|
|
const emptyFile = fileURLToPath(new URL("fixtures/npm-empty/package.json", import.meta.url));
|
2023-09-04 23:03:57 +00:00
|
|
|
const poetryFile = fileURLToPath(new URL("fixtures/poetry/pyproject.toml", import.meta.url));
|
|
|
|
const dualFile = fileURLToPath(new URL("fixtures/dual", import.meta.url));
|
|
|
|
|
2021-04-20 18:48:48 +00:00
|
|
|
const testPkg = JSON.parse(readFileSync(testFile, "utf8"));
|
2022-10-26 13:23:15 +00:00
|
|
|
const testDir = mkdtempSync(join(tmpdir(), "updates-"));
|
2024-05-23 21:53:45 +00:00
|
|
|
const script = fileURLToPath(new URL("dist/index.js", import.meta.url));
|
2019-12-18 17:19:05 +00:00
|
|
|
|
2020-03-08 09:56:31 +00:00
|
|
|
const dependencyTypes = [
|
|
|
|
"dependencies",
|
|
|
|
"devDependencies",
|
|
|
|
"peerDependencies",
|
|
|
|
"optionalDependencies",
|
2020-10-21 18:22:26 +00:00
|
|
|
"resolutions",
|
2020-03-08 09:23:44 +00:00
|
|
|
];
|
2019-12-18 17:19:05 +00:00
|
|
|
|
2024-05-23 21:53:45 +00:00
|
|
|
const testPackages: Set<string> = new Set();
|
2020-03-08 09:56:31 +00:00
|
|
|
for (const dependencyType of dependencyTypes) {
|
2020-07-14 22:01:04 +00:00
|
|
|
for (const name of Object.keys(testPkg[dependencyType] || [])) {
|
2020-03-15 00:14:12 +00:00
|
|
|
testPackages.add(name);
|
2020-03-08 09:56:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-22 23:45:10 +00:00
|
|
|
const pyTestPackages = new Set(["djlint", "PyYAML"]);
|
|
|
|
|
2024-05-23 21:53:45 +00:00
|
|
|
function makeUrl(server: Server) {
|
|
|
|
const {port}: any = server.address();
|
2020-10-21 18:22:26 +00:00
|
|
|
return Object.assign(new URL("http://localhost"), {port}).toString();
|
2020-04-18 12:54:05 +00:00
|
|
|
}
|
|
|
|
|
2024-05-23 21:53:45 +00:00
|
|
|
function defaultRoute(req: any, res: any) {
|
2020-07-21 18:38:38 +00:00
|
|
|
console.error(`default handler hit for ${req.url}`);
|
|
|
|
res.send(404);
|
|
|
|
}
|
|
|
|
|
2024-05-23 21:53:45 +00:00
|
|
|
function resolutionsBasePackage(name: string) {
|
2020-10-21 18:22:26 +00:00
|
|
|
const packages = name.match(/(@[^/]+\/)?([^/]+)/g) || [];
|
|
|
|
return packages[packages.length - 1];
|
|
|
|
}
|
|
|
|
|
2024-05-23 21:53:45 +00:00
|
|
|
let npmServer: Service<Protocol.HTTP> | Server;
|
|
|
|
let githubServer: Service<Protocol.HTTP> | Server;
|
|
|
|
let pypiServer: Service<Protocol.HTTP> | Server;
|
|
|
|
|
|
|
|
let githubUrl: string;
|
|
|
|
let pypiUrl: string;
|
|
|
|
let npmUrl: string;
|
|
|
|
|
2020-03-08 09:23:44 +00:00
|
|
|
beforeAll(async () => {
|
2023-06-22 23:45:10 +00:00
|
|
|
let commits, tags;
|
2020-03-09 22:57:04 +00:00
|
|
|
|
2023-06-22 23:45:10 +00:00
|
|
|
[npmServer, githubServer, pypiServer, commits, tags] = await Promise.all([
|
2023-06-17 22:01:55 +00:00
|
|
|
restana({defaultRoute}),
|
2020-07-21 18:38:38 +00:00
|
|
|
restana({defaultRoute}),
|
|
|
|
restana({defaultRoute}),
|
2022-10-26 13:48:08 +00:00
|
|
|
readFile(fileURLToPath(new URL("fixtures/github/updates-commits.json", import.meta.url))),
|
|
|
|
readFile(fileURLToPath(new URL("fixtures/github/updates-tags.json", import.meta.url))),
|
2020-03-09 22:57:04 +00:00
|
|
|
]);
|
2020-03-08 19:04:37 +00:00
|
|
|
|
2020-10-21 18:22:26 +00:00
|
|
|
for (const pkgName of testPackages) {
|
|
|
|
const name = testPkg.resolutions[pkgName] ? resolutionsBasePackage(pkgName) : pkgName;
|
|
|
|
const urlName = name.replace(/\//g, "%2f");
|
2022-10-26 13:48:08 +00:00
|
|
|
// can not use file URLs because node stupidely throws on "%2f" in paths.
|
|
|
|
const path = join(dirname(fileURLToPath(import.meta.url)), `fixtures/npm/${urlName}.json`);
|
2020-10-21 18:22:26 +00:00
|
|
|
npmServer.get(`/${urlName}`, async (_, res) => res.send(await readFile(path)));
|
2019-12-18 17:19:05 +00:00
|
|
|
}
|
|
|
|
|
2023-06-22 23:45:10 +00:00
|
|
|
for (const pkgName of pyTestPackages) {
|
|
|
|
const path = join(dirname(fileURLToPath(import.meta.url)), `fixtures/pypi/${pkgName}.json`);
|
|
|
|
pypiServer.get(`/pypi/${pkgName}/json`, async (_, res) => res.send(await readFile(path)));
|
|
|
|
}
|
|
|
|
|
2020-07-21 18:54:05 +00:00
|
|
|
githubServer.get("/repos/silverwind/updates/commits", (_, res) => res.send(commits));
|
|
|
|
githubServer.get("/repos/silverwind/updates/git/refs/tags", (_, res) => res.send(tags));
|
2020-03-15 00:14:12 +00:00
|
|
|
|
2023-06-17 22:01:55 +00:00
|
|
|
[githubServer, pypiServer, npmServer] = await Promise.all([
|
2020-04-18 12:54:05 +00:00
|
|
|
githubServer.start(0),
|
2023-06-17 22:01:55 +00:00
|
|
|
pypiServer.start(0),
|
2020-04-18 12:54:05 +00:00
|
|
|
npmServer.start(0),
|
2020-03-15 00:14:12 +00:00
|
|
|
]);
|
2020-03-08 18:12:16 +00:00
|
|
|
|
2020-04-18 12:54:05 +00:00
|
|
|
githubUrl = makeUrl(githubServer);
|
|
|
|
npmUrl = makeUrl(npmServer);
|
2023-06-17 22:01:55 +00:00
|
|
|
pypiUrl = makeUrl(pypiServer);
|
2020-04-18 12:54:05 +00:00
|
|
|
|
2020-03-15 00:14:12 +00:00
|
|
|
await writeFile(join(testDir, ".npmrc"), `registry=${npmUrl}`); // Fake registry
|
2020-07-14 22:01:04 +00:00
|
|
|
await writeFile(join(testDir, "package.json"), JSON.stringify(testPkg, null, 2)); // Copy fixture
|
2020-03-08 09:23:44 +00:00
|
|
|
});
|
2019-12-18 17:19:05 +00:00
|
|
|
|
2020-03-08 09:23:44 +00:00
|
|
|
afterAll(async () => {
|
2020-03-08 18:12:16 +00:00
|
|
|
await Promise.all([
|
2022-11-23 20:45:54 +00:00
|
|
|
rm(testDir, {recursive: true}),
|
2022-10-26 13:23:15 +00:00
|
|
|
npmServer?.close(),
|
|
|
|
githubServer?.close(),
|
2020-03-08 18:12:16 +00:00
|
|
|
]);
|
2020-03-08 09:23:44 +00:00
|
|
|
});
|
2019-01-19 19:05:26 +00:00
|
|
|
|
2024-05-23 21:53:45 +00:00
|
|
|
function makeTest(args: string) {
|
2020-03-08 09:23:44 +00:00
|
|
|
return async () => {
|
2023-06-17 22:01:55 +00:00
|
|
|
const argsArr = [
|
|
|
|
...args.split(/\s+/), "-c",
|
|
|
|
"--githubapi", githubUrl,
|
|
|
|
"--pypiapi", pypiUrl,
|
|
|
|
];
|
2020-07-14 22:01:04 +00:00
|
|
|
const {stdout} = await execa(script, argsArr, {cwd: testDir});
|
2020-03-08 16:06:58 +00:00
|
|
|
const {results} = JSON.parse(stdout);
|
2020-03-08 16:44:04 +00:00
|
|
|
|
|
|
|
// Parse results, with custom validation for the dynamic "age" property
|
2023-09-05 22:48:25 +00:00
|
|
|
for (const mode of Object.keys(results || {})) {
|
|
|
|
for (const dependencyType of [
|
|
|
|
...dependencyTypes,
|
|
|
|
"tool.poetry.dependencies",
|
|
|
|
"tool.poetry.dev-dependencies",
|
|
|
|
"tool.poetry.test-dependencies",
|
|
|
|
"tool.poetry.group.dev.dependencies",
|
|
|
|
"tool.poetry.group.test.dependencies",
|
|
|
|
]) {
|
|
|
|
for (const name of Object.keys(results?.[mode]?.[dependencyType] || {})) {
|
|
|
|
delete results[mode][dependencyType][name].age;
|
|
|
|
}
|
2020-03-08 16:06:58 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-10 21:02:48 +00:00
|
|
|
|
2023-06-17 21:51:04 +00:00
|
|
|
expect(results).toMatchSnapshot();
|
2020-03-08 09:23:44 +00:00
|
|
|
};
|
2019-01-19 19:05:26 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 22:01:04 +00:00
|
|
|
test("simple", async () => {
|
2023-06-17 22:01:55 +00:00
|
|
|
const {stdout, stderr, exitCode} = await execa(script, [
|
|
|
|
"-C",
|
|
|
|
"--githubapi", githubUrl,
|
|
|
|
"--pypiapi", pypiUrl,
|
2023-06-18 10:00:00 +00:00
|
|
|
"--registry", npmUrl,
|
2023-06-17 22:01:55 +00:00
|
|
|
"-f", testFile,
|
|
|
|
]);
|
2020-07-14 22:01:04 +00:00
|
|
|
expect(stderr).toEqual("");
|
2022-10-17 21:36:44 +00:00
|
|
|
expect(stdout).toContain("prismjs");
|
|
|
|
expect(stdout).toContain("https://github.com/silverwind/updates");
|
2020-07-14 22:01:04 +00:00
|
|
|
expect(exitCode).toEqual(0);
|
|
|
|
});
|
|
|
|
|
2022-10-26 13:36:46 +00:00
|
|
|
test("empty", async () => {
|
2023-06-17 22:01:55 +00:00
|
|
|
const {stdout, stderr, exitCode} = await execa(script, [
|
|
|
|
"-C",
|
|
|
|
"--githubapi", githubUrl,
|
|
|
|
"--pypiapi", pypiUrl,
|
|
|
|
"-f", emptyFile,
|
|
|
|
]);
|
2022-10-26 13:36:46 +00:00
|
|
|
expect(stderr).toEqual("");
|
2022-10-26 16:22:10 +00:00
|
|
|
expect(stdout).toContain("No dependencies");
|
2022-10-26 13:36:46 +00:00
|
|
|
expect(exitCode).toEqual(0);
|
|
|
|
});
|
|
|
|
|
2023-06-17 21:51:04 +00:00
|
|
|
if (env.CI) {
|
2020-07-21 20:41:43 +00:00
|
|
|
test("global", async () => {
|
|
|
|
await execa("npm", ["i", "-g", "."]);
|
2023-06-17 22:01:55 +00:00
|
|
|
const {stdout, stderr, exitCode} = await execa("updates", [
|
|
|
|
"-C",
|
|
|
|
"--githubapi", githubUrl,
|
|
|
|
"--pypiapi", pypiUrl,
|
|
|
|
"-f", testFile,
|
|
|
|
]);
|
2020-07-21 20:41:43 +00:00
|
|
|
expect(stderr).toEqual("");
|
2022-10-17 21:36:44 +00:00
|
|
|
expect(stdout).toContain("prismjs");
|
|
|
|
expect(stdout).toContain("https://github.com/silverwind/updates");
|
2020-07-21 20:41:43 +00:00
|
|
|
expect(exitCode).toEqual(0);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-06-17 21:51:04 +00:00
|
|
|
test("latest", makeTest("-j"));
|
|
|
|
test("greatest", makeTest("-j -g"));
|
|
|
|
test("prerelease", makeTest("-j -g -p"));
|
|
|
|
test("release", makeTest("-j -R"));
|
|
|
|
test("patch", makeTest("-j -P"));
|
2023-08-25 23:17:17 +00:00
|
|
|
test("include", makeTest("-j -i noty"));
|
2023-10-20 12:11:25 +00:00
|
|
|
test("include 2", makeTest("-j -i noty -i noty,noty"));
|
|
|
|
test("include 3", makeTest("-j -i /^noty/"));
|
2023-08-25 23:17:17 +00:00
|
|
|
test("exclude", makeTest("-j -e gulp-sourcemaps,prismjs,svgstore,html-webpack-plugin,noty,jpeg-buffer-orientation,styled-components,@babel/preset-env,versions/updates,react"));
|
2023-10-20 12:11:25 +00:00
|
|
|
test("exclude 2", makeTest("-j -e gulp-sourcemaps -i /react/"));
|
|
|
|
test("exclude 3", makeTest("-j -i gulp*"));
|
|
|
|
test("exclude 4", makeTest("-j -i /^gulp/ -P gulp*"));
|
2023-09-04 23:03:57 +00:00
|
|
|
test("pypi", makeTest(`-j -f ${poetryFile}`));
|
|
|
|
test("dual", makeTest(`-j -f ${dualFile}`));
|
2023-10-20 12:11:25 +00:00
|
|
|
test("dual 2", makeTest(`-j -f ${dualFile} -i noty`));
|