-
Notifications
You must be signed in to change notification settings - Fork 150
Testing
-
Always store
Driver
andSession
instances asdescribe
block level variables to ensure they are accessible throughout the test file -
Always use the
Neo4j
helper class to construct driver instances and create database sessions - Always query the database (either directly or via GraphQL) using bookmarks to ensure safety when querying against a causal cluster
- Use
toIncludeSameMembers
when asserting the values of arrays - this will check for array members and length, but ignore order
An instance of the Neo4j driver should be constructed per test file in the beforeAll
hook, and closed in the afterAll
hook.
We have a helper class Neo4j
located in packages/graphql/tests/integration/neo4j.ts
to assist in driver construction.
⚠️ Neo4j.getDriver()
must be used for driver construction.
A template test file might look as follows:
import type { Driver } from "neo4j-driver";
import Neo4j from "./neo4j";
describe("This is a test file", () => {
let driver: Driver;
beforeAll(async () => {
neo4j = new Neo4j();
driver = await neo4j.getDriver();
});
afterAll(async () => {
await driver.close();
});
});
Integration tests should be written in a way where database sessions are opened in either the beforeEach
or beforeAll
hook, and closed in the corresponding afterEach
or afterAll
hook.
⚠️ Neo4j.getSession()
must be used for session creation to ensure that the test database is targeted.
This should generally be preferred to ensure that test scope is fully encapsulated within a single database session. It is applicable when no test data is needed, or when test data is being created on a per-test basis.
An example test file might look as follows:
import type { Driver, Session } from "neo4j-driver";
import Neo4j from "./neo4j";
describe("This is a test file", () => {
let neo4j: Neo4j;
let driver: Driver;
let session: Session;
beforeAll(async () => {
neo4j = new Neo4j();
driver = await neo4j.getDriver();
});
beforeEach(async () => {
session = await neo4j.getSession();
});
afterAll(async () => {
await session.close();
});
afterAll(async () => {
await driver.close();
});
});
This should only really be preferred if test data is being created for use throughout an entire test file.
An example might look like this:
import type { Driver, Session } from "neo4j-driver";
import Neo4j from "./neo4j";
describe("This is a test file", () => {
let neo4j: Neo4j;
let driver: Driver;
let session: Session;
beforeAll(async () => {
neo4j = new Neo4j();
driver = await neo4j.getDriver();
session = await neo4j.getSession();
});
afterAll(async () => {
await session.close();
await driver.close();
});
});
The order of arrays returned from queries against the Neo4j GraphQL Library are rarely guaranteed unless specified, so using toBe()
or toEqual()
to check their values will result in test flakiness.
To address this, we have installed jest-extended
as a dependency which includes the toIncludeSameMembers()
matcher, which checks for array values and length, but ignores order.
For example:
const array = [1, 2, 3]; // assume that we don't know the order here
expect(array).toIncludeSameMembers([3, 2, 1]);
This also works for nested items, for instance:
const o = {
nestedArray = [1, 2, 3], // assume that we don't know the order here
};
expect(o).toEqual({
nestedArray: expect.toIncludeSameMembers([3, 2, 1]),
});
This should be our de facto standard for asserting the values of arrays unless we're 100% sure of the order.
Causal clustering is how Neo4j runs in a clustered environment, which includes Aura Professional instances. This introduces the risk that if we insert test data and then query for it, it may not be present on the cluster members that a created session gets connected to. To address this, we must utilise the concept of database bookmarks to let the driver know where our data is.