I'm trying to unit test with Nuxt. Everything's going smoothly, but my problem lies with unit testing fetch. It seems that since this.$axios isn't a library (well, it is, but is injected to the context), there's no easy way to jest.mock it. I've the few posts that there are on this, but they have not worked.
async fetch() {
try {
this.maxSpace = await this.$axios.$get('/api/system/max-space')
}
catch (err) {
this.maxSpace = 0
}
},
This is the simple code I'm attempting to unit test
Related
I'm trying to test an ExpressJS (4.17.8) and NodeJS (16.3) powered server (app) with tap, and later with supertest. First I'm testing the instantiation of the server, and later its routes.
For this, my app is wrapped in a Connector Class that:
has an ExpressJS server (app)
connects to an external system
registers endpoints
has a method startup that calls app.listen
So I have a test file like this:
import test, { Test } from "tape-promise/tape";
test("connects to X", async (t: Test) => {
connector = new Connector();
await connector.ConnectToExternalSystem(); // connects to external system
await connector.registerEndpoints(); // e.g., sets to the Express app: app[get](/endpoint)...
await connector.listen(); // gets stuck?
t.ok(connector);
t.end();
My problem is that for every test I perform, tap seems to get stuck (happens with Jest as well) in connector.listen() - leading for the test to timeout.
My project and tests are written in Typescript 4.3.5. I am using the following npm script to run the tests:
"test": "tap --ts --jobs=1 --node-arg=--max-old-space-size=4096 --timeout=15 --branches=45 --functions=70 --lines=75 --statements=75 \"src/test/{unit,integration}/\"",
Is there anything I'm doing wrong? Appreciate your advice on this.
Thanks.
Depends on what the implementation of Connector really looks like. Assuming that the .listen() method of it calls express' listen under the hood the issue might be that you are not handling the success callback or that it's not wired up properly to the returned promise via the resolve callback of the promise.
So something like this could work (rough pseudo code, not tested):
class Connector {
listen(): Promise<void> {
return new Promise((resolve, reject) => {
this.expressApp.listen((err: Error) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
}
What the above does is ensures that the returned promise resolves once the callback has been invoked (or rejects if the callback was passed in an error which is the standard NodeJS error handling style)
I am getting an error in Jest test cases that says assignedElements is not a function.
In the code, I am trying to query slots and then fetch the value as mentioned below:
let slot = this.element.shadowRoot?.querySelector('slot');
const testItems = slot.assignedElements({flatten:true});
This code is working fine on most of the browsers, but it is failing in Jest test cases. I thought of mocking and spying on this API, but no luck there either.
Some environments may not have slot.assignedElements yet, but it is super easy to polyfill on top of slot.assignedNodes:
if (!HTMLSlotElement.prototype.assignedElements) {
HTMLSlotElement.prototype.assignedElements = function (...args) {
return HTMLSlotElement.prototype.assignedNodes
.apply(this, args)
.filter((n) => n instanceof Element)
}
}
Change .assignedElements() to .assignedElements?.()
and .assignedNodes() to .assignedNodes?.()
I cannot get nockBack to record any fixtures, although it should do that. My test code looks as follows:
describe("#searchForProjects", function () {
beforeEach(function () {
nock.back.setMode("record");
this.con = getTestConnection(ApiType.Production);
});
it("finds a home project", async function () {
const { nockDone, context } = await nock.back("search_for_project.json");
await searchForProjects(this.con, "home:dancermak", {
idOnly: true,
exactMatch: true
}).should.eventually.deep.equal([
{
name: "home:dancermak",
apiUrl: normalizeUrl(ApiType.Production)
}
]);
nockDone();
});
});
Just running this specific test results in a NetConnectNotAllowedError: Nock: Disallowed net connect for $URL.
I have tried including a nock.restore() before the whole test, which results in the request going through, but nock doesn't bother recording anything.
The underlying code is using the https module from nodejs, so that shouldn't be a problem?
Any help would be greatly appreciated.
I have finally managed to crack this and the solution is embarrassingly simple: recording must be activated before creating any http(s).request calls. In my case it was obscured a bit as I have a class that on construction saves either http.request or https.request in a member variable. Activating the recorder beforehands solves the issue.
For me the problem was that I had a failing assertion in my test. This meant that nockDone was not called and so no nocks were written to disk.
I was writing tests for some authentication endpoints when I came across a bug like issue that I cannot seem to figure out.
This test won't pass:
it("Testing /auth/signup/lol", () => {
const test = true;
expect(test).toBe(true);
console.log("finished test?");
});
The only way I can reproduce this issue is taking all the setup and teardown code, then moving it to another file, along with the test that's troubling me (as I have done, this test copied from auth.test.js).
I've spent the morning trying to figure out the issue, the only time the test has passed is when I removed the setup code. However on notebooks.test.js and auth.test.js (excluding the last two three tests at the bottom of the auth.tests.js script) the setup codes works as intended.
What's wrong with this code?
Steps to reproduce:
Clone this repository
Switch to the develop branch
Go to the backend directory
Install all packages
Run 'npm test tests/endpoints/auth2.test.js'
I would post a small program reproducing the issue, but all attempts to do so failed.
there's a timeout in the afterEach() method because collections.users.drop() returns an undefined value (result is undefined).
At the minimum, add an else clause when testing result value so you can exit method before reaching the 10s timeout.
Maybe some additional code is required but I don't know the logic of your code and test so maybe afterEach should do more things.
Here is the working code:
afterEach(done => {
server.getTokenManager().empty()
let collections = server.getClient()?.connection.collections
if (collections === undefined) {
done()
return
}
if (collections.users !== undefined) {
collections.users.drop((err: any, result: any) => {
if (result) {
done()
} else {
done()
}
})
}
}, 10000)
The rest of the code is ok.
I'm correctly working on refactoring my clone of the express-decorator NPM package. This includes refactoring the unit tests that were previously done using AVA. I decided to rewrite them using Mocha and Chai because I like the way they define tests a lot more.
So, what is my issue? Take a look at this code (I broke it down to illustrate the problem):
test('express', (t) => {
#web.basePath('/test')
class Test {
#web.get('/foo/:id')
foo(request, response) {
/* The test in question. */
t.is(parseInt(request.params.id), 5);
response.send();
}
}
let app = express();
let controller = new Test();
web.register(app, controller);
t.plan(1);
return supertest(app)
.get('/test/foo/5')
.expect(200);
});
This code works.
Here's (basically) the same code, now using Mocha and Chai and multiple tests:
describe('The test express server', () => {
#web.basePath('/test')
class Test {
#web.get('/foo/:id')
foo(request, response) {
/* The test in question. */
it('should pass TEST #1',
() => expect(toInteger(request.params.id)).to.equal(5))
response.send()
}
}
const app = express()
const controller = new Test()
web.register(app, controller)
it('should pass TEST #2', (done) => {
return chai.request(app)
.get('/test/foo/5')
.end((err, res) => {
expect(err).to.be.null
expect(res).to.have.status(200)
done()
})
})
})
The problem is that the TEST #1 is ignored by Mocha although that part of the code is run during the tests. I tried to console.log something there and it appeared in the Mocha log where I expected it to appear.
So how do I get that test to work? My idea would be to somehow pass down the context (the test suite) to the it function, but that's not possible with Mocha, or is it?
It looks like you are moving from tape or some similar test runner to Mocha. You're going to need to significantly change your approach because Mocha works significantly differently.
tape and similar runners don't need to know ahead of time what tests exist in the suite. They discover tests as they go along executing your test code, and a test can contain another test. Mocha on the other hand requires that the entire suite be discoverable before running any test.* It needs to know each and every test that will exist in your suite. It has some disadvantages in that you cannot add tests while the Mocha is running the test. You could not have a before hook for instance do a query from a database and from that create tests. You'd have instead to perform the query before the suite has started. However, this way of doing things also has some advantages. You can use the --grep option to select only a subset of tests and Mocha will do it without any trouble. You can also use it.only to select a single test without trouble. Last I checked, tape and its siblings have trouble doing this.
So the reason your Mocha code is not working is because you are creating a test after Mocha has started running the tests. Mocha won't right out crash on you but when you do this, the behavior you get is undefined. I've seen cases where Mocha would ignore the new test, and I've seen cases where it executed it in an unexpected order.
If this were my test what I'd do is:
Remove the call to it from foo.
Modify foo to simply record the request parameters I care about on the controller instance.
foo(request, response) {
// Remember to initialize this.requests in the constructor...
this.requests.push(request);
response.send()
}
Have the test it("should pass test #2" check the requests recorded on the controller:
it('should pass TEST #2', (done) => {
return chai.request(app)
.get('/test/foo/5')
.end((err, res) => {
expect(err).to.be.null
expect(res).to.have.status(200)
expect(controler.requests).to.have.lengthOf(1);
// etc...
done()
})
})
And would use a beforeEach hook to reset the controller between tests so that tests are isolated.