fix(npm): reload an npm package's dependency's information when version not found (#18622)

This reloads an npm package's dependency's information when a
version/version req/tag is not found.

This PR applies only to dependencies of npm packages. It does NOT yet
cause npm specifiers to have their dependency information cache busted.
That requires a different solution, but this should help cache bust in
more scenarios.

Part of #16901, but doesn't close it yet
This commit is contained in:
David Sherret 2023-04-06 21:41:19 -04:00 committed by GitHub
parent 0dca0c5196
commit 5c7f76c570
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 257 additions and 57 deletions

View file

@ -1,5 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use deno_core::serde_json;
use deno_core::serde_json::Value;
use pretty_assertions::assert_eq;
use std::process::Stdio;
use test_util as util;
@ -1546,3 +1548,124 @@ itest!(node_modules_import_check {
copy_temp_dir: Some("npm/node_modules_import/"),
exit_code: 1,
});
itest!(non_existent_dep {
args: "cache npm:@denotest/non-existent-dep",
envs: env_vars_for_npm_tests(),
http_server: true,
exit_code: 1,
output_str: Some(concat!(
"Download http://localhost:4545/npm/registry/@denotest/non-existent-dep\n",
"Download http://localhost:4545/npm/registry/@denotest/non-existent\n",
"error: npm package '@denotest/non-existent' does not exist.\n"
)),
});
itest!(non_existent_dep_version {
args: "cache npm:@denotest/non-existent-dep-version",
envs: env_vars_for_npm_tests(),
http_server: true,
exit_code: 1,
output_str: Some(concat!(
"Download http://localhost:4545/npm/registry/@denotest/non-existent-dep-version\n",
"Download http://localhost:4545/npm/registry/@denotest/esm-basic\n",
// does two downloads because when failing once it max tries to
// get the latest version a second time
"Download http://localhost:4545/npm/registry/@denotest/non-existent-dep-version\n",
"Download http://localhost:4545/npm/registry/@denotest/esm-basic\n",
"error: Could not find npm package '@denotest/esm-basic' matching '=99.99.99'.\n"
)),
});
#[test]
fn reload_info_not_found_cache_but_exists_remote() {
fn remove_version(registry_json: &mut Value, version: &str) {
registry_json
.as_object_mut()
.unwrap()
.get_mut("versions")
.unwrap()
.as_object_mut()
.unwrap()
.remove(version);
}
// This tests that when a local machine doesn't have a version
// specified in a dependency that exists in the npm registry
let test_context = TestContextBuilder::for_npm()
.use_sync_npm_download()
.use_temp_cwd()
.build();
let deno_dir = test_context.deno_dir();
let temp_dir = test_context.temp_dir();
temp_dir.write(
"main.ts",
"import 'npm:@denotest/esm-import-cjs-default@1.0.0';",
);
// cache successfully to the deno_dir
let output = test_context.new_command().args("cache main.ts").run();
output.assert_matches_text(concat!(
"Download http://localhost:4545/npm/registry/@denotest/esm-import-cjs-default\n",
"Download http://localhost:4545/npm/registry/@denotest/cjs-default-export\n",
"Download http://localhost:4545/npm/registry/@denotest/cjs-default-export/1.0.0.tgz\n",
"Download http://localhost:4545/npm/registry/@denotest/esm-import-cjs-default/1.0.0.tgz\n",
));
// modify the package information in the cache to remove the latest version
let registry_json_path = "npm/localhost_4545/npm/registry/@denotest/cjs-default-export/registry.json";
let mut registry_json: Value =
serde_json::from_str(&deno_dir.read_to_string(registry_json_path)).unwrap();
remove_version(&mut registry_json, "1.0.0");
deno_dir.write(
registry_json_path,
serde_json::to_string(&registry_json).unwrap(),
);
// should error when `--cache-only` is used now because the version is not in the cache
let output = test_context
.new_command()
.args("run --cached-only main.ts")
.run();
output.assert_exit_code(1);
output.assert_matches_text("error: Could not find npm package '@denotest/cjs-default-export' matching '^1.0.0'.\n");
// now try running without it, it should download the package now
let output = test_context.new_command().args("run main.ts").run();
output.assert_matches_text(concat!(
"Download http://localhost:4545/npm/registry/@denotest/esm-import-cjs-default\n",
"Download http://localhost:4545/npm/registry/@denotest/cjs-default-export\n",
"Node esm importing node cjs\n[WILDCARD]",
));
output.assert_exit_code(0);
// now remove the information for the top level package
let registry_json_path = "npm/localhost_4545/npm/registry/@denotest/esm-import-cjs-default/registry.json";
let mut registry_json: Value =
serde_json::from_str(&deno_dir.read_to_string(registry_json_path)).unwrap();
remove_version(&mut registry_json, "1.0.0");
deno_dir.write(
registry_json_path,
serde_json::to_string(&registry_json).unwrap(),
);
// should error again for --cached-only
let output = test_context
.new_command()
.args("run --cached-only main.ts")
.run();
output.assert_exit_code(1);
output.assert_matches_text(concat!(
"error: Could not find npm package '@denotest/esm-import-cjs-default' matching '1.0.0'. Try retrieving the latest npm package information by running with --reload\n",
" at file:///[WILDCARD]/main.ts:1:8\n",
));
// now try running without it, it currently will error, but this should work in the future
// todo(https://github.com/denoland/deno/issues/16901): fix this
let output = test_context.new_command().args("run main.ts").run();
output.assert_exit_code(1);
output.assert_matches_text(concat!(
"error: Could not find npm package '@denotest/esm-import-cjs-default' matching '1.0.0'. Try retrieving the latest npm package information by running with --reload\n",
" at file:///[WILDCARD]/main.ts:1:8\n",
));
}