Issue with Cypress.js and uncaught exceptions - javascript

I'm very new to Cypress.js.
Problem statement:
I'm running cypress in headless mode (Chrome) and one of the API calls is failing with uncaught exception. However, when I manually visit the url it works fine!
I'm not sure if its because of some SSL certificate issue or what's happening. Everything works normally when I visit the url in my chrome/firefox/safari.
Follow-up questions:
My recording shows it's uncaught exception but I don't know why / what is failing.
How do I log my failing network requests into a log file to see what the actual error is?
Am I missing any configuration?
This is my configuration:
cypress/plugins/index.js
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
on('before:browser:launch', (browser = {}, launchOptions) => {
launchOptions.args.push('--ignore-urlfetcher-cert-requests')
launchOptions.args.push(`--ignore-certificate-errors`)
launchOptions.args.push(`--unsafely-treat-insecure-origin-as-secure=http://localhost:9999`)
return launchOptions
})
}
Cypress.json
{
"reporter": "junit",
"reporterOptions": {
"mochaFile": "cypress/results/helltool.xml",
"toConsole": true
},
"defaultCommandTimeout": 20000,
"pageLoadTimeout": 20000,
"responseTimeout": 20000,
"chromeWebSecurity": false
}
Sample Test
Cypress.on('uncaught:exception', (err, runnable) => {
console.log(`CYPRESS uncaught exception FLOW:::: ${err}`);
debugger;
return false;
});
describe('Flow Sanity Tests', () => {
before(() => {
// We need to login before we can do anything
// TODO: Abstract this inside Looker.explore
cy.login('admin', { flow: true })
})
it('Test to check Flow exists and run it', () => {
// Some test to execute after login
})
Login flow (in support/commands.js)
Cypress.Commands.add('login', (userType, options = {}) => {
const types = {
admin: {
email: 'demo#demo',
password: 'thisisademopassword',
},
}
// Go to login page
cy.goTo('login', options)
// grab the user
const { email, password } = types[userType]
cy.wait(2000)
// type the stuff.
cy.get('#login-email', { timeout: 30000 }).should('exist').debug()
cy.get('#login-email').type(email)
cy.get('#login-password').type(password)
cy.get('#login-submit').click()
})
Execution:
npm run cypress:run -- --spec "cypress/integration/flow/demo.spec.js"
--browser chrome

Related

I am facing an undefined reading length error in my code below

This is the error I am getting when I try to deploy the code:
Error: ERROR processing /home/anooj-patnaik/hh-fcc/hardhat-fund-me-fcc/deploy/00-deploy-mocks.js:
TypeError: Cannot read properties of undefined (reading 'length')
const { network } = require("hardhat")
const {
developmentChains,
DECIMALS,
INITIAL_ANSWER,
} = require("../helper-hardhat-config")
module.exports = async ({ getNamedAccounts, deployments }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
if (developmentChains.includes(network.name)) {
log("Local Network Detected! Deploying Mocks...")
await deploy("MockV3Aggregator", {
contract: "MockV3Aggregator",
from: deployer,
log: true,
args: [DECIMALS, INITIAL_ANSWER],
})
log("Mocks deployed")
log("---------------------------")
}
}
module.exports.tags = ["all", "mocks"]
I have defined all the variables in a hardhat-helper-config.js and hardhat.config.js. The MockV3Aggregator is in a separate contract
Tried to deploy the code above and faced with an error
When you call await getNamedAccounts(), it looks in your hardhat.config.js for the namedAccounts section, and reads the length of the named accounts.
You'll want to make sure this is in there!
namedAccounts: {
deployer: {
default: 0, // here this will by default take the first account as deployer
},
},

Jest trying to import after environment torn down, caused by AWS SDK

My Jest integration tests for my application create records in a local DynamoDB, all the tests pass fine, but in the cleanup afterwards, I get a message saying that
ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.
at Object.userAgent (node_modules/aws-sdk/lib/util.js:34:43)
at HttpRequest.setUserAgent (node_modules/aws-sdk/lib/http.js:111:78)
at new HttpRequest (node_modules/aws-sdk/lib/http.js:104:10)
at new Request (node_modules/aws-sdk/lib/request.js:328:24)
at features.constructor.makeRequest (node_modules/aws-sdk/lib/service.js:202:19)
npm ERR! Test failed. See above for more details.
I have an afterAll setup to run after each test and delete the created records like follows:
afterAll(async () => {
ECs.forEach(async (EC) => {
await deleteUser(EC);
})
ECs = [];
})
I have tried using fake timers with no success. The tests are also all running sequentially. This is an example of one of the tests:
test("Create new user", async () => {
const johnECInitialRequestParams = {
EC: {
firstName: "John",
email: "john.smith#gmail.com",
},
responsibleFor: "8b8a9eb9-840f-4245-9200-719fe05f6612"
}
const johnECResultStoredObject = {
ECID: "f576d1cb-4df0-4093-9b2d-b94c70a28e18",
firstName: "John",
email: "john.smith#gmail.com",
responsibilities: [
{
greenID: "8b8a9eb9-840f-4245-9200-719fe05f6612",
RID: "8e76e90c-8088-40d3-add3-e39c1d4024d8",
status: "pending"
}
]
}
uuidv4
.mockReturnValue(null) // should only be called twice
.mockReturnValueOnce(johnECResultStoredObject.ECID) // for ECID
.mockReturnValueOnce(johnECResultStoredObject.responsibilities[0].RID) // for RID
ECs.push(johnECResultStoredObject.ECID); // to delete the object after the test execution
try {
await handler(johnECInitialRequestParams, undefined, undefined);
}
catch (err) {
console.error(err);
throw err
}
expect(await getUser(johnECResultStoredObject.ECID)).toMatchObject(johnECResultStoredObject);
});
After the imports, add jest.useFakeTimers() in your test file

Error with Typescript Pact.io test: PopsicleError: Unable to connect to

Expected: Running npm run pactTest should generate a pact file (JSON).
Results: I get an Unable to connect error.
Pact.io JavaScript implementation guide.
Pact.io Typescript test example.
Appreciate any thoughts or ideas as to what I'm doing wrong :)
The Error
FAIL src/services/api/TotalPayout.test.pact.ts
The API
getUsersTotalPayout
✕ Should call getUsersTotalPayout and return an object with the total_payout (45ms)
● The API › getUsersTotalPayout › Should call getUsersTotalPayout and return an object with the total_payout
PopsicleError: Unable to connect to "http://127.0.0.1:12345/interactions"
Caused by: Error: connect ECONNREFUSED 127.0.0.1:12345
at Request.Object.<anonymous>.Request.error (node_modules/popsicle/src/request.ts:91:12)
at ClientRequest.<anonymous> (node_modules/popsicle/src/index.ts:218:31)
package.json script:
"pactTest": "export NODE_ENV=pactTest && jest --testRegex \"/*(.test.pact.ts)\" --runInBand --setupFiles ./pactSetup.ts --setupTestFrameworkScriptFile ./pactTestWrapper.ts",
My src/pactSetup.ts file
// #ts-ignore
import path from 'path';
import { Pact } from '#pact-foundation/pact/pact';
​
// #ts-ignore
global.provider = new Pact({
port: 1234,
log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
dir: path.resolve(process.cwd(), 'pacts'),
spec: 2,
cors: true,
pactfileWriteMode: 'update',
consumer: 'Exchange',
provider: 'LP Service'
});
My src/pactTestWrapper.ts
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // This is to give the pact mock server time to start
​
// #ts-ignore
beforeAll(() => provider.setup()); // Create mock provider
// #ts-ignore
afterEach(() => provider.verify()); // Ensure the mock provider verifies expected interactions for each test
// #ts-ignore
afterAll(() => provider.finalize()); // Tear down the mock and write the pact
The test: src/services/api/TotalPayout.test.pact.ts
// #ts-ignore
import path from 'path';
import { Pact } from '#pact-foundation/pact';
import { getTotalPayout } from './apiPayout';
const port = 12345;
const endpoint = '/frontoffice/api/get-total-payout';
const EXPECTED_BODY = {
total_payout: 100.21,
};
const userId = 'foo';
const provider = new Pact({
port,
log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
dir: path.resolve(process.cwd(), 'pacts'),
spec: 2,
consumer: 'Exchange',
provider: 'LP Service',
pactfileWriteMode: 'merge'
});
​​
describe('The API', () => {
// Copy this block once per interaction under test
describe('getUsersTotalPayout', () => {
beforeEach(() => {
const interaction = {
uponReceiving: 'a GET request with a user id',
withRequest: {
method: 'GET',
path: endpoint,
headers: {
Accept: 'application/json',
},
},
willRespondWith: {
status: 200,
headers: {
'Content-Type': 'application/json'
},
body: EXPECTED_BODY
},
};
// #ts-ignore
return provider.addInteraction(interaction);
});
​
// add expectations
it('Should call getUsersTotalPayout and return an object with the total_payout', done => {
getTotalPayout(userId)
.then((response: any) => {
expect(response).toEqual(EXPECTED_BODY);
})
.then(done);
});
});
});
The api service file apiPayout.ts
// #ts-ignore
import axios, * as others from 'axios';
const endpoint = '/frontoffice/api/';
export const getTotalPayout = async (userId: string) => {
const response = await axios.get(`${endpoint}get-total-payout`, { params: userId });
return response.data;
};
From the mockserver-integration.log
I, [2018-09-19T11:07:41.259437 #79922] INFO -- : Verifying - interactions matched
I, [2018-09-19T11:07:41.264440 #79922] INFO -- : Cleared interactions
From the debug-log
20 error code ELIFECYCLE
21 error errno 1
22 error react-redux-starter-kit#1.0.0 pactTest: `export NODE_ENV=pactTest && jest --testRegex "/*(.test.pact.ts)" --runInBand --setupFiles ./pactSetup.ts --setupTestFrameworkScriptFile ./pactTestWrapper.ts`
22 error Exit status 1
23 error Failed at the react-redux-starter-kit#1.0.0 pactTest script.
Update
After commenting out the provider setup logic in the test.pact file and re-running npm run pactTest I get the following:
console.error node_modules/#pact-foundation/pact/pact.js:110
Pact verification failed!
console.error node_modules/#pact-foundation/pact/pact.js:111
Actual interactions do not match expected interactions for mock MockService.
Missing requests:
GET /frontoffice/api/liquidity-pool/get-total-payout
See /Users/leongaban/projects/trade.io/tradeio-front/logs/mockserver-integration.log for details.
And my updated mockserver-intergration.log
I, [2018-09-19T14:12:19.128823 #82330] INFO -- : Registered expected interaction GET /frontoffice/api/liquidity-pool/get-total-payout
D, [2018-09-19T14:12:19.129127 #82330] DEBUG -- : {
"description": "a GET request with a user id",
"request": {
"method": "GET",
"path": "/frontoffice/api/liquidity-pool/get-total-payout",
"headers": {
"Accept": "application/json"
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
"total_payout": 100.21
}
}
}
W, [2018-09-19T14:12:19.139198 #82330] WARN -- : Verifying - actual interactions do not match expected interactions.
Missing requests:
GET /frontoffice/api/liquidity-pool/get-total-payout
W, [2018-09-19T14:12:19.139254 #82330] WARN -- : Missing requests:
GET /frontoffice/api/liquidity-pool/get-total-payout
Several issues I can point out:
You seem to be declaring and spinning a pact mock server twice: in the src/pactSetup.ts file and also in TotalPayout.test.pact.ts which I'm not sure it's what you intended to do. You probably want to avoid declaring the provider in the TotalPayout test, and instead you already have the provider object on the global scope as part of the test framework setup files.
In the code apiPayout.ts you are referring to the endpoint URL, but to which port is it sending the request? This API call should be ultimately caught by the pact mock provider that you are spinning up. If you call to a different port than what the mock provider is listening on you'll never hit it.
A small nitpick: /frontoffice/api/get-total-payout is not a RESTful. You want to avoid including verbs such as "get" in your API and use the proper HTTP method for that (GET).
Not sure if that was your problem, but I had the order of writePact and finalize wrong. I had:
afterAll(async () => {
await provider.finalize()
await provider.writePact()
})
instead of the correct order:
afterAll(async () => {
await provider.writePact()
await provider.finalize()
})

How to use pact with typescript

I am trying to implement pact-node using typescript. (https://github.com/pact-foundation/pact-node). I am having some problems and the resulting errors messages are not very descriptive. It's probably something I am doing wrong in the setup, a lot of the documentation and examples available online use pact.js and there are some differences. Below is my code:
const path = require('path');
import { Pact } from '../../../node_modules/#pact-foundation/pact';
import { Interaction, InteractionObject } from '../../../node_modules/#pact-foundation/pact';
import { expect } from 'chai';
import { afterEach, before, beforeEach, describe, it, after } from 'mocha';
import { myService } from '../../main/typescript/service/test-service';
describe('My Pact Test', () => {
const port = 5428;
let service: myService;
const provider = new Pact({
port,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'pacts'),
spec: 2,
consumer: 'MyConsumer',
provider: 'MyProvider',
pactfileWriteMode: 'merge',
});
const EXPECTED_BODY = [{
'auctionStartTime': 1549652248000,
'auctionEndTime': 1549911448000,
'resolveTime': 1539670248000,
'openTimestamp': 1533496996000,
'closeTimestamp': 1547804158000,
'previewStartTime': 1549393048000,
}];
before(() => provider.setup());
after(() => provider.finalize());
afterEach(() => provider.verify());
describe ('should get items ', () => {
console.log ('message 1 ');
before(() => {
console.log ('message 2');
return provider.addInteraction({
state: 'item present in database,
uponReceiving: 'a request for items',
withRequest: {
method: 'GET',
path: 'path_to_my_api_endpoint,
headers: {
Accept: 'application/json',
},
},
willRespondWith: {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: EXPECTED_BODY,
},
});
});
it('returns the correct response', (done) => {
console.log ('message 3');
service.getInfo('123', '123')
.then((response: any) => {
expect(response.data).to.eql(EXPECTED_BODY);
done();
});
});
});
})
However when I try to run this I get the following error:
1) My Pact Test "before all" hook:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
2) My Pact Test "after all" hook:
Error: Failed to get the current sub/segment from the context.
at Object.contextMissingRuntimeError [as contextMissing] (node_modules/aws-xray-sdk-core/lib/context_utils.js:21:15)
at Object.getSegment (node_modules/aws-xray-sdk-core/lib/context_utils.js:92:45)
at Object.resolveSegment (node_modules/aws-xray-sdk-core/lib/context_utils.js:73:19)
at captureOutgoingHTTPs (node_modules/aws-xray-sdk-core/lib/patchers/http_p.js:67:31)
at captureHTTPsRequest (node_modules/aws-xray-sdk-core/lib/patchers/http_p.js:152:12)
at node_modules/popsicle/src/index.ts:126:30
at new WrappedPromise (node_modules/async-listener/es6-wrapped-promise.js:13:18)
at node_modules/popsicle/src/index.ts:112:16
at propagateAslWrapper (node_modules/async-listener/index.js:502:23)
at node_modules/async-listener/glue.js:188:31
at node_modules/async-listener/index.js:539:70
at node_modules/async-listener/glue.js:188:31
at <anonymous>
Anybody got any idea what I am doing wrong? Or failing that, does anyone have an example of how they implemented pact using typescript?
Thanks!
Is there a reason why you're not using https://github.com/pact-foundation/pact-js?
Pact Node is a lower level library probably not ideally suited to what you're doing. Pact JS is the higher level DSL for tests as you've created.
There is a TypeScript example in there.
update: you might need to increase the timeout, it seems your system is taking longer than 2s to start the mock server and is bailing.
The second error described looks unrelated to pact.
Sometimes I have seen changing the node port also resolves the timeout issue.

How to start a server before protractor runs and clean up afterwards

It seems protractor doesn't provide any out of the box solution for starting a server before it runs. Having to run multiple commands before functional tests will run is a bad user experience and bad for automated testing.
Angular-cli has its own solution that is rather complicated, which this plugin claims to duplicate, although it doesn't work for me and may be unmaintained. https://www.npmjs.com/package/protractor-webpack
EDIT: BETTER SOLUTION ACCEPTED BELOW
I came up with a solution using child_process.exec that seems to work well, although I don't like it very much. I'd like to share it in case anyone needs it and to see if anyone can come up with a better solution.
Launch the process in the beforeLaunch hook of protractor:
beforeLaunch: () => {
webpackServerProcess = exec(`webpack-dev-server --port=3003 --open=false`, null, () => {
console.log(`Webpack Server process reports that it exited. Its possible a server was already running on port ${port}`)
});
},
Then above the configuration block we set up the exit handlers to make positively sure that server gets killed when we are done.
let webpackServerProcess; // Set below in beforeLaunch hook
function cleanUpServer(eventType) {
console.log(`Server Cleanup caught ${eventType}, killing server`);
if (webpackServerProcess) {
webpackServerProcess.kill();
console.log(`SERVER KILLED`);
}
}
[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`].forEach((eventType) => {
process.on(eventType, cleanUpServer.bind(null, eventType));
})
The various event listeners are needed to handle cntrl+c events and situations where the process is killed by ID. Strange that node does not provide an event to encompass all of these.
Protractor also has onCleanUp that will run after all the specs in the file have finished.
And you are doing the right thing by keeping a reference to your process so that you can kill it later.
let webpackServerProcess;
beforeLaunch: () {
webpackServerProcess = exec('blah'); // you could use spawn instead of exec
},
onCleanUp: () {
process.kill(webpackServerProcess.pid);
// or webpackServerProcess.exit();
}
Since you are launching the serverProcess with child_process.exec, and not in a detached state, it should go away if the main process is killed with SIGINT or anything else. So you might not even have to kill it or cleanup.
I found a much more reliable way to do it using the webpack-dev-server node api. That way no separate process is spawned and we don't have to clean anything. Also, it blocks protractor until webpack is ready.
beforeLaunch: () => {
return new Promise((resolve, reject) => {
new WebpackDevServer(webpack(require('./webpack.config.js')()), {
// Do stuff
}).listen(APP_PORT, '0.0.0.0', function(err) {
console.log('webpack dev server error is ', err)
resolve()
}).on('error', (error) => {
console.log('dev server error ', error)
reject(error)
})
})
},
// conf.js
var jasmineReporters = require('jasmine-reporters');
var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');
const path = require('path');
const WebpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');
let webpackServerProcess;
beforeLaunch: () => {
return new Promise(resolve => {
setTimeout(() => {
const compiler = webpack(require('./webpack.config.js'));
const server = new WebpackDevServer(compiler, {
stats: 'errors-only'
});
server.listen(0, 'localhost', () => {
// `server.listeningApp` will be returned by `server.listen()`
// in `webpack-dev-server#~2.0.0`
const address = server.listeningApp.address();
config.baseUrl = `http://localhost:${address.port}`;
resolve();
});
}, 5000);
});
};
exports.config = {
framework: 'jasmine',
//seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['Test/spec.js'],
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome'/*,
chromeOptions: {
args: [ '--headless','--log-level=1', '--disable-gpu', '--no-sandbox', '--window-size=1920x1200' ]
}*/
},
onPrepare: function() {
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
filePrefix: 'guitest-xmloutput',
savePath: 'reports'
}));
jasmine.getEnv().addReporter(new Jasmine2HtmlReporter({
savePath: 'reports/',
screenshotsFolder: 'images',
takeScreenshots: true,
takeScreenshotsOnlyOnFailures: true,
cleanDestination: false,
fileName: 'TestReport'
}));
},
}
onCleanUp: ()=> {
//process.kill(webpackServerProcess.pid);
webpackServerProcess.exit();
}

Categories