Browse Source

Add option for jest test scaffolding (#2200)

* Add in option for jest scaffolding

* Add tests for Jest in both JS/TS

* Clone moved value; use new function name

* Remove invalid tests
Kyle Gilliam 2 years ago
parent
commit
23c9717af1
2 changed files with 173 additions and 37 deletions
  1. 47 17
      cli/src/lib.rs
  2. 126 20
      cli/src/template.rs

+ 47 - 17
cli/src/lib.rs

@@ -68,6 +68,8 @@ pub enum Command {
         javascript: bool,
         #[clap(long)]
         no_git: bool,
+        #[clap(long)]
+        jest: bool,
     },
     /// Builds the workspace.
     #[clap(name = "build", alias = "b")]
@@ -359,7 +361,8 @@ pub fn entry(opts: Opts) -> Result<()> {
             name,
             javascript,
             no_git,
-        } => init(&opts.cfg_override, name, javascript, no_git),
+            jest,
+        } => init(&opts.cfg_override, name, javascript, no_git, jest),
         Command::New { name } => new(&opts.cfg_override, name),
         Command::Build {
             idl,
@@ -466,7 +469,13 @@ pub fn entry(opts: Opts) -> Result<()> {
     }
 }
 
-fn init(cfg_override: &ConfigOverride, name: String, javascript: bool, no_git: bool) -> Result<()> {
+fn init(
+    cfg_override: &ConfigOverride,
+    name: String,
+    javascript: bool,
+    no_git: bool,
+    jest: bool,
+) -> Result<()> {
     if Config::discover(cfg_override)?.is_some() {
         return Err(anyhow!("Workspace already initialized"));
     }
@@ -474,7 +483,7 @@ fn init(cfg_override: &ConfigOverride, name: String, javascript: bool, no_git: b
     // We need to format different cases for the dir and the name
     let rust_name = name.to_snake_case();
     let project_name = if name == rust_name {
-        name
+        rust_name.clone()
     } else {
         name.to_kebab_case()
     };
@@ -496,15 +505,28 @@ fn init(cfg_override: &ConfigOverride, name: String, javascript: bool, no_git: b
     fs::create_dir("app")?;
 
     let mut cfg = Config::default();
-    cfg.scripts.insert(
-        "test".to_owned(),
-        if javascript {
-            "yarn run mocha -t 1000000 tests/"
-        } else {
-            "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
-        }
-        .to_owned(),
-    );
+    if jest {
+        cfg.scripts.insert(
+            "test".to_owned(),
+            if javascript {
+                "yarn run jest"
+            } else {
+                "yarn run jest --preset ts-jest"
+            }
+            .to_owned(),
+        );
+    } else {
+        cfg.scripts.insert(
+            "test".to_owned(),
+            if javascript {
+                "yarn run mocha -t 1000000 tests/"
+            } else {
+                "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+            }
+            .to_owned(),
+        );
+    }
+
     let mut localnet = BTreeMap::new();
     localnet.insert(
         rust_name,
@@ -540,20 +562,25 @@ fn init(cfg_override: &ConfigOverride, name: String, javascript: bool, no_git: b
     if javascript {
         // Build javascript config
         let mut package_json = File::create("package.json")?;
-        package_json.write_all(template::package_json().as_bytes())?;
+        package_json.write_all(template::package_json(jest).as_bytes())?;
 
-        let mut mocha = File::create(&format!("tests/{}.js", &project_name))?;
-        mocha.write_all(template::mocha(&project_name).as_bytes())?;
+        if jest {
+            let mut test = File::create(&format!("tests/{}.test.js", &project_name))?;
+            test.write_all(template::jest(&project_name).as_bytes())?;
+        } else {
+            let mut test = File::create(&format!("tests/{}.js", &project_name))?;
+            test.write_all(template::mocha(&project_name).as_bytes())?;
+        }
 
         let mut deploy = File::create("migrations/deploy.js")?;
         deploy.write_all(template::deploy_script().as_bytes())?;
     } else {
         // Build typescript config
         let mut ts_config = File::create("tsconfig.json")?;
-        ts_config.write_all(template::ts_config().as_bytes())?;
+        ts_config.write_all(template::ts_config(jest).as_bytes())?;
 
         let mut ts_package_json = File::create("package.json")?;
-        ts_package_json.write_all(template::ts_package_json().as_bytes())?;
+        ts_package_json.write_all(template::ts_package_json(jest).as_bytes())?;
 
         let mut deploy = File::create("migrations/deploy.ts")?;
         deploy.write_all(template::ts_deploy_script().as_bytes())?;
@@ -3169,6 +3196,7 @@ mod tests {
             "await".to_string(),
             true,
             false,
+            false,
         )
         .unwrap();
     }
@@ -3184,6 +3212,7 @@ mod tests {
             "fn".to_string(),
             true,
             false,
+            false,
         )
         .unwrap();
     }
@@ -3199,6 +3228,7 @@ mod tests {
             "1project".to_string(),
             true,
             false,
+            false,
         )
         .unwrap();
     }

+ 126 - 20
cli/src/template.rs

@@ -221,9 +221,49 @@ describe("{}", () => {{
     )
 }
 
-pub fn package_json() -> String {
+pub fn jest(name: &str) -> String {
     format!(
-        r#"{{
+        r#"const anchor = require("@project-serum/anchor");
+
+describe("{}", () => {{
+  // Configure the client to use the local cluster.
+  anchor.setProvider(anchor.AnchorProvider.env());
+
+  it("Is initialized!", async () => {{
+    // Add your test here.
+    const program = anchor.workspace.{};
+    const tx = await program.methods.initialize().rpc();
+    console.log("Your transaction signature", tx);
+  }});
+}});
+"#,
+        name,
+        name.to_upper_camel_case(),
+    )
+}
+
+pub fn package_json(jest: bool) -> String {
+    if jest {
+        format!(
+            r#"{{
+        "scripts": {{
+            "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
+            "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
+        }},
+        "dependencies": {{
+            "@project-serum/anchor": "^{0}"
+        }},
+        "devDependencies": {{
+            "jest": "^29.0.3",
+            "prettier": "^2.6.2"
+        }}
+    }}
+    "#,
+            VERSION
+        )
+    } else {
+        format!(
+            r#"{{
     "scripts": {{
         "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
         "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
@@ -238,13 +278,37 @@ pub fn package_json() -> String {
     }}
 }}
 "#,
-        VERSION
-    )
+            VERSION
+        )
+    }
 }
 
-pub fn ts_package_json() -> String {
-    format!(
-        r#"{{
+pub fn ts_package_json(jest: bool) -> String {
+    if jest {
+        format!(
+            r#"{{
+        "scripts": {{
+            "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
+            "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
+        }},
+        "dependencies": {{
+            "@project-serum/anchor": "^{0}"
+        }},
+        "devDependencies": {{
+            "@types/bn.js": "^5.1.0",
+            "@types/jest": "^29.0.3",
+            "jest": "^29.0.3",
+            "prettier": "^2.6.2",
+            "ts-jest": "^29.0.2",
+            "typescript": "^4.3.5"
+        }}
+    }}
+    "#,
+            VERSION
+        )
+    } else {
+        format!(
+            r#"{{
     "scripts": {{
         "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
         "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
@@ -264,8 +328,9 @@ pub fn ts_package_json() -> String {
     }}
 }}
 "#,
-        VERSION
-    )
+            VERSION
+        )
+    }
 }
 
 pub fn ts_mocha(name: &str) -> String {
@@ -295,18 +360,59 @@ describe("{}", () => {{
     )
 }
 
-pub fn ts_config() -> &'static str {
-    r#"{
-  "compilerOptions": {
-    "types": ["mocha", "chai"],
-    "typeRoots": ["./node_modules/@types"],
-    "lib": ["es2015"],
-    "module": "commonjs",
-    "target": "es6",
-    "esModuleInterop": true
-  }
+pub fn ts_jest(name: &str) -> String {
+    format!(
+        r#"import * as anchor from "@project-serum/anchor";
+import {{ Program }} from "@project-serum/anchor";
+import {{ {} }} from "../target/types/{}";
+
+describe("{}", () => {{
+  // Configure the client to use the local cluster.
+  anchor.setProvider(anchor.AnchorProvider.env());
+
+  const program = anchor.workspace.{} as Program<{}>;
+
+  it("Is initialized!", async () => {{
+    // Add your test here.
+    const tx = await program.methods.initialize().rpc();
+    console.log("Your transaction signature", tx);
+  }});
+}});
+"#,
+        name.to_upper_camel_case(),
+        name.to_snake_case(),
+        name,
+        name.to_upper_camel_case(),
+        name.to_upper_camel_case(),
+    )
 }
-"#
+
+pub fn ts_config(jest: bool) -> &'static str {
+    if jest {
+        r#"{
+            "compilerOptions": {
+              "types": ["jest"],
+              "typeRoots": ["./node_modules/@types"],
+              "lib": ["es2015"],
+              "module": "commonjs",
+              "target": "es6",
+              "esModuleInterop": true
+            }
+          }
+          "#
+    } else {
+        r#"{
+            "compilerOptions": {
+              "types": ["mocha", "chai"],
+              "typeRoots": ["./node_modules/@types"],
+              "lib": ["es2015"],
+              "module": "commonjs",
+              "target": "es6",
+              "esModuleInterop": true
+            }
+          }
+          "#
+    }
 }
 
 pub fn git_ignore() -> &'static str {