Playwright testing with JanusGraph
This article covers how to connect to multiple JanusGraph instances in Playwright using TypeScript, manage connections securely with environment variables, and utilize custom fixtures for setup and teardown.
Prerequisites
Node.js and TypeScript installed.
Playwright and Gremlin client libraries installed.
Access to JanusGraph instances with a JKS truststore certificate (converted to PEM format).
Environment variables setup (use
.env
files if needed).
1. Install Required Dependencies
Install Playwright, Gremlin client, and TypeScript typings:
npm install playwright gremlin @types/gremlin
2. Set Up Environment Variables
Define sensitive data like the username and password in a .env
file in the project root. You may want to use different credentials for each JanusGraph instance if needed.
Create a .env
file:
JANUSGRAPH1_USERNAME=yourUsername1
JANUSGRAPH1_PASSWORD=yourPassword1
JANUSGRAPH2_USERNAME=yourUsername2
JANUSGRAPH2_PASSWORD=yourPassword2
Load these environment variables into your project with dotenv:
npm install dotenv
Add the following at the top of your test file to load environment variables:
import * as dotenv from 'dotenv';
dotenv.config();
3. Converting JKS to PEM Format
Follow these steps to convert your JKS file to a PEM certificate, required by Node.js:
Use
keytool
to export from JKS to DER:keytool -exportcert -alias your-alias -keystore your-truststore.jks -file cert.der
Convert the
.der
file to PEM using OpenSSL:openssl x509 -inform der -in cert.der -out cert.pem
4. Configure Playwright with Multiple Connections
playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'JanusGraph Tests - Instance 1',
testDir: './tests',
workers: 1,
},
{
name: 'JanusGraph Tests - Instance 2',
testDir: './tests',
workers: 1,
},
],
});
tests/janusgraph.spec.ts
The following setup defines a custom fixture to connect to multiple JanusGraph instances using different credentials, with credentials loaded from environment variables.
import { test as base, expect } from '@playwright/test';
import gremlin from 'gremlin';
import * as fs from 'fs';
import * as dotenv from 'dotenv';
dotenv.config(); // Load environment variables
// Define a custom type for multiple connections
type JanusConnections = {
g1: gremlin.process.GraphTraversalSource;
g2: gremlin.process.GraphTraversalSource;
};
// Extend Playwright's base test with the fixture
export const test = base.extend<{ janusConnections: JanusConnections }>({
janusConnections: async ({}, use) => {
const { DriverRemoteConnection } = gremlin.driver;
const { Graph } = gremlin.structure;
// Load PEM certificate for both connections
const caCert = fs.readFileSync('path/to/cert.pem');
// Establish a connection for JanusGraph instance 1
const conn1 = new DriverRemoteConnection(
'wss://janusgraph-instance-1-endpoint',
{
mimeType: 'application/json',
headers: {
Authorization:
'Basic ' +
Buffer.from(
`${process.env.JANUSGRAPH1_USERNAME}:${process.env.JANUSGRAPH1_PASSWORD}`
).toString('base64'),
},
ca: [caCert],
}
);
// Establish a connection for JanusGraph instance 2
const conn2 = new DriverRemoteConnection(
'wss://janusgraph-instance-2-endpoint',
{
mimeType: 'application/json',
headers: {
Authorization:
'Basic ' +
Buffer.from(
`${process.env.JANUSGRAPH2_USERNAME}:${process.env.JANUSGRAPH2_PASSWORD}`
).toString('base64'),
},
ca: [caCert],
}
);
// Create graph traversal sources
const graph1 = new Graph();
const g1 = graph1.traversal().withRemote(conn1);
const graph2 = new Graph();
const g2 = graph2.traversal().withRemote(conn2);
// Provide both connections to tests
await use({ g1, g2 });
// Teardown: Close both connections after tests
await conn1.close();
await conn2.close();
},
});
// Example test using both JanusGraph connections
test('should fetch vertices from both JanusGraph instances', async ({
janusConnections,
}) => {
const { g1, g2 } = janusConnections;
// Perform read-only query on instance 1
const vertices1 = await g1.V().toList();
expect(vertices1.length).toBeGreaterThan(0);
// Perform read-only query on instance 2
const vertices2 = await g2.V().toList();
expect(vertices2.length).toBeGreaterThan(0);
});
Explanation
Environment Variables:
- Environment variables store sensitive credentials and are accessed using
process.env
.
- Environment variables store sensitive credentials and are accessed using
Multiple Connections:
g1
andg2
represent two different JanusGraph connections, each with unique credentials and endpoints.Separate
DriverRemoteConnection
instances handle each connection’s setup, ensuring no interference between them.
Reusable Fixture:
- The
janusConnections
fixture is shared across tests and closes connections in the teardown phase, maintaining resource efficiency.
- The
Running the Tests
To run the tests, execute:
npx playwright test
Notes
Error Handling: In production, consider adding error handling around the connection to manage network or authentication issues.
Environment Management: Consider using different
.env
files or configuration files for various environments (e.g., development, staging, production).
Subscribe to my newsletter
Read articles from Pawan Gangwani directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Pawan Gangwani
Pawan Gangwani
I’m Pawan Gangwani, a passionate Full Stack Developer with over 12 years of experience in web development. Currently serving as a Lead Software Engineer at Lowes India, I specialize in modern web applications, particularly in React and performance optimization. I’m dedicated to best practices in coding, testing, and Agile methodologies. Outside of work, I enjoy table tennis, exploring new cuisines, and spending quality time with my family.