Merge branch 'master' into package-json-files-field

master
rhysd 6 years ago
commit 14c27f8aed
  1. 2
      docs/src/commands/build.md
  2. 56
      docs/src/commands/test.md
  3. 5
      src/build.rs
  4. 2
      src/command/build.rs
  5. 14
      src/command/test.rs
  6. 13
      src/license.rs
  7. 28
      src/manifest/mod.rs
  8. 2
      src/manifest/npm/commonjs.rs
  9. 2
      src/manifest/npm/esmodules.rs
  10. 2
      src/manifest/npm/nomodules.rs
  11. 8
      src/test/mod.rs
  12. 29
      tests/all/license.rs
  13. 57
      tests/all/manifest.rs
  14. 43
      tests/all/utils/fixture.rs
  15. 1
      tests/all/utils/manifest.rs

@ -59,7 +59,7 @@ wasm-pack build --target nodejs
| Option | Description | | Option | Description |
|-----------|-----------------------------------------------------------------------------------------------------------------| |-----------|-----------------------------------------------------------------------------------------------------------------|
| `nodejs` | Outputs JS that uses CommonJS modules, for use with a `require` statement. `main` key in `package.json`. | | `nodejs` | Outputs JS that uses CommonJS modules, for use with a `require` statement. `main` key in `package.json`. |
| `nomodules` | Outputs JS that use no modules. `browser` key in `package.json`. | | `no-modules` | Outputs JS that use no modules. `browser` key in `package.json`. |
| `browser` | Outputs JS that uses ES6 modules, primarily for use with `import` statements and/or bundlers such as `webpack`. `module` key in `package.json`. `sideEffects: false` by default. | | `browser` | Outputs JS that uses ES6 modules, primarily for use with `import` statements and/or bundlers such as `webpack`. `module` key in `package.json`. `sideEffects: false` by default. |
## Scope ## Scope

@ -0,0 +1,56 @@
# wasm-pack test
The `wasm-pack test` command wraps the [wasm-bindgen-test-runner](https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/index.html)
CLI allowing you to run wasm tests in different browsers without needing to install the different
webdrivers yourself.
```
wasm-pack test --help
```
## Path
The `wasm-pack test` command can be given an optional path argument.
This path should point to a directory that contains a `Cargo.toml` file. If no
path is given, the `test` command will run in the current directory.
```
# Run tests for the current directory's crate
wasm-pack test
# Run tests for a specified crate
wasm-pack test crates/crate-in-my-workspace
```
## Profile
The `test` command accepts an optional profile argument: `--release`.
If none is supplied, then a debug test build will be used.
## Test environment
Choose where to run your tests by passing in any combination of testing environment flags.
`--headless` is useful for running browser tests in a headless browser as part of a CI process.
```
wasm-pack test --node --firefox --chrome --safari --headless
```
## Extra options
The `test` command can pass extra options straight to `cargo test` even if they are not
supported in wasm-pack.
To use them you should add standalone `--` argument at the very
end of your command, and all the arguments you want to pass to cargo should go after.
Here's an example of running only tests that contain the world "apple".
```
wasm-pack test --firefox --headless -- --manifest-path=crates/my-workspace-crate/Cargo.toml apple
```
`cargo test -h` for a list of all options that you can pass through.

