@jsenv/cli 0.0.2 → 0.0.5

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 (90) hide show
  1. package/README.md +7 -0
  2. package/jsenv_cli.js +342 -0
  3. package/package.json +7 -5
  4. package/template-node-package/.eslintignore +2 -0
  5. package/template-node-package/.eslintrc.cjs +102 -0
  6. package/template-node-package/.jsenv/jsenv_tests_output.txt +8 -0
  7. package/template-node-package/.prettierrc.yml +2 -0
  8. package/template-node-package/package.json +23 -0
  9. package/template-node-package/scripts/test.mjs +25 -0
  10. package/template-node-package/src/main.js +8 -0
  11. package/template-node-package/src/message.js +11 -0
  12. package/template-node-package/tests/message.test.mjs +21 -0
  13. package/template-web/.eslintignore +3 -0
  14. package/template-web/.eslintrc.cjs +138 -0
  15. package/template-web/.prettierrc.yml +2 -0
  16. package/template-web/babel.config.cjs +3 -0
  17. package/template-web/package.json +33 -0
  18. package/template-web/scripts/build.mjs +21 -0
  19. package/template-web/scripts/build_serve.mjs +16 -0
  20. package/template-web/scripts/dev.mjs +15 -0
  21. package/template-web/scripts/test.mjs +29 -0
  22. package/template-web/src/app/animals.js +11 -0
  23. package/template-web/src/app/counter.js +11 -0
  24. package/template-web/src/index.html +27 -0
  25. package/template-web/src/jsenv_logo.svg +140 -0
  26. package/template-web/src/main.css +4 -0
  27. package/template-web/src/main.js +31 -0
  28. package/template-web/src/tests/animals.test.html +32 -0
  29. package/template-web/src/tests/app.test.mjs +26 -0
  30. package/template-web-components/.eslintignore +3 -0
  31. package/template-web-components/.eslintrc.cjs +138 -0
  32. package/template-web-components/.prettierrc.yml +2 -0
  33. package/template-web-components/babel.config.cjs +3 -0
  34. package/template-web-components/package.json +35 -0
  35. package/template-web-components/scripts/build.mjs +21 -0
  36. package/template-web-components/scripts/build_serve.mjs +16 -0
  37. package/template-web-components/scripts/dev.mjs +15 -0
  38. package/template-web-components/scripts/test.mjs +29 -0
  39. package/template-web-components/src/app/animals.js +11 -0
  40. package/template-web-components/src/app/app_custom_element.css +4 -0
  41. package/template-web-components/src/app/app_custom_element.js +31 -0
  42. package/template-web-components/src/app/counter.js +11 -0
  43. package/template-web-components/src/app/custom_elements_redefine.js +5 -0
  44. package/template-web-components/src/index.html +27 -0
  45. package/template-web-components/src/jsenv_logo.svg +140 -0
  46. package/template-web-components/src/main.js +11 -0
  47. package/template-web-components/src/tests/animals.test.html +32 -0
  48. package/template-web-components/src/tests/app.test.mjs +26 -0
  49. package/template-web-preact/.eslintignore +3 -0
  50. package/template-web-preact/.eslintrc.cjs +175 -0
  51. package/template-web-preact/.prettierrc.yml +2 -0
  52. package/template-web-preact/babel.config.cjs +11 -0
  53. package/template-web-preact/package.json +40 -0
  54. package/template-web-preact/scripts/build.mjs +23 -0
  55. package/template-web-preact/scripts/build_serve.mjs +16 -0
  56. package/template-web-preact/scripts/dev.mjs +21 -0
  57. package/template-web-preact/scripts/test.mjs +28 -0
  58. package/template-web-preact/src/app/animals.js +11 -0
  59. package/template-web-preact/src/app/app.css +42 -0
  60. package/template-web-preact/src/app/app.jsx +52 -0
  61. package/template-web-preact/src/app/counter.jsx +20 -0
  62. package/template-web-preact/src/index.html +28 -0
  63. package/template-web-preact/src/main.jsx +5 -0
  64. package/template-web-preact/src/preact_logo.svg +6 -0
  65. package/template-web-preact/src/tests/animals.test.html +32 -0
  66. package/template-web-preact/src/tests/app.test.mjs +26 -0
  67. package/template-web-react/.eslintignore +3 -0
  68. package/template-web-react/.eslintrc.cjs +175 -0
  69. package/template-web-react/.prettierrc.yml +2 -0
  70. package/template-web-react/babel.config.cjs +12 -0
  71. package/template-web-react/package.json +41 -0
  72. package/template-web-react/scripts/build.mjs +23 -0
  73. package/template-web-react/scripts/build_serve.mjs +16 -0
  74. package/template-web-react/scripts/dev.mjs +21 -0
  75. package/template-web-react/scripts/test.mjs +28 -0
  76. package/template-web-react/src/app/animals.js +11 -0
  77. package/template-web-react/src/app/app.css +42 -0
  78. package/template-web-react/src/app/app.jsx +55 -0
  79. package/template-web-react/src/app/counter.jsx +19 -0
  80. package/template-web-react/src/index.html +28 -0
  81. package/template-web-react/src/main.jsx +14 -0
  82. package/template-web-react/src/react_logo.svg +7 -0
  83. package/template-web-react/src/tests/animals.test.html +32 -0
  84. package/template-web-react/src/tests/app.test.mjs +26 -0
  85. package/src/command_build.mjs +0 -185
  86. package/src/command_dev.mjs +0 -38
  87. package/src/command_preview.mjs +0 -22
  88. package/src/command_test.mjs +0 -59
  89. package/src/jsenv_cli.mjs +0 -66
  90. package/src/package_installer.js +0 -122
