I’ve got a vanilla Node.js project using docker-compose, and I’m trying to run my tests via mocha in the container. This works fine for me locally, but fails on CircleCI.
Relevant files:
Dockerfile:
FROM node:10.10.0-alpine
RUN apk update && apk add --no-cache build-base postgresql-dev
RUN mkdir -p /opt/my-service
WORKDIR /opt/my-service
COPY package*.json ./
RUN npm install
COPY . ./
CMD npm start
docker-compose -p tests run -e "NODE_ENV=test" my-service-api npm test
Starting tests_my-service-redis_1 ... done
Starting tests_my-service-postgres_1 ... done
> my-service@1.0.0 test /opt/my-service
> mocha
GET /health
✓ responds with a 200 status (40ms)
✓ responds with "application/json; charset=utf-8" content type
✓ responds with a json response body
3 passing (65ms)
When run in CircleCI build:
> my-service@1.0.0 test /opt/my-service
> mocha
sh: mocha: not found
npm ERR! Test failed. See above for more details.
Exited with code 1
Hmm, that is very odd. The benefit of DC is that you’re using images that ought to behave in the same way regardless of environment.
It looks like your node:10.10.0-alpine container cannot find the mocha binary. I would get an SSH session after a failed build, and then spin up that container like so:
docker run node:10.10.0-alpine sleep 10000
Then I’d get a shell on that container:
docker exec -it <containername> sh
Finally I’d see if Mocha can be found from the container’s perspective:
which mocha
Try this sequence locally too - there should be no differences in behaviour. If there is, you might be running different image versions, possibly?
Thanks for replying @halfer . Note that mocha is a dev dependency in my package.json, and I do an “npm install”. So mocha does NOT get installed globally, but instead installed locally. This puts it in /opt/my-service/node_modules/. I had tried exactly what you had described by ssh’ing into a failed build to poke around.
circleci@default-dff78443-2e7e-4b36-9e40-cb20e84f0977:~$ docker commit c89b21ed4355 test
sha256:5cfbc5ac3133d6ca69ad82ac7f903f2334f3b3390e08abbbee90a4bd9e5dee5f
circleci@default-dff78443-2e7e-4b36-9e40-cb20e84f0977:~$ docker run -ti --entrypoint=sh test
/opt/my-service # cd node_modules/mocha/bin/
/opt/my-service/node_modules/mocha/bin # ll
total 32
drwxr-xr-x 2 root root 4096 Sep 23 21:44 ./
drwxr-xr-x 5 root root 4096 Sep 23 21:44 ../
-rwxr-xr-x 1 root root 14619 Oct 26 1985 _mocha*
-rwxr-xr-x 1 root root 2249 Oct 26 1985 mocha*
-rw-r--r-- 1 root root 897 Oct 26 1985 options.js
/opt/my-service/node_modules/mocha/bin # mocha
sh: mocha: not found
/opt/my-service/node_modules/mocha/bin # ./mocha
Warning: Could not find any test files matching pattern: test
No test files found
/opt/my-service/node_modules/mocha/bin # cd ../../../
/opt/my-service # ./node_modules/mocha/bin/mocha
GET /health
✓ responds with a 200 status
✓ responds with "application/json; charset=utf-8" content type
✓ responds with a json response body
3 passing (35ms)
As you can see, when I specify the whole path to mocha it works fine when I’m in the container. However, when I change the “test” command in package.json to be the full path to mocha, it still can’t find it.
Successfully tagged node:10.10.0-alpine
WARNING: Image for service my-service-api was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
> my-service@1.0.0 test /opt/my-service
> /opt/my-service/node_modules/mocha/bin/mocha
sh: /opt/my-service/node_modules/mocha/bin/mocha: not found
npm ERR! Test failed. See above for more details.
Exited with code 1
WTF? OK, so I added a step in Dockerfile to install mocha globally (npm install -g mocha) which helps it find mocha, but then it can’t find express:
...........snip............
Step 10/12 : RUN npm install -g mocha
---> Running in 123127131b60
/usr/local/bin/mocha -> /usr/local/lib/node_modules/mocha/bin/mocha
/usr/local/bin/_mocha -> /usr/local/lib/node_modules/mocha/bin/_mocha
+ mocha@5.2.0
added 24 packages from 436 contributors in 1.003s
Removing intermediate container 123127131b60
---> ed8caef98469
Step 11/12 : COPY . ./
---> c6912fcc9d98
Step 12/12 : CMD npm start
---> Running in d972bf71103e
Removing intermediate container d972bf71103e
---> 4bd6c4f74874
Successfully built 4bd6c4f74874
Successfully tagged node:10.10.0-alpine
WARNING: Image for service my-service-api was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
> my-service@1.0.0 test /opt/my-service
> mocha
internal/modules/cjs/loader.js:583
throw err;
^
Error: Cannot find module 'express'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
at Function.Module._load (internal/modules/cjs/loader.js:507:25)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:20:18)
at Object.<anonymous> (/opt/my-service/test/helper.js:3:17)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:20:18)
at /usr/local/lib/node_modules/mocha/lib/mocha.js:250:27
at Array.forEach (<anonymous>)
at Mocha.loadFiles (/usr/local/lib/node_modules/mocha/lib/mocha.js:247:14)
at Mocha.run (/usr/local/lib/node_modules/mocha/lib/mocha.js:576:10)
at Object.<anonymous> (/usr/local/lib/node_modules/mocha/bin/_mocha:637:18)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
at startup (internal/bootstrap/node.js:279:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:696:3)
npm ERR! Test failed. See above for more details.
Exited with code 1
So there’s clearly something fundamentally wrong with my setup that I’m just not spotting. Any other help greatly appreciated!
is not the same as the Linux path error previously. I agree it’s odd, since it looks like Docker images are not behaving consistently. However, as I said before, they may not be the same image.
I believe you can supply an env var to a JS app to indicate where to find the libraries dependencies. I don’t know what that var is, but I am sure a search engine search would reveal it.
As I understand it the image id by it’s nature will not be the same across different environments since I’m building a new image based on node:10.10.0-alpine. But yes, I tried setting NODE_PATH (the env var in question) and it has no effect. :-/
Figured it out. I had incorrectly mounted the local directory as a volume, which is NOT mounted during a build. As a result, node_modules isn’t present in /opt/my-service. I had node_modules on my local machine, which is why it works for me locally.