Pdf2json integrated with Protactor - npm

Has someone integrated pdf2json npm package with Protractor? I have been able to create a standalone node application to convert a PDF to json.
What I'm trying to do now is to add pdf2json to protractor.config.js and be able to use it in my test specs.

I managed to make it work myself so I thought to post what I did just in case someone needs the same.
Add the following to the Protractor config file
// PDF Parser
var PDFParser = require("pdf2json");
global.pdfParser = new PDFParser();
In the spec, we just need to wait for the async call to load the PDF to finish - note the done() (see Jasmine Async Support). The spec would look like:
var fs = require('fs');
describe('PDF Parser', function() {
it ("The spec", function(done){
// Capture the error
pdfParser.on("pdfParser_dataError", errData => {
console.error(errData);
done();
});
// Transform to json
pdfParser.on("pdfParser_dataReady", pdfData => {
fs.writeFile("path/to/save/json/file", JSON.stringify(pdfData));
done();
});
// This is an async call. We have to wait for it, so we use done in the 'it'
pdfParser.loadPDF("path/to/pdf/file");
});
});

Related

Testcafe data driven testing - how to drive tests with data fetched from API

I'm having trouble figuring out how to drive tests with data fetched from a request. I've read the documentation here: https://testcafe.io/documentation/402804/recipes/best-practices/create-data-driven-tests, and all examples use static json file data available at compile time.
I can't fetch the data in fixture.before hook, because it will only be available inside of the test context, but I need to access the data outside of the test context for iteration, such that the test is inside of a for loop.
I've tried this solution: https://github.com/DevExpress/testcafe/issues/1948, however this fails with testcafe ERROR No tests found in the specified source files. Ensure the sources contain the 'fixture' and 'test' directives., even when I use the flag disable-test-syntax-validation and .run({ disableTestSyntaxValidation: true }); option.
I am looking for suggestions and workarounds so that I can await some data, then run my tests. Even if Testcafe doesn't explicitly support something like this, I figure there must be some workaround... Thanks in advance.
Edit:
file-a.ts
export function tSteps(...args) {
// some setup
const testcase = args[args.length - 1];
const testCtx = test(name, async t => {
...
});
return testCtx;
}
----
file-b.ts
export const parameterizedTest = <T>(..., testcase: (scenario: T) => TestFn) => {
// some setup...
// I have also tried awaiting rows data here, which does not work
// because tests are not discoverable at compile time
...
const scenarios: T[] = rows.map(row => {
...
});
scenarios.forEach((scenario, idx) => {
return testcase(scenario).meta({
some metadata
});
});
};
----
tests.ts
fixture(...).before(async () => {
// can't get the data i need here because it needs to be available outside of the fixture context
})
parameterizedTest<MyInterface>(some params, (scenario: MyInterface) => {
return tSteps('my test',
async f => {
// some setup
// test code goes here which uses scenario.attributex, scenario.attributey, etc.
}
).meta(...);
}
);
In v1.0.0 and later, TestCafe does not validate test syntax. Please specify the TestCafe version that you use when you see the validation error.
Unfortunately, we cannot use pseudo-code to reproduce the issue you encountered. Please share some code that we could run to see the problematic behavior.
Generally speaking, TestCafe allows you to fetch data asynchronously and then spawn tests based on the received values. For instance, the following code works fine for me with TestCafe 1.18.3:
import { fixture, test } from 'testcafe';
import fetch from './node-fetch-mock';
(async () => {
const testData = await fetch();
testData
.map(n => () => {
fixture `Fixture ${n}`
.page `https://google.com`;
test(`Test ${n}`, async t => {
await t.expect(true).ok();
});
})
.map(async test => { await test(); });
})();
node-fetch-mock.js
export default async function fetch() {
return [1, 2, 3, 4, 5];
}
The only caveat is that I have to import fixture and test explicitly because I call them from callbacks.
Could you please provide us with any test code snippet that demonstrates the problem? We need to correctly understand the cause of the problem and reproduce it on our side.

TestCafe RequestLogger - How to implement for every request in the test framework

