mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-26 22:25:40 +00:00
feat: enhance hook control flow and response handling
This commit is contained in:
@@ -38,6 +38,71 @@ const getCACertHostRegex = (domain) => {
|
||||
return '^https:\\/\\/' + domain.replaceAll('.', '\\.').replaceAll('*', '.*');
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply runner control signals from a script/hook result
|
||||
* @param {object} result - Result from script/hook execution
|
||||
* @param {object} state - Current runner state (modified in place)
|
||||
* @param {string|undefined} state.nextRequestName - Current next request name
|
||||
* @param {boolean} state.shouldStopRunnerExecution - Current stop flag
|
||||
* @returns {object} Updated state with nextRequestName and shouldStopRunnerExecution
|
||||
*/
|
||||
const applyRunnerControlFromResult = (result, state) => {
|
||||
if (result?.nextRequestName !== undefined) {
|
||||
state.nextRequestName = result.nextRequestName;
|
||||
}
|
||||
if (result?.stopExecution) {
|
||||
state.shouldStopRunnerExecution = true;
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a standardized skipped response object
|
||||
* @param {object} options - Options for creating the response
|
||||
* @param {string} options.filename - The relative file pathname
|
||||
* @param {object} options.request - The request object
|
||||
* @param {string} options.statusText - The reason for skipping
|
||||
* @param {array} [options.preRequestTestResults] - Pre-request test results
|
||||
* @param {array} [options.postResponseTestResults] - Post-response test results
|
||||
* @param {string} [options.nextRequestName] - Next request name if set
|
||||
* @param {boolean} [options.shouldStopRunnerExecution] - Stop execution flag
|
||||
* @returns {object} Standardized skipped response object
|
||||
*/
|
||||
const createSkippedResponse = ({
|
||||
filename,
|
||||
request,
|
||||
statusText,
|
||||
preRequestTestResults = [],
|
||||
postResponseTestResults = [],
|
||||
nextRequestName,
|
||||
shouldStopRunnerExecution = false
|
||||
}) => {
|
||||
return {
|
||||
test: { filename },
|
||||
request: {
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
headers: request.headers,
|
||||
data: request.data
|
||||
},
|
||||
response: {
|
||||
status: 'skipped',
|
||||
statusText,
|
||||
data: null,
|
||||
responseTime: 0
|
||||
},
|
||||
error: null,
|
||||
status: 'skipped',
|
||||
skipped: true,
|
||||
assertionResults: [],
|
||||
testResults: [],
|
||||
preRequestTestResults,
|
||||
postResponseTestResults,
|
||||
nextRequestName,
|
||||
shouldStopRunnerExecution
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Extract prompt variables from a request
|
||||
* Tries to respect the hierarchy of the variables and avoid unnecessary prompts as much as possible
|
||||
@@ -136,31 +201,12 @@ const runSingleRequest = async function (
|
||||
if (promptVars.length > 0) {
|
||||
const errorMsg = `Prompt variables detected in request. CLI execution is not supported for requests with prompt variables. \nPrompts: ${promptVars.join(', ')}`;
|
||||
console.log(chalk.yellow(stripExtension(relativeItemPathname) + ' Skipped:') + chalk.dim(` (${errorMsg})`));
|
||||
return {
|
||||
test: {
|
||||
filename: relativeItemPathname
|
||||
},
|
||||
request: {
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
headers: request.headers,
|
||||
data: request.data
|
||||
},
|
||||
response: {
|
||||
status: 'skipped',
|
||||
statusText: errorMsg,
|
||||
data: null,
|
||||
responseTime: 0
|
||||
},
|
||||
error: null,
|
||||
status: 'skipped',
|
||||
skipped: true,
|
||||
assertionResults: [],
|
||||
testResults: [],
|
||||
preRequestTestResults: [],
|
||||
postResponseTestResults: [],
|
||||
return createSkippedResponse({
|
||||
filename: relativeItemPathname,
|
||||
request,
|
||||
statusText: errorMsg,
|
||||
shouldStopRunnerExecution
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
request.__bruno__executionMode = 'cli';
|
||||
@@ -194,12 +240,28 @@ const runSingleRequest = async function (
|
||||
// Hooks are called in registration order: collection -> folder(s) -> request
|
||||
const beforeRequestEventData = { request, req: new BrunoRequest(request), collection };
|
||||
|
||||
await executeAllHooksConsolidated(
|
||||
const beforeRequestHooksResult = await executeAllHooksConsolidated(
|
||||
{ collectionHooks, folderHooks, requestHooks },
|
||||
HOOK_EVENTS.HTTP_BEFORE_REQUEST,
|
||||
beforeRequestEventData
|
||||
);
|
||||
|
||||
// Check runner control from hooks
|
||||
const runnerState = { nextRequestName, shouldStopRunnerExecution };
|
||||
applyRunnerControlFromResult(beforeRequestHooksResult, runnerState);
|
||||
nextRequestName = runnerState.nextRequestName;
|
||||
shouldStopRunnerExecution = runnerState.shouldStopRunnerExecution;
|
||||
|
||||
if (beforeRequestHooksResult?.skipRequest) {
|
||||
return createSkippedResponse({
|
||||
filename: relativeItemPathname,
|
||||
request,
|
||||
statusText: 'request skipped via beforeRequest hook',
|
||||
nextRequestName,
|
||||
shouldStopRunnerExecution
|
||||
});
|
||||
}
|
||||
|
||||
// run pre request script
|
||||
const requestScriptFile = get(request, 'script.req');
|
||||
if (requestScriptFile?.length) {
|
||||
@@ -216,40 +278,18 @@ const runSingleRequest = async function (
|
||||
runSingleRequestByPathname,
|
||||
collectionName
|
||||
);
|
||||
if (result?.nextRequestName !== undefined) {
|
||||
nextRequestName = result.nextRequestName;
|
||||
}
|
||||
|
||||
if (result?.stopExecution) {
|
||||
shouldStopRunnerExecution = true;
|
||||
}
|
||||
applyRunnerControlFromResult(result, runnerState);
|
||||
nextRequestName = runnerState.nextRequestName;
|
||||
shouldStopRunnerExecution = runnerState.shouldStopRunnerExecution;
|
||||
|
||||
if (result?.skipRequest) {
|
||||
return {
|
||||
test: {
|
||||
filename: relativeItemPathname
|
||||
},
|
||||
request: {
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
headers: request.headers,
|
||||
data: request.data
|
||||
},
|
||||
response: {
|
||||
status: 'skipped',
|
||||
statusText: 'request skipped via pre-request script',
|
||||
data: null,
|
||||
responseTime: 0
|
||||
},
|
||||
error: null,
|
||||
status: 'skipped',
|
||||
skipped: true,
|
||||
assertionResults: [],
|
||||
testResults: [],
|
||||
return createSkippedResponse({
|
||||
filename: relativeItemPathname,
|
||||
request,
|
||||
statusText: 'request skipped via pre-request script',
|
||||
preRequestTestResults: result?.results || [],
|
||||
postResponseTestResults: [],
|
||||
shouldStopRunnerExecution
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
preRequestTestResults = result?.results || [];
|
||||
@@ -685,12 +725,17 @@ const runSingleRequest = async function (
|
||||
collection
|
||||
};
|
||||
|
||||
await executeAllHooksConsolidated(
|
||||
const afterResponseHooksResult = await executeAllHooksConsolidated(
|
||||
{ collectionHooks, folderHooks, requestHooks },
|
||||
HOOK_EVENTS.HTTP_AFTER_RESPONSE,
|
||||
afterResponseEventData
|
||||
);
|
||||
|
||||
// Check runner control from hooks
|
||||
applyRunnerControlFromResult(afterResponseHooksResult, runnerState);
|
||||
nextRequestName = runnerState.nextRequestName;
|
||||
shouldStopRunnerExecution = runnerState.shouldStopRunnerExecution;
|
||||
|
||||
// run post-response vars
|
||||
const postResponseVars = get(item, 'request.vars.res');
|
||||
if (postResponseVars?.length) {
|
||||
@@ -724,13 +769,9 @@ const runSingleRequest = async function (
|
||||
runSingleRequestByPathname,
|
||||
collectionName
|
||||
);
|
||||
if (result?.nextRequestName !== undefined) {
|
||||
nextRequestName = result.nextRequestName;
|
||||
}
|
||||
|
||||
if (result?.stopExecution) {
|
||||
shouldStopRunnerExecution = true;
|
||||
}
|
||||
applyRunnerControlFromResult(result, runnerState);
|
||||
nextRequestName = runnerState.nextRequestName;
|
||||
shouldStopRunnerExecution = runnerState.shouldStopRunnerExecution;
|
||||
|
||||
postResponseTestResults = result?.results || [];
|
||||
logResults(postResponseTestResults, 'Post-Response Tests');
|
||||
@@ -774,13 +815,9 @@ const runSingleRequest = async function (
|
||||
);
|
||||
testResults = get(result, 'results', []);
|
||||
|
||||
if (result?.nextRequestName !== undefined) {
|
||||
nextRequestName = result.nextRequestName;
|
||||
}
|
||||
|
||||
if (result?.stopExecution) {
|
||||
shouldStopRunnerExecution = true;
|
||||
}
|
||||
applyRunnerControlFromResult(result, runnerState);
|
||||
nextRequestName = runnerState.nextRequestName;
|
||||
shouldStopRunnerExecution = runnerState.shouldStopRunnerExecution;
|
||||
|
||||
logResults(testResults, 'Tests');
|
||||
} catch (error) {
|
||||
|
||||
@@ -1478,13 +1478,37 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
// Call beforeRequest hooks using consolidated approach when multiple levels have hooks
|
||||
const beforeRequestEventData = { request, req: new BrunoRequest(request), collection, collectionUid };
|
||||
|
||||
await executeAllHooksConsolidated(
|
||||
const beforeRequestHooksResult = await executeAllHooksConsolidated(
|
||||
{ collectionHooks, folderHooks, requestHooks },
|
||||
HOOK_EVENTS.HTTP_BEFORE_REQUEST,
|
||||
beforeRequestEventData,
|
||||
hookOptions
|
||||
);
|
||||
|
||||
// Check runner control from hooks
|
||||
if (beforeRequestHooksResult?.nextRequestName !== undefined) {
|
||||
nextRequestName = beforeRequestHooksResult.nextRequestName;
|
||||
}
|
||||
if (beforeRequestHooksResult?.stopExecution) {
|
||||
stopRunnerExecution = true;
|
||||
}
|
||||
if (beforeRequestHooksResult?.skipRequest) {
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: 'runner-request-skipped',
|
||||
error: 'Request has been skipped from beforeRequest hook',
|
||||
responseReceived: {
|
||||
status: 'skipped',
|
||||
statusText: 'request skipped via beforeRequest hook',
|
||||
data: null,
|
||||
responseTime: 0,
|
||||
headers: null
|
||||
},
|
||||
...eventData
|
||||
});
|
||||
currentRequestIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
let preRequestScriptResult;
|
||||
let preRequestError = null;
|
||||
try {
|
||||
@@ -1716,13 +1740,21 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid
|
||||
};
|
||||
|
||||
await executeAllHooksConsolidated(
|
||||
const afterResponseHooksResult = await executeAllHooksConsolidated(
|
||||
{ collectionHooks, folderHooks, requestHooks },
|
||||
HOOK_EVENTS.HTTP_AFTER_RESPONSE,
|
||||
afterResponseEventData,
|
||||
hookOptions
|
||||
);
|
||||
|
||||
// Check runner control from hooks
|
||||
if (afterResponseHooksResult?.nextRequestName !== undefined) {
|
||||
nextRequestName = afterResponseHooksResult.nextRequestName;
|
||||
}
|
||||
if (afterResponseHooksResult?.stopExecution) {
|
||||
stopRunnerExecution = true;
|
||||
}
|
||||
|
||||
let postResponseScriptResult;
|
||||
let postResponseError = null;
|
||||
try {
|
||||
|
||||
@@ -157,6 +157,15 @@ const executeConsolidatedHooks = async (extractedHooks, hookEvent, eventData, op
|
||||
|
||||
if (result?.hookManager) {
|
||||
await result.hookManager.call(hookEvent, eventData);
|
||||
|
||||
// IMPORTANT: Re-capture runner control values AFTER hooks have been called
|
||||
// The hooks may have called bru.runner.setNextRequest(), bru.runner.skipRequest(), etc.
|
||||
// These values are stored on the bru instance which is returned in result.__bru
|
||||
if (result.__bru) {
|
||||
result.nextRequestName = result.__bru.nextRequest;
|
||||
result.skipRequest = result.__bru.skipRequest;
|
||||
result.stopExecution = result.__bru.stopExecution;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -153,7 +153,11 @@ class HooksRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
persistentEnvVariables: bru.persistentEnvVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables)
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution,
|
||||
__bru: bru
|
||||
};
|
||||
}
|
||||
|
||||
@@ -176,7 +180,11 @@ class HooksRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
persistentEnvVariables: bru.persistentEnvVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables)
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution,
|
||||
__bru: bru
|
||||
};
|
||||
}
|
||||
|
||||
@@ -199,7 +207,11 @@ class HooksRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
persistentEnvVariables: bru.persistentEnvVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables)
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution,
|
||||
__bru: bru
|
||||
};
|
||||
}
|
||||
|
||||
@@ -257,7 +269,11 @@ class HooksRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
persistentEnvVariables: bru.persistentEnvVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables)
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution,
|
||||
__bru: bru
|
||||
};
|
||||
}
|
||||
|
||||
@@ -328,7 +344,11 @@ class HooksRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
persistentEnvVariables: bru.persistentEnvVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables)
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution,
|
||||
__bru: bru
|
||||
};
|
||||
}
|
||||
|
||||
@@ -350,7 +370,12 @@ class HooksRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
persistentEnvVariables: bru.persistentEnvVariables,
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables)
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution,
|
||||
// Include bru reference so callers can read updated values after hook execution
|
||||
__bru: bru
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
meta {
|
||||
name: legacy-set-next-request-first
|
||||
type: http
|
||||
seq: 300
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] Testing legacy bru.setNextRequest() API');
|
||||
|
||||
// Clear any previous markers
|
||||
bru.deleteVar('legacy-set-next-skipped-ran');
|
||||
|
||||
// Mark that this request started
|
||||
bru.setVar('legacy-set-next-first-ran', 'true');
|
||||
|
||||
console.log('[beforeRequest] Legacy first request starting');
|
||||
});
|
||||
|
||||
bru.hooks.http.onAfterResponse(({ res }) => {
|
||||
console.log('[afterResponse] Using legacy bru.setNextRequest() to jump to target');
|
||||
|
||||
// Use the legacy API to jump to the target request
|
||||
bru.setNextRequest('legacy-set-next-request-target');
|
||||
|
||||
console.log('[afterResponse] Called bru.setNextRequest("legacy-set-next-request-target")');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("first request should execute successfully", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
|
||||
test("first request marker should be set", function() {
|
||||
const ran = bru.getVar('legacy-set-next-first-ran');
|
||||
expect(ran).to.equal('true');
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
meta {
|
||||
name: legacy-set-next-request-skipped
|
||||
type: http
|
||||
seq: 301
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] ERROR: This request should have been skipped by legacy setNextRequest!');
|
||||
|
||||
// If this request runs, set an error marker
|
||||
bru.setVar('legacy-set-next-skipped-ran', 'true');
|
||||
|
||||
console.log('[beforeRequest] Setting error marker - legacy setNextRequest jump failed');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("this request should be skipped due to legacy setNextRequest jump", function() {
|
||||
// If we get here, the request ran when it should have been skipped
|
||||
const ran = bru.getVar('legacy-set-next-skipped-ran');
|
||||
expect(ran).to.be.undefined;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
meta {
|
||||
name: legacy-set-next-request-target
|
||||
type: http
|
||||
seq: 302
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] Target request reached via legacy bru.setNextRequest() jump');
|
||||
|
||||
// Mark that target was reached
|
||||
bru.setVar('legacy-set-next-target-reached', 'true');
|
||||
|
||||
console.log('[beforeRequest] Legacy target request starting');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("target request should execute successfully", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
|
||||
test("target should have been reached via legacy API", function() {
|
||||
const reached = bru.getVar('legacy-set-next-target-reached');
|
||||
expect(reached).to.equal('true');
|
||||
});
|
||||
|
||||
test("first request should have run before jump", function() {
|
||||
const firstRan = bru.getVar('legacy-set-next-first-ran');
|
||||
expect(firstRan).to.equal('true');
|
||||
});
|
||||
|
||||
test("skipped request should NOT have run", function() {
|
||||
const skippedRan = bru.getVar('legacy-set-next-skipped-ran');
|
||||
expect(skippedRan).to.be.undefined;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
meta {
|
||||
name: set-next-null-should-not-run
|
||||
type: http
|
||||
seq: 901
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] ERROR: This request should NOT have run after setNextRequest(null)!');
|
||||
|
||||
// If this request runs, set an error marker
|
||||
bru.setVar('set-next-null-error', 'Request ran when setNextRequest(null) should have stopped the runner');
|
||||
|
||||
console.log('[beforeRequest] Setting error marker - setNextRequest(null) failed');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("this request should not run - setNextRequest(null) should have stopped the runner", function() {
|
||||
// If we get here, the request ran when it should have been stopped
|
||||
const error = bru.getVar('set-next-null-error');
|
||||
expect(error).to.be.undefined;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
meta {
|
||||
name: set-next-null-trigger
|
||||
type: http
|
||||
seq: 900
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] Testing bru.runner.setNextRequest(null) API');
|
||||
|
||||
// Clear any previous error markers
|
||||
bru.deleteVar('set-next-null-error');
|
||||
|
||||
// Mark that this request started
|
||||
bru.setVar('set-next-null-trigger-ran', 'true');
|
||||
|
||||
console.log('[beforeRequest] setNextRequest(null) trigger starting');
|
||||
});
|
||||
|
||||
bru.hooks.http.onAfterResponse(({ res }) => {
|
||||
console.log('[afterResponse] Setting next request to null to stop runner gracefully');
|
||||
|
||||
// Setting nextRequest to null should stop the runner gracefully
|
||||
bru.runner.setNextRequest(null);
|
||||
|
||||
console.log('[afterResponse] Called bru.runner.setNextRequest(null) - runner should stop');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("trigger request should execute successfully", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
|
||||
test("trigger marker should be set", function() {
|
||||
const ran = bru.getVar('set-next-null-trigger-ran');
|
||||
expect(ran).to.equal('true');
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
meta {
|
||||
name: set-next-request-first
|
||||
type: http
|
||||
seq: 200
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] Testing bru.runner.setNextRequest() API');
|
||||
|
||||
// Clear any previous markers
|
||||
bru.deleteVar('set-next-request-skipped-ran');
|
||||
|
||||
// Mark that this request started
|
||||
bru.setVar('set-next-request-first-ran', 'true');
|
||||
|
||||
console.log('[beforeRequest] First request starting');
|
||||
});
|
||||
|
||||
bru.hooks.http.onAfterResponse(({ res }) => {
|
||||
console.log('[afterResponse] Setting next request to jump to target');
|
||||
|
||||
// Jump to the target request, skipping the intermediate request
|
||||
bru.runner.setNextRequest('set-next-request-target');
|
||||
|
||||
console.log('[afterResponse] Called bru.runner.setNextRequest("set-next-request-target")');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("first request should execute successfully", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
|
||||
test("first request marker should be set", function() {
|
||||
const ran = bru.getVar('set-next-request-first-ran');
|
||||
expect(ran).to.equal('true');
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
meta {
|
||||
name: set-next-request-skipped
|
||||
type: http
|
||||
seq: 201
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] ERROR: This request should have been skipped by setNextRequest!');
|
||||
|
||||
// If this request runs, set an error marker
|
||||
bru.setVar('set-next-request-skipped-ran', 'true');
|
||||
|
||||
console.log('[beforeRequest] Setting error marker - setNextRequest jump failed');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("this request should be skipped due to setNextRequest jump", function() {
|
||||
// If we get here, the request ran when it should have been skipped
|
||||
const ran = bru.getVar('set-next-request-skipped-ran');
|
||||
expect(ran).to.be.undefined;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
meta {
|
||||
name: set-next-request-target
|
||||
type: http
|
||||
seq: 202
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] Target request reached via setNextRequest jump');
|
||||
|
||||
// Mark that target was reached
|
||||
bru.setVar('set-next-request-target-reached', 'true');
|
||||
|
||||
console.log('[beforeRequest] Target request starting');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("target request should execute successfully", function() {
|
||||
expect(res.getStatus()).to.equal(200);
|
||||
});
|
||||
|
||||
test("target should have been reached", function() {
|
||||
const reached = bru.getVar('set-next-request-target-reached');
|
||||
expect(reached).to.equal('true');
|
||||
});
|
||||
|
||||
test("first request should have run before jump", function() {
|
||||
const firstRan = bru.getVar('set-next-request-first-ran');
|
||||
expect(firstRan).to.equal('true');
|
||||
});
|
||||
|
||||
test("skipped request should NOT have run", function() {
|
||||
const skippedRan = bru.getVar('set-next-request-skipped-ran');
|
||||
expect(skippedRan).to.be.undefined;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
meta {
|
||||
name: skip-request-in-before-hook
|
||||
type: http
|
||||
seq: 100
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
script:hooks {
|
||||
bru.hooks.http.onBeforeRequest(({ req }) => {
|
||||
console.log('[beforeRequest] Testing bru.runner.skipRequest() API');
|
||||
|
||||
// Set a marker to confirm the hook executed
|
||||
bru.setVar('skip-request-hook-executed', 'true');
|
||||
|
||||
// Skip this request - the main request should not execute
|
||||
bru.runner.skipRequest();
|
||||
|
||||
console.log('[beforeRequest] Called bru.runner.skipRequest() - request should be skipped');
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("hook should have executed before skip", function() {
|
||||
const hookExecuted = bru.getVar('skip-request-hook-executed');
|
||||
expect(hookExecuted).to.equal('true');
|
||||
});
|
||||
}
|
||||
@@ -10,10 +10,10 @@ test.describe.serial('Hooks feature', () => {
|
||||
await runCollection(page, 'hooks-comprehensive-tests');
|
||||
|
||||
await validateRunnerResults(page, {
|
||||
totalRequests: 45,
|
||||
passed: 45,
|
||||
totalRequests: 51,
|
||||
passed: 50,
|
||||
failed: 0,
|
||||
skipped: 0
|
||||
skipped: 1
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -26,10 +26,10 @@ test.describe.serial('Hooks feature', () => {
|
||||
await runCollection(page, 'hooks-comprehensive-tests');
|
||||
|
||||
await validateRunnerResults(page, {
|
||||
totalRequests: 45,
|
||||
passed: 45,
|
||||
totalRequests: 51,
|
||||
passed: 50,
|
||||
failed: 0,
|
||||
skipped: 0
|
||||
skipped: 1
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user