@ -25,7 +25,7 @@ pub fn check_rustc_version(step: &Step) -> Result<String, Error> {
} else { } else {
Ok(mv.to_string()) Ok(mv.to_string())
} }
}, }
None => bail!("We can't figure out what your Rust version is- which means you might not have Rust installed. Please install Rust version 1.30.0 or higher."), None => bail!("We can't figure out what your Rust version is- which means you might not have Rust installed. Please install Rust version 1.30.0 or higher."),
} }
} }
@ -95,6 +95,9 @@ pub fn cargo_build_wasm(
} }
/// Run `cargo build --tests` targetting `wasm32-unknown-unknown`. /// Run `cargo build --tests` targetting `wasm32-unknown-unknown`.
///
/// This generates the `Cargo.lock` file that we use in order to know which version of
/// wasm-bindgen-cli to use when running tests.
pub fn cargo_build_wasm_tests(path: &Path, debug: bool) -> Result<(), Error> { pub fn cargo_build_wasm_tests(path: &Path, debug: bool) -> Result<(), Error> {
let mut cmd = Command::new("cargo"); let mut cmd = Command::new("cargo");
cmd.current_dir(path).arg("build").arg("--tests"); cmd.current_dir(path).arg("build").arg("--tests");

@ -19,7 +19,7 @@ use std::str::FromStr;
use std::time::Instant; use std::time::Instant;
use PBAR; use PBAR;
/// Everything required to configure and run the `wasm-pack init` command. /// Everything required to configure and run the `wasm-pack build` command.
#[allow(missing_docs)] #[allow(missing_docs)]
pub struct Build { pub struct Build {
pub crate_path: PathBuf, pub crate_path: PathBuf,

@ -78,6 +78,10 @@ pub struct TestOptions {
#[structopt(long = "release", short = "r")] #[structopt(long = "release", short = "r")]
/// Build with the release profile. /// Build with the release profile.
pub release: bool, pub release: bool,
#[structopt(last = true)]
/// List of extra options to pass to `cargo test`
pub extra_options: Vec<String>,
} }
/// A configured `wasm-pack test` command. /// A configured `wasm-pack test` command.
@ -96,6 +100,7 @@ pub struct Test {
headless: bool, headless: bool,
release: bool, release: bool,
test_runner_path: Option<PathBuf>, test_runner_path: Option<PathBuf>,
extra_options: Vec<String>,
} }
type TestStep = fn(&mut Test, &Step) -> Result<(), Error>; type TestStep = fn(&mut Test, &Step) -> Result<(), Error>;
@ -115,6 +120,7 @@ impl Test {
geckodriver, geckodriver,
safari, safari,
safaridriver, safaridriver,
extra_options,
} = test_opts; } = test_opts;
let crate_path = set_crate_path(path)?; let crate_path = set_crate_path(path)?;
@ -147,6 +153,7 @@ impl Test {
headless, headless,
release, release,
test_runner_path: None, test_runner_path: None,
extra_options,
}) })
} }
@ -306,6 +313,7 @@ impl Test {
"CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER", "CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER",
&self.test_runner_path.as_ref().unwrap(), &self.test_runner_path.as_ref().unwrap(),
)), )),
&self.extra_options,
)?; )?;
info!("Finished running tests in node."); info!("Finished running tests in node.");
Ok(()) Ok(())
@ -349,7 +357,7 @@ impl Test {
envs.push(("NO_HEADLESS", "1")); envs.push(("NO_HEADLESS", "1"));
} }
test::cargo_test_wasm(&self.crate_path, self.release, envs)?; test::cargo_test_wasm(&self.crate_path, self.release, envs, &self.extra_options)?;
Ok(()) Ok(())
} }
@ -391,7 +399,7 @@ impl Test {
envs.push(("NO_HEADLESS", "1")); envs.push(("NO_HEADLESS", "1"));
} }
test::cargo_test_wasm(&self.crate_path, self.release, envs)?; test::cargo_test_wasm(&self.crate_path, self.release, envs, &self.extra_options)?;
Ok(()) Ok(())
} }
@ -430,7 +438,7 @@ impl Test {
envs.push(("NO_HEADLESS", "1")); envs.push(("NO_HEADLESS", "1"));
} }
test::cargo_test_wasm(&self.crate_path, self.release, envs)?; test::cargo_test_wasm(&self.crate_path, self.release, envs, &self.extra_options)?;
Ok(()) Ok(())
} }
} }

@ -57,8 +57,8 @@ pub fn copy_from_crate(
"crate's pkg directory should exist" "crate's pkg directory should exist"
); );
match crate_data.crate_license() { match (crate_data.crate_license(), crate_data.crate_license_file()) {
Some(_) => { (Some(_), _) => {
let msg = format!("{}Copying over your LICENSE...", emoji::DANCERS); let msg = format!("{}Copying over your LICENSE...", emoji::DANCERS);
PBAR.step(step, &msg); PBAR.step(step, &msg);
let license_files = glob_license_files(path); let license_files = glob_license_files(path);
@ -80,7 +80,14 @@ pub fn copy_from_crate(
Err(_) => PBAR.info("origin crate has no LICENSE"), Err(_) => PBAR.info("origin crate has no LICENSE"),
} }
} }
None => { (None, Some(license_file)) => {
let crate_license_path = path.join(&license_file);
let new_license_path = out_dir.join(&license_file);
if fs::copy(&crate_license_path, &new_license_path).is_err() {
PBAR.info("origin crate has no LICENSE");
}
}
(None, None) => {
PBAR.step(step, "No LICENSE found in Cargo.toml, skipping..."); PBAR.step(step, "No LICENSE found in Cargo.toml, skipping...");
} }
}; };