We are trying to track down a network issue in our company which causes a Browser Disconnect General Error. I want to use RequestLogger timestamp to help us highlight when this intermittent issue occurs and also any additional request/response information at that time.
In the Request Logger documentation the .requestHooks(logger) is initiated at every test case level. And then console.log(logRecord.X.X) is used to log the record at that specific time.
But how can I have a continuous logging throughout my whole test framework without using console.log(logRecord.X.X) on every line?
Is it somehow possible to have the RequestLogger continuously running via my test-runner function?
if(nodeConfig.util.getEnv('NODE_ENV') == "jenkins-ci")
{
// #ts-ignore
// createTestCafe("localhost", port1, port2).then(tc => {
createTestCafe().then(tc => {
this.testcafe = tc;
this.runner = this.testcafe.createRunner();
return this.runner
.src(testPath)
.filter(filterSettings)
.browsers(environment.browserToLaunch)
.concurrency(environment.concurrencyAmount)
.reporter(reporterSettings)
.run(runSettingsCi);
})
.then(failedCount => {
console.log('Location ' + testPath + ' tests failed: ' + failedCount);
this.testcafe.close();
process.exit(0);
})
.catch((err) => {
console.log('Location ' + testPath + ' General Error');
console.log(err);
this.testcafe.close();
process.exit(1);
});
}
TestCafe doesn't allow attaching request hooks with the test runner class. At the same time, you can attach it to each fixture. RequestLogger will collect information about all requests.
For example:
import { Selector, RequestLogger } from 'testcafe';
const logger = RequestLogger();
fixture `Log all requests`
.page`devexpress.github.io/testcafe`
.requestHooks(logger)
.afterEach(() => console.log(logger.requests));
test('Test 1', async t => {
await t
.click(Selector('span').withText('Docs'))
.click(Selector('a').withText('Using TestCafe'))
.click(Selector('a').withText('Test API'));
});
test('Test 2', async t => {
await t
.click(Selector('span').withText('Docs'))
.click(Selector('a').withText('Continuous Integration'))
.click(Selector('a').withText('How It Works'));
});
Previously, TestCafe allowed you to attach request hooks to one test or fixture at a time. In the new TestCafe v1.19.0, you can also define global request hooks in a JavaScript configuration file .testcaferc.js to attach them to all fixtures and tests within a test run. You can learn more here: Global Request Hooks.
Please note that you can use the configFile option in CLI and program API to specify the path to a config file.
For the initial usage scenario, you can use the following example:
const { RequestLogger } = require('testcafe');
const logger = RequestLogger();
module.exports = {
hooks: {
request: logger,
},
};

Let Puppeteer wait for globalSetup to finish

I use Jest-Puppeteer to end2end test a webapplication. All tests run parallel with async functions. Now I find that the first test already runs before the globalSetup has finished and the data preperation is done (initializing client-settings etc.)
I've tried to timeout after the request, but that isn't working because now all requests have a timeout.
import puppeteer from "puppeteer";
import { getUrlByPath, post } from "../helper";
module.exports = async function globalSetup(globalConfig) {
await setupPuppeteer(globalConfig);
puppeteer.launch({args: ["--no-sandbox", "--disable-setuid-sandbox"]}).then(async browser => {
const page = await browser.newPage();
await post(
page,
getUrlByPath("somePath"),
"prepare_data_for_testing",
);
await browser.close();
});
};
Above code runs a globalConfig, after that it starts preparing the data for the testing environment.
Is there a way to make the test suites run AFTER this script returns the post with http 200: ok ?
I had to place await before puppeteer.launch and add require("expect-puppeteer"); at the top.

Compatibility between cypress and react-apollo

