Deploy Express server and test GraphQL API via CircleCI - node.js

I wish to test that my Express server launches properly and that my endpoint retrieves the correct information. I wish to do this in CI so that I can monitor when my application is no longer working, if I make any changes in the future.
It's a very simple application, my server looks like this:
server.js
import express from 'express';
import graphqlHTTP from 'express-graphql';
import { GraphQLObjectType, GraphQLString, GraphQLSchema } from 'graphql';
import cors from 'cors';
const QueryRoot = new GraphQLObjectType({
name: 'Query',
fields: () => ({
hello: {
type: GraphQLString,
resolve: () => "Hello world!"
}
})
});
const schema = new GraphQLSchema({ query: QueryRoot });
const app = express();
app.use(cors()); // enable cors
app.use('/api', graphqlHTTP({
schema: schema,
graphiql: true,
}));
app.listen(1337, () => {
console.log('Server running on port: 1337');
});
basicTest.test.js:
const chai = require('chai');
const expect = chai.expect;
const url = `http://localhost:1337`;
const request = require('supertest')(url);
describe('GraphQL', () => {
it('Response returns hello world', (done) => {
request.post('/api')
.send({ query: ' { hello }' })
.expect(200)
.end((err, res) => {
if (err) return done(err);
expect(res.body.data.hello).to.contain('Hello world!');
done();
});
});
});
My .circleci/config.yml looks like this:
# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2
jobs:
build:
docker:
# specify the version you desire here
- image: circleci/node:10.16.0
# Specify service dependencies here if necessary
# CircleCI maintains a library of pre-built images
# documented at https://circleci.com/docs/2.0/circleci-images/
# - image: circleci/mongo:3.4.4
working_directory: ~/repo
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run: npm install
- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}
- run:
npm start &
npm test
and package.json:
{
"name": "graphql-express-server",
"repository": {
"url": "myURL"
},
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon -r esm server.js",
"test": "mocha test/*.test.js"
},
"author": "AuthorName",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"esm": "^3.2.25",
"express": "^4.17.1",
"express-graphql": "^0.9.0",
"graphql": "^14.4.2",
"nodemon": "^1.19.1",
"supertest": "^4.0.2"
},
"devDependencies": {
"chai": "^4.2.0",
"mocha": "^6.2.0"
}
}
I tried adding & to the end of my npm start command but that just skips the entire process as far as I can see. The issue I'm getting is 'Error: ECONNREFUSED: Connection refused' when the test gets executed.
Do I need to host the server elsewhere? I'm unsure what I'm supposed to do. I've never really tested the back end in CI before.
EDIT:
My commands are as follows:
- run:
npm start &
- run:
sleep 5
- run:
npm test
And my output in CI is as follows:
--------------------------------
***npm start &***
#!/bin/bash -eo pipefail
npm start &
--------------------------------
***sleep 5***
#!/bin/bash -eo pipefail
sleep 5
--------------------------------
***npm test***
#!/bin/bash -eo pipefail
npm test
> graphql-express-server#1.0.0 test /home/circleci/repo
> mocha test/*.test.js
GraphQL
1) Response returns hello world
0 passing (14ms)
1 failing
1) GraphQL
Response returns hello world:
Error: ECONNREFUSED: Connection refused
at Test.assert (node_modules/supertest/lib/test.js:165:15)
at localAssert (node_modules/supertest/lib/test.js:131:12)
at /home/circleci/repo/node_modules/supertest/lib/test.js:128:5
at Test.Request.callback (node_modules/superagent/lib/node/index.js:728:3)
at ClientRequest.req.once.err (node_modules/superagent/lib/node/index.js:647:10)
at Socket.socketErrorListener (_http_client.js:392:9)
at emitErrorNT (internal/streams/destroy.js:91:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
npm ERR! Test failed. See above for more details.
Exited with code 1
--------------------------------
As you can see, the message Server running on port: 1337 does not show up in my npm start & step console section.
Any suggestions? Am I doing something wrong?

npm start & won't wait for server to start, are you sure your server is listening on the port by the time your test makes a request? I.e. do you have 'Server running on port: 1337' in your console on CI? If not then try running sleep 3 before starting tests

Related

Shopify node api context initalize errors out

I'm trying to make an app following these directions:
https://github.com/Shopify/shopify-node-api/blob/main/docs/getting_started.md
I have all the code configred and it looks like this:
// src/index.ts
import http from 'http';
import url from 'url';
import querystring from 'querystring';
import Shopify, { ApiVersion } from '#shopify/shopify-api';
require('dotenv').config();
const { API_KEY, API_SECRET_KEY, SCOPES, SHOP, HOST } = process.env
Shopify.Context.initialize({
API_KEY,
API_SECRET_KEY,
SCOPES: [SCOPES],
HOST_NAME: HOST.replace(/https?:\/\//, ""),
HOST_SCHEME: HOST.split("://")[0],
IS_EMBEDDED_APP: {boolean},
API_VERSION: ApiVersion.{version} // all supported versions are available, as well as "unstable" and "unversioned"
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS: { [key: string]: string | undefined } = {};
async function onRequest(
request: http.IncomingMessage,
response: http.ServerResponse,
): Promise<void> {
const {headers, url: req_url} = request;
const pathName: string | null = url.parse(req_url).pathname;
const queryString: string = String(url.parse(req_url).query);
const query: Record<string, any> = querystring.parse(queryString);
switch (pathName) {
default:
// This shop hasn't been seen yet, go through OAuth to create a session
if (ACTIVE_SHOPIFY_SHOPS[SHOP] === undefined) {
// not logged in, redirect to login
response.writeHead(302, {Location: `/login`});
response.end();
} else {
response.write('Hello world!');
// Load your app skeleton page with App Bridge, and do something amazing!
}
return;
} // end of default path
} // end of onRequest()
http.createServer(onRequest).listen(3000);
Package JSON looks like this:
{
"name": "shopify-checkout-apit",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"#shopify/shopify-api": "^3.1.0"
},
"devDependencies": {
"#types/node": "^17.0.40",
"dotenv": "^16.0.1",
"typescript": "^4.7.3"
},
"scripts": {
"build": "npx tsc",
"prestart": "yarn run build",
"start": "node dist/index.js"
}
}
When I go to run the app with yarn start I get a ton of errors
PS C:\Users\kawnah\shopify-checkout-apit> yarn start yarn run v1.22.18
$ yarn run build $ npx tsc src/index.ts:17:27 - error TS1003:
Identifier expected.
17 API_VERSION: ApiVersion.{version} // all supported versions are
available, as well as "unstable" and "unversioned"
~
src/index.ts:18:1 - error TS1005: ',' expected.
18 }); ~
Found 2 errors in the same file, starting at: src/index.ts:17
error Command failed with exit code 2. info Visit
https://yarnpkg.com/en/docs/cli/run for documentation about this
command. error Command failed with exit code 2. info Visit
https://yarnpkg.com/en/docs/cli/run for documentation about this
command. PS C:\Users\kawnah\shopify-checkout-apit>
I have no idea what any of this means.
Typescript Error TS1003 when attempting to access object properties using bracket notation
Why does this trigger an Identifier Expected error in Typescript?
I tried deleting node modules and reinstalling but it didn't work.
How do you fix this?
the config needs to look like this
Shopify.Context.initialize({
API_KEY,
API_SECRET_KEY,
SCOPES: [SCOPES],
HOST_NAME: HOST.replace(/https?:\/\//, ""),
HOST_SCHEME: HOST.split("://")[0],
IS_EMBEDDED_APP: true,
API_VERSION: ApiVersion.October21 // all supported versions are available, as well as "unstable" and "unversioned"
});

Unhandled error while running jest-puppeteer test

I am trying to set up testing for my puppeteer project. I was following a basic guide and the test passes but there is 2 console errors in the terminal.
The error doesn't show up when using https://google.com or https://youtube.com. So it looks like it could be a thing with the specific site?
console.error
Unhandled error
at process.uncaught (node_modules/jest-jasmine2/build/jasmine/Env.js:248:21)
at handler (node_modules/jest-environment-puppeteer/lib/PuppeteerEnvironment.js:17:11)
at map (node_modules/mitt/src/index.ts:74:75)
at Array.map (<anonymous>)
at Object.emit (node_modules/mitt/src/index.ts:74:56)
at Page.emit (node_modules/puppeteer/lib/EventEmitter.js:72:22)
console.error
at process.uncaught (node_modules/jest-jasmine2/build/jasmine/Env.js:249:21)
at handler (node_modules/jest-environment-puppeteer/lib/PuppeteerEnvironment.js:17:11)
at map (node_modules/mitt/src/index.ts:74:75)
at Array.map (<anonymous>)
at Object.emit (node_modules/mitt/src/index.ts:74:56)
at Page.emit (node_modules/puppeteer/lib/EventEmitter.js:72:22)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 5.613 s
Ran all test suites.
Here is my code
describe('NCAA Home', () => {
beforeAll(async () => {
await page.goto('http://stats.ncaa.org/rankings/change_sport_year_div');
});
it('should be titled "NCAA Statistics"', async () => {
await expect(page.title()).resolves.toMatch('NCAA Statistics');
});
});
Here is my jest.config.js
module.exports = {
preset: "jest-puppeteer",
testMatch: [
"**/test/**/*.test.js"
],
verbose: true
}
package.json
{
"name": "stackoverflow",
"version": "1.0.0",
"description": "",
"main": "index.js",
"jest": {
"preset": "jest-puppeteer"
},
"scripts": {
"test": "jest"
},
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^26.1.0",
"jest-puppeteer": "^4.4.0"
},
"dependencies": {
"puppeteer": "^5.1.0"
}
}
All of the things I have come across have mentioned an issue with async/await but anything I have tried produces the same, if not, more errors. I have made a new project with these files and I am getting the same error
The error is from the website itself. Check the console of the website. Hence for a websites like google.com or youtube.com, it works without any errors.
I have created clean repo which reproduces issue.
https://github.com/sergtimosh/jest-puppeteer-issue-reproduction.git
clone repository
npm i
npm test test.spec.js
or
HEADLESS=false npm test test.spec.js
A workaround is to create incognito browser context in jest-environment.js.
Just uncomment two lines in this file and tests are passing with no issues. But problem is still here if you need to share browser context between test suites(files).
const PuppeteerEnvironment = require('jest-environment-puppeteer');
class JestEnvironment extends PuppeteerEnvironment {
async setup() {
await super.setup()
//to fix issue uncomment next two lines
// const incognitoContext = await this.global.browser.createIncognitoBrowserContext()
// this.global.page = await incognitoContext.newPage()
}
async teardown() {
await super.teardown()
}
}
module.exports = JestEnvironment;