@@ -0,0 +1,175 @@
1
+ /*
2
+ * This file uses "@jsenv/eslint-config" to configure ESLint
3
+ * https://github.com/jsenv/eslint-config#eslint-config----
4
+ */
5
+
6
+ const {
7
+ composeEslintConfig,
8
+ eslintConfigBase,
9
+ eslintConfigForPrettier,
10
+ eslintConfigToPreferExplicitGlobals,
11
+ jsenvEslintRules,
12
+ jsenvEslintRulesForImport,
13
+ jsenvEslintRulesForReact,
14
+ } = require("@jsenv/eslint-config");
15
+
16
+ const eslintConfig = composeEslintConfig(
17
+ eslintConfigBase,
18
+
19
+ // By default files are meant to be executed in Node.js
20
+ // and we want to tell this to ESLint.
21
+ // As a result ESLint can consider `window` as undefined
22
+ // and `global` as an existing global variable.
23
+ {
24
+ env: {
25
+ node: true,
26
+ },
27
+ },
28
+
29
+ // enable top level await
30
+ {
31
+ parserOptions: {
32
+ ecmaVersion: 2022,
33
+ },
34
+ },
35
+
36
+ // use "@babel/eslint-parser" until import assertions is supported natively by ESLint
37
+ {
38
+ parser: "@babel/eslint-parser",
39
+ parserOptions: {
40
+ requireConfigFile: false,
41
+ },
42
+ },
43
+
44
+ // Reuse jsenv eslint rules
45
+ {
46
+ rules: {
47
+ ...jsenvEslintRules,
48
+ // Example of code changing the ESLint configuration to enable a rule:
49
+ // 'prefer-const': ['error']
50
+ },
51
+ },
52
+
53
+ // Enable import plugin
54
+ {
55
+ plugins: ["import"],
56
+ settings: {
57
+ "import/resolver": {
58
+ "@jsenv/eslint-import-resolver": {
59
+ rootDirectoryUrl: __dirname,
60
+ packageConditions: ["node", "import"],
61
+ },
62
+ },
63
+ },
64
+ rules: jsenvEslintRulesForImport,
65
+ },
66
+
67
+ // Enable HTML plugin
68
+ {
69
+ plugins: ["html"],
70
+ settings: {
71
+ extensions: [".html"],
72
+ settings: {
73
+ "html/javascript-mime-types": [
74
+ "text/javascript",
75
+ "module",
76
+ "text/jsx",
77
+ "module/jsx",
78
+ ],
79
+ },
80
+ },
81
+ },
82
+
83
+ // react
84
+ {
85
+ plugins: ["react"],
86
+ settings: {
87
+ react: {
88
+ version: "detect",
89
+ },
90
+ },
91
+ rules: {
92
+ ...jsenvEslintRulesForReact,
93
+ "react/jsx-filename-extension": ["error", { extensions: [".jsx"] }],
94
+ "react/react-in-jsx-scope": ["off"],
95
+ },
96
+ },
97
+
98
+ // jsx
99
+ {
100
+ parser: "@babel/eslint-parser",
101
+ parserOptions: {
102
+ ecmaFeatures: {
103
+ jsx: true,
104
+ },
105
+ },
106
+ settings: {
107
+ extensions: [".jsx"],
108
+ },
109
+ },
110
+
111
+ // Configure which files are written for the web
112
+ {
113
+ overrides: [
114
+ {
115
+ files: ["./src/**"],
116
+ env: {
117
+ browser: true,
118
+ node: false,
119
+ },
120
+ settings: {
121
+ "import/resolver": {
122
+ "@jsenv/eslint-import-resolver": {
123
+ rootDirectoryUrl: `${__dirname}/src/`,
124
+ packageConditions: ["browser", "import"],
125
+ },
126
+ },
127
+ },
128
+ },
129
+ ],
130
+ },
131
+
132
+ // package is "type": "module" so:
133
+ // 1. disable commonjs globals by default
134
+ // 2. Re-enable commonjs into *.cjs files
135
+ {
136
+ globals: {
137
+ __filename: "off",
138
+ __dirname: "off",
139
+ require: "off",
140
+ exports: "off",
141
+ },
142
+ overrides: [
143
+ {
144
+ files: ["**/*.cjs"],
145
+ env: {
146
+ commonjs: true,
147
+ },
148
+ // inside *.cjs files. restore commonJS "globals"
149
+ globals: {
150
+ __filename: true,
151
+ __dirname: true,
152
+ require: true,
153
+ exports: true,
154
+ },
155
+ // inside *.cjs files, use commonjs module resolution
156
+ settings: {
157
+ "import/resolver": {
158
+ "@jsenv/eslint-import-resolver": {
159
+ rootDirectoryUrl: __dirname,
160
+ packageConditions: ["node", "require"],
161
+ },
162
+ },
163
+ },
164
+ },
165
+ ],
166
+ },
167
+
168
+ eslintConfigToPreferExplicitGlobals,
169
+
170
+ // We are using prettier, disable all eslint rules
171
+ // already handled by prettier.
172
+ eslintConfigForPrettier,
173
+ );
174
+
175
+ module.exports = eslintConfig;
@@ -0,0 +1,2 @@
1
+ trailingComma: "all"
2
+ quoteProps: "consistent"
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ plugins: [
3
+ "@babel/plugin-syntax-import-assertions",
4
+ [
5
+ "@babel/plugin-transform-react-jsx",
6
+ {
7
+ pragma: "React.createElement",
8
+ pragmaFrag: "React.Fragment",
9
+ },
10
+ ],
11
+ ],
12
+ };
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "jsenv-template-web-react",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "start": "npm run dev -- --open",
8
+ "dev": "node ./scripts/dev.mjs",
9
+ "test": "node ./scripts/test.mjs",
10
+ "test:coverage": "npm run test -- --coverage",
11
+ "build": "node ./scripts/build.mjs",
12
+ "build:serve": "node ./scripts/build_serve.mjs --open",
13
+ "eslint": "npx eslint . --ext=.html,.js,.jsx,.mjs,.cjs",
14
+ "prettier": "prettier --write .",
15
+ "playwright:install": "npx playwright install-deps && npx playwright install"
16
+ },
17
+ "dependencies": {
18
+ "react": "18.3.1",
19
+ "react-dom": "18.3.1"
20
+ },
21
+ "devDependencies": {
22
+ "@babel/eslint-parser": "7.24.8",
23
+ "@babel/plugin-syntax-import-assertions": "7.24.7",
24
+ "@babel/plugin-transform-react-jsx": "7.24.7",
25
+ "@jsenv/assert": "4.1.4",
26
+ "@jsenv/core": "39.2.1",
27
+ "@jsenv/plugin-react": "1.5.2",
28
+ "@jsenv/plugin-bundling": "2.6.17",
29
+ "@jsenv/plugin-minification": "1.5.5",
30
+ "@jsenv/eslint-config": "16.5.2",
31
+ "@jsenv/eslint-import-resolver": "8.1.2",
32
+ "@jsenv/test": "3.3.11",
33
+ "eslint": "8.56.0",
34
+ "eslint-plugin-html": "8.1.1",
35
+ "eslint-plugin-import": "2.29.1",
36
+ "eslint-plugin-react": "7.34.4",
37
+ "open": "10.1.0",
38
+ "@playwright/browser-chromium": "1.45.2",
39
+ "prettier": "3.3.3"
40
+ }
41
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Optimize source files and write them into "./dist/"
3
+ * Read more in https://github.com/jsenv/core/wiki
4
+ */
5
+
6
+ import { build } from "@jsenv/core";
7
+ import { jsenvPluginReact } from "@jsenv/plugin-react";
8
+
9
+ await build({
10
+ sourceDirectoryUrl: new URL("../src/", import.meta.url),
11
+ buildDirectoryUrl: new URL("../dist/", import.meta.url),
12
+ entryPoints: {
13
+ "./index.html": "index.html",
14
+ },
15
+ plugins: [jsenvPluginReact()],
16
+ bundling: {
17
+ js_module: {
18
+ chunks: {
19
+ vendors: { "file:///**/node_modules/": true },
20
+ },
21
+ },
22
+ },
23
+ });
@@ -0,0 +1,16 @@
1
+ /*
2
+ * Start a server serving files into dist/.
3
+ * Useful to test the files generated during the build
4
+ * Read more in https://github.com/jsenv/core/wiki
5
+ */
6
+
7
+ import open from "open";
8
+ import { startBuildServer } from "@jsenv/core";
9
+
10
+ const buildServer = await startBuildServer({
11
+ buildDirectoryUrl: new URL("../dist/", import.meta.url),
12
+ port: 3501,
13
+ });
14
+ if (process.argv.includes("--open")) {
15
+ open(buildServer.origin);
16
+ }
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Start a development server for files inside src/
3
+ * Read more in https://github.com/jsenv/core/wiki
4
+ */
5
+
6
+ import open from "open";
7
+ import { startDevServer } from "@jsenv/core";
8
+ import { jsenvPluginReact } from "@jsenv/plugin-react";
9
+
10
+ export const devServer = await startDevServer({
11
+ sourceDirectoryUrl: new URL("../src/", import.meta.url),
12
+ plugins: [
13
+ jsenvPluginReact({
14
+ refreshInstrumentation: true,
15
+ }),
16
+ ],
17
+ port: 3400,
18
+ });
19
+ if (process.argv.includes("--open")) {
20
+ open(`${devServer.origin}`);
21
+ }
@@ -0,0 +1,28 @@
1
+ /*
2
+ * Execute all test files
3
+ * Read more in https://github.com/jsenv/core/wiki
4
+ */
5
+
6
+ import { executeTestPlan, chromium, nodeWorkerThread } from "@jsenv/test";
7
+
8
+ await executeTestPlan({
9
+ rootDirectoryUrl: new URL("../", import.meta.url),
10
+ testPlan: {
11
+ "./src/**/*.test.html": {
12
+ chromium: {
13
+ runtime: chromium(),
14
+ },
15
+ },
16
+ "./src/**/*.test.mjs": {
17
+ node: {
18
+ runtime: nodeWorkerThread(),
19
+ },
20
+ },
21
+ },
22
+ webServer: {
23
+ origin: "http://localhost:3400",
24
+ moduleUrl: new URL("./dev.mjs", import.meta.url),
25
+ },
26
+ coverage: process.argv.includes("--coverage"),
27
+ githubCheck: false,
28
+ });
@@ -0,0 +1,11 @@
1
+ /*
2
+ * This file exists to show code using the browser runtime to operate:
3
+ * code writes "countDogs" function on window
4
+ *
5
+ * As a result testing "countDogs" should be done in a browser.
6
+ * See "animals.test.html"
7
+ */
8
+
9
+ window.countDogs = (animals) => {
10
+ return animals.filter((animal) => animal === "dog").length;
11
+ };
@@ -0,0 +1,42 @@
1
+ .app {
2
+ text-align: center;
3
+ }
4
+
5
+ .app_logo {
6
+ height: 40vmin;
7
+ pointer-events: none;
8
+ }
9
+
10
+ @media (prefers-reduced-motion: no-preference) {
11
+ .app_logo {
12
+ animation: app_logo_spin infinite 20s linear;
13
+ }
14
+ }
15
+
16
+ .app_header {
17
+ background-color: #282c34;
18
+ min-height: 100vh;
19
+ display: flex;
20
+ flex-direction: column;
21
+ align-items: center;
22
+ justify-content: center;
23
+ font-size: calc(10px + 2vmin);
24
+ color: white;
25
+ }
26
+
27
+ .app_link {
28
+ color: #61dafb;
29
+ }
30
+
31
+ @keyframes app_logo_spin {
32
+ from {
33
+ transform: rotate(0deg);
34
+ }
35
+ to {
36
+ transform: rotate(360deg);
37
+ }
38
+ }
39
+
40
+ button {
41
+ font-size: calc(10px + 2vmin);
42
+ }
@@ -0,0 +1,55 @@
1
+ import { useLayoutEffect } from "react";
2
+
3
+ import appStyleSheet from "./app.css" with { type: "css" };
4
+ import { Counter } from "./counter.jsx";
5
+
6
+ const reactLogoUrl = new URL("../react_logo.svg", import.meta.url);
7
+
8
+ export const App = () => {
9
+ useLayoutEffect(() => {
10
+ document.adoptedStyleSheets = [
11
+ ...document.adoptedStyleSheets,
12
+ appStyleSheet,
13
+ ];
14
+ return () => {
15
+ document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
16
+ (s) => s !== appStyleSheet,
17
+ );
18
+ };
19
+ }, []);
20
+
21
+ return (
22
+ <div className="app">
23
+ <header className="app_header">
24
+ <img src={reactLogoUrl} className="app_logo" alt="logo" />
25
+ <p>Hello jsenv + React!</p>
26
+ <p>
27
+ <Counter />
28
+ </p>
29
+ <p>
30
+ Edit{" "}
31
+ <a
32
+ className="app_link"
33
+ onClick={(e) => {
34
+ e.preventDefault();
35
+ window.fetch("/__open_in_editor__/app/app.jsx");
36
+ }}
37
+ >
38
+ app.jsx
39
+ </a>{" "}
40
+ and save to test HMR updates.
41
+ </p>
42
+ <p>
43
+ <a
44
+ className="app_link"
45
+ href="https://github.com/jsenv/core"
46
+ target="_blank"
47
+ rel="noopener noreferrer"
48
+ >
49
+ Jsenv documentation
50
+ </a>
51
+ </p>
52
+ </header>
53
+ </div>
54
+ );
55
+ };
@@ -0,0 +1,19 @@
1
+ import { useState, Fragment } from "react";
2
+
3
+ export const Counter = () => {
4
+ const [count, setCount] = useState(0);
5
+
6
+ return (
7
+ <Fragment>
8
+ <button
9
+ id="counter_button"
10
+ type="button"
11
+ onClick={() => setCount((count) => count + 1)}
12
+ >
13
+ Click me
14
+ </button>
15
+ <br />
16
+ number of click: <span id="counter_output">{count}</span>
17
+ </Fragment>
18
+ );
19
+ };
@@ -0,0 +1,28 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/react_logo.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
11
+ "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
12
+ "Helvetica Neue", sans-serif;
13
+ -webkit-font-smoothing: antialiased;
14
+ -moz-osx-font-smoothing: grayscale;
15
+ }
16
+
17
+ code {
18
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
19
+ monospace;
20
+ }
21
+ </style>
22
+ <title>Jsenv App</title>
23
+ </head>
24
+ <body>
25
+ <div id="root"></div>
26
+ <script type="module" src="./main.jsx"></script>
27
+ </body>
28
+ </html>
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+
4
+ import { App } from "./app/app.jsx";
5
+
6
+ ReactDOM.createRoot(document.querySelector("#root")).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>,
10
+ );
11
+
12
+ if (import.meta.hot) {
13
+ import.meta.hot.accept();
14
+ }
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
2
+ <g fill="#61DAFB">
3
+ <path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
4
+ <circle cx="420.9" cy="296.5" r="45.7"/>
5
+ <path d="M520.5 78.1z"/>
6
+ </g>
7
+ </svg>
@@ -0,0 +1,32 @@
1
+ <!--
2
+ This HTML file demo how to write a test using jsenv.
3
+ This file is testing a "countDogs" function implemented in "animals.js"
4
+ -->
5
+ <!doctype html>
6
+ <html>
7
+ <head>
8
+ <meta charset="utf-8" />
9
+ <link rel="icon" href="data:," />
10
+ </head>
11
+
12
+ <body>
13
+ <script type="module">
14
+ import { assert } from "@jsenv/assert";
15
+ import "/app/animals.js";
16
+
17
+ {
18
+ const actual = window.countDogs(["dog", "dog"]);
19
+ const expect = 2;
20
+ assert({ actual, expect });
21
+ }
22
+
23
+ {
24
+ const actual = window.countDogs(["dog", "cat"]);
25
+ const expect = 1;
26
+ assert({ actual, expect });
27
+ }
28
+
29
+ document.body.appendChild(document.createTextNode("ok"));
30
+ </script>
31
+ </body>
32
+ </html>
@@ -0,0 +1,26 @@
1
+ import { chromium } from "playwright";
2
+ import { assert } from "@jsenv/assert";
3
+
4
+ const browser = await chromium.launch();
5
+
6
+ try {
7
+ const browserContext = await browser.newContext({ ignoreHTTPSErrors: true });
8
+ const page = await browserContext.newPage();
9
+ await page.goto(`http://localhost:3400`);
10
+
11
+ const getCounterOutput = () => {
12
+ return page.locator("#counter_output").innerHTML();
13
+ };
14
+
15
+ assert({
16
+ actual: await getCounterOutput(),
17
+ expect: "0",
18
+ });
19
+ await page.locator("#counter_button").click();
20
+ assert({
21
+ actual: await getCounterOutput(),
22
+ expect: "1",
23
+ });
24
+ } finally {
25
+ browser.close();
26
+ }