Skip to content

Commit

Permalink
User scripts e2e testing (#137)
Browse files Browse the repository at this point in the history
* Add configurable user scripts location via env var

* Add smoke test for user-activate
* Add JS example script to default user scripts content

Fixes #136

TODO:

* [ ] Add more smoke tests
* [ ] Handle new my-lib location somehow

* Make user JS scripts reload when run

* Create user example script exports work

* Add tests for running user scripts

* Consolidate test files some

* Add test for reloading js scripts

* Add check for minimum passed assertions

Fixes #138

* Only create getting started user content if activate is missing

Fixes #139

* Add test run launch config

* Open extension host in workspace 1 folder by default
  • Loading branch information
PEZ authored Jan 6, 2023
1 parent cd1528a commit efb89ab
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 87 deletions.
21 changes: 19 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,30 @@
"version": "0.2.0",
"configurations": [
{
"name": "Launch Extension",
"name": "Launch Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}"
"--disable-extensions",
"--extensionDevelopmentPath=${workspaceRoot}",
"--extensionTestsPath=${workspaceRoot}/vscode-test-runner/runTests.js",
"--folder-uri=${workspaceRoot}/vscode-test-runner/workspace-1"
],
//"sourceMaps": true,
//"outFiles": [
// "${workspaceFolder}/out/**/*.js"
//]
},
{
"name": "Launch Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}",
"--folder-uri=${workspaceRoot}/vscode-test-runner/workspace-1"
],
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
Expand Down
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ Changes to Joyride
## [Unreleased]

- [Enable using JS files as user and workspace scripts](https://github.com/BetterThanTomorrow/joyride/issues/132)
- Fix [Allow `js/require` to be used in joyride](https://github.com/BetterThanTomorrow/joyride/issues/134)
- Fix: [Allow `js/require` to be used in joyride](https://github.com/BetterThanTomorrow/joyride/issues/134)
- Dev internals: [Add basic e2e tests for user scripts](https://github.com/BetterThanTomorrow/joyride/issues/136)
- Dev internals: [Ensure that Joyride's `cljs.test` actually runs tests](https://github.com/BetterThanTomorrow/joyride/issues/138)
- Fix: [Default user content places `my_lib.cljs` in `scripts` folder, should be in `src` folder](https://github.com/BetterThanTomorrow/joyride/issues/139)

## [0.0.29] - 2023-01-02

Expand Down
26 changes: 26 additions & 0 deletions assets/getting-started-content/user/hello_joyride_user_script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const vscode = require("vscode");

// You can write your Joyride scripts in JavaScript, if you want.

const hello = () => {
return "Hello World!";
};

const showHelloMessage = async () => {
const button = await vscode.window.showInformationMessage("Hello World!", "Cancel", "OK");
if (button === "OK") {
vscode.window.showInformationMessage("You clicked OK! Try clicking Cancel too?.");
} else {
const name = await vscode.window.showInputBox({
title: "CIA wants to know",
prompt: "What is your name?",
});
vscode.window.showInformationMessage(`Hello ${name}!`);
}
};

hello();
showHelloMessage();

exports.hello = hello;
exports.showHelloMessage = showHelloMessage;
39 changes: 39 additions & 0 deletions assets/getting-started-content/user/problem_hover.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
(ns problem-hover
(:require ["vscode" :as vscode]))

;; Adding diagnostics info to the top of the hover to get it above the fold

(defonce !problems (atom {}))

(defn on-changed-diagnostics [event]
(doseq [uri (.-uris event)]
(swap! !problems assoc (.-fsPath uri) (vscode/languages.getDiagnostics uri))))

(defn- provide-hover [document position]
(let [hover (vscode/MarkdownString.)
problems (->> (get @!problems (-> document .-uri .-fsPath))
(keep (fn [problem]
(let [range (.-range problem)]
(when (.contains range position)
problem)))))]
(doseq [problem problems]
(.appendCodeblock hover (str (.-message problem)
"; " (.-source problem)
(when (.-code problem)
(str "(" (.-code problem) ")")))
; highlight hover as 'ini', because works
"ini"))
(new vscode/Hover #js [hover])))

(defn register-diagnostics-handler! []
(vscode/languages.onDidChangeDiagnostics on-changed-diagnostics))

(defn register-provider! []
; Use "*" instead of "clojure" to add this to all file types
(vscode/languages.registerHoverProvider "clojure" #js {:provideHover provide-hover}))

(comment
foo
(remove 1 2 3)
:rcf)

4 changes: 3 additions & 1 deletion src/joyride/config.cljs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
(ns joyride.config
(:require ["os" :as os]
["path" :as path]
["process" :as process]
[joyride.db :as db]))

(def user-config-path (path/join (os/homedir) ".config"))
(def user-config-path (or (aget process/env "VSCODE_JOYRIDE_USER_CONFIG_PATH")
(path/join (os/homedir) ".config")))
(def user-scripts-path (path/join "joyride" "scripts"))

(defn user-abs-scripts-path
Expand Down
62 changes: 18 additions & 44 deletions src/joyride/getting_started.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -24,49 +24,24 @@
(js/console.info "Creating " ^String (.-fsPath dest-uri))
(vscode/workspace.fs.copy source-uri dest-uri)))

(defn user-activate-uri-section-and-subpath []
[(conf/user-abs-scripts-path)
"user"
"user_activate.cljs"])

(defn user-hello-uri-section-and-subpath []
[(conf/user-abs-scripts-path)
"user"
"hello_joyride_user_script.cljs"])

(defn user-my-lib-uri-section-and-subpath []
[(conf/user-abs-scripts-path)
"user"
"my_lib.cljs"])

(defn workspace-activate-uri-section-and-subpath []
[(conf/workspace-abs-scripts-path)
"workspace"
"workspace_activate.cljs"])

(defn workspace-hello-uri-section-and-subpath []
[(conf/workspace-abs-scripts-path)
"workspace"
"hello_joyride_workspace_script.cljs"])

(defn- dest-uri-uri-exists?+ [section-and-subpath]
(p/let [dest-uri (apply destination-uri section-and-subpath)
exists?+ (utils/path-or-uri-exists?+ dest-uri)]
[dest-uri exists?+]))

(defn maybe-create-user-content+ []
(p/let [section-and-subpath (user-activate-uri-section-and-subpath)
[activate-dest-uri activate-exists?+] (dest-uri-uri-exists?+ section-and-subpath)]
(defn- maybe-create-content+ [section-and-subpath]
(p/let [[activate-dest-uri activate-exists?+] (dest-uri-uri-exists?+ section-and-subpath)]
(when-not activate-exists?+
(apply (partial create-content-file+ activate-dest-uri) section-and-subpath)))
(p/let [section-and-subpath (user-hello-uri-section-and-subpath)
[hello-dest-uri hello-exists?+] (dest-uri-uri-exists?+ section-and-subpath)]
(when-not hello-exists?+
(apply (partial create-content-file+ hello-dest-uri) section-and-subpath)))
(p/let [section-and-subpath (user-my-lib-uri-section-and-subpath)
[my-lib-dest-uri my-lib-exists?+] (dest-uri-uri-exists?+ section-and-subpath)]
(when-not my-lib-exists?+
(apply (partial create-content-file+ my-lib-dest-uri) section-and-subpath))))
(apply (partial create-content-file+ activate-dest-uri) section-and-subpath))))

(defn maybe-create-user-content+ []
(p/let [[_ user-activate-exists?] (dest-uri-uri-exists?+ [(conf/user-abs-scripts-path) "user" "user_activate.cljs"])]
(when-not user-activate-exists?
(maybe-create-content+ [(conf/user-abs-scripts-path) "user" "user_activate.cljs"])
(maybe-create-content+ [(conf/user-abs-scripts-path) "user" "hello_joyride_user_script.cljs"])
(maybe-create-content+ [(conf/user-abs-scripts-path) "user" "hello_joyride_user_script.js"])
(maybe-create-content+ [(conf/user-abs-src-path) "user" "problem_hover.cljs"])
(maybe-create-content+ [(conf/user-abs-src-path) "user" "my_lib.cljs"]))))

(defn create-and-open-content-file+ [content-file-uri section-and-subpath]
(fn []
Expand All @@ -75,14 +50,13 @@
(vscode/window.showTextDocument
#js {:preview false, :preserveFocus false})))))

(defn maybe-create-workspace-activate-fn+ []
(p/let [section-and-subpath (workspace-activate-uri-section-and-subpath)
[activate-dest-uri activate-exists?+] (dest-uri-uri-exists?+ section-and-subpath)]
(defn maybe-create-and-open-content+ [section-and-subpath]
(p/let [[activate-dest-uri activate-exists?+] (dest-uri-uri-exists?+ section-and-subpath)]
(when-not activate-exists?+
(create-and-open-content-file+ activate-dest-uri section-and-subpath))))

(defn maybe-create-workspace-activate-fn+ []
(maybe-create-and-open-content+ [(conf/workspace-abs-scripts-path) "workspace" "workspace_activate.cljs"]))

(defn maybe-create-workspace-hello-fn+ []
(p/let [section-and-subpath (workspace-hello-uri-section-and-subpath)
[hello-dest-uri hello-exists?+] (dest-uri-uri-exists?+ section-and-subpath)]
(when-not hello-exists?+
(create-and-open-content-file+ hello-dest-uri section-and-subpath))))
(maybe-create-and-open-content+ [(conf/workspace-abs-scripts-path) "workspace" "hello_joyride_workspace_script.cljs"]))
6 changes: 5 additions & 1 deletion src/joyride/scripts_handler.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@
function (function))))))

(defn- cljs-snippet-requiring-js [abs-path]
(str "(js/require \"" abs-path "\")"))
(str "(require '[\"module\" :as module])
(let [req (module/createRequire \"/\")
resolved (.resolve req \"" abs-path "\")]
(aset (.-cache req) resolved js/undefined)
(js/require resolved))"))

(defn run-script+
([menu-conf+ base-path scripts-path]
Expand Down
42 changes: 39 additions & 3 deletions vscode-test-runner/launch.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
const path = require("path");
const process = require("process");
const os = require("os");
const fs = require("fs");
const { runTests } = require('@vscode/test-electron');

function init() {
return new Promise((resolve, reject) => {
try {
const USER_CONFIG_PATH_KEY = "VSCODE_JOYRIDE_USER_CONFIG_PATH";
if (!process.env[USER_CONFIG_PATH_KEY]) {
const tmpConfigPath = path.join(
os.tmpdir(),
"vscode-test-runner-joyride",
"user-config"
);
if (fs.existsSync(tmpConfigPath)) {
fs.rmSync(tmpConfigPath, { recursive: true });
}
fs.mkdirSync(tmpConfigPath, { recursive: true });
process.env[USER_CONFIG_PATH_KEY] = tmpConfigPath;
console.info(`USER_CONFIG_PATH: ${process.env[USER_CONFIG_PATH_KEY]}`);
}
resolve();
} catch (error) {
reject(error);
}
});
}

async function main() {
try {
// The folder containing the Extension Manifest package.json
Expand All @@ -20,11 +47,20 @@ async function main() {
extensionDevelopmentPath,
extensionTestsPath,
launchArgs,
});
}).then((_result) => {
console.info('Tests finished');
}).catch((err) => {
console.error('Tests finished:', err);
process.exit(1);
});
} catch (err) {
console.error('Failed to run tests');
console.error('Failed to run tests:', err);
process.exit(1);
}
}

void main();
void init().then(() => main())
.catch((error) => {
console.error('Failed to initialize test running environment:', error);
process.exit(1);
});
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
(ns integration-test.workspace-activate-test
(ns integration-test.activate-test
(:require [cljs.test :refer [deftest testing is]]
["path" :as path]))

(deftest ws-activate
(deftest user-activate
(testing "User activation script is required"
(is #_{:clj-kondo/ignore [:unresolved-namespace]}
(= #'user-activate/!db
((ns-publics 'user-activate) '!db))))

(testing "my-lib is required"
(is (seq
(ns-publics 'my-lib)))))

(deftest ws-activate
(testing "Workspace activation script defines a symbol"
(is (= :symbol-1
#_{:clj-kondo/ignore [:unresolved-namespace]}
workspace-activate/symbol-1)))

(testing "Workspace activation script defines a function"
(is (= :fn-1
#_{:clj-kondo/ignore [:unresolved-namespace]}
(workspace-activate/fn-1))))

(testing "Workspace activation script finds workspace root"
(is (= "workspace-1"
#_{:clj-kondo/ignore [:unresolved-namespace]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,28 @@

(defmethod cljs.test/report [:cljs.test/default :end-run-tests] [m]
(old-end-run-tests m)
(let [{:keys [running fail error]} @db/!state]
(let [{:keys [running pass fail error]} @db/!state
passed-minimum-threshold 20
fail-reason (cond
(> 0 (+ fail error)) "FAILURE: Some tests failed or errored"
(< pass passed-minimum-threshold) (str "FAILURE: Less than " passed-minimum-threshold " assertions passed")
:else nil)]
(println "Runner: tests run, results:" (select-keys @db/!state [:pass :fail :error]))
(if (zero? (+ fail error))
(p/resolve! running true)
(p/reject! running true))))
(if fail-reason
(p/reject! running fail-reason)
(p/resolve! running true))))

;; We rely on that the user_activate.cljs script is run before workspace_activate.cljs
(defn- run-when-ws-activated [tries]
(if (:ws-activated? @db/!state)
(do
(println "Runner: Workspace activated, running tests")
(require '[integration-test.workspace-activate-test])
(require '[integration-test.ws-scripts-test])
(require '[integration-test.activate-test])
(require '[integration-test.scripts-test])
(require '[integration-test.require-js-test])
(require '[integration-test.npm-test])
(cljs.test/run-tests 'integration-test.workspace-activate-test
'integration-test.ws-scripts-test
(cljs.test/run-tests 'integration-test.activate-test
'integration-test.scripts-test
'integration-test.require-js-test
'integration-test.npm-test))
(do
Expand Down
Loading

0 comments on commit efb89ab

Please sign in to comment.