"Failed to get configuration" using Wolkenkit client in Mocha test through Node

I am trying to interact with my Wolkenkit application through a Mocha test in Node.
Following the tutorial on client connections, when running the test, I get the following error:
Error: Failed to get configuration.
at ConfigurationWatcher.wentOffline (node_modules/wolkenkit-client/dist/ConfigurationWatcher.js:113:28)
at /home/aef/Projects/experiments/wolkenkit_bullet/node_modules/wolkenkit-client/dist/ConfigurationWatcher.js:101:16
at tryCatch (node_modules/es6-promise/dist/es6-promise.js:409:12)
at invokeCallback (node_modules/es6-promise/dist/es6-promise.js:424:13)
at publish (node_modules/es6-promise/dist/es6-promise.js:398:7)
at publishRejection (node_modules/es6-promise/dist/es6-promise.js:339:3)
at flush (node_modules/es6-promise/dist/es6-promise.js:128:5)
at processTicksAndRejections (internal/process/task_queues.js:79:11)
Any help on resolving this is highly appreciated.
I added the following dependencies in package.json:
"devDependencies": {
"chai": "^4.2.0",
"mocha": "^7.0.1"
},
"dependencies": {
"wolkenkit": "^3.1.2",
"wolkenkit-client": "^3.1.0"
},
My test code looks like this:
'using strict';
const expect = require('chai').expect;
const wolkenkit = require('wolkenkit-client');
describe("wolkenkit app", () => {
it("first test", async () => {
const app = await wolkenkit.connect({host: 'local.wolkenkit.io', port: 3000});
});
})
While setting the environment variable within Node didn't work, the problem has been solved by setting NODE_TLS_REJECT_UNAUTHORIZED to 0 in the system environment like:
export NODE_TLS_REJECT_UNAUTHORIZED=0
Thanks to #mattwagl for pointing into the right direction.
This error is probably caused by your local self signed certificate. The client is not able to connect to the backend since it does not trust this certificate. You can bypass this check using the process.env.NODE_TLS_REJECT_UNAUTHORIZED flag like this…
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
suite('integration', () => {
let application;
suiteSetup(async () => {
application = await wolkenkit.connect({ host: 'local.wolkenkit.io', port: 3000 });
});
Another option would be to add the certificate to your trusted certificates.

Pact exited with code 1

I'm trying to execute some tests with Pact library and I'm getting some errors. Here is the test configuration:
const path = require('path');
const Pact = require('pact');
const expect = require('expect.js');
const config = require('../../../src/server/config');
const service = require('../../../src/routes/interactions/interactions.service');
describe('#component/interactions tests', () => {
const url = 'http://localhost';
const port = 8989;
const provider = Pact({
port: port,
log: path.resolve(process.cwd(), 'test/component/interactions/log/interactions-pact.log'),
dir: path.resolve(process.cwd(), 'test/component/interactions/pacts'),
spec: 2,
consumer: 'cx_issue',
provider: 'interaction',
// logLevel: 'WARN'
});
config.settingsToExport.INTERACTION_URL = `${url}:${port}`;
before(done => {
provider.setup()
.then(() => {
done();
})
.catch(err => {
done(err);
});
});
after(done => {
provider.finalize()
.then(() => {
done();
})
.catch(err => {
done(err);
});
});
describe('#createInteraction', () => {
before(done => {
const INTERACTION_BODY = {
contact: 'contact1'
};
const TERM = {
generate: '0dae5b93-9451-4b08-b7bb-f0b944fbcdf2',
matcher: '^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
};
const pactInteractionCreate = {
state: 'Creates a new interaction',
uponReceiving: 'a new interaction is created successfully',
withRequest: {
method: 'POST',
path: '/interactions',
body: INTERACTION_BODY
},
willRespondWith: {
status: 201,
body: {
id: Pact.Matchers.term(TERM)
}
}
};
const promises = [
provider.addInteraction(pactInteractionCreate)
];
Promise.all(promises)
.then(() => {
done();
});
});
it('/api/interactions POST', done => {
const interaction = {
contact: 'The xx'
};
service.createInteraction(interaction)
.then(response => {
expect(response.id).to.be.equal(TERM.generate);
done();
})
.catch(done);
});
});
});
This is my package.json file content, with all dependencies I've installed:
{
"name": "issueAPI",
"version": "1.0.0",
"private": true,
"main": "./src/index.js",
"scripts": {
"dev": "nodemon -e js ./src/index.js",
"start": "node ./src/index.js",
"linter": "node ./node_modules/eslint/bin/eslint.js ./src",
"test": "mocha test",
"test-component": "mocha test/component",
"install-test-build": "npm install && npm test && npm run linter",
"test-build": "npm test && npm run linter"
},
"jshintConfig": {
"esversion": 6
},
"dependencies": {
"ajv": "^4.11.3",
"body-parser": "^1.17.2",
"express": "^4.15.3",
"express-winston": "^2.4.0",
"request": "^2.81.0",
"winston": "^2.3.1",
"yamljs": "^0.2.9"
},
"devDependencies": {
"#pact-foundation/pact-node": "^4.8.3",
"dotenv": "^4.0.0",
"eslint": "^4.2.0",
"eslint-config-node": "^1.6.0",
"expect.js": "^0.3.1",
"mocha": "^3.2.0",
"nodemon": "^1.11.0",
"pact": "^2.3.3",
"sinon": "^2.3.8",
"supertest": "^3.0.0"
}
}
And this is the error I get:
Basically, right now I don't mind at all if the tests are well or not. The main problem right now is that the pact mock server is not being started.
The weird thing here is that I have other project where the pact tests run properly. I've moved the service I want to test from the project where is failing to the one which executes those tests fine, and it is working (at least the pact mock server is launched). The dependencies in this other project are almost the same as the problemathic project:
"dependencies": {
"ajv": "^4.11.3",
"body-parser": "^1.16.1",
"dotenv": "^4.0.0",
"express": "^4.14.0",
"jsonwebtoken": "^7.4.1",
"jwt-simple": "^0.5.1",
"morgan": "^1.8.1",
"mustache-express": "^1.2.4",
"node-env-file": "^0.1.8",
"request": "^2.79.0",
"when": "^3.7.8"
},
"devDependencies": {
"#pact-foundation/pact-node": "^4.8.3",
"eslint": "^3.17.1",
"eslint-config-node": "^1.6.0",
"expect.js": "^0.3.1",
"mocha": "^3.2.0",
"nodemon": "^1.11.0",
"pact": "^2.3.3",
"sinon": "^1.17.7",
"supertest": "^3.0.0",
"nock": "^9.0.13"
}
What's going on with this situation?
EDIT: I've launched the pact tests with DEBUG flag and this is the log generated:
It looks like the server is unable to start up correctly, judging by the exit code of 1. This could be a port conflict on port 8989, so that's worth checking.
It could be related to https://github.com/pact-foundation/pact-js/issues/64 (Windows file paths limited in length).
Could you please enable DEBUG logging with logLevel: 'DEBUG' and note what it outputs, and also share any *.log file. It could be an argument is not being correctly formatted when starting the server.
As you note, it is unable to start the underlying Ruby process so we need to get to the bottom of that.
Finally, after #Matthew Fellows answer and after reading his link to https://github.com/pact-foundation/pact-js/issues/64, I moved my project to a shorter path location, simimlar to D:\myproject\, and then the pact mock server was launched and my tests was passed. So until a better solution is discovered I'll work under that short path directory in order to avoid more problems.
Please, read the previous link in order to get more information about this bug because there is very well explained.
Looks to me that the server isn't starting up properly, this is normally because the port is already being used. To see if this is the case, in your node command line (in cmd, type node to go to the node command line), copy/paste the following:
require('http').createServer(function(){}).listen(11108);
The 'listen' function takes in the port number, which I took from your screenshot. Look at what node outputs; my guess is it will show something like this:
Error: listen EADDRINUSE :::11108
at Object.exports._errnoException (util.js:1018:11)
at exports._exceptionWithHostPort (util.js:1041:20)
at Server._listen2 (net.js:1258:14)
at listen (net.js:1294:10)
at Server.listen (net.js:1390:5)
at repl:1:44
at sigintHandlersWrap (vm.js:22:35)
at sigintHandlersWrap (vm.js:73:12)
at ContextifyScript.Script.runInThisContext (vm.js:21:12)
at REPLServer.defaultEval (repl.js:340:29)
This means that there is in fact a port conflict. Look at your task manager and make sure there aren't any instances of node running in the background that might be interfering with your tests spinning up a new server. You might also want to check for any versions of the ruby.exe running; sadly, we have to package the ruby.exe with pact-node, and it spins up a new instance of the mock server using ruby, since that's the language it's written in. From time to time, it does happen that node simply "loses track" of the ruby instance and doesn't shut it off properly.
This is a problem that is well known to us and is something we're actively trying to fix by consolidating all core pact code into a single shared library that can be used across all languages and operating systems without the need to spin up an extra instance. Please bear with us as we get some of these kinks out :)

TypeError: Cannot read property 'address' of undefined supertest

I need some help to resolve my problem with testing on nodejs codes. I'm using mocha and supertest. I'm confused with the implementation in supertest. I don't know to resolved it. I'm trying to automate downloading a file.
describe('GET /entry/:entryId/file/:id/download', function(){
it('should pass download function', function(done){
this.timeout(15000);
request(app.webServer)
.get('/entry/543CGsdadtrE/file/wDRDasdDASAS/download')
.set('Authorization', 'Bearer eyJ0eXAiOiJKV1QiLCJhbGco')
.expect(200)
.end(function(err, res) {
if (err) return done(err);
console.log(err, res);
done();
});
});
});
I received a similar error from mocha when testing an express app. Full text of error:
0 passing (185ms)
2 failing
1) loading express responds to /:
TypeError: app.address is not a function
at Test.serverAddress (test.js:55:18)
at new Test (test.js:36:12)
at Object.obj.(anonymous function) [as get] (index.js:25:14)
at Context.testSlash (test.js:12:14)
2) loading express 404 everything else:
TypeError: app.address is not a function
at Test.serverAddress (test.js:55:18)
at new Test (test.js:36:12)
at Object.obj.(anonymous function) [as get] (index.js:25:14)
at Context.testPath (test.js:17:14)
I fixed it by adding this to my express server.js, i.e. export the server object
module.exports = app
Typescript users, who are facing this error, check two things:
The express server should have module.exports = app (thanks to #Collin D)
Use import * as app from "./app"
instead of wrong import app from "./app"
I was facing same problem, above solution didn't work for me, some one in my shoes
kindly follow this guy's
exports in server.js should be
module.exports.app = app;
If you have multiple modules than use es6 feature
module.exports = {
app,
something-else,
and-so-on
}
my package.json for version cross ref..
{
"name": "expressjs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha **/*.test.js",
"start": "node app.js",
"test-watch": "nodemon --exec npm test"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.4",
"hbs": "^4.0.1"
},
"devDependencies": {
"mocha": "^5.2.0",
"supertest": "^3.3.0"
}
}

Resources