I am using react-apollo to make GraphQL queries, and I am using Cypress for testing.
The problem is that these 2 dont seem to play well along. Apollo seems to be making all its requests through the Fetch API.
But Cypress seems like it is not able to capture anything, except XHR requests.
So what could I do to solve this problem? Is there a way for Cypress to capture "fetch" requests? Is there a way for react-apollo to use "xhr" instead of "fetch"?
Try out cypress-graphql-mock
You just pass it your schema:
const schema = fs.readFileSync('../../app-schema.graphql', 'utf8');
// alternatively, using a dumped introspection query:
// const schema = require('../../dumped-schema.json')
beforeEach(() => {
cy.server();
cy.mockGraphql({ schema });
});
An easy workaround is to use whatwg-fetch, which you'd add as a dependency via npm and then...
cypress/support/fetch_to_xhr.js
function fetchToXhr() {
let polyfill
before(() => {
cy.readFile('node_modules/whatwg-fetch/dist/fetch.umd.js')
.then((contents) => polyfill = contents)
Cypress.on('window:before:load', (win) => {
delete win.fetch
win.eval(polyfill)
})
})
}
fetchToXhr()
cypress/support/index.js
import "./fetch_to_xhr";
After that cypress will capture the graphql requests
Cypress now officially supports working with GQL: Working with GraphQL.
I recommend reading their documentation in detail, but at your own risk here is a VERY crude TLDR:
cy.intercept('your-url-here/graphql', (req) => {
const { body } = req;
if (body.hasOwnProperty('your-operationName-here')) {
// do something with the request, like:
req.reply('your-mock-here');
}
});

How to test promises in Mongo(ose)/Express app?

I'm using promises to wrap asynchronous (Mongo) DB ops at the end of an (expressJS) route.
I want to try and figure out how to test the following code.
userService
userService.findOne = function (id) {
var deferred = q.defer();
User.findOne({"_id" : id})
.exec(function (error, user) {
if (error) {
deferred.reject(error);
} else {
deferred.resolve(user);
}
});
return deferred.promise;
};
userRoute
var user = function (req, res) {
var userId = req.params.id
, userService = req.load("userService");
// custom middleware that enables me to inject mocks
return userService.findOne(id)
.then(function (user) {
console.log("called then");
res.json({
msg: "foo"
});
}).catch(function (error) {
console.log("called catch");
res.json({
error: error
});
}).done();
};
Here's an attempt to test the above with mocha
userTest
it("when resolved", function (done) {
var jsonSpy = sinon.spy(httpMock.res, "json")
, httpMock = require("/path/to/mock/http/object")
, serviceMock = require("/path/to/mock/service"),
, deferred = q.defer()
, findStub = sinon.stub(serviceMock, "findOne")
.returns(deferred.promise)
, loadStub = sinon.stub(httpMock.req, "load")
.returns(serviceMock),
retPromise;
// trigger route
routes.user(httpMock.req, httpMock.res);
// force promise to resolve?
deferred.resolve();
expect(jsonSpy.called).to.be.true; // fails
// chai as promised
retPromise = findStub.returnValues[0];
expect(retPromise).to.be.fulfilled; // passes
});
the http mock is just an empty object with no-ops where expressJS would normally start rendering stuff. I've added some logging inside those no-ops to get an idea on how this is hanging together.
This isn't really working out. I want to verify how the whole is integrated, to establish some sort of regression suite - but I've effectively mocked it to smithereens and I'm just testing my mocks (not entirely successfully at that).
I'm also noticing that the console logs inside my http mocks triggered by then and catch are firing twice - but the jsonSpy that is invoked inside the actual code (verified by logging out the sinon spy within the userRoute code) is not called in test.
Has anyone got some advice on integration testing strategies for express apps backed by Mongo?
It looks to me like you're not giving your promise an opportunity to fire before you check if the result has been called. You need to wait asynchronously for userService.findOne()'s promise chain to complete before jsonSpy.called will be set. Try this instead:
// start of code as normal
q.when(
routes.user(httpMock.req, httpMock.res),
function() { expect(jsonSpy.called).to.be.true; }
);
deferred.resolve();
// rest of code as normal
That should chain off the routes.user() promise and pass as expected.
One word of caution: I'm not familiar with your framework, so I don't know if it will wait patiently for all async events to go off. If it's giving you problems calling back into your defer chain, you may want to try nodeunit instead, which handles async tests very well (IMO).