The Update/updateTestDataInNewRow extension adds a new row to a Virtuoso test data table by using the supplied environment, project, table name, API token, and JSON key-value data.
This is useful when a journey needs to create fresh runtime test data, such as a generated email address, and store it in a selected data table for later test steps or future executions.
Parameters:
-
envrequired, a string that selects the Virtuoso API environment. Supported values in the source arePRODUCTION,US,UK, andAPP2; -
tokenrequired, a valid Virtuoso API token with permission to read and update test data tables; -
projectIdrequired, the project ID that contains the target data table; -
tablerequired, the exact name of the data table to update; -
datarequired, a JSON string containing key-value pairs where each key must match a column name in the target table.
Note: The data value must parse as a JSON object. Each object key is treated as a column name, and the matching value is written into the next available row.
NLP usage
Use the extension in a journey by calling Update/updateTestDataInNewRow with the execute command. Pass each value to the matching extension input using as inputName.
Note: This extension performs API calls and uses done/doneError, so it must be configured to run asynchronously.
execute "Update/updateTestDataInNewRow" using "PRODUCTION" as env, "$setTestDataToken" as token, "31694" as projectId, "setTestData" as table, '{"SampleHeader":"sample.user@example.com"}' as data returning $responseUpdate/updateTestDataInNewRow("PRODUCTION", $setTestDataToken, "31694", "setTestData", $data)You can also pass values from variables when the token, project, table name, or row data is generated earlier in the journey.
execute "Update/updateTestDataInNewRow" using "$environment" as env, "$setTestDataToken" as token, "$projectId" as projectId, "$tableName" as table, "$data" as data returning $responsestore value ${"SampleHeader":"sample.user@example.com"} in $data
execute "Update/updateTestDataInNewRow" using "PRODUCTION" as env, "$setTestDataToken" as token, "31694" as projectId, "setTestData" as table, "$data" as data returning $responseExample output when the table update succeeds:
Table UpdatedThis extension requires the following resources:
The extension should be configured as:
- Run asynchronously: Yes
- Scope: Global
Limitation: This extension depends on Virtuoso API availability, a valid token, and correct project/table permissions. The env value must match one of the supported keys in the source. Column matching is exact and based on table attribute names, so missing or differently cased column names can fail. The script finds the first empty numeric row index by scanning existing values, so sparse or non-standard table value structures may affect where the new row is inserted. It also sends the API token in query-string URLs for table operations, so the journey should avoid exposing logs or URLs containing sensitive tokens.
Add the extension to your Virtuoso instance
Select the domain that matches your Virtuoso account.
View source
Last updated: 25/05/2026
Resources:
// Note this extension is not a product feature of Virtuoso and is not officially supported
// Extensions use javascript which may or may not be compatible with systems under test (SUTs)
// We welcome you to use this extension or adapt it for your needs
const endpoints = {
PRODUCTION: "https://api.virtuoso.qa/api",
US: "https://api-us.virtuoso.qa/api",
UK: "https://api-uk.virtuoso.qa/api",
APP2: "https://api-app2.virtuoso.qa/api"
};
const BASE_URL = endpoints[env];
if (!BASE_URL) {
doneError("Invalid environment " + env + ". Please use PRODUCTION, US, UK, or APP2");
}
async function getTable() {
const endpoint = `${BASE_URL}/projects/${projectId}/dataTables?envelope=false&token=${token}`;
const dataTables = await axios.get(endpoint)
.catch(error => {
doneError('Error fetching data table id: ' + error);
});
const dataTable = Object.values(dataTables.data).find(value => value.name === table);
if (!dataTable) return doneError(`Table ${table} not found`);
return dataTable;
}
function getColumnId(table, columnName) {
const column = Object.values(table.attributes).find(attribute => attribute.name === columnName);
if (!column) {
doneError(`Could not find column ${columnName} in table`);
}
return column.id;
}
function getColumnName(table, columnId) {
const column = Object.values(table.attributes).find(attribute => attribute.id === columnId);
if (!column) {
doneError(`Could not find column with ID ${columnId} in table`);
}
return column.name;
}
async function getTableValues(tableId) {
const endpoint = `${BASE_URL}/testdata/tables/${tableId}/values?envelope=false&token=${token}`;
const { data: tableValues } = await axios.get(endpoint)
.catch(error => {
doneError('Error fetching data table values: ' + error);
});
return tableValues;
}
async function updateTable(tableId, newValues, modifiedDate) {
const endpointUrl = `${BASE_URL}/testdata/tables/${tableId}/values?envelope=false&token=${token}`;
const requestData = {
modifiedDate: modifiedDate,
newTestDataValues: newValues
};
await axios.put(endpointUrl, requestData)
.catch(error => {
doneError('Error updating table');
});
}
function updateTableValues(table, rows, oldValues, data) {
let dataObj = {};
try {
dataObj = JSON.parse(data);
} catch (e) {
doneError("Could not parse data, make sure that it's correctly formatted in JSON");
}
for (const [key, value] of Object.entries(dataObj)) {
const columnId = getColumnId(table, key);
try {
rows.forEach(row => {
if (!oldValues[row]) oldValues[row] = {};
oldValues[row][columnId] = value;
});
} catch (e) {
doneError(`Error updating value ${key} in row ${row} of table`);
}
}
return oldValues;
}
async function setTableData(data) {
const tableObj = await getTable();
const oldValues = await getTableValues(tableObj.id);
let nextEmptyRowIndex = 0;
while (oldValues[nextEmptyRowIndex]) {
nextEmptyRowIndex++;
}
const newValues = updateTableValues(tableObj, [nextEmptyRowIndex], oldValues, data);
await updateTable(tableObj.id, newValues, tableObj.modifiedDate);
done("Table Updated");
}
setTableData(data);
Comments
0 comments
Please sign in to leave a comment.