Testing
Framework came out with vitest support. When you named files {Something}.test.js then it will be added to tests
Please put test files near main files that you are testing and put the same name to that file. If you want to test “Auth.js” please create a file “Auth.test.js” and put it on the same folder
Frawemork (app) instance
Of course inside a test you need to have access to framework instance. In will available via global variable ‘global.server.app’
Run tests
npm test
Before scripts
Test entry points happen on project level ‘src/test/setupVite.js’. This file prepares all folder configs, require framework setup and prepare global setup for tests
Minimum vite config file should contains :
test: {
globalSetup: [ // this script will start mongo
'node_modules/@adaptivestone/framework/tests/globalSetupVitest',
],
setupFiles: [
'./src/tests/setup.js', // this is a local config file (see below)
'@adaptivestone/framework/tests/setupVitest', // this is entry point for testing from framework
],
}
global.testSetup
This is a special variable that configures the global behaviour of tests.
You have two hooks that will happen globally before the test run and after the test run.
global.testSetup.beforeAll
global.testSetup.afterAll
In additional you have ability to disable default user creating by adjusting variable
global.testSetup.disableUserCreate
Example:
global.testSetup = {
disableUserCreate: true, // we diabled user creating default one
beforeAll: async () => {
const User = global.server.app.getModel("User");
global.user = await User.create({
email: "test@test.com",
password: "testPassword",
role: ["admin"], // That new behaviour
}).catch((e) => {
console.error(e);
console.info(
"That error can happens in case you have custom user model. Please use global.testSetup.disableUserCreate flag to skip user creating"
);
});
global.authToken = await global.user.generateToken();
// here can be init for some connection, like for test instance of elastic search or redis
},
afterAll: async () => {
// If you made connection do not miss to close it after test
},
};
Default user for testing
By default, create a default user with email 'test@test.com' and password 'testPassword'. User instance as ‘global.user’ and ‘global.authToken’ for auth token
You can change that behaviour by global variable ‘global.testSetup.disableUserCreate’
Mongo instance
As a framework designed to work with mongo db and provide easy integration to it - then it comes with mongo db integration on tests too.
Integration came with help with MongoDbMemoryServer package
By default, the framework starts the mongo memory server and afterwards stops it. So you can use mongo during your test
Mongo tests on ARM64 machines (docker)
For ARM64 we have an interesting situation. Mongo Inc provides binaries for Ubuntu and not for Debian, but node official images exist for Debian but not for Ubuntu.
To solve that situation we provide our own node docker image based on ubuntu. You can find it here ubuntu-node-docker
Running tests in CI (gitlab)
Important stuff about testing - tests should be executed in an auto way on every git commit. That where CI (continue integration) go to light
.gitlab-ci.yml sample bellow
stages:
- install
- checks
install:
stage: install
image: registry.gitlab.com/adaptivestone/ubuntu-node:latest
script:
- node -v
- npm install
artifacts:
paths:
- node_modules/
expire_in: 2 hour
codestyle:
stage: checks
image: registry.gitlab.com/adaptivestone/ubuntu-node:latest
needs:
- install
dependencies:
- install
allow_failure: true
script:
- npm run codestyle
tests:
stage: checks
image: registry.gitlab.com/adaptivestone/ubuntu-node:latest
needs:
- install
dependencies:
- install
script:
- npm run test
Http endpoint testing
Framework provides special function global.server.testingGetUrl to detect testing url
const url = global.server.testingGetUrl("/auth");
Full example
describe("module", () => {
describe("functon", () => {
it("test", async () => {
expect.assertions(1);
const { status } = await fetch(
global.server.testingGetUrl("/some/endpoint"),
{
method: "POST",
headers: {
"Content-type": "application/json",
Authorization: global.User.token.token,
},
body: JSON.stringify({
// request object
oneData: 1,
secondDate: 2,
}),
}
).catch(() => {});
expect(status).toBe(400);
});
});
});
Mock
In most cases your code depends on external services, but you still need to perform testing. Calling external service for each test can be expensive and that is not necessary. For this problem jset provides moch options. That when you instead of calling real sdk of service will call a fake function that provide result without api calls
https://vitest.dev/api/vi.html#vi-mock
Mocking function
https://vitest.dev/api/vi.html#mocking-functions-and-objects
You able to redefine import for you own import
vi.doMock("../file.js", () => ({
fileFunction: async () => ({
isSuccess: true,
}),
}));
Redefine one method in file
import S3 from "../S3.js";
vi.spyOn(S3, "validateCreds").mockImplementation(() => true);
there are much more mocking options. Please reffer to Vitest documentation about other one