Developing an OpenLayers app from scratch in ES6 using Mocha, Webpack and Karma: Arctic sea-ice data visualisation
… where we finally visualise actual sea-ice concentration data and migrate our tests to karma.
Visualising Arctic sea-ice concentration data
Now we have enough building blocks in place to be able to display the sea-ice concentration data for the Arctic. We’ll do this by adding a PNG image layer where the pixel colours represent the sea-ice concentration value. Sea-ice concentration is a percentage measure which indicates how much ice covers a given area and is measured from space via satellite. The standard data set (e.g. from the Japan Aerospace Exploration Agency (JAXA)) uses 6km x 6km pixels: a value of 20% means that 20% of a 6km x 6km area is covered with ice.
The company I work for, Drift+Noise, takes low-level swath data from JAXA and combines the information into a running composite image (a continuously updated image containing data from the last roughly 28 satellite swaths). These images are available in various formats (e.g. GeoTIFF, HDF5, PNG); the format that is of interest for us here is the PNG format which can be downloaded via the API at https://svalnav.driftnoise.com. To find out the URL of the latest 6km sea-ice concentration image, one can use this API lookup:
https://svalnav.driftnoise.com/api/sea_ice_data_files/?sea_ice_data_product=sea-ice-concentration-6k&latest=true
The output is JSON and the url
field contains the information we need. To
download the latest image, we can use the following one-liner:
which I’ve split over several lines to improve its readability in this text.
This command uses curl
to fetch the JSON metadata about the latest image,
the -s
option stops curl
from showing some diagnostic output which we
don’t need to see, we then translate all commas to newlines so that we can
grep
for the url
field. Once we have the url
field from the JSON, we
cut the resulting string on double quotes and take the fourth field from the
resulting output. This is then the URL of the latest sea-ice concentration
image. The curl
command is run in a subprocess, the result of which we
pass to wget
to download the file to src/sea-ice-concentration.png
.
This way we have a simple filename that we can use as the source data for
the image layer we want to add to our OpenLayers map.
The sea-ice concentration image should look similar to this
where pixels coinciding with landmasses or any sea-ice concentration below 15% have been made transparent. Looking at the image it’s possible to discern Greenland (at the bottom, in the middle) as well as the Bering Strait (top left-hand corner).
Our OpenLayers map currently has only one layer: the OpenStreetMap
TileLayer
. We therefore expect to have two layers in the map once the
image layer has been added. Let’s add a test for this expectation to help
drive the development. Add the following test to the map-test.js
file:
Running the tests fails (as we expect)
1) Basic map
should have 2 layers:
AssertionError: expected 1 to equal 2
+ expected - actual
-1
+2
and with the error we expect (that there’s only one layer, but we wanted to see two).
To add the new layer we need to import the ImageLayer
class, instantiate a
new object from this class, and add this object to the list of layers in the
map. Therefore, we need to add
to the list of imports; we create a variable sicLayer
:
and we extend the list of layers passed to the Map
constructor:
The test suite now passes. Sweet!
Basic map
✓ should have a view centred on Longyearbyen
✓ should have a default zoom of 6
✓ should have a default rotation of 45 degrees
✓ should have 2 layers
EPSG:3413
✓ should use EPSG:3413 as its projection code
✓ should use the NSIDC north pole max sea ice extent
6 passing (11ms)
However, we’ve not actually added the PNG image to the layer. To do that we
need to add what’s called a “source” (in the OpenLayers nomenclature) to the
image layer. We therefore expect there to be a source associated with the
sicLayer
object and we can test for this. Let’s start a new suite of
tests describing the sea-ice concentration image layer. Add a new
describe
block to map-test.js
:
This test is based upon the information in the OpenLayers API docs for
ImageLayer
which says that the default source of a layer is null
. It would be better
to use a “positive” test here (i.e. one where we expect a definite value,
not that we don’t expect a non-value) but this should get things going.
The tests show that the variable sicLayer
isn’t defined.
SIC layer
1) should have a valid image source
EPSG:3413
✓ should use EPSG:3413 as its projection code
✓ should use the NSIDC north pole extent
6 passing (16ms)
1 failing
1) SIC layer
should have a valid image source:
ReferenceError: sicLayer is not defined
We’ll now export this variable so that we’ve got direct access to it in the
tests. Change the last line in index.js
to read:
and import the sicLayer
variable in map-test.js
:
The tests fail and sort of how we would expect them to:
SIC layer
1) should have a valid image source
EPSG:3413
✓ should use EPSG:3413 as its projection code
✓ should use the NSIDC north pole extent
6 passing (23ms)
1 failing
1) SIC layer
should have a valid image source:
TypeError: Cannot read property 'should' of null
This output means that the test isn’t actually checking for null
as we
want it to do, however since the value we get back is null
and hence the
should
part of the assertion fails, we still get the feedback we want from
the test.
Let’s add a minimal image source. Import the Static
class:
instantiate an empty source object for the sicLayer
(before the definition
of sicLayer
):
and pass this variable as the source
parameter to the ImageLayer
constructor:
And the tests pass. Wicked!
Basic map
✓ should have a view centred on Longyearbyen
✓ should have a default zoom of 6
✓ should have a default rotation of 45 degrees
✓ should have 2 layers
SIC layer
✓ should have a valid image source
EPSG:3413
✓ should use EPSG:3413 as its projection code
✓ should use the NSIDC north pole max sea ice extent
7 passing (12ms)
Our image source should have three parameters defined to ensure that it has been correctly set up: the projection for the view, the image extent (defined by the lower-left and upper-right coordinates in the relevant projection units), and a URL pointing to the image file.
We’ll make sure we’re using the correct projection by checking the code of
the source’s projection object. Add this test to the SIC layer
test
suite:
We can also remove the 'should have a valid image source'
test because the
new test will implicitly check that the source is non-null.
The tests fail with an error that looks sensible:
SIC layer
1) should have a source which uses EPSG:3413
EPSG:3413
✓ should use EPSG:3413 as its projection code
✓ should use the NSIDC north pole extent
6 passing (13ms)
1 failing
1) SIC layer
should have a source which uses EPSG:3413:
TypeError: Cannot read property 'getCode' of null
because the call to getCode()
is made on a null
object, which means that
the projection hasn’t been defined. Adding the projection
property to
sicSource
gets the tests to pass again.
Basic map
✓ should have a view centred on Longyearbyen
✓ should have a default zoom of 6
✓ should have a default rotation of 45 degrees
✓ should have 2 layers
SIC layer
✓ should have a source which uses EPSG:3413
EPSG:3413
✓ should use EPSG:3413 as its projection code
✓ should use the NSIDC north pole max sea ice extent
7 passing (16ms)
Now add a test for the extent to the SIC layer
test suite:
where the JAXA Arctic extent in projection coordinates was calculated from the AMSR2 data product manual (i.e. the manual for the instrument on the satellite from which the sea-ice concentration data is measured).
The tests fail because there isn’t yet an extent defined for this source
SIC layer
✓ should have a source which uses EPSG:3413
1) should have a source with the JAXA Arctic extent
EPSG:3413
✓ should use EPSG:3413 as its projection code
✓ should use the NSIDC north pole extent
7 passing (14ms)
1 failing
1) SIC layer
should have a source with the JAXA Arctic extent:
TypeError: Cannot read property 'should' of undefined
Setting the imageExtent
property in the Static
constructor to the
appropriate value
gets the tests to pass again.
Basic map
✓ should have a view centred on Longyearbyen
✓ should have a default zoom of 6
✓ should have a default rotation of 45 degrees
✓ should have 2 layers
SIC layer
✓ should have a source which uses EPSG:3413
✓ should have a source with the JAXA Arctic extent
EPSG:3413
✓ should use EPSG:3413 as its projection code
✓ should use the NSIDC north pole max sea ice extent
8 passing (13ms)
The test to check for the correct value of the url
parameter is tricky.
The reason it’s tricky is because of the bundling issue. One might naively
think that one could pass the filename directly as the url
parameter to
the Static
constructor, i.e. something like this:
Unfortunately, this doesn’t work because webpack won’t be able to find the file in order to bundle it and the path to the file won’t be correct. If you try this out, you’ll find that the bundle gets built, but there aren’t any PNG images added to it.
The solution is to use the file-loader
loader in webpack; the first
example in the file-loader
documentation gives
us the outline of a concrete solution. Before we can start, we need to
install the file-loader
package:
$ npm install --save-dev file-loader
Now we need to tell webpack to look for .png
files, so we add the
following code to the list of rules
in webpack.config.js
And now comes the trick: we load the image as if it were a module:
and then we pass the variable sicImage
as the url
parameter in the
Static
constructor for the static image we want to load:
Building the application bundle with make build
, you’ll notice that a PNG
image does get bundled as part of the application (see the Names
section
below):
Hash: d1b643d80b3078b0350a
Version: webpack 4.43.0
Time: 1385ms
Built at: 05/10/2020 11:15:34 PM
Asset Size Chunks Chunk
Names
26c42ed1b81ea4d34d28813a35e40310.png 132 KiB [emitted]
bundle.js 2.34 MiB main [emitted] main
index.html 343 bytes [emitted]
Entrypoint main = bundle.js
[./src/js/index.js] 958 bytes {main} [built]
[./src/js/projections.js] 529 bytes {main} [built]
[./src/sea-ice-concentration.png] 80 bytes {main} [built]
+ 312 hidden modules
Child HtmlWebpackCompiler:
1 asset
Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
[./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html] 590
bytes {HtmlWebpackPlugin_0} [built]
But better than that, reloading the app in a browser, we see that the sea-ice concentration data is now being displayed! Brilliant!
Ok, given we know how to do this, let’s imagine that we’ve not coded any of this yet and we’ll guide the development using tests. Note that we know roughly how to proceed because we’ve already thrown together a prototype solution in the code above.
So what do we test for? We can’t test that the url
property is equal to a
string that looks like 'sea-ice-concentration.png'
because we’re assigning
the variable sicImage
to the url
parameter and it’s not likely that the
value of sicImage
is going to be the same as the image filename.
That actually the begs the question: what is the value of sicImage
after
the bundle has been built? To work this out, we can implement the prototype
code above as well as the file-loader
setup and run
$ make build
and see what turns up in the dist/
output directory. If you now list the
contents of the dist/
directory you should see something like this:
$ ls dist/
26c42ed1b81ea4d34d28813a35e40310.png bundle.js index.html
In other words, we see our automatically generated JavaScript bundle and the
main HTML file as well as a PNG file with an automatically generated
filename containing only hexadecimal digits. If you view this file you’ll
see that it’s the same as our sea-ice-concentration.png
file in the src/
directory. Let’s try logging the value of sicImage
as loaded into our
app by adding the following line after the import statements
Then, if we build the package (make build
), reload the app in the browser
and use F12 to see the console output, we’ll find that the value of
sicImage
is the filename of the bundled, automatically generated PNG file.
That’s cool, because now we have a much better idea of what we can sensibly
test.
Remove the console.log()
code and add the following test to the ‘SIC
layer’ test suite, which we expect to pass because we now know what to look
for and we’ve already implemented a working solution:
The purpose of this test is to check that the URL matches a string of
hexadecimal digits and ends with the literal text .png
. However, the test
suite fails, which we didn’t expect to happen this time. Why? Well, if we
think about things carefully, we’ll realise we’re testing the source code
directly, not the code that the bundler generates.
Let’s take a step back and save the state we had after having a passing test
for the Arctic extent. Therefore, let’s remove the 'should have a url
matching a PNG file'
test, remove the url
parameter, and remove the
import of the sicImage
file. You should find that the tests are passing
again. Let’s commit this state to the repo:
# mention that this code prepares the stage for static images to be loaded
$ git commit src/js/index.js test/map-test.js
We’re now in a bit of a conundrum: testing the source code directly doesn’t
help us anymore because we actually need to test the bundled code, i.e. the
code that the browser is going to be executing. Have you also noticed a
mismatch here between the code we’re testing and the environment in which
the code is going to be running? Note that we’re testing the code from
within node
which is basically a version of JavaScript for servers,
however our code is intended to run within a browser. So this begs the
question: why don’t we just run our tests in the browser? Can we have our
nice mocha test framework as well as the ability to test and run our code in
an environment that is much better matched to that which our users are
actually going to be running? It turns out the answer is yes. What we need
is karma.
Increasing our karma with JavaScript
karma is a test runner
for JavaScript and allows unit tests to run on real devices and in real
browsers. This is in contrast to the common way to run JavaScript tests:
from within the Node.js environment. Running tests in node
is a good idea
if the production JavaScript code is going to run within a node
environment (e.g. on a server as part of an app’s backend). We’ve now seen
that in our case running tests in a different environment to that which we
use for our production environment can have its limits.
To install karma, simply use npm
:
$ npm install --save-dev karma
In the project we’re developing here, we’re also using mocha, chai and webpack, so we also have to install the relevant karma adapters for these libraries:
$ npm install --save-dev karma-mocha karma-chai karma-webpack
We also need some launchers for the browsers that we want to use (Google Chrome and Firefox), so let’s install the packages for them as well:
$ npm install --save-dev karma-chrome-launcher karma-firefox-launcher
We now need to configure karma; the configuration lives by default in a file
called karma.conf.js
; create a new file with this name in your favourite
editor and add the following boilerplate code:
Karma needs to know which files it needs to look for so that it can run the
appropriate code in the browser. This is configured via the files
option,
which we append to the options passed to config.set()
. The browser needs
to know about both the source and test files, hence we glob for all
JavaScript files under src/
and test/
:
It doesn’t make much sense to run this yet, because we haven’t told karma
which browsers we want to use for the tests. Let’s get things started by
concentrating on Chrome first. We specify the browsers to use via the
browsers
option:
We can now run the tests by using the following command:
$ npx karma start --single-run --browsers ChromeHeadless karma.conf.js
You should see this command fail and it will give output like this:
05 05 2020 14:46:00.327:INFO [karma-server]: Karma v5.0.4 server started at
http://0.0.0.0:9876/
05 05 2020 14:46:00.330:INFO [launcher]: Launching browsers ChromeHeadless
with concurrency unlimited
05 05 2020 14:46:00.344:INFO [launcher]: Starting browser ChromeHeadless
05 05 2020 14:46:16.123:INFO [Chrome Headless 81.0.4044.129 (Linux x86_64)]:
Connected on socket GTDtsXVG5Sir-AkMAAAA with id 40140894
Chrome Headless 81.0.4044.129 (Linux x86_64) ERROR
Uncaught SyntaxError: Cannot use import statement outside a module
at src/js/index.js:1:1
SyntaxError: Cannot use import statement outside a module
What this is trying to tell us is that we’ve not packaged the code before
trying to run it: we need to package the code with webpack before it can be
run correctly in the browser. To fix this issue, we need the
preprocessors
option in the karma configuration. We therefore get karma
to preprocess the source and test files with webpack before running the
tests:
Running the karma command again we get the following error (among others):
05 05 2020 14:55:54.754:ERROR [preprocess]: Can not load "webpack"!
To fix this issue, we need to set the webpack
option with the value of our
webpack configuration. We therefore require
the webpack configuration
file and assign its value to a variable which we can then pass to karma’s
webpack
option; add the following line to the top of karma.config.js
:
and set the webpack
option:
You should now see output from the karma command similar to this:
ℹ 「wdm」: Hash: 8e56442c989820840bbc
Version: webpack 4.43.0
Time: 615ms
Built at: 05/10/2020 11:41:48 PM
Asset Size Chunks Chunk
Names
index.html 598 bytes [emitted]
main.js 2.34 MiB main [emitted] main
src/js/index.js 2.34 MiB src/js/index [emitted]
src/js/index
src/js/projections.js 432 KiB src/js/projections [emitted]
src/js/projections
test/map-test.js 2.7 MiB test/map-test [emitted]
test/map-test
test/projections-test.js 800 KiB test/projections-test [emitted]
test/projections-test
Entrypoint main = main.js
Entrypoint src/js/index = src/js/index.js
Entrypoint src/js/projections = src/js/projections.js
Entrypoint test/map-test = test/map-test.js
Entrypoint test/projections-test = test/projections-test.js
[./node_modules/chai/index.js] 40 bytes {test/map-test}
{test/projections-test} [built]
[./node_modules/chai/register-should.js] 40 bytes {test/map-test}
{test/projections-test} [built]
[./node_modules/ol/index.js] 1.6 KiB {main} {src/js/index} {test/map-test}
[built]
[./node_modules/ol/layer/Image.js] 1.71 KiB {main} {src/js/index}
{test/map-test} [built]
[./node_modules/ol/layer/Tile.js] 1.74 KiB {main} {src/js/index}
{test/map-test} [built]
[./node_modules/ol/ol.css] 490 bytes {main} {src/js/index} {test/map-test}
[./node_modules/ol/proj.js] 23.2 KiB {main} {src/js/index}
{src/js/projections} {test/map-test} {test/projections-test} [built]
[./node_modules/ol/proj/proj4.js] 1.65 KiB {main} {src/js/index}
{src/js/projections} {test/map-test} {test/projections-test} [built]
[./node_modules/ol/source/ImageStatic.js] 5.29 KiB {main} {src/js/index}
{test/map-test} [built]
[./node_modules/ol/source/OSM.js] 3.57 KiB {main} {src/js/index}
{test/map-test} [built]
[./node_modules/proj4/lib/index.js] 554 bytes {main} {src/js/index}
{src/js/projections} {test/map-test} {test/projections-test} [built]
[./src/js/index.js] 864 bytes {main} {src/js/index} {test/map-test} [built]
[./src/js/projections.js] 529 bytes {src/js/projections} {main}
{src/js/index} {test/map-test} {test/projections-test} [built]
[./test/map-test.js] 1.41 KiB {test/map-test} [built]
[./test/projections-test.js] 573 bytes {test/projections-test} [built]
+ 341 hidden modules
Child HtmlWebpackCompiler:
Asset Size Chunks Chunk Names
__child-HtmlWebpackPlugin_0 4.71 KiB HtmlWebpackPlugin_0
HtmlWebpackPlugin_0
Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
[./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html] 590
bytes {HtmlWebpackPlugin_0} [built]
ℹ 「wdm」: Compiled successfully.
10 05 2020 23:41:49.017:INFO [karma-server]: Karma v5.0.5 server started at
http://0.0.0.0:9876/
10 05 2020 23:41:49.018:INFO [launcher]: Launching browsers ChromeHeadless
with concurrency unlimited
10 05 2020 23:41:49.037:INFO [launcher]: Starting browser ChromeHeadless
10 05 2020 23:41:49.302:INFO [Chrome Headless 81.0.4044.129 (Linux x86_64)]:
Connected on socket yUjGmvuw_r7l9KPvAAAA with id 38661624
Chrome Headless 81.0.4044.129 (Linux x86_64) ERROR
Uncaught ReferenceError: describe is not defined
at webpack:///./test/map-test.js?:13:1
ReferenceError: describe is not defined
at eval (webpack:///./test/map-test.js?:13:1)
at Module../test/map-test.js (test/map-test.js:4305:1)
at __webpack_require__ (test/map-test.js:20:30)
at test/map-test.js:84:18
at test/map-test.js:87:10
Wow! We got much further! You’ll notice that karma has used webpack to
bundle our software and then has passed it on to the browser to run the test
suite. The tests couldn’t run because the describe
keyword isn’t defined;
the main hint in all the noise of the error output is:
ReferenceError: describe is not defined
The solution here is to tell karma which frameworks we’re using for the
tests. We’re using mocha and chai, so we just need to set the frameworks
option to the following value:
Running the karma command again, we get (among other things):
Chrome Headless 81.0.4044.129 (Linux x86_64): Executed 8 of 8 SUCCESS (0.032 secs / 0.008 secs)
TOTAL: 8 SUCCESS
Yay! The tests are running in karma!
Unfortunately, the detailed output we got from running the tests through mocha no longer appears. To be able to see this information again we need to use the mocha reporter in karma. Let’s install that
$ npm install --save-dev karma-mocha-reporter
and tell karma to use this library to report the test output by setting the
reporters
option:
Now, when we run the karma test runner, we get this output:
Basic map
✔ should have a view centred on Longyearbyen
✔ should have a default zoom of 6
✔ should have a default rotation of 45 degrees
✔ should have 2 layers
SIC layer
✔ should have a source which uses EPSG:3413
✔ should have a source with the JAXA Arctic extent
EPSG:3413
✔ should use EPSG:3413 as its projection code
✔ should use the NSIDC north pole extent
Finished in 0.035 secs / 0.003 secs @ 19:23:55 GMT+0200 (Central European Summer Time)
SUMMARY:
✔ 8 tests completed
That’s pretty cool! Let’s now run the tests in Firefox as well; add
'Firefox'
to the browsers
option list:
and mention Firefox
in the karma
command:
$ npx karma start --single-run --browsers ChromeHeadless,Firefox karma.conf.js
although we now see that 16 tests have been run:
SUMMARY:
✔ 16 tests completed
which means that we’re running the tests in both browsers! That’s excellent, and exactly what we hope to see here.
Unfortunately, a Firefox window appears and disappears while the tests are running. This could get a bit annoying when we run the tests, but more than that, this means that the Firefox tests probably won’t run in a “headless” environment such as Jenkins. We need to get Firefox to run in “headless” mode to stop the browser window from appearing, and to set this up in karma, we need to define a custom launcher 1:
Now, if we run karma with FirefoxHeadless
as one of its browsers
$ npx karma start --single-run --browsers ChromeHeadless,FirefoxHeadless karma.conf.js
we find that we still have 16 tests completed (in other words the tests ran
in both browsers) but we don’t get the extra Firefox window appearing.
Let’s now make this our default test
command in package.json
:
which means that we can now run the test suite simply by running
$ make test
Now would be a good time to save our work to the repository:
$ git add karma.conf.js
# mention use of karma for tests in commit message and why we wanted to do this
$ git commit package-lock.json package.json karma.conf.js
Picking up from where we left off
Now that we’ve got our tests running in the browser, we can go back and get
our test of the sea-ice concentration image filename to work. Let’s
reinstate our test for the image in map-test.js
:
The tests fail, which is what we now expect.
Basic map
✔ should have a view centred on Longyearbyen
✔ should have a default zoom of 6
✔ should have a default rotation of 45 degrees
✔ should have 2 layers
SIC layer
✔ should have a source which uses EPSG:3413
✔ should have a source with the JAXA Arctic extent
✖ should have a url matching a PNG file
EPSG:3413
✔ should use EPSG:3413 as its projection code
✔ should use the NSIDC north pole max sea ice extent
Finished in 0.038 secs / 0.009 secs @ 23:48:39 GMT+0200 (Central European Summer Time)
SUMMARY:
✔ 16 tests completed
✖ 2 tests failed
FAILED TESTS:
SIC layer
✖ should have a url matching a PNG file
Chrome Headless 81.0.4044.129 (Linux x86_64)
Firefox 76.0 (Linux x86_64)
_src_js_index_js__WEBPACK_IMPORTED_MODULE_2__.sicLayer.getSource(...).getUrl(...) is undefined
@webpack:///./test/map-test.js?:44:79
Note also that the summary mentions that two tests failed. This is because we’re using two browsers; in actual fact there’s only one test failing2.
We ensure that the file-loader
webpack loader is set up:
that the image is imported into the main file (src/js/index.js
):
and that the url
option to the Static
constructor is set:
If we now run the test suite, we see that the tests pass. Yay!
Basic map
✔ should have a view centred on Longyearbyen
✔ should have a default zoom of 6
✔ should have a default rotation of 45 degrees
✔ should have 2 layers
SIC layer
✔ should have a source which uses EPSG:3413
✔ should have a source with the JAXA Arctic extent
✔ should have a url matching a PNG file
EPSG:3413
✔ should use EPSG:3413 as its projection code
✔ should use the NSIDC north pole max sea ice extent
Finished in 0.033 secs / 0.008 secs @ 23:51:14 GMT+0200 (Central European Summer Time)
SUMMARY:
✔ 18 tests completed
That’s definitely time for a little celebration! Have another dance
Time for a last git commit
:
$ git add src/sea-ice-concentration.png
# mention addition of test for PNG image and why in commit message
$ git commit src/ test/ webpack.config.js
Now, if we run make build
and load the application in a browser, we see
that the application still works as we want it to
namely that the sea-ice concentration data is displayed over a map centred over Svalbard.
You can explore the map by using the mouse to drag the map around; you can
also zoom in and out with the +
and -
buttons in the top, left-hand
corner of the screen.
Where to from here?
We could now work out a way to download the latest sea-ice concentration image from the upstream API and we could even add a button to the map to trigger download and display of new sea-ice concentration images. One could even think about using a different coastline map in the background, or possibly extend the app to use PWA technology so that the user could install the app locally on their own device. Basically, the sky’s the limit, however, I think that’ll do for now.
Recap and winding down
Wow! We did it! We have an OpenLayers app showing actual satellite data on a map and we managed to test the application and get them to run within both Google Chrome and Firefox. That’s quite an achievement and a pat on the back is order.
Hopefully you’ve also been able to see how to get mocha, webpack and karma working together on what is really a fairly simple application, and that you’ll be able to extend what you’ve learned here to more complex situations.
I wish you luck writing your next JavaScript app, and above all have fun!
-
I spotted this tip on Meziantou’s blog. ↩
-
I think it would be interesting to see a test pass in one browser, but fail in another, however adding this here would be going overboard. ↩
Support
If you liked this post and want to see more like this, please buy me a coffee!