@verdaccio/e2e-cli 2.10.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/Cargo.lock +1591 -0
  2. package/Cargo.toml +19 -0
  3. package/bin/e2e-cli.js +26 -6
  4. package/build/bin/verdaccio-e2e +0 -0
  5. package/build/cjs/index.cjs +11 -166
  6. package/build/esm/index.js +10 -153
  7. package/build/index.d.ts +15 -6
  8. package/package.json +14 -16
  9. package/scripts/build-js-package.mjs +25 -0
  10. package/src/e2e_tests/audit.rs +51 -0
  11. package/src/e2e_tests/ci.rs +32 -0
  12. package/src/e2e_tests/deprecate.rs +64 -0
  13. package/src/e2e_tests/dist_tags.rs +56 -0
  14. package/src/e2e_tests/info.rs +43 -0
  15. package/src/e2e_tests/install.rs +27 -0
  16. package/src/e2e_tests/login.rs +64 -0
  17. package/src/e2e_tests/mod.rs +104 -0
  18. package/src/e2e_tests/ping.rs +33 -0
  19. package/src/e2e_tests/publish.rs +68 -0
  20. package/src/e2e_tests/search.rs +14 -0
  21. package/src/e2e_tests/unpublish.rs +37 -0
  22. package/src/main.rs +1411 -0
  23. package/src/scenarios/install_multiple_deps.rs +99 -0
  24. package/src/scenarios/minimum_release_age.rs +45 -0
  25. package/src/scenarios/mod.rs +11 -0
  26. package/build/adapters/adapter.d.ts +0 -1
  27. package/build/adapters/bun.d.ts +0 -2
  28. package/build/adapters/deno.d.ts +0 -2
  29. package/build/adapters/index.d.ts +0 -6
  30. package/build/adapters/npm.d.ts +0 -2
  31. package/build/adapters/pnpm.d.ts +0 -2
  32. package/build/adapters/yarn-classic.d.ts +0 -2
  33. package/build/adapters/yarn-modern.d.ts +0 -2
  34. package/build/cjs/_virtual/_rolldown/runtime.cjs +0 -23
  35. package/build/cjs/adapters/bun.cjs +0 -63
  36. package/build/cjs/adapters/bun.cjs.map +0 -1
  37. package/build/cjs/adapters/deno.cjs +0 -58
  38. package/build/cjs/adapters/deno.cjs.map +0 -1
  39. package/build/cjs/adapters/index.cjs +0 -6
  40. package/build/cjs/adapters/npm.cjs +0 -75
  41. package/build/cjs/adapters/npm.cjs.map +0 -1
  42. package/build/cjs/adapters/pnpm.cjs +0 -104
  43. package/build/cjs/adapters/pnpm.cjs.map +0 -1
  44. package/build/cjs/adapters/yarn-classic.cjs +0 -98
  45. package/build/cjs/adapters/yarn-classic.cjs.map +0 -1
  46. package/build/cjs/adapters/yarn-modern.cjs +0 -206
  47. package/build/cjs/adapters/yarn-modern.cjs.map +0 -1
  48. package/build/cjs/index.cjs.map +0 -1
  49. package/build/cjs/reporter.cjs +0 -113
  50. package/build/cjs/reporter.cjs.map +0 -1
  51. package/build/cjs/runner.cjs +0 -141
  52. package/build/cjs/runner.cjs.map +0 -1
  53. package/build/cjs/scenarios/index.cjs +0 -8
  54. package/build/cjs/scenarios/index.cjs.map +0 -1
  55. package/build/cjs/scenarios/install-multiple-deps.cjs +0 -117
  56. package/build/cjs/scenarios/install-multiple-deps.cjs.map +0 -1
  57. package/build/cjs/scenarios/minimum-release-age.cjs +0 -112
  58. package/build/cjs/scenarios/minimum-release-age.cjs.map +0 -1
  59. package/build/cjs/tests/audit.cjs +0 -47
  60. package/build/cjs/tests/audit.cjs.map +0 -1
  61. package/build/cjs/tests/ci.cjs +0 -83
  62. package/build/cjs/tests/ci.cjs.map +0 -1
  63. package/build/cjs/tests/deprecate.cjs +0 -107
  64. package/build/cjs/tests/deprecate.cjs.map +0 -1
  65. package/build/cjs/tests/dist-tags.cjs +0 -43
  66. package/build/cjs/tests/dist-tags.cjs.map +0 -1
  67. package/build/cjs/tests/index.cjs +0 -33
  68. package/build/cjs/tests/index.cjs.map +0 -1
  69. package/build/cjs/tests/info.cjs +0 -42
  70. package/build/cjs/tests/info.cjs.map +0 -1
  71. package/build/cjs/tests/install.cjs +0 -27
  72. package/build/cjs/tests/install.cjs.map +0 -1
  73. package/build/cjs/tests/login.cjs +0 -117
  74. package/build/cjs/tests/login.cjs.map +0 -1
  75. package/build/cjs/tests/ping.cjs +0 -30
  76. package/build/cjs/tests/ping.cjs.map +0 -1
  77. package/build/cjs/tests/publish.cjs +0 -37
  78. package/build/cjs/tests/publish.cjs.map +0 -1
  79. package/build/cjs/tests/search.cjs +0 -19
  80. package/build/cjs/tests/search.cjs.map +0 -1
  81. package/build/cjs/tests/unpublish.cjs +0 -40
  82. package/build/cjs/tests/unpublish.cjs.map +0 -1
  83. package/build/cjs/utils/info.cjs +0 -25
  84. package/build/cjs/utils/info.cjs.map +0 -1
  85. package/build/cjs/utils/process.cjs +0 -85
  86. package/build/cjs/utils/process.cjs.map +0 -1
  87. package/build/cjs/utils/project.cjs +0 -55
  88. package/build/cjs/utils/project.cjs.map +0 -1
  89. package/build/cjs/utils/registry-client.cjs +0 -56
  90. package/build/cjs/utils/registry-client.cjs.map +0 -1
  91. package/build/esm/adapters/bun.js +0 -61
  92. package/build/esm/adapters/bun.js.map +0 -1
  93. package/build/esm/adapters/deno.js +0 -56
  94. package/build/esm/adapters/deno.js.map +0 -1
  95. package/build/esm/adapters/index.js +0 -7
  96. package/build/esm/adapters/npm.js +0 -73
  97. package/build/esm/adapters/npm.js.map +0 -1
  98. package/build/esm/adapters/pnpm.js +0 -102
  99. package/build/esm/adapters/pnpm.js.map +0 -1
  100. package/build/esm/adapters/yarn-classic.js +0 -96
  101. package/build/esm/adapters/yarn-classic.js.map +0 -1
  102. package/build/esm/adapters/yarn-modern.js +0 -203
  103. package/build/esm/adapters/yarn-modern.js.map +0 -1
  104. package/build/esm/index.js.map +0 -1
  105. package/build/esm/reporter.js +0 -107
  106. package/build/esm/reporter.js.map +0 -1
  107. package/build/esm/runner.js +0 -138
  108. package/build/esm/runner.js.map +0 -1
  109. package/build/esm/scenarios/index.js +0 -8
  110. package/build/esm/scenarios/index.js.map +0 -1
  111. package/build/esm/scenarios/install-multiple-deps.js +0 -114
  112. package/build/esm/scenarios/install-multiple-deps.js.map +0 -1
  113. package/build/esm/scenarios/minimum-release-age.js +0 -109
  114. package/build/esm/scenarios/minimum-release-age.js.map +0 -1
  115. package/build/esm/tests/audit.js +0 -44
  116. package/build/esm/tests/audit.js.map +0 -1
  117. package/build/esm/tests/ci.js +0 -80
  118. package/build/esm/tests/ci.js.map +0 -1
  119. package/build/esm/tests/deprecate.js +0 -104
  120. package/build/esm/tests/deprecate.js.map +0 -1
  121. package/build/esm/tests/dist-tags.js +0 -41
  122. package/build/esm/tests/dist-tags.js.map +0 -1
  123. package/build/esm/tests/index.js +0 -33
  124. package/build/esm/tests/index.js.map +0 -1
  125. package/build/esm/tests/info.js +0 -40
  126. package/build/esm/tests/info.js.map +0 -1
  127. package/build/esm/tests/install.js +0 -25
  128. package/build/esm/tests/install.js.map +0 -1
  129. package/build/esm/tests/login.js +0 -113
  130. package/build/esm/tests/login.js.map +0 -1
  131. package/build/esm/tests/ping.js +0 -28
  132. package/build/esm/tests/ping.js.map +0 -1
  133. package/build/esm/tests/publish.js +0 -35
  134. package/build/esm/tests/publish.js.map +0 -1
  135. package/build/esm/tests/search.js +0 -17
  136. package/build/esm/tests/search.js.map +0 -1
  137. package/build/esm/tests/unpublish.js +0 -38
  138. package/build/esm/tests/unpublish.js.map +0 -1
  139. package/build/esm/utils/info.js +0 -24
  140. package/build/esm/utils/info.js.map +0 -1
  141. package/build/esm/utils/process.js +0 -82
  142. package/build/esm/utils/process.js.map +0 -1
  143. package/build/esm/utils/project.js +0 -50
  144. package/build/esm/utils/project.js.map +0 -1
  145. package/build/esm/utils/registry-client.js +0 -53
  146. package/build/esm/utils/registry-client.js.map +0 -1
  147. package/build/reporter.d.ts +0 -7
  148. package/build/runner.d.ts +0 -13
  149. package/build/scenarios/index.d.ts +0 -5
  150. package/build/scenarios/install-multiple-deps.d.ts +0 -2
  151. package/build/scenarios/minimum-release-age.d.ts +0 -11
  152. package/build/tests/audit.d.ts +0 -2
  153. package/build/tests/ci.d.ts +0 -2
  154. package/build/tests/deprecate.d.ts +0 -2
  155. package/build/tests/dist-tags.d.ts +0 -2
  156. package/build/tests/index.d.ts +0 -15
  157. package/build/tests/info.d.ts +0 -2
  158. package/build/tests/install.d.ts +0 -2
  159. package/build/tests/login.d.ts +0 -2
  160. package/build/tests/ping.d.ts +0 -2
  161. package/build/tests/publish.d.ts +0 -2
  162. package/build/tests/search.d.ts +0 -2
  163. package/build/tests/unpublish.d.ts +0 -2
  164. package/build/types.d.ts +0 -81
  165. package/build/utils/index.d.ts +0 -4
  166. package/build/utils/info.d.ts +0 -14
  167. package/build/utils/process.d.ts +0 -4
  168. package/build/utils/project.d.ts +0 -6
  169. package/build/utils/registry-client.d.ts +0 -15