@ -40,7 +40,10 @@ struct CargoPackage {
name: String, name: String,
description: Option<String>, description: Option<String>,
license: Option<String>, license: Option<String>,
#[serde(rename = "license-file")]
license_file: Option<String>,
repository: Option<String>, repository: Option<String>,
homepage: Option<String>,
#[serde(default)] #[serde(default)]
metadata: CargoMetadata, metadata: CargoMetadata,
@ -199,6 +202,7 @@ struct NpmData {
files: Vec<String>, files: Vec<String>,
dts_file: Option<String>, dts_file: Option<String>,
main: String, main: String,
homepage: Option<String>, // https://docs.npmjs.com/files/package.json#homepage
} }
#[doc(hidden)] #[doc(hidden)]
@ -349,6 +353,11 @@ impl CrateData {
&self.manifest.package.license &self.manifest.package.license
} }
/// Get the license file path for the crate at the given path.
pub fn crate_license_file(&self) -> &Option<String> {
&self.manifest.package.license_file
}
/// Returns the path to this project's target directory where artifacts are /// Returns the path to this project's target directory where artifacts are
/// located after a cargo build. /// located after a cargo build.
pub fn target_directory(&self) -> &Path { pub fn target_directory(&self) -> &Path {
@ -440,9 +449,19 @@ impl CrateData {
dts_file, dts_file,
files, files,
main: js_file, main: js_file,
homepage: self.manifest.package.homepage.clone(),
} }
} }
fn license(&self) -> Option<String> {
self.manifest.package.license.clone().or_else(|| {
self.manifest.package.license_file.clone().map(|file| {
// When license is written in file: https://docs.npmjs.com/files/package.json#license
format!("SEE LICENSE IN {}", file)
})
})
}
fn to_commonjs(&self, scope: &Option<String>, disable_dts: bool, out_dir: &Path) -> NpmPackage { fn to_commonjs(&self, scope: &Option<String>, disable_dts: bool, out_dir: &Path) -> NpmPackage {
let data = self.npm_data(scope, true, disable_dts, out_dir); let data = self.npm_data(scope, true, disable_dts, out_dir);
let pkg = &self.data.packages[self.current_idx]; let pkg = &self.data.packages[self.current_idx];
@ -454,7 +473,7 @@ impl CrateData {
collaborators: pkg.authors.clone(), collaborators: pkg.authors.clone(),
description: self.manifest.package.description.clone(), description: self.manifest.package.description.clone(),
version: pkg.version.clone(), version: pkg.version.clone(),
license: self.manifest.package.license.clone(), license: self.license(),
repository: self repository: self
.manifest .manifest
.package .package
@ -466,6 +485,7 @@ impl CrateData {
}), }),
files: data.files, files: data.files,
main: data.main, main: data.main,
homepage: data.homepage,
types: data.dts_file, types: data.dts_file,
}) })
} }
@ -486,7 +506,7 @@ impl CrateData {
collaborators: pkg.authors.clone(), collaborators: pkg.authors.clone(),
description: self.manifest.package.description.clone(), description: self.manifest.package.description.clone(),
version: pkg.version.clone(), version: pkg.version.clone(),
license: self.manifest.package.license.clone(), license: self.license(),
repository: self repository: self
.manifest .manifest
.package .package
@ -498,6 +518,7 @@ impl CrateData {
}), }),
files: data.files, files: data.files,
module: data.main, module: data.main,
homepage: data.homepage,
types: data.dts_file, types: data.dts_file,
side_effects: "false".to_string(), side_effects: "false".to_string(),
}) })
@ -519,7 +540,7 @@ impl CrateData {
collaborators: pkg.authors.clone(), collaborators: pkg.authors.clone(),
description: self.manifest.package.description.clone(), description: self.manifest.package.description.clone(),
version: pkg.version.clone(), version: pkg.version.clone(),
license: self.manifest.package.license.clone(), license: self.license(),
repository: self repository: self
.manifest .manifest
.package .package
@ -531,6 +552,7 @@ impl CrateData {
}), }),
files: data.files, files: data.files,
browser: data.main, browser: data.main,
homepage: data.homepage,
types: data.dts_file, types: data.dts_file,
}) })
} }

