I'm trying to load test a Node.js Socket.IO server using Artillery. My server expects an authentication token as a query parameter during the handshake. I'm using Artillery's socketio.beforeConnect hook to generate this token and assign it to context.vars.token, and then attempting to use {{token}} in the socketio.query block in my YAML config.
The Problem:
Despite setupWebSocketConnection successfully generating and assigning a token to context.vars.token (verified by console.log within the processor), the token query parameter sent to the Socket.IO server is consistently undefined. This leads to "jwt malformed" errors on my server because it receives token=undefined.
The log statements in my Artillery scenario also show:
Token being sent (before connect): undefined
Token being sent (after connect attempt): undefined
Expected Behavior
The {{token}} placeholder in the socketio.query section of my Artillery configuration should interpolate the value of context.vars.token that was set by the beforeConnect hook, sending a valid JWT in the query string.
Error Messages from Server:
query: [Object: null prototype] {
token: 'undefined', // <-- This is the core issue
platformType: 'android',
acceptLanguage: 'en',
contentType: 'application/json',
EIO: '4',
transport: 'polling',
t: 't0odf7d9'
}
Found token in query parameters
Attempting to verify token for socket connection
Socket authentication error details: JsonWebTokenError: jwt malformed
at module.exports [as verify] (E:\work\zeXmeet-Phase2-NodeJs\homepage-service\node_modules\jsonwebtoken\verify.js:70:17)
// ... rest of stack trace
Artillery Configuration (getAllPosts.yml):
config:
target: "http://localhost:3000"
engine: "socketio"
socketio:
beforeConnect: "setupWebSocketConnection"
query:
token: "{{token}}" # PROBLEM: This is 'undefined' on the server side
platformType: "android"
acceptLanguage: "en"
contentType: "application/json"
processor: "../../utils/websocket-utils/getAllPosts.processors.js"
phases:
- name: "WebSocket Connection Phase"
duration: 2
arrivalRate: 1
scenarios:
- name: "Homepage Feed WebSocket Test"
flow:
- log: "Token being sent (before connect): {{ token }}"
- connect: {}
- log: "Token being sent (after connect attempt): {{ token }}"
- function: "requestHomepageFeed"
- think: 2
- function: "cleanupConnection"
- disconnect: {}
Processor File (getAllPosts.processors.js):
const { generateTokens } = require("../generateTokens.js");
module.exports = {
setupWebSocketConnection: async function (context, events) {
console.log("🧪 setupWebSocketConnection STARTED (beforeConnect hook)");
try {
const tokens = await generateTokens();
const user = tokens[Math.floor(Math.random() * tokens.length)];
context.vars.token = user.token;
context.vars.userId = user.userId;
console.log("✅ Token and User ID assigned:");
console.log("token:", context.vars.token);
console.log("userId:", context.vars.userId);
return true;
} catch (error) {
console.error("❌ setupWebSocketConnection failed:", error);
throw new Error("Failed to set up WebSocket connection: " + error.message);
}
},
onConnect: function (socket, context, done) {
console.log("✅ Socket.IO connection established for:", context.vars.userId || "unknown user");
context.socket = socket;
return done();
},
requestHomepageFeed: async function (context, events) {
// ...
},
onSocketMessage: function (message, context, events, done) {
// ...
},
cleanupConnection: function (context, events) {
// ...
},
};
What I’ve Tried:
- Using both
auth.tokenandquery.tokenonconnect - Mutating
context.socketio.queryorcontext.socketio.authin the hook - Calling
done()in the processor vs returning a Promise - Forcing
transports: ["websocket"]
Nothing makes the token ever appear in the outgoing handshake.