@@ -0,0 +1,56 @@
1
+ use super::prelude::*;
2
+
3
+ pub(crate) fn test_dist_tags(ctx: &mut TestContext<'_>) -> Result<()> {
4
+ let pkg1 = format!("@foo/dt1-{}", ctx.run_id);
5
+ let tf1 = prepare_project(ctx, &pkg1, "1.0.0", BTreeMap::new(), BTreeMap::new())?;
6
+ publish_pkg(ctx, &tf1)?;
7
+ bump_version(ctx, &tf1, "minor")?;
8
+ publish_pkg_extra(ctx, &tf1, vec!["--tag".into(), "beta".into()])?;
9
+ let mut args = vec!["dist-tag".into(), "ls".into(), "--json".into()];
10
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
11
+ let resp = exec_adapter(ctx, Some(&tf1), args)?;
12
+ assert_eq_str(
13
+ &normalize_dist_tag_list(&resp.stdout),
14
+ "beta: 1.1.0\nlatest: 1.0.0",
15
+ )?;
16
+
17
+ let pkg2 = format!("@verdaccio/dt2-{}", ctx.run_id);
18
+ let tf2 = prepare_project(ctx, &pkg2, "1.0.0", BTreeMap::new(), BTreeMap::new())?;
19
+ publish_pkg(ctx, &tf2)?;
20
+ bump_version(ctx, &tf2, "minor")?;
21
+ publish_pkg_extra(ctx, &tf2, vec!["--tag".into(), "beta".into()])?;
22
+ let mut args = vec![
23
+ "dist-tag".into(),
24
+ "rm".into(),
25
+ format!("{pkg2}@1.1.0"),
26
+ "beta".into(),
27
+ ];
28
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
29
+ let resp = exec_adapter(ctx, Some(&tf2), args)?;
30
+ assert_eq_str(resp.stdout.trim(), &format!("-beta: {pkg2}@1.1.0"))?;
31
+
32
+ let pkg3 = format!("@verdaccio/dt3-{}", ctx.run_id);
33
+ let tf3 = prepare_project(ctx, &pkg3, "1.0.0", BTreeMap::new(), BTreeMap::new())?;
34
+ publish_pkg(ctx, &tf3)?;
35
+ bump_version(ctx, &tf3, "minor")?;
36
+ publish_pkg(ctx, &tf3)?;
37
+ let mut args = vec![
38
+ "dist-tag".into(),
39
+ "add".into(),
40
+ format!("{pkg3}@1.1.0"),
41
+ "alfa".into(),
42
+ ];
43
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
44
+ let resp = exec_adapter(ctx, Some(&tf3), args)?;
45
+ assert_eq_str(resp.stdout.trim(), &format!("+alfa: {pkg3}@1.1.0"))?;
46
+ Ok(())
47
+ }
48
+
49
+ fn normalize_dist_tag_list(output: &str) -> String {
50
+ output
51
+ .lines()
52
+ .map(str::trim)
53
+ .filter(|line| !line.is_empty())
54
+ .collect::<Vec<_>>()
55
+ .join("\n")
56
+ }
@@ -0,0 +1,43 @@
1
+ use super::prelude::*;
2
+
3
+ pub(crate) fn test_info(ctx: &mut TestContext<'_>) -> Result<()> {
4
+ let dir = create_temp_dir(ctx.state, "info-test")?
5
+ .path()
6
+ .to_path_buf();
7
+ fs::write(
8
+ dir.join("package.json"),
9
+ r#"{"name":"info-test","version":"1.0.0"}"#,
10
+ )?;
11
+ let mut args = vec!["info".into(), "verdaccio".into(), "--json".into()];
12
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
13
+ let resp = exec_adapter(ctx, Some(&dir), args)?;
14
+ match ctx.adapter.kind {
15
+ AdapterType::YarnClassic => {
16
+ let found = resp.stdout.lines().any(|line| {
17
+ serde_json::from_str::<Value>(line)
18
+ .ok()
19
+ .and_then(|v| v.get("type").cloned())
20
+ .and_then(|v| v.as_str().map(|s| s == "inspect"))
21
+ .unwrap_or(false)
22
+ });
23
+ assert_true(
24
+ found,
25
+ "Expected yarn info NDJSON to contain an inspect entry",
26
+ )?;
27
+ }
28
+ AdapterType::Deno => assert_contains(&(resp.stdout + &resp.stderr), "verdaccio")?,
29
+ _ => {
30
+ let parsed = parse_info_json(&resp.stdout)?;
31
+ assert_eq_json(
32
+ parsed.get("name"),
33
+ "verdaccio",
34
+ "Expected package name verdaccio",
35
+ )?;
36
+ assert_true(
37
+ parsed.get("dependencies").is_some(),
38
+ "Expected dependencies to be defined",
39
+ )?;
40
+ }
41
+ }
42
+ Ok(())
43
+ }
@@ -0,0 +1,27 @@
1
+ use super::prelude::*;
2
+
3
+ pub(crate) fn test_install(ctx: &mut TestContext<'_>) -> Result<()> {
4
+ let mut deps = BTreeMap::new();
5
+ deps.insert("react".into(), "18.2.0".into());
6
+ let temp = prepare_project(
7
+ ctx,
8
+ &format!("install-test-{}", ctx.run_id),
9
+ "1.0.0",
10
+ deps,
11
+ BTreeMap::new(),
12
+ )?;
13
+ let mut args = vec!["install".into()];
14
+ if ctx.adapter.kind == AdapterType::Npm {
15
+ args.push("--json".into());
16
+ }
17
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
18
+ let resp = exec_adapter(ctx, Some(&temp), args)?;
19
+ if ctx.adapter.kind == AdapterType::Npm {
20
+ let parsed: Value = serde_json::from_str(&resp.stdout)?;
21
+ assert_true(
22
+ parsed.get("added").is_some(),
23
+ "Expected \"added\" field in install response",
24
+ )?;
25
+ }
26
+ Ok(())
27
+ }
@@ -0,0 +1,64 @@
1
+ use super::prelude::*;
2
+
3
+ pub(crate) fn test_login(ctx: &mut TestContext<'_>) -> Result<()> {
4
+ if ctx.adapter.kind != AdapterType::YarnModern {
5
+ return Ok(());
6
+ }
7
+ let user1 = format!("login-a-{}", ctx.run_id);
8
+ let password1 = "test-password-123";
9
+ let email1 = format!("{user1}@test.example.com");
10
+ sub_test(ctx, "create new user + whoami", |ctx| {
11
+ let tf = prepare_login_project(ctx, &format!("verdaccio-login1-{}", ctx.run_id))?;
12
+ let login = yarn_login(ctx, &tf, &user1, password1, &email1)?;
13
+ assert_true(
14
+ login.stdout.contains("Logged in") || login.stdout.contains("token saved"),
15
+ "Expected login success message",
16
+ )?;
17
+ assert_contains(&yarn_whoami(ctx, &tf)?, &user1)
18
+ })?;
19
+ sub_test(ctx, "login existing user", |ctx| {
20
+ let tf = prepare_login_project(ctx, &format!("verdaccio-login2-{}", ctx.run_id))?;
21
+ let login = yarn_login(ctx, &tf, &user1, password1, &email1)?;
22
+ assert_true(
23
+ login.stdout.contains("Logged in") || login.stdout.contains("token saved"),
24
+ "Expected login success message",
25
+ )?;
26
+ assert_contains(&yarn_whoami(ctx, &tf)?, &user1)
27
+ })?;
28
+ sub_test(ctx, "wrong password fails", |ctx| {
29
+ let tf = prepare_login_project(ctx, &format!("verdaccio-login3-{}", ctx.run_id))?;
30
+ let failed = yarn_login(ctx, &tf, &user1, "wrong-password", &email1).is_err();
31
+ assert_true(failed, "Login with wrong password should have failed")
32
+ })?;
33
+ sub_test(ctx, "login then publish", |ctx| {
34
+ let pkg = format!("@verdaccio/login-pub-{}", ctx.run_id);
35
+ let tf = create_temp_dir(ctx.state, &format!("login-pub-{}", ctx.run_id))?
36
+ .path()
37
+ .to_path_buf();
38
+ fs::write(
39
+ tf.join(".yarnrc.yml"),
40
+ yarn_config(&ctx.registry_url, None, ctx.adapter.yarn_major)?,
41
+ )?;
42
+ fs::write(
43
+ tf.join("package.json"),
44
+ package_json(&pkg, "1.0.0", BTreeMap::new(), BTreeMap::new())?,
45
+ )?;
46
+ fs::write(tf.join("README.md"), readme(&pkg))?;
47
+ import_plugin(ctx, &tf, "npm-login")?;
48
+ yarn_login(ctx, &tf, &user1, password1, &email1)?;
49
+ exec_adapter(ctx, Some(&tf), vec!["install".into()])?;
50
+ let published = exec_adapter(ctx, Some(&tf), vec!["publish".into()])?;
51
+ assert_contains(&published.stdout, "Package archive published")
52
+ })?;
53
+ sub_test(ctx, "switch users", |ctx| {
54
+ let user2 = format!("login-b-{}", ctx.run_id);
55
+ let password2 = "other-password-456";
56
+ let email2 = format!("{user2}@test.example.com");
57
+ let tf = prepare_login_project(ctx, &format!("verdaccio-login5-{}", ctx.run_id))?;
58
+ yarn_login(ctx, &tf, &user1, password1, &email1)?;
59
+ assert_contains(&yarn_whoami(ctx, &tf)?, &user1)?;
60
+ yarn_login(ctx, &tf, &user2, password2, &email2)?;
61
+ assert_contains(&yarn_whoami(ctx, &tf)?, &user2)
62
+ })?;
63
+ Ok(())
64
+ }
@@ -0,0 +1,104 @@
1
+ pub(crate) mod audit;
2
+ pub(crate) mod ci;
3
+ pub(crate) mod deprecate;
4
+ pub(crate) mod dist_tags;
5
+ pub(crate) mod info;
6
+ pub(crate) mod install;
7
+ pub(crate) mod login;
8
+ pub(crate) mod ping;
9
+ pub(crate) mod publish;
10
+ pub(crate) mod search;
11
+ pub(crate) mod unpublish;
12
+
13
+ pub(crate) mod prelude {
14
+ pub(crate) use anyhow::{Context, Result};
15
+ pub(crate) use reqwest::blocking::Client;
16
+ pub(crate) use serde_json::Value;
17
+ pub(crate) use std::collections::BTreeMap;
18
+ pub(crate) use std::fs;
19
+
20
+ pub(crate) use crate::*;
21
+ }
22
+
23
+ pub(crate) fn all_tests() -> Vec<crate::TestDefinition> {
24
+ vec![
25
+ crate::TestDefinition {
26
+ name: "publish",
27
+ requires: &["publish"],
28
+ applies_to: |_| true,
29
+ run: publish::test_publish,
30
+ },
31
+ crate::TestDefinition {
32
+ name: "install",
33
+ requires: &["install"],
34
+ applies_to: |_| true,
35
+ run: install::test_install,
36
+ },
37
+ crate::TestDefinition {
38
+ name: "ci",
39
+ requires: &["install"],
40
+ applies_to: |_| true,
41
+ run: ci::test_ci,
42
+ },
43
+ crate::TestDefinition {
44
+ name: "audit",
45
+ requires: &["audit"],
46
+ applies_to: |_| true,
47
+ run: audit::test_audit,
48
+ },
49
+ crate::TestDefinition {
50
+ name: "info",
51
+ requires: &["info"],
52
+ applies_to: |_| true,
53
+ run: info::test_info,
54
+ },
55
+ crate::TestDefinition {
56
+ name: "deprecate",
57
+ requires: &["deprecate"],
58
+ applies_to: |_| true,
59
+ run: deprecate::test_deprecate,
60
+ },
61
+ crate::TestDefinition {
62
+ name: "dist-tags",
63
+ requires: &["dist-tag"],
64
+ applies_to: |_| true,
65
+ run: dist_tags::test_dist_tags,
66
+ },
67
+ crate::TestDefinition {
68
+ name: "login",
69
+ requires: &["login"],
70
+ applies_to: |_| true,
71
+ run: login::test_login,
72
+ },
73
+ crate::TestDefinition {
74
+ name: "ping",
75
+ requires: &["ping"],
76
+ applies_to: |_| true,
77
+ run: ping::test_ping,
78
+ },
79
+ crate::TestDefinition {
80
+ name: "search",
81
+ requires: &["search"],
82
+ applies_to: |_| true,
83
+ run: search::test_search,
84
+ },
85
+ crate::TestDefinition {
86
+ name: "unpublish",
87
+ requires: &["unpublish"],
88
+ applies_to: |_| true,
89
+ run: unpublish::test_unpublish,
90
+ },
91
+ crate::TestDefinition {
92
+ name: "scenario:install-multiple-deps",
93
+ requires: &["publish", "install", "info"],
94
+ applies_to: |_| true,
95
+ run: crate::scenarios::install_multiple_deps::scenario_install_multiple_deps,
96
+ },
97
+ crate::TestDefinition {
98
+ name: "scenario:minimum-release-age",
99
+ requires: &["publish", "install"],
100
+ applies_to: crate::is_pnpm_minimum_release_age_capable,
101
+ run: crate::scenarios::minimum_release_age::scenario_minimum_release_age,
102
+ },
103
+ ]
104
+ }
@@ -0,0 +1,33 @@
1
+ use super::prelude::*;
2
+
3
+ pub(crate) fn test_ping(ctx: &mut TestContext<'_>) -> Result<()> {
4
+ let cwd = if ctx.adapter.kind == AdapterType::YarnModern {
5
+ let temp = prepare_project(
6
+ ctx,
7
+ &format!("verdaccio-ping-{}", ctx.run_id),
8
+ "1.0.0",
9
+ BTreeMap::new(),
10
+ BTreeMap::new(),
11
+ )?;
12
+ import_plugin(ctx, &temp, "npm-ping")?;
13
+ Some(temp)
14
+ } else {
15
+ None
16
+ };
17
+ let mut args = vec!["ping".into()];
18
+ if ctx.adapter.kind != AdapterType::YarnModern {
19
+ args.push("--json".into());
20
+ }
21
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
22
+ let resp = exec_adapter(ctx, cwd.as_deref(), args)?;
23
+ if ctx.adapter.kind != AdapterType::YarnModern {
24
+ let parsed: Value = serde_json::from_str(&resp.stdout)?;
25
+ let expected_registry = format!("{}/", ctx.registry_url);
26
+ assert_eq_json(
27
+ parsed.get("registry"),
28
+ expected_registry.as_str(),
29
+ "Registry mismatch",
30
+ )?;
31
+ }
32
+ Ok(())
33
+ }
@@ -0,0 +1,68 @@
1
+ use super::prelude::*;
2
+
3
+ pub(crate) fn test_publish(ctx: &mut TestContext<'_>) -> Result<()> {
4
+ let packages = vec![
5
+ format!("verdaccio-memory-{}", ctx.run_id),
6
+ format!("verdaccio-{}", ctx.run_id),
7
+ format!("@verdaccio/foo-{}", ctx.run_id),
8
+ format!("@verdaccio/some-foo-{}", ctx.run_id),
9
+ ];
10
+ for pkg_name in packages {
11
+ let temp = prepare_project(ctx, &pkg_name, "1.0.0", BTreeMap::new(), BTreeMap::new())?;
12
+ if ctx.adapter.kind == AdapterType::YarnModern {
13
+ exec_adapter(ctx, Some(&temp), vec!["install".into()])?;
14
+ }
15
+ let mut args = vec!["publish".into(), "--json".into()];
16
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
17
+ let resp = exec_adapter(ctx, Some(&temp), args)?;
18
+ match ctx.adapter.kind {
19
+ AdapterType::YarnModern => assert_contains(&resp.stdout, "Package archive published")?,
20
+ AdapterType::YarnClassic => {
21
+ assert_true(!resp.stdout.is_empty(), "Expected publish output")?
22
+ }
23
+ AdapterType::Bun => {}
24
+ _ => {
25
+ if let Ok(parsed) = serde_json::from_str::<Value>(&resp.stdout) {
26
+ let expected_id = format!("{pkg_name}@1.0.0");
27
+ let published_name = parsed.get("name").and_then(Value::as_str);
28
+ let published_id = parsed.get("id").and_then(Value::as_str);
29
+ if published_name.is_some() || published_id.is_some() {
30
+ assert_true(
31
+ published_name == Some(pkg_name.as_str())
32
+ || published_id == Some(expected_id.as_str()),
33
+ &format!(
34
+ "Expected package name \"{pkg_name}\" or id \"{expected_id}\""
35
+ ),
36
+ )?;
37
+ }
38
+ }
39
+ }
40
+ }
41
+ assert_published(ctx, &pkg_name)?;
42
+ }
43
+ Ok(())
44
+ }
45
+
46
+ fn assert_published(ctx: &TestContext<'_>, pkg_name: &str) -> Result<()> {
47
+ let encoded = pkg_name.replace('/', "%2F");
48
+ let response = Client::new()
49
+ .get(format!(
50
+ "{}/{}",
51
+ ctx.registry_url.trim_end_matches('/'),
52
+ encoded
53
+ ))
54
+ .bearer_auth(&ctx.token)
55
+ .send()
56
+ .with_context(|| format!("failed to fetch published package {pkg_name}"))?;
57
+ let status = response.status();
58
+ let body: Value = response.json().unwrap_or(Value::Null);
59
+ assert_true(
60
+ status.is_success(),
61
+ &format!("Expected published package {pkg_name}, got {status} {body}"),
62
+ )?;
63
+ assert_eq_json(
64
+ body.get("name"),
65
+ pkg_name,
66
+ "Expected published registry package name",
67
+ )
68
+ }
@@ -0,0 +1,14 @@
1
+ use super::prelude::*;
2
+
3
+ pub(crate) fn test_search(ctx: &mut TestContext<'_>) -> Result<()> {
4
+ let mut args = vec!["search".into(), "@verdaccio/cli".into(), "--json".into()];
5
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
6
+ let resp = exec_adapter(ctx, None, args)?;
7
+ let parsed: Value = serde_json::from_str(&resp.stdout)?;
8
+ let found = parsed
9
+ .as_array()
10
+ .unwrap_or(&Vec::new())
11
+ .iter()
12
+ .any(|item| item.get("name").and_then(Value::as_str) == Some("@verdaccio/cli"));
13
+ assert_true(found, "Expected to find @verdaccio/cli in search results")
14
+ }
@@ -0,0 +1,37 @@
1
+ use super::prelude::*;
2
+
3
+ pub(crate) fn test_unpublish(ctx: &mut TestContext<'_>) -> Result<()> {
4
+ let pkg = format!("@verdaccio/unpub1-{}", ctx.run_id);
5
+ let temp = prepare_project(ctx, &pkg, "1.0.0", BTreeMap::new(), BTreeMap::new())?;
6
+ for bump in ["minor", "minor", "major"] {
7
+ publish_pkg(ctx, &temp)?;
8
+ bump_version(ctx, &temp, bump)?;
9
+ }
10
+ publish_pkg(ctx, &temp)?;
11
+ let mut args = vec![
12
+ "unpublish".into(),
13
+ pkg.clone(),
14
+ "--force".into(),
15
+ "--loglevel=info".into(),
16
+ "--json".into(),
17
+ ];
18
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
19
+ let resp = exec_adapter(ctx, Some(&temp), args)?;
20
+ assert_contains(&resp.stdout, &pkg)?;
21
+
22
+ let pkg2 = format!("@verdaccio/unpub2-{}", ctx.run_id);
23
+ let temp2 = prepare_project(ctx, &pkg2, "1.0.0", BTreeMap::new(), BTreeMap::new())?;
24
+ publish_pkg(ctx, &temp2)?;
25
+ bump_version(ctx, &temp2, "minor")?;
26
+ publish_pkg(ctx, &temp2)?;
27
+ let mut args = vec![
28
+ "unpublish".into(),
29
+ format!("{pkg2}@1.0.0"),
30
+ "--force".into(),
31
+ "--loglevel=info".into(),
32
+ "--json".into(),
33
+ ];
34
+ args.extend(registry_arg(&ctx.adapter, &ctx.registry_url));
35
+ let resp = exec_adapter(ctx, Some(&temp2), args)?;
36
+ assert_contains(&resp.stdout, &pkg2)
37
+ }