The Stoobly Javascript library provides convenient access to stoobly-agent API.
Node 18 or higher.
Install the package with:
npm install stoobly --save-dev
const Stoobly = require('stoobly');
Or using ES modules:
import Stoobly from 'stoobly';
Configures requests with origin https://docs.stoobly.com to specify a scenario. sessionId defaults to current time.
import Stoobly from 'stoobly';
const stoobly = new Stoobly();
const interceptor = stoobly.interceptor({
scenarioKey: '<SCENARIO-KEY>',
scenarioName: '<SCENARIO-NAME>', // If scenario name is used instead of key, it should be unique
urls: [{ pattern: new RegExp('https://docs.stoobly.com/.*') }]
});
const sessionId = interceptor.apply();
Configures requests with origin https://docs.stoobly.com to specify a scenario. After a session has started, change sessions with withSessionId().
import Stoobly from 'stoobly';
const stoobly = new Stoobly();
const interceptor = stoobly.interceptor({
scenarioKey: '<SCENARIO-KEY>',
sessionId: '<SESSION-ID>',
urls: [{ pattern: new RegExp('https://docs.stoobly.com/.*') }]
});
const sessionId = interceptor.apply();
interceptor.withSessionId('<NEW-SESSION-ID>');
Configures requests https://docs.stoobly.com/use-cases and https://docs.stoobly.com/getting-started to specify a scenario.
import Stoobly from 'stoobly';
const stoobly = new Stoobly();
const interceptor = stoobly.interceptor({
scenarioKey: '<SCENARIO-KEY>',
urls: [
{ pattern: 'https://docs.stoobly.com/use-cases' },
{ pattern: 'https://docs.stoobly.com/getting-started' }
]
});
interceptor.apply();
Record requests with specific policy, order, and strategy options:
import Stoobly from 'stoobly';
import {
RecordPolicy,
RecordOrder,
RecordStrategy,
// Additional constants available:
//
// InterceptMode, // mock, record, replay, test
// MockPolicy, // All, Found
// ReplayPolicy, // All
// TestPolicy, // All, Found
// TestStrategy, // Diff, Fuzzy, Custom
// FirewallAction, // Exclude, Include
// RequestParameter // Header, BodyParam, QueryParam
} from 'stoobly/constants';
const stoobly = new Stoobly();
const interceptor = stoobly.interceptor({
urls: [{ pattern: 'https://docs.stoobly.com/use-cases' }],
record: {
policy: RecordPolicy.All,
order: RecordOrder.Overwrite, // Defaults to RecordOrder.Append
strategy: RecordStrategy.Full,
}
});
interceptor.applyRecord();
Stop recording requests:
interceptor.clearRecord();
Stop all interception (recording, mocking, etc.):
interceptor.clear();
cypressInterceptor()playwrightInterceptor()interceptor(), which patches fetch and XMLHttpRequest directlyimport Stoobly from 'stoobly';
import { RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';
const stoobly = new Stoobly();
const stooblyInterceptor = stoobly.cypressInterceptor({
record: {
policy: RecordPolicy.All,
order: RecordOrder.Overwrite, // Defaults to RecordOrder.Append
strategy: RecordStrategy.Full,
},
scenarioKey: '<SCENARIO-KEY>',
urls: [{ pattern: '<URLS>' }],
});
describe('Scenario', () => {
beforeEach(() => {
// WARNING: if a synchronous request is used, this will cause Cypress to hang. See: https://github.com/cypress-io/cypress/issues/29566
// Example of a synchronous request: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Synchronous_and_Asynchronous_Requests#synchronous_request
stooblyInterceptor.apply();
// Use the following instead to record requests
// stooblyInterceptor.applyRecord();
});
});
Key Points:
describe blockinterceptor.apply() must be called in beforeEach because it uses cy.intercept. cy.intercept gets reset before every test. See: https://docs.cypress.io/api/commands/intercept#:~:text=All intercepts are automatically cleared before every test.import { test } from '@playwright/test';
import Stoobly from 'stoobly';
import { RecordPolicy, RecordOrder, RecordStrategy } from 'stoobly/constants';
const stoobly = new Stoobly();
const stooblyInterceptor = stoobly.playwrightInterceptor({
record: {
policy: RecordPolicy.All,
order: RecordOrder.Overwrite, // Defaults to RecordOrder.Append
strategy: RecordStrategy.Full,
},
scenarioKey: '<SCENARIO-KEY>',
urls: [{ pattern: '<URLS>' }],
});
test.describe('Scenario', () => {
test.beforeEach(async ({ page }, testInfo) => {
await stooblyInterceptor.withPage(page).apply();
// Use the following instead to record requests
// await stooblyInterceptor.withPage(page).applyRecord();
stooblyInterceptor.withTestTitle(testInfo.title);
});
});
Key Points:
describe blockwithPage() and withTestTitle() must be called in beforeEach() to update the page and test titles for each test because Playwright does not provide a global API to auto-detect test titlesBy default, Playwright intercepts requests at the page level using withPage(). To intercept requests from browser extensions, service workers, or all pages in a browser context, use withContext():
test.beforeEach(async ({ context, page }, testInfo) => {
await stooblyInterceptor
.withContext(context) // Intercept all requests in the browser context
.apply();
stooblyInterceptor.withTestTitle(testInfo.title);
});
Using withContext() enables:
Note: You can use withContext() alone, withPage() alone, or both together. When both are used, routes are applied to both the page and context, ensuring comprehensive request interception.
Run unit tests:
npm test
Run Cypress end-to-end tests:
npm run test:cypress
Run Playwright end-to-end tests:
npm run test:playwright
Full API documentation is available at: https://stoobly.github.io/stoobly-js/
To regenerate TypeDoc docs locally:
npx typedoc