Functions
LEGACY — Shiplight Cloud v1
This page documents Shiplight Cloud v1 (app.shiplight.ai), which is no longer the current product. For the current cloud platform, see Shiplight Cloud.
Functions are reusable code components that can be called from your tests, providing powerful capabilities for complex operations and integrations.
Table of Contents
- Creating and Managing Functions
- Available Parameters
- Function Editor Features
- Importing Packages
- Common Use Cases
- Using Functions in Tests
- Function Testing
- Function Status
- Limitations
- Best Practices
Creating and Managing Functions
Functions are created and managed from the Functions sidebar menu (not from within tests):
- Navigate to Functions in the sidebar
- Click Create Function to open the function editor
- Define your function with:
- Name - Unique identifier for the function
- Description - What the function does
- Code - The function implementation
- Test Code - "Try it out" test to validate the function
Available Parameters
Every function receives three pre-defined parameters that are automatically passed when the function is called:
| Parameter | Type | Description |
|---|---|---|
page | Playwright Page | The current browser page |
testContext | Shiplight variable store | Read and write test variables. Aliases: $, ctx |
request | Playwright APIRequestContext | For making HTTP requests |
The following are available as globals inside function code (no need to add them to the function signature):
| Variable | Type | Description |
|---|---|---|
agent | Shiplight WebAgent | AI-powered actions — assertions, natural language step execution |
expect | Playwright assertions | For writing assertions |
console | Captured console | Logs appear in the test run output |
Your function signature should always start with the pre-defined parameters, followed by any custom parameters:
async function my_function(page, testContext, request, customParam1, customParam2) {
// Use page for browser interactions
await page.click("#button");
// Use request for API calls
const response = await request.get("https://api.example.com/data");
// Use testContext to store/retrieve variables
testContext.myValue = "stored value";
$.anotherValue = "also stored"; // $ is an alias for testContext
// Use agent (available as global)
await agent.assert(page, "The button was clicked successfully");
}Working with testContext
testContext (also $ and ctx) is a proxy to the test's variable store. Values set here are available in all subsequent steps — including natural language steps — for the duration of the test run.
// Write a variable
testContext.orderId = "12345";
// Read a variable
const id = testContext.orderId;
// Write a sensitive value (masked in logs)
testContext.set("apiToken", "secret-value", true);
// Read explicitly
const token = testContext.get("apiToken");Using agent
The agent object gives you access to Shiplight's AI capabilities from inside a function.
agent.assert(page, statement) — AI-powered assertion. The agent looks at the current page and verifies whether the statement is true.
await agent.assert(page, "The shopping cart shows 3 items");agent.execute(page, statement) — Execute a natural language instruction. The agent reads the page and performs the described action, just like a natural language step.
await agent.execute(page, "Fill out the registration form with test data");agent.extract(page, description, variableName) — Extract a value from the page using AI and store it in testContext.
await agent.extract(page, "the order confirmation number", "orderNumber");Function Editor Features
The function editor provides a tabbed interface for managing your functions:
Editor Tabs
The function editor includes three main tabs:
Overview - The main editing interface where you define your function:
- Split-pane interface - Code editor on left, live browser view on right
- Live browser preview - If your function operates on the page, see real-time results
- "Try it out" testing - Write and run test code that calls your function
- Status management - Draft or Active
Usage - View which of your tests are using this function
Settings - Configure function-specific settings and preferences, such as selecting the environment to run test code
Importing Packages
You can use await import() to import Node.js built-in modules and pre-installed npm packages inside a function.
async function read_downloaded_pdf(page, testContext, request) {
const fs = await import("node:fs");
let pdfParse = await import("pdf-parse");
pdfParse = pdfParse.default || pdfParse;
const filePath = agent.getRecentDownloadedFilePath();
const buffer = fs.readFileSync(filePath);
const result = await pdfParse(buffer);
testContext.pdfText = result.text;
}Pre-installed Packages
The following third-party packages are available out of the box:
| Package | Description |
|---|---|
pdf-parse | Extract text from PDF files |
mammoth | Convert Word documents (.docx) to text or HTML |
exceljs | Read and write Excel files (.xlsx) |
Node.js built-in modules (fs, path, crypto, etc.) are always available.
Dynamic import only
Static import statements (e.g., import fs from 'fs') are not supported — only await import() works. This is because function code runs as an inline script, not as an ES module.
CommonJS packages
Some older packages only expose a default export when imported this way. If destructuring doesn't work, access the module via .default:
const mod = await import("some-package");
const lib = mod.default;Common Use Cases
API Integrations
async function get_order_details(page, testContext, request, orderId) {
const response = await request.get(`${testContext.apiUrl}/orders/${orderId}`, {
headers: { Authorization: `Bearer ${testContext.apiToken}` },
});
const data = await response.json();
// Store results in test context for subsequent steps to access
$.orderData = data;
testContext.orderId = data.id;
$.orderStatus = data.status;
}Complex Operations
async function authenticate_with_mfa(page, testContext, request, username, password) {
await page.fill("#username", username);
await page.fill("#password", password);
await page.click("#login");
// Wait for MFA prompt
await page.waitForSelector("#mfa-code");
// Generate TOTP code from secret key
const crypto = await import("node:crypto");
const mfaCode = generateTOTP(testContext.get("otp_secret_key"), crypto);
await page.fill("#mfa-code", mfaCode);
await page.click("#verify");
// Verify login succeeded
await agent.assert(page, "The user is logged in and on the dashboard");
}File Processing
async function verify_excel_report(page, testContext, request) {
await agent.waitForDownloadComplete(page, 10);
const filePath = agent.getRecentDownloadedFilePath();
let ExcelJS = await import("exceljs");
ExcelJS = ExcelJS.default || ExcelJS;
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.readFile(filePath);
const sheet = workbook.getWorksheet(1);
testContext.rowCount = sheet.rowCount;
testContext.headers = sheet.getRow(1).values;
}async function verify_word_document(page, testContext, request) {
await agent.waitForDownloadComplete(page, 10);
const filePath = agent.getRecentDownloadedFilePath();
let mammoth = await import("mammoth");
mammoth = mammoth.default || mammoth;
const result = await mammoth.extractRawText({ path: filePath });
testContext.documentText = result.value;
}Using Functions in Tests
Once created, functions can be called from your tests in two ways:
Using the Function Statement (Easy)
- Insert a new statement in your test
- From the dropdown menu, switch to Function (or press
Ctrl + Alt + F) - Pick a function from the list
- Fill in the parameters
This is the recommended approach for most users.
Using a Code Block (Programmatic Way)
Create a Code step and call the function directly by name:
await get_order_details(page, testContext, request, $.orderId);
console.log($.orderTotal); // Access stored valueAccessing Function Results
Important: Functions cannot directly return values to tests. Instead, store values in testContext:
// In your function:
async function get_order_details(page, testContext, request, orderId) {
const response = await request.get(`/api/orders/${orderId}`);
const data = await response.json();
// Store results in test context instead of returning
$.orderTotal = data.total;
$.orderStatus = data.status;
ctx.orderItems = data.items;
}Function Testing
Each function includes a "Try it out" section where you can:
- Write test code that calls your function
- Execute the test to verify function behavior
- See live browser results if the function interacts with pages
- Debug and refine your function implementation
Function Status
Functions have two status levels:
- Draft - In development, can be edited and tested
- Active - Ready for use in tests
Limitations
- Dynamic import only. Static
importstatements are not supported. Useawait import()instead. See Importing Packages. - Pre-installed packages only. You can only import packages that are already available in the Shiplight runtime. You cannot install arbitrary npm packages.
- No return values. Functions cannot return values to tests. Use
testContextto pass data between functions and steps. - Node.js context only. Function code runs on the Node.js side, not in the browser. Use
page.evaluate()to access browser globals likewindow,document, orlocalStorage.
Best Practices
- Keep functions focused — each function should do one thing well with a clear input/output contract.
- Document your functions — write clear descriptions and document expected parameters.
- Use
testContextfor output — store all results intestContextso subsequent steps can access them. - Test thoroughly — use the "Try it out" feature to validate, including edge cases and error conditions.
- Handle errors — throw meaningful errors so test failures are easy to diagnose.