@ -16,5 +16,7 @@ pub struct CommonJSPackage {
pub files: Vec<String>, pub files: Vec<String>,
pub main: String, pub main: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub homepage: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub types: Option<String>, pub types: Option<String>,
} }

@ -16,6 +16,8 @@ pub struct ESModulesPackage {
pub files: Vec<String>, pub files: Vec<String>,
pub module: String, pub module: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub homepage: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub types: Option<String>, pub types: Option<String>,
#[serde(rename = "sideEffects")] #[serde(rename = "sideEffects")]
pub side_effects: String, pub side_effects: String,

@ -16,5 +16,7 @@ pub struct NoModulesPackage {
pub files: Vec<String>, pub files: Vec<String>,
pub browser: String, pub browser: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub homepage: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub types: Option<String>, pub types: Option<String>,
} }

@ -10,7 +10,12 @@ use std::process::Command;
/// Run `cargo test` with the `nightly` toolchain and targeting /// Run `cargo test` with the `nightly` toolchain and targeting
/// `wasm32-unknown-unknown`. /// `wasm32-unknown-unknown`.
pub fn cargo_test_wasm<I, K, V>(path: &Path, release: bool, envs: I) -> Result<(), failure::Error> pub fn cargo_test_wasm<I, K, V>(
path: &Path,
release: bool,
envs: I,
extra_options: &[String],
) -> Result<(), failure::Error>
where where
I: IntoIterator<Item = (K, V)>, I: IntoIterator<Item = (K, V)>,
K: AsRef<OsStr>, K: AsRef<OsStr>,
@ -23,6 +28,7 @@ where
cmd.arg("--release"); cmd.arg("--release");
} }
cmd.arg("--target").arg("wasm32-unknown-unknown"); cmd.arg("--target").arg("wasm32-unknown-unknown");
cmd.args(extra_options);
child::run(cmd, "cargo test").context("Running Wasm tests with wasm-bindgen-test failed")?; child::run(cmd, "cargo test").context("Running Wasm tests with wasm-bindgen-test failed")?;
// NB: `child::run` took care of ensuring that test output gets printed. // NB: `child::run` took care of ensuring that test output gets printed.

