diff --git a/.gitignore b/.gitignore
index 699ea82f61..5eb826d30f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,7 +24,7 @@ caddy_linux_amd64
.ebextensions/*
\.ebextensions/
-public/js/lib/*
+public/js/*
*.pem
*.crt
@@ -33,5 +33,4 @@ public/js/lib/*
!tests/**
!package.json
!jsdoc*.json
-!codi.json
-!nodemon.json
\ No newline at end of file
+!codi.json
\ No newline at end of file
diff --git a/DEVELOPING.md b/DEVELOPING.md
index faee483bf1..d8aecda64c 100644
--- a/DEVELOPING.md
+++ b/DEVELOPING.md
@@ -24,7 +24,7 @@ Please check the full list of dependencies as defined in the [package.json](http
The MAPP and MAPP.UI library must be build with [esbuild](https://esbuild.github.io/) prior to launching the host.
- npx esbuild ./lib/mapp.mjs ./lib/ui.mjs --bundle --minify --tree-shaking=false --sourcemap --format=iife --outdir=./public/js/lib
+ npx esbuild ./lib/mapp.mjs ./lib/ui.mjs --bundle --minify --tree-shaking=false --sourcemap --format=iife --outdir=./public/js
The build command is stored in the package.json as `_build` script.
@@ -36,7 +36,93 @@ ESBuild must also be used to compile the CSS supporting the MAPP and MAPP.UI ele
npx esbuild --bundle public/css/_ui.css --outfile=public/css/ui.css --loader:.svg=dataurl
-### Hot rebuild with VSCode Debugger
+## Hot rebuild with nodemon & VSCode Chrome Debugger
+
+### nodemon
+
+The development environment uses nodemon to watch for changes and automatically rebuild the necessary files. This is configured in `nodemon.json`:
+
+```json
+{
+ "watch": [
+ "lib/**/*",
+ "tests/**/*",
+ "public/css/*",
+ "../xyz_resources/**/*"
+ ],
+ "ext": ".js,.mjs,.json,.css,.svg",
+ "ignore": [
+ "public/js/**/*",
+ "public/css/mapp.css",
+ "public/css/ui.css"
+ ],
+ "env": {
+ "NODE_ENV": "DEVELOPMENT"
+ },
+ "exec": "npx concurrently \"node esbuild.config.mjs\" \"npm run ui_css\" \"npm run mapp_css\"",
+ "events": {
+ "start": "echo \"Watching for changes...\"",
+ "exit": "echo \"Build complete\""
+ }
+}
+```
+
+#### Watched Directories
+
+* `lib/**/*`: All files in the lib directory
+* `tests/**/*`: All test files
+* `public/css/*`: CSS source files
+* `../xyz_resources/**/*`: External resource files.
+
+#### File Types Watched
+
+* JavaScript files (`.js`)
+* ES Modules (`.mjs`)
+* JSON files (`.json`)
+* CSS files (`.css`)
+* SVG files (`.svg`)
+
+#### Ignored Files
+
+* Built JavaScript files (`public/js/**/*`)
+
+* Compiled CSS files:
+ * `public/css/mapp.css`
+ * `public/css/ui.css`
+
+#### Automatic Actions
+
+When changes are detected:
+
+1. Rebuilds JavaScript using esbuild
+2. Recompiles UI CSS
+3. Recompiles MAPP CSS
+4. All tasks run concurrently for faster builds
+
+### Running nodemon
+
+1. Start the watch mode:
+
+```bash
+ npx nodemon
+```
+
+2. Nodemon will:
+ * Set `NODE_ENV` to "DEVELOPMENT"
+ * Watch for file changes
+ * Automatically rebuild affected files
+ * Display "Watching for changes..." when started
+ * Show "Build complete" after each rebuild
+
+3. The application will rebuild automatically when you:
+ * Modify test files
+ * Change source code
+ * Update CSS
+ * Modify resources
+
+This ensures that your test environment always has the latest changes without manual rebuilds.
+
+### VSCode Tasks & Launch
A task can be added to the `.vscode/tasks.json` to execute `nodemon` and `browser-sync` concurrently. This will allow VSCode to rebuild the application on script changes in the editor.
@@ -79,13 +165,13 @@ A task can be added to the `.vscode/tasks.json` to execute `nodemon` and `browse
}
```
-The `browser-sync` script is defined in the `package.json` as `"npx browser-sync start --proxy localhost:3000 --port 3001 --ui-port 3002 --files public/js/lib/**/* --no-open --no-notify"`
+The `browser-sync` script is defined in the `package.json` as `"npx browser-sync start --proxy localhost:3000 --port 3001 --ui-port 3002 --files public/js/**/* --no-open --no-notify"`
The application running on port 3000 will be proxied to port 3001 for the browser-sync event. The browser window will refresh when the node application rebuilds after changes to the script in a VSCode editor.
-#### VSCode / Chrome Debugging
+#### VSCode / Chrome Debugging
-An additional debug configuration in `.vscode/launch.json` is required to debug the mapp lib code in VSCode.
+An additional debug configuration in `.vscode/launch.json` is required to debug the mapp lib code in VSCode.
```json
{
@@ -103,7 +189,7 @@ The Chrome debug config must be launched as an additional session. VSCode run an
Breakpoints set in the mapp lib script will now be respected in the VSCode debug editor window. Breakpoints set in the Chrome dev tools will also break in the VSCode editor.
-The browser will automatically reload on changes to files in the `lib`, 'tests' and `public/css' directories.
+The browser will automatically reload on changes to files in the `lib`, 'tests' and `public/css' directories.
#### Additional settings for VSCode
diff --git a/TESTING.md b/TESTING.md
index 7cd6a65165..8dc74a7b1f 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -1,78 +1,256 @@
# Testing
-Testing in xyz is split up into 3 different sections.
+Testing in xyz is split into 3 different sections:
1. cli (console)
2. module (browser)
3. integrity
-## cli (console)
+## Testing Environment Setup
-The cli tests are normal vanilla javascript tests that execute with the nodejs runtime using the [Codi Test framework](https://www.npmjs.com/package/codi-test-framework).
-These tests focus on the xyz (mod) directory to test as many things as possible. These tests mostly focus on code that does not require things that would only be found in the browser.
+### Prerequisites
-1. Setup
- - Ensure that you have installed the node modules `npm install`
- - Ensure that you have bun.sh installed in your enviroment
- - To run the tests you can execute `npm run test`
+The minimum requirements are:
-2. Output
- - You will find an output of a summary of all the past/failed tests.
+* Node.js (version 18 and above)
+* [codi](https://github.com/RobAndrewHurst/codi)
+* Node modules installed via `npm install`
-## module (browser)
+## Test Structure
-The module tests are designed to make use of the browser environment by having full access to the DOM.
-With these tests will have full access to the mapp library and a mapview for the loaded application. This allows us to not need to mock different module imports. Everything will be part of the build. All these tests also make use of the Codi test framework, and make use of the test runner, that is designed to run specifically in a view.
+Tests are organized in the `/tests` directory with two main subdirectories:
-To run these tests you will need to lauch the application with specific test settings. These will be provided only to GEOLYTIX developers.
+* `/tests/mod`: CLI tests for the xyz (mod) directory
+* `/tests/lib`: Module tests for browser environment
-Launch the application and navigate to localhost:3000/test?template=test_view and open the console of the window.
-You will see the output of the tests running in the console with any passes/failures.
+```bash
+xyz/
+├── mod/
+│ ├── module1/
+│ │ └── feature1.mjs
+├── lib/
+│ ├── module2/
+│ │ └── feature2.mjs
+├── tests/
+│ ├── mod/
+│ │ ├── module1/
+│ │ │ ├── feature1.test.mjs
+│ │ │ └── index.mjs
+│ └── lib/
+│ └── module2/
+│ ├── feature2.test.mjs
+│ └── index.mjs
-## integrity
+```
+
+Each test folder exports an object matching its corresponding directory structure:
+
+```javascript
+// tests/mod/module1/index.mjs
+export default {
+ feature1: () => import('./feature1.test.mjs')
+};
+```
+
+## 1. CLI (Console) Tests
+
+CLI tests are vanilla JavaScript tests that execute in the Node.js runtime using the Codi Test framework. These tests focus on the xyz (mod) directory and code that doesn't require browser-specific features.
+
+### Running CLI Tests
+
+The codi test suit will iterate through the tests directory [ignoring the folders specified in codi.json] and log the results from each test suit.
+
+```bash
+npm run test
+```
+
+Summary statistics for all tests will be logged with the `-- quiet` flag (codi v0.0.47+):
+
+```bash
+npm run test -- --quiet
+```
+
+## 2. Module (Browser) Tests
+
+Module tests are designed for the browser environment with full access to:
-The integrity tests are designed to check data integrity on deployed appications.
-To run these test naviate to any deployed instance and ensure that you have `?template=test_view&integrity=true` is included in the params of the URL.
+* DOM
+* Mapp library
+* Mapview for loaded application
+* No mocking required for module imports
-This will give you a similar output to the normal test_view.
+### Running Module Tests
-## Writing tests
+A [test application view](https://github.com/GEOLYTIX/xyz/blob/main/public/views/_test.html) is provided in the public folder to execute browser tests.
-When writing tests you will need to make use of different Codi elements to make up your test.
+Mapp module test require ressources which are not publicly accessible. This is to be addressed in a future release.
-Include the describe and it functions. These are used as the building blocks to the tests. The describe block is used to describe the overall function and what the test suite is actually trying to achive. The It block is used to make more granular descriptions of different elements/functions of the code.
+Please ensure to run the `_build` script prior to launching the test environment.
-In this example we describe what the main output should be. And then we assert the different elements that are part of the module.
-Part of this code is the `assertTrue` function that is used to check if a value is true.
+The current tests require an active user.
-```js
+The test view will be requested as the default view from the XYZ View API when the local node process is opened on `localhost:3000/test`.
+
+The test results will be logged to the browser dev console.
+
+VSCode can be used to debug tests and mapp library modules as outlined in the [developer notes](https://github.com/GEOLYTIX/xyz/blob/main/DEVELOPING.md).
+
+## 3. Integrity Tests
+
+Integrity tests check data integrity of a workspace through the test view document. The test view hosted in the public directory is set as a view templates in the workspace templates. This can be requested from the View API by setting `test_view` as template URL parameter.
+
+The data integrity tests are currently evaluated for public access.
+
+## Writing Tests
+
+### Test Structure
+
+Tests use the describe-it pattern for organization:
+
+```javascript
import { describe, it, assertTrue } from 'codi';
+
+describe('Feature Description', () => {
+ it('should behave in a specific way', () => {
+ // Test code
+ });
+});
+```
+
+Example with multiple assertions:
+
+```javascript
describe('All languages should have the same base language entries', () => {
-...
- Object.keys(mapp.dictionaries).forEach(language => {
- it(`The ${language} dictionary should have all the base keys`, () => {
- Object.keys(base_dictionary).forEach(key => {
- assertTrue(!!mapp.dictionaries[language][key], `${language} should have ${key}`);
- });
- });
- });
-...
+ Object.keys(mapp.dictionaries).forEach(language => {
+ it(`The ${language} dictionary should have all the base keys`, () => {
+ Object.keys(base_dictionary).forEach(key => {
+ assertTrue(!!mapp.dictionaries[language][key],
+ `${language} should have ${key}`);
+ });
});
+ });
+});
```
-Assertion Functions 🧪
-Codi provides several assertion functions to compare expected and actual values:
+### Available Assertions
+
+Codi provides several built-in assertions:
+
+* `assertEqual(actual, expected, message)` ⚖️
+ * Asserts that the actual value equals the expected value
+* `assertNotEqual(actual, expected, message)` 🙅♂️
+ * Asserts that the actual value does not equal the expected value
+* `assertTrue(actual, message)` ✅
+ * Asserts that the actual value is true
+* `assertFalse(actual, message)` ❌
+ * Asserts that the actual value is false
+* `assertThrows(callback, errorMessage, message)` 💥
+ * Asserts that the callback throws an error with the specified message
+* `assertNoDuplicates(callback, errorMessage, message)` 👬
+ * Asserts that there are no duplicates in a provided array.
+
+
+## Best Practices
+
+* Maintain parallel structure between source and test directories
+* Use descriptive test names
+* One describe per test suite
+* Group related tests in the same describe block
+* Use test bundles for reusable configurations
+* Keep tests focused and isolated
+* Use `--quiet` flag in CI/CD pipelines. (can also be used on other test fuctions).
+
+## Common Issues and Solutions
+
+### Test Discovery
+
+Codi automatically discovers tests in files with the pattern:
+
+* `*.test.mjs`
+
+### Error Handling
+
+If tests fail to run:
+
+1. Ensure Bun.sh version is compatible (v1.1.0+ for Codi v0.0.47)
+2. Check file extensions are `.mjs`
+3. Verify import/export syntax is ESM compatible
+4. Confirm test directory structure matches source directories
+5. Verify test settings in xyz_settings/tests/launch.json
+
+For more information, please visit the [Codi GitHub repository](https://github.com/RobAndrewHurst/codi).
+
+## Browser Tests Development Environment Setup
+
+### Build Configuration
+
+Tests require an unminified build to enable debugging and stepping through code. This is handled by the build system (`esbuild.config.mjs`).
+
+Setting process environment `NODE_ENV=DEVELOPMENT` disables minification in build processes.
+
+```javascript
+// esbuild.config.mjs
+import * as esbuild from 'esbuild'
+
+const isDev = process.env.NODE_ENV !== 'DEVELOPMENT';
+
+const buildOptions = {
+ entryPoints: isDev
+ ? ['./lib/mapp.mjs', './lib/ui.mjs']
+ : ['./lib/mapp.mjs', './lib/ui.mjs', './tests/_mapp.test.mjs'],
+ bundle: true,
+ minify: isDev, // Code won't be minified in development
+ sourcemap: true,
+ sourceRoot: '/lib',
+ format: 'iife',
+ outbase: '.',
+ outdir: 'public/js',
+ metafile: true,
+ logLevel: 'info'
+};
+
+try {
+ await esbuild.build(buildOptions);
+} catch (err) {
+ console.error('Build failed:', err);
+ process.exit(1);
+}
+```
+
+### Running Tests in Development Mode
+
+1. Set the environment variable:
+
+ ```bash
+ NODE_ENV=DEVELOPMENT
+ ```
+
+> This can be defined in your .env or in your nodemon.json config.
+
+2. Build the project:
+
+ ```bash
+ npm run _build
+ ```
+
+3. Verify that:
+ * Test files are included in the build
+ * Source maps are generated
+ * Code is not minified
-- `assertEqual(actual, expected, message)`: Asserts that the actual value is equal to the expected value. ⚖️
-- `assertNotEqual(actual, expected, message)`: Asserts that the actual value is not equal to the expected value. 🙅♂️
-- `assertTrue(actual, message)`: Asserts that the actual value is true. ✅
-- `assertFalse(actual, message)`: Asserts that the actual value is false. ❌
-- `assertThrows(callback, errorMessage, message)`: Asserts that the provided callback function throws an error with the specified error message. 💥
+4. Launch the application and navigate to `localhost:3000/test?template=test_view`
-### cli
+5. Open Chrome DevTools to:
+ * View test results in the console
+ * Debug and step through unminified code
+ * Use source maps for accurate file locations
-The directory that you need to add these cli tests are in the `tests/mod` directory. This directory needs to replicate the same kind of structure as the mod directory. Reason we do this is to ensure that test correlates to the position in the project that they are referencing.
+### Debugging Benefits
-### module
+The unminified development build provides several advantages:
-The directory that you need to add these module tests are in the `tests/lib` directory.
+* Clear, readable code in Chrome DevTools
+* Accurate source mapping to original files
+* Ability to set breakpoints in original source files
+* Step-through debugging from Chrome to VSCode
+* Easier identification of test failures
diff --git a/esbuild.config.mjs b/esbuild.config.mjs
index 1bdeabf39a..20b4c3db54 100644
--- a/esbuild.config.mjs
+++ b/esbuild.config.mjs
@@ -4,13 +4,14 @@ import * as esbuild from 'esbuild'
const isDev = process.env.NODE_ENV !== 'DEVELOPMENT';
const buildOptions = {
- entryPoints: ['./lib/mapp.mjs', './lib/ui.mjs'],
+ entryPoints: ['./lib/mapp.mjs', './lib/ui.mjs', './tests/_mapp.test.mjs'],
bundle: true,
minify: isDev,
sourcemap: true,
sourceRoot: '/lib',
format: 'iife',
- outdir: './public/js/lib',
+ outbase: '.',
+ outdir: 'public/js',
metafile: true,
logLevel: 'info'
};
diff --git a/eslint.config.mjs b/eslint.config.mjs
index d5cb190633..5a624d6ea1 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,6 +1,6 @@
export default [
{
- ignores: ['public/js/lib/*', 'docs/**/*'],
+ ignores: ['public/js/**/*', 'docs/**/*'],
},
{
files: ['**/*.js', '**/*.mjs'],
diff --git a/nodemon.json b/nodemon.json
deleted file mode 100644
index 89c1545b1c..0000000000
--- a/nodemon.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "watch": [
- "lib/**/*",
- "tests/**/*",
- "public/css/*",
- "../xyz_resources/**/*"
- ],
- "ext": ".js,.mjs,.json,.css,.svg",
- "ignore": [
- "public/js/**/*",
- "public/css/mapp.css",
- "public/css/ui.css"
- ],
- "env": {
- "NODE_ENV": "DEVELOPMENT"
- },
- "exec": "npx concurrently \"node esbuild.config.mjs\" \"npm run ui_css\" \"npm run mapp_css\"",
- "events": {
- "start": "echo \"Watching for changes...\"",
- "exit": "echo \"Build complete\""
- }
-}
\ No newline at end of file
diff --git a/package.json b/package.json
index 28b5948bb5..e12873fd15 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
"scripts": {
"test": "codi tests",
"_build": "node esbuild.config.mjs",
- "browser-sync": "npx browser-sync start --proxy localhost:3000 --port 3001 --ui-port 3002 --files public/js/lib/**/* --no-open --no-notify",
+ "browser-sync": "npx browser-sync start --proxy localhost:3000 --port 3001 --ui-port 3002 --files public/js/**/* --no-open --no-notify",
"ui_css": "npx esbuild --bundle public/css/_ui.css --outfile=public/css/ui.css --loader:.svg=dataurl",
"mapp_css": "npx esbuild --bundle public/css/_mapp.css --outfile=public/css/mapp.css",
"generate-docs": "jsdoc --configure jsdoc_mapp.json --verbose && jsdoc --configure jsdoc_xyz.json --verbose && jsdoc --configure jsdoc_test.json --verbose",
@@ -33,7 +33,7 @@
"@eslint/js": "^9.13.0",
"browser-sync": "^3.0.3",
"clean-jsdoc-theme": "^4.3.0",
- "codi-test-framework": "^0.0.33",
+ "codi-test-framework": "^0.0.47",
"concurrently": "^9.1.0",
"cookie-parser": "^1.4.5",
"dotenv": "^16.4.5",
diff --git a/public/tests/layer.test.mjs b/public/tests/layer.test.mjs
index 93207d2ffa..256062e8d8 100644
--- a/public/tests/layer.test.mjs
+++ b/public/tests/layer.test.mjs
@@ -27,7 +27,7 @@ export async function layerTest(mapview) {
if (layer.style?.themes) {
for (const theme in layer.style.themes) {
- console.log(`Testing theme ${theme}`);
+ console.log(`Testing -- Layer: ${layer.key}: Theme: ${theme}`);
layer.style.theme = layer.style.themes[theme];
layer.reload();
diff --git a/public/views/_test.html b/public/views/_test.html
index 2b53d3aca1..7bfd1442c1 100644
--- a/public/views/_test.html
+++ b/public/views/_test.html
@@ -18,13 +18,13 @@
+ }
+