Files
bruno/packages/bruno-js/tests/script-runtime-scripted-entries.spec.js

210 lines
8.2 KiB
JavaScript

// Mocked so bru.sendRequest doesn't hit the network.
jest.mock('@usebruno/requests', () => {
const realCookies = jest.requireActual('@usebruno/requests').cookies;
return {
cookies: realCookies,
scripting: {
createSendRequest: jest.fn((_config, options) => {
return async (requestConfig) => {
const normalized = typeof requestConfig === 'string' ? { url: requestConfig } : requestConfig;
options?.onComplete?.({
request: {
method: (normalized.method || 'GET').toUpperCase(),
url: normalized.url,
headers: normalized.headers || {},
data: normalized.data
},
response: {
statusCode: 200,
statusText: 'OK',
headers: {},
data: 'mocked',
dataBuffer: Buffer.from('mocked').toString('base64'),
size: 6,
duration: 3
},
error: null,
startedAt: 1,
completedAt: 4
});
return { status: 200, data: 'mocked' };
};
})
}
};
});
const ScriptRuntime = require('../src/runtime/script-runtime');
const TestRuntime = require('../src/runtime/test-runtime');
const baseRequest = { method: 'GET', url: 'http://localhost/', headers: {}, data: undefined };
const baseResponse = { status: 200, statusText: 'OK', data: {} };
describe('ScriptRuntime — scripted entries across the three script phases', () => {
describe('pre-request (runRequestScript)', () => {
test('drains bru.sendRequest calls into result.scriptedRequestEntries', async () => {
const script = `await bru.sendRequest('https://example.com/ping');`;
const runtime = new ScriptRuntime({ runtime: 'nodevm' });
const result = await runtime.runRequestScript(
script, { ...baseRequest }, {}, {}, '.', null, process.env
);
expect(result.scriptedRequestEntries).toHaveLength(1);
expect(result.scriptedRequestEntries[0]).toEqual(
expect.objectContaining({
source: 'sendRequest',
request: expect.objectContaining({ url: 'https://example.com/ping' })
})
);
});
test('returns an empty array when the script makes no scripted requests', async () => {
const runtime = new ScriptRuntime({ runtime: 'nodevm' });
const result = await runtime.runRequestScript(
`bru.setVar('foo', 'bar');`, { ...baseRequest }, {}, {}, '.', null, process.env
);
expect(result.scriptedRequestEntries).toEqual([]);
});
test('__bruSetScope from inside the script stamps scope onto every later entry', async () => {
const script = `
__bruSetScope({ type: 'collection', sourceFile: 'collection.bru' });
await bru.sendRequest('https://example.com/a');
__bruSetScope({ type: 'request', sourceFile: 'auth/login.bru' });
await bru.sendRequest('https://example.com/b');
`;
const runtime = new ScriptRuntime({ runtime: 'nodevm' });
const result = await runtime.runRequestScript(
script, { ...baseRequest }, {}, {}, '.', null, process.env
);
expect(result.scriptedRequestEntries).toHaveLength(2);
expect(result.scriptedRequestEntries[0].scope).toEqual({ type: 'collection', sourceFile: 'collection.bru' });
expect(result.scriptedRequestEntries[1].scope).toEqual({ type: 'request', sourceFile: 'auth/login.bru' });
});
test('bru.runRequest is wired to the host function and records a runRequest entry', async () => {
// Stands in for the electron-side runRequestByItemPathname bridge.
const host = jest.fn(async (pathname, callerBru) => {
callerBru._recordScriptedRequest({
source: 'runRequest',
request: { method: 'GET', url: 'inferred/from/' + pathname, headers: {}, data: undefined },
response: { statusCode: 200, statusText: 'OK', headers: {}, data: '', dataBuffer: '', size: 0, duration: 1 },
error: null,
startedAt: 0,
completedAt: 1
});
return { status: 200 };
});
const script = `
__bruSetScope({ type: 'request', sourceFile: 'driver.bru' });
await bru.runRequest('target.bru');
`;
const runtime = new ScriptRuntime({ runtime: 'nodevm' });
const result = await runtime.runRequestScript(
script, { ...baseRequest }, {}, {}, '.', null, process.env, {}, host
);
expect(host).toHaveBeenCalledTimes(1);
// bindRunRequest must forward the caller's bru as the second arg.
expect(host.mock.calls[0][0]).toBe('target.bru');
expect(host.mock.calls[0][1]).toBeDefined();
expect(result.scriptedRequestEntries).toHaveLength(1);
expect(result.scriptedRequestEntries[0]).toEqual(
expect.objectContaining({
source: 'runRequest',
scope: { type: 'request', sourceFile: 'driver.bru' }
})
);
});
});
describe('post-response (runResponseScript)', () => {
test('drains bru.sendRequest calls into result.scriptedRequestEntries', async () => {
const script = `await bru.sendRequest('https://example.com/after');`;
const runtime = new ScriptRuntime({ runtime: 'nodevm' });
const result = await runtime.runResponseScript(
script, { ...baseRequest }, { ...baseResponse }, {}, {}, '.', null, process.env
);
expect(result.scriptedRequestEntries).toHaveLength(1);
expect(result.scriptedRequestEntries[0].source).toBe('sendRequest');
});
test('records bru.runRequest calls with the current scope', async () => {
const host = jest.fn(async (_pathname, callerBru) => {
callerBru._recordScriptedRequest({
source: 'runRequest',
request: { method: 'GET', url: 'x', headers: {}, data: undefined },
response: null,
error: null,
startedAt: 0,
completedAt: 0
});
});
const script = `
__bruSetScope({ type: 'folder', sourceFile: 'auth/folder.bru' });
await bru.runRequest('next.bru');
`;
const runtime = new ScriptRuntime({ runtime: 'nodevm' });
const result = await runtime.runResponseScript(
script, { ...baseRequest }, { ...baseResponse }, {}, {}, '.', null, process.env, {}, host
);
expect(result.scriptedRequestEntries).toHaveLength(1);
expect(result.scriptedRequestEntries[0]).toEqual(
expect.objectContaining({
source: 'runRequest',
scope: { type: 'folder', sourceFile: 'auth/folder.bru' }
})
);
});
});
describe('tests (TestRuntime.runTests)', () => {
test('drains scripted requests issued from inside test scripts', async () => {
const testsFile = `
__bruSetScope({ type: 'request', sourceFile: 'spec.bru' });
test('calls sendRequest', async () => {
await bru.sendRequest('https://example.com/from-tests');
});
`;
const runtime = new TestRuntime({ runtime: 'nodevm' });
const result = await runtime.runTests(
testsFile, { ...baseRequest }, { ...baseResponse }, {}, {}, '.', null, process.env
);
expect(result.scriptedRequestEntries).toHaveLength(1);
expect(result.scriptedRequestEntries[0]).toEqual(
expect.objectContaining({
source: 'sendRequest',
scope: { type: 'request', sourceFile: 'spec.bru' },
request: expect.objectContaining({ url: 'https://example.com/from-tests' })
})
);
});
});
describe('partial results on script error', () => {
test('pre-request: entries recorded before the throw are preserved on partialResults', async () => {
const script = `
await bru.sendRequest('https://example.com/before');
throw new Error('explode');
`;
const runtime = new ScriptRuntime({ runtime: 'nodevm' });
let captured;
try {
await runtime.runRequestScript(script, { ...baseRequest }, {}, {}, '.', null, process.env);
} catch (err) {
captured = err;
}
expect(captured).toBeDefined();
expect(captured.partialResults).toBeDefined();
expect(captured.partialResults.scriptedRequestEntries).toHaveLength(1);
expect(captured.partialResults.scriptedRequestEntries[0].source).toBe('sendRequest');
});
});
});