@ -34,7 +34,7 @@ fn it_copies_a_license_default_path() {
} }
#[test] #[test]
fn it_copies_a_license_provied_path() { fn it_copies_a_license_provided_path() {
let fixture = fixture::single_license(); let fixture = fixture::single_license();
let out_dir = fixture.path.join("pkg"); let out_dir = fixture.path.join("pkg");
fs::create_dir(&out_dir).expect("should create pkg directory OK"); fs::create_dir(&out_dir).expect("should create pkg directory OK");
@ -128,3 +128,30 @@ fn it_copies_all_licenses_provided_path() {
let pkg_license_2 = utils::file::read_file(&pkg_license_path_2).unwrap(); let pkg_license_2 = utils::file::read_file(&pkg_license_path_2).unwrap();
assert_eq!(crate_license_2, pkg_license_2); assert_eq!(crate_license_2, pkg_license_2);
} }
#[test]
fn it_copies_a_non_standard_license_provided_path() {
let license_file = "NON-STANDARD-LICENSE";
let fixture = fixture::non_standard_license(license_file);
let out_dir = fixture.path.join("pkg");
fs::create_dir(&out_dir).expect("should create pkg directory OK");
let crate_data = CrateData::new(&fixture.path);
let step = wasm_pack::progressbar::Step::new(1);
assert!(license::copy_from_crate(&crate_data.unwrap(), &fixture.path, &out_dir, &step).is_ok());
let crate_license_path = fixture.path.join(license_file);
let pkg_license_path = out_dir.join(license_file);
println!(
"wasm-pack: should have copied LICENSE from '{}' to '{}'",
crate_license_path.display(),
pkg_license_path.display()
);
assert!(fs::metadata(&crate_license_path).is_ok());
assert!(fs::metadata(&pkg_license_path).is_ok());
let crate_license = utils::file::read_file(&crate_license_path).unwrap();
let pkg_license = utils::file::read_file(&pkg_license_path).unwrap();
assert_eq!(crate_license, pkg_license);
}

@ -279,6 +279,63 @@ fn it_errors_when_wasm_bindgen_is_not_declared() {
assert!(crate_data.check_crate_config(&step).is_err()); assert!(crate_data.check_crate_config(&step).is_err());
} }
#[test]
fn it_sets_homepage_field_if_available_in_cargo_toml() {
// When 'homepage' is available
let fixture = utils::fixture::Fixture::new();
fixture.hello_world_src_lib().file(
"Cargo.toml",
r#"
[package]
authors = ["The wasm-pack developers"]
description = "so awesome rust+wasm package"
license = "WTFPL"
name = "homepage-field-test"
repository = "https://github.com/rustwasm/wasm-pack.git"
version = "0.1.0"
homepage = "https://rustwasm.github.io/wasm-pack/"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "=0.2"
[dev-dependencies]
wasm-bindgen-test = "=0.2"
"#,
);
let out_dir = fixture.path.join("pkg");
let crate_data = manifest::CrateData::new(&fixture.path).unwrap();
let step = wasm_pack::progressbar::Step::new(2);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
crate_data
.write_package_json(&out_dir, &None, true, "", &step)
.unwrap();
let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap();
assert_eq!(
pkg.homepage,
Some("https://rustwasm.github.io/wasm-pack/".to_string()),
);
// When 'homepage' is unavailable
let fixture = fixture::js_hello_world();
let out_dir = fixture.path.join("pkg");
let crate_data = manifest::CrateData::new(&fixture.path).unwrap();
let step = wasm_pack::progressbar::Step::new(2);
wasm_pack::command::utils::create_pkg_dir(&out_dir, &step).unwrap();
crate_data
.write_package_json(&out_dir, &None, true, "", &step)
.unwrap();
let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap();
assert_eq!(pkg.homepage, None);
}
#[test] #[test]
fn it_does_not_error_when_wasm_bindgen_is_declared() { fn it_does_not_error_when_wasm_bindgen_is_declared() {
let fixture = fixture::js_hello_world(); let fixture = fixture::js_hello_world();

@ -137,6 +137,39 @@ impl Fixture {
) )
} }
/// Add a `Cargo.toml` with a correctly configured `wasm-bindgen`
/// dependency, `wasm-bindgen-test` dev-dependency, and `crate-type =
/// ["cdylib"]`.
///
/// `name` is the crate's name.
/// `license_file` is license file path
pub fn cargo_toml_with_license_file(&self, name: &str, license_file: &str) -> &Self {
self.file(
"Cargo.toml",
&format!(
r#"
[package]
authors = ["The wasm-pack developers"]
description = "so awesome rust+wasm package"
name = "{}"
license-file = "{}"
repository = "https://github.com/rustwasm/wasm-pack.git"
version = "0.1.0"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "=0.2.21"
[dev-dependencies]
wasm-bindgen-test = "=0.2.21"
"#,
name, license_file
),
)
}
/// Add a `src/lib.rs` file that contains a "hello world" program. /// Add a `src/lib.rs` file that contains a "hello world" program.
pub fn hello_world_src_lib(&self) -> &Self { pub fn hello_world_src_lib(&self) -> &Self {
self.file( self.file(
@ -661,3 +694,13 @@ pub fn dual_license() -> Fixture {
.hello_world_src_lib(); .hello_world_src_lib();
fixture fixture
} }
pub fn non_standard_license(license_file: &str) -> Fixture {
let fixture = Fixture::new();
fixture
.readme()
.cargo_toml_with_license_file("dual_license", license_file)
.file(license_file, "license file for test")
.hello_world_src_lib();
fixture
}

@ -23,6 +23,7 @@ pub struct NpmPackage {
pub types: String, pub types: String,
#[serde(default = "default_none", rename = "sideEffects")] #[serde(default = "default_none", rename = "sideEffects")]
pub side_effects: String, pub side_effects: String,
pub homepage: Option<String>,
} }
fn default_none() -> String { fn default_none() -> String {

Loading…
Cancel
Save