Bug 40447: Add comprehensive JSDoc documentation to Cypress plugins
This patch adds detailed JSDoc documentation to all Cypress testing plugin files. Documentation added to: - insertData.js: Data insertion utilities with examples - api-client.js: API wrapper functions with usage patterns - mockData.js: Schema-based mock data generation - auth.js: Authentication helper functions - db.js: Database query utilities - readYamlFile.js: YAML file reading utilities - index.js: Main plugin configuration Each function now includes: - Complete parameter descriptions with types - Return value documentation - Practical usage examples - Error conditions and handling - Module-level overviews This addresses the documentation gap identified during QA review, hopefully making it easier for future devs to adopt the new framework of tools. Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
3f6a2cb872
commit
d9122cd5ac
|
|
@ -1,7 +1,33 @@
|
|||
/**
|
||||
* Koha API Client for Cypress Testing
|
||||
*
|
||||
* This module provides a wrapper around the Koha API client for use in Cypress tests.
|
||||
* It handles authentication, request preparation, and provides convenient methods
|
||||
* for making API calls during test execution.
|
||||
*
|
||||
* @module api-client
|
||||
*/
|
||||
|
||||
const { APIClient } = require("./dist/api-client.cjs.js");
|
||||
|
||||
const client = APIClient.default.koha;
|
||||
|
||||
/**
|
||||
* Prepares request parameters for API calls by extracting and organizing headers and URL.
|
||||
*
|
||||
* @function prepareRequest
|
||||
* @param {Object} params - Request parameters
|
||||
* @param {string} params.baseUrl - Base URL for the API
|
||||
* @param {string} params.endpoint - API endpoint path
|
||||
* @param {string} [params.authHeader] - Authorization header value
|
||||
* @param {Object} [params.headers={}] - Additional headers to include
|
||||
* @param {...*} params.rest - Other parameters to pass through
|
||||
* @returns {Object} Prepared request object
|
||||
* @returns {string} returns.url - Complete URL for the request
|
||||
* @returns {Object} returns.headers - Combined headers object
|
||||
* @returns {Object} returns.rest - Pass-through parameters
|
||||
* @private
|
||||
*/
|
||||
const prepareRequest = params => {
|
||||
const { baseUrl, endpoint, authHeader, headers = {}, ...rest } = params;
|
||||
const url = baseUrl + endpoint;
|
||||
|
|
@ -12,6 +38,33 @@ const prepareRequest = params => {
|
|||
return { url, headers: finalHeaders, rest };
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a GET request to the Koha API.
|
||||
*
|
||||
* @function apiGet
|
||||
* @param {Object} params - Request parameters
|
||||
* @param {string} params.baseUrl - Base URL for the API
|
||||
* @param {string} params.endpoint - API endpoint path
|
||||
* @param {string} [params.authHeader] - Authorization header value
|
||||
* @param {Object} [params.headers={}] - Additional headers to include
|
||||
* @param {...*} params.rest - Additional parameters for the request
|
||||
* @returns {Promise<*>} API response data
|
||||
* @example
|
||||
* // Get a list of patrons
|
||||
* const patrons = await apiGet({
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* endpoint: '/api/v1/patrons',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Get a specific patron with query parameters
|
||||
* const patron = await apiGet({
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* endpoint: '/api/v1/patrons?q={"patron_id":123}',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*/
|
||||
const apiGet = params => {
|
||||
const { url, headers, rest } = prepareRequest(params);
|
||||
return client.get({
|
||||
|
|
@ -21,6 +74,32 @@ const apiGet = params => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a POST request to the Koha API.
|
||||
*
|
||||
* @function apiPost
|
||||
* @param {Object} params - Request parameters
|
||||
* @param {string} params.baseUrl - Base URL for the API
|
||||
* @param {string} params.endpoint - API endpoint path
|
||||
* @param {string} [params.authHeader] - Authorization header value
|
||||
* @param {Object} [params.headers={}] - Additional headers to include
|
||||
* @param {Object} [params.body] - Request body data
|
||||
* @param {...*} params.rest - Additional parameters for the request
|
||||
* @returns {Promise<*>} API response data
|
||||
* @example
|
||||
* // Create a new patron
|
||||
* const newPatron = await apiPost({
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* endpoint: '/api/v1/patrons',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0',
|
||||
* body: {
|
||||
* firstname: 'John',
|
||||
* surname: 'Doe',
|
||||
* library_id: 'CPL',
|
||||
* category_id: 'PT'
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
const apiPost = params => {
|
||||
const { url, headers, rest } = prepareRequest(params);
|
||||
return client.post({
|
||||
|
|
@ -30,6 +109,29 @@ const apiPost = params => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a PUT request to the Koha API.
|
||||
*
|
||||
* @function apiPut
|
||||
* @param {Object} params - Request parameters
|
||||
* @param {string} params.baseUrl - Base URL for the API
|
||||
* @param {string} params.endpoint - API endpoint path
|
||||
* @param {string} [params.authHeader] - Authorization header value
|
||||
* @param {Object} [params.headers={}] - Additional headers to include
|
||||
* @param {Object} [params.body] - Request body data
|
||||
* @param {...*} params.rest - Additional parameters for the request
|
||||
* @returns {Promise<*>} API response data
|
||||
* @example
|
||||
* // Update a patron
|
||||
* const updatedPatron = await apiPut({
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* endpoint: '/api/v1/patrons/123',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0',
|
||||
* body: {
|
||||
* email: 'newemail@example.com'
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
const apiPut = params => {
|
||||
const { url, headers, rest } = prepareRequest(params);
|
||||
return client.put({
|
||||
|
|
@ -39,6 +141,25 @@ const apiPut = params => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a DELETE request to the Koha API.
|
||||
*
|
||||
* @function apiDelete
|
||||
* @param {Object} params - Request parameters
|
||||
* @param {string} params.baseUrl - Base URL for the API
|
||||
* @param {string} params.endpoint - API endpoint path
|
||||
* @param {string} [params.authHeader] - Authorization header value
|
||||
* @param {Object} [params.headers={}] - Additional headers to include
|
||||
* @param {...*} params.rest - Additional parameters for the request
|
||||
* @returns {Promise<*>} API response data
|
||||
* @example
|
||||
* // Delete a patron
|
||||
* await apiDelete({
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* endpoint: '/api/v1/patrons/123',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*/
|
||||
const apiDelete = params => {
|
||||
const { url, headers, rest } = prepareRequest(params);
|
||||
return client.delete({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,33 @@
|
|||
/**
|
||||
* Authentication utilities for Cypress testing
|
||||
*
|
||||
* This module provides authentication helper functions for use in Cypress tests
|
||||
* when making API calls that require authentication.
|
||||
*
|
||||
* @module auth
|
||||
*/
|
||||
|
||||
const { Buffer } = require("buffer");
|
||||
|
||||
/**
|
||||
* Generates a Basic Authentication header from username and password.
|
||||
*
|
||||
* @function getBasicAuthHeader
|
||||
* @param {string} username - Username for authentication
|
||||
* @param {string} password - Password for authentication
|
||||
* @returns {string} Basic authentication header value in format "Basic <base64>"
|
||||
* @example
|
||||
* // Generate auth header for API calls
|
||||
* const authHeader = getBasicAuthHeader('koha', 'koha');
|
||||
* // Returns: "Basic a29oYTprb2hh"
|
||||
*
|
||||
* // Use with API client
|
||||
* const response = await apiGet({
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* endpoint: '/api/v1/patrons',
|
||||
* authHeader: getBasicAuthHeader('koha', 'koha')
|
||||
* });
|
||||
*/
|
||||
const getBasicAuthHeader = (username, password) => {
|
||||
const credentials = Buffer.from(`${username}:${password}`).toString(
|
||||
"base64"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,21 @@
|
|||
/**
|
||||
* Database Query Utilities for Cypress Testing
|
||||
*
|
||||
* This module provides direct database access for Cypress tests when API
|
||||
* endpoints are not available or when direct database operations are needed
|
||||
* for test setup and cleanup.
|
||||
*
|
||||
* @module db
|
||||
*/
|
||||
|
||||
const mysql = require("mysql2/promise");
|
||||
|
||||
/**
|
||||
* Database connection configuration
|
||||
*
|
||||
* @todo Replace hardcoded credentials with environment variables
|
||||
* @type {Object}
|
||||
*/
|
||||
const connectionConfig = {
|
||||
host: "db",
|
||||
user: "koha_kohadev",
|
||||
|
|
@ -7,6 +23,39 @@ const connectionConfig = {
|
|||
database: "koha_kohadev",
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes a SQL query with optional parameters.
|
||||
*
|
||||
* @async
|
||||
* @function query
|
||||
* @param {string} sql - SQL query string with optional parameter placeholders (?)
|
||||
* @param {Array} [params=[]] - Array of parameter values for the query
|
||||
* @returns {Promise<Array>} Query results as an array of rows
|
||||
* @throws {Error} When database connection or query execution fails
|
||||
* @description This function:
|
||||
* - Creates a new database connection for each query
|
||||
* - Uses parameterized queries to prevent SQL injection
|
||||
* - Automatically closes the connection after execution
|
||||
* - Returns the raw result rows from the database
|
||||
*
|
||||
* @example
|
||||
* // Simple SELECT query
|
||||
* const patrons = await query('SELECT * FROM borrowers LIMIT 10');
|
||||
*
|
||||
* @example
|
||||
* // Parameterized query for safety
|
||||
* const patron = await query(
|
||||
* 'SELECT * FROM borrowers WHERE borrowernumber = ?',
|
||||
* [123]
|
||||
* );
|
||||
*
|
||||
* @example
|
||||
* // DELETE query with multiple parameters
|
||||
* await query(
|
||||
* 'DELETE FROM issues WHERE issue_id IN (?, ?, ?)',
|
||||
* [1, 2, 3]
|
||||
* );
|
||||
*/
|
||||
async function query(sql, params = []) {
|
||||
const connection = await mysql.createConnection(connectionConfig);
|
||||
const [rows] = await connection.execute(sql, params);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,14 @@
|
|||
/**
|
||||
* Cypress Plugin Configuration
|
||||
*
|
||||
* This is the main Cypress plugin configuration file that registers all
|
||||
* testing utilities as Cypress tasks. It provides a bridge between Cypress
|
||||
* tests and the various utility modules for data generation, API access,
|
||||
* and database operations.
|
||||
*
|
||||
* @module cypress-plugins
|
||||
*/
|
||||
|
||||
const { startDevServer } = require("@cypress/webpack-dev-server");
|
||||
|
||||
const { buildSampleObject, buildSampleObjects } = require("./mockData.js");
|
||||
|
|
@ -17,6 +28,43 @@ const { query } = require("./db.js");
|
|||
|
||||
const { apiGet, apiPost, apiPut, apiDelete } = require("./api-client.js");
|
||||
|
||||
/**
|
||||
* Cypress plugin configuration function.
|
||||
*
|
||||
* @function
|
||||
* @param {Function} on - Cypress plugin registration function
|
||||
* @param {Object} config - Cypress configuration object
|
||||
* @param {string} config.baseUrl - Base URL for the application under test
|
||||
* @param {Object} config.env - Environment variables from cypress.config.js
|
||||
* @param {string} config.env.apiUsername - Username for API authentication
|
||||
* @param {string} config.env.apiPassword - Password for API authentication
|
||||
* @returns {Object} Modified Cypress configuration
|
||||
* @description This function:
|
||||
* - Registers all testing utilities as Cypress tasks
|
||||
* - Sets up authentication headers for API calls
|
||||
* - Configures the development server for component testing
|
||||
* - Provides automatic parameter injection for common arguments
|
||||
*
|
||||
* Available Cypress tasks:
|
||||
* - Data Generation: buildSampleObject, buildSampleObjects
|
||||
* - Data Insertion: insertSampleBiblio, insertSampleHold, insertSampleCheckout, insertSamplePatron
|
||||
* - Data Cleanup: deleteSampleObjects
|
||||
* - API Access: apiGet, apiPost, apiPut, apiDelete
|
||||
* - Database Access: query
|
||||
* - Authentication: getBasicAuthHeader
|
||||
*
|
||||
* @example
|
||||
* // Usage in Cypress tests
|
||||
* cy.task('insertSampleBiblio', { item_count: 2 }).then(result => {
|
||||
* // Test with the created biblio
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // API call through task
|
||||
* cy.task('apiGet', { endpoint: '/api/v1/patrons' }).then(patrons => {
|
||||
* // Work with patron data
|
||||
* });
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
const baseUrl = config.baseUrl;
|
||||
const authHeader = getBasicAuthHeader(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,51 @@
|
|||
/**
|
||||
* Koha Cypress Testing Data Insertion Utilities
|
||||
*
|
||||
* This module provides functions to create and manage test data for Cypress tests.
|
||||
* It handles creating complete bibliographic records, patrons, holds, checkouts,
|
||||
* and other Koha objects with proper relationships and dependencies.
|
||||
*
|
||||
* @module insertData
|
||||
*/
|
||||
|
||||
const { buildSampleObject, buildSampleObjects } = require("./mockData.js");
|
||||
const { query } = require("./db.js");
|
||||
|
||||
const { apiGet, apiPost } = require("./api-client.js");
|
||||
|
||||
/**
|
||||
* Creates a complete bibliographic record with associated items and libraries.
|
||||
*
|
||||
* @async
|
||||
* @function insertSampleBiblio
|
||||
* @param {Object} params - Configuration parameters
|
||||
* @param {number} params.item_count - Number of items to create for this biblio
|
||||
* @param {Object} [params.options] - Additional options
|
||||
* @param {boolean} [params.options.different_libraries] - If true, creates different libraries for each item
|
||||
* @param {string} params.baseUrl - Base URL for API calls
|
||||
* @param {string} params.authHeader - Authorization header for API calls
|
||||
* @returns {Promise<Object>} Created biblio with items, libraries, and item_type
|
||||
* @returns {Object} returns.biblio - The created bibliographic record
|
||||
* @returns {Array<Object>} returns.items - Array of created item records
|
||||
* @returns {Array<Object>} returns.libraries - Array of created library records
|
||||
* @returns {Object} returns.item_type - The created item type record
|
||||
* @example
|
||||
* // Create a biblio with 3 items using the same library
|
||||
* const result = await insertSampleBiblio({
|
||||
* item_count: 3,
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Create a biblio with 2 items using different libraries
|
||||
* const result = await insertSampleBiblio({
|
||||
* item_count: 2,
|
||||
* options: { different_libraries: true },
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*/
|
||||
const insertSampleBiblio = async ({
|
||||
item_count,
|
||||
options,
|
||||
|
|
@ -160,6 +203,39 @@ const insertSampleBiblio = async ({
|
|||
return { biblio, items: createdItems, libraries, item_type };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a hold request for a bibliographic record or item.
|
||||
*
|
||||
* @async
|
||||
* @function insertSampleHold
|
||||
* @param {Object} params - Configuration parameters
|
||||
* @param {Object} [params.item] - Item to place hold on (optional if biblio provided)
|
||||
* @param {Object} [params.biblio] - Biblio to place hold on (optional if item provided)
|
||||
* @param {string} [params.library_id] - Library ID for pickup location (defaults to item's home library)
|
||||
* @param {string} params.baseUrl - Base URL for API calls
|
||||
* @param {string} params.authHeader - Authorization header for API calls
|
||||
* @returns {Promise<Object>} Created hold with associated patron and patron_category
|
||||
* @returns {Object} returns.hold - The created hold record
|
||||
* @returns {Object} returns.patron - The patron who placed the hold
|
||||
* @returns {Object} returns.patron_category - The patron's category
|
||||
* @throws {Error} When neither library_id nor item is provided
|
||||
* @example
|
||||
* // Create a hold on a specific item
|
||||
* const holdResult = await insertSampleHold({
|
||||
* item: { item_id: 123, home_library_id: 'CPL' },
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Create a biblio-level hold
|
||||
* const holdResult = await insertSampleHold({
|
||||
* biblio: { biblio_id: 456 },
|
||||
* library_id: 'CPL',
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*/
|
||||
const insertSampleHold = async ({
|
||||
item,
|
||||
biblio,
|
||||
|
|
@ -199,6 +275,38 @@ const insertSampleHold = async ({
|
|||
return { hold, patron, patron_category };
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a checkout record with associated biblio, item, and optional patron.
|
||||
*
|
||||
* @async
|
||||
* @function insertSampleCheckout
|
||||
* @param {Object} params - Configuration parameters
|
||||
* @param {Object} [params.patron] - Existing patron to check out to (creates new if not provided)
|
||||
* @param {string} params.baseUrl - Base URL for API calls
|
||||
* @param {string} params.authHeader - Authorization header for API calls
|
||||
* @returns {Promise<Object>} Created checkout with all associated records
|
||||
* @returns {Object} returns.biblio - The bibliographic record
|
||||
* @returns {Array<Object>} returns.items - Array of item records
|
||||
* @returns {Array<Object>} returns.libraries - Array of library records
|
||||
* @returns {Object} returns.item_type - The item type record
|
||||
* @returns {Object} returns.checkout - The checkout record
|
||||
* @returns {Object} [returns.patron] - The patron record (if generated)
|
||||
* @returns {Object} [returns.patron_category] - The patron category (if generated)
|
||||
* @example
|
||||
* // Create a checkout with a new patron
|
||||
* const checkoutResult = await insertSampleCheckout({
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Create a checkout for an existing patron
|
||||
* const checkoutResult = await insertSampleCheckout({
|
||||
* patron: { patron_id: 123 },
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*/
|
||||
const insertSampleCheckout = async ({ patron, baseUrl, authHeader }) => {
|
||||
const { biblio, items, libraries, item_type } = await insertSampleBiblio({
|
||||
item_count: 1,
|
||||
|
|
@ -248,6 +356,35 @@ const insertSampleCheckout = async ({ patron, baseUrl, authHeader }) => {
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a patron record with associated library and category.
|
||||
*
|
||||
* @async
|
||||
* @function insertSamplePatron
|
||||
* @param {Object} params - Configuration parameters
|
||||
* @param {Object} [params.library] - Library to assign patron to (creates new if not provided)
|
||||
* @param {Object} [params.patron_category] - Patron category to assign (creates new if not provided)
|
||||
* @param {string} params.baseUrl - Base URL for API calls
|
||||
* @param {string} params.authHeader - Authorization header for API calls
|
||||
* @returns {Promise<Object>} Created patron with associated records
|
||||
* @returns {Object} returns.patron - The created patron record
|
||||
* @returns {Object} [returns.library] - The library record (if generated)
|
||||
* @returns {Object} [returns.patron_category] - The patron category record (if generated)
|
||||
* @example
|
||||
* // Create a patron with new library and category
|
||||
* const patronResult = await insertSamplePatron({
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Create a patron for an existing library
|
||||
* const patronResult = await insertSamplePatron({
|
||||
* library: { library_id: 'CPL' },
|
||||
* baseUrl: 'http://localhost:8081',
|
||||
* authHeader: 'Basic dGVzdDp0ZXN0'
|
||||
* });
|
||||
*/
|
||||
const insertSamplePatron = async ({
|
||||
library,
|
||||
patron_category,
|
||||
|
|
@ -324,6 +461,33 @@ const insertSamplePatron = async ({
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes test objects from the database in the correct order to respect foreign key constraints.
|
||||
*
|
||||
* @async
|
||||
* @function deleteSampleObjects
|
||||
* @param {Object|Array<Object>} allObjects - Object(s) to delete, can be single object or array
|
||||
* @returns {Promise<boolean>} True if deletion was successful
|
||||
* @description This function handles cleanup of test data by:
|
||||
* - Accepting single objects or arrays of objects
|
||||
* - Grouping objects by type (holds, checkouts, patrons, items, etc.)
|
||||
* - Deleting in dependency order to avoid foreign key violations
|
||||
* - Supporting all major Koha object types
|
||||
* @example
|
||||
* // Delete a single test result
|
||||
* await deleteSampleObjects(checkoutResult);
|
||||
*
|
||||
* @example
|
||||
* // Delete multiple test results
|
||||
* await deleteSampleObjects([biblioResult, holdResult, checkoutResult]);
|
||||
*
|
||||
* @example
|
||||
* // Delete after creating test data
|
||||
* const biblio = await insertSampleBiblio({ item_count: 2, baseUrl, authHeader });
|
||||
* const hold = await insertSampleHold({ item: biblio.items[0], baseUrl, authHeader });
|
||||
* // ... run tests ...
|
||||
* await deleteSampleObjects([biblio, hold]);
|
||||
*/
|
||||
const deleteSampleObjects = async allObjects => {
|
||||
if (!Array.isArray(allObjects)) {
|
||||
allObjects = [allObjects];
|
||||
|
|
@ -458,6 +622,20 @@ const deleteSampleObjects = async allObjects => {
|
|||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a library record via API, filtering out unsupported fields.
|
||||
*
|
||||
* @async
|
||||
* @function insertLibrary
|
||||
* @param {Object} params - Configuration parameters
|
||||
* @param {Object} params.library - Library object to insert
|
||||
* @param {string} params.baseUrl - Base URL for API calls
|
||||
* @param {string} params.authHeader - Authorization header for API calls
|
||||
* @returns {Promise<Object>} Created library record
|
||||
* @private
|
||||
* @description This is a helper function that removes fields not supported by the API
|
||||
* before creating the library record.
|
||||
*/
|
||||
const insertLibrary = async ({ library, baseUrl, authHeader }) => {
|
||||
const {
|
||||
pickup_items,
|
||||
|
|
@ -476,6 +654,31 @@ const insertLibrary = async ({ library, baseUrl, authHeader }) => {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic function to insert various types of Koha objects.
|
||||
*
|
||||
* @async
|
||||
* @function insertObject
|
||||
* @param {Object} params - Configuration parameters
|
||||
* @param {string} params.type - Type of object to insert ('library', 'item_type', 'hold', 'checkout', 'vendor', 'basket')
|
||||
* @param {Object} params.object - Object data to insert
|
||||
* @param {string} params.baseUrl - Base URL for API calls
|
||||
* @param {string} params.authHeader - Authorization header for API calls
|
||||
* @returns {Promise<Object|boolean>} Created object or true if successful
|
||||
* @throws {Error} When object type is not supported
|
||||
* @private
|
||||
* @description This is a generic helper function that handles the specifics of creating
|
||||
* different types of Koha objects. Each object type may require different field filtering,
|
||||
* API endpoints, or database operations.
|
||||
*
|
||||
* Supported object types:
|
||||
* - library: Creates library via API
|
||||
* - item_type: Creates item type via database query
|
||||
* - hold: Creates hold via API
|
||||
* - checkout: Creates checkout via API with confirmation token support
|
||||
* - vendor: Creates vendor via API
|
||||
* - basket: Creates basket via database query
|
||||
*/
|
||||
const insertObject = async ({ type, object, baseUrl, authHeader }) => {
|
||||
if (type == "library") {
|
||||
const keysToKeep = ["library_id", "name"];
|
||||
|
|
|
|||
|
|
@ -1,10 +1,42 @@
|
|||
/**
|
||||
* Mock Data Generation for Cypress Testing
|
||||
*
|
||||
* This module provides functions to generate realistic test data for Koha objects
|
||||
* based on OpenAPI schema definitions. It uses Faker.js to generate random data
|
||||
* that conforms to the API specifications.
|
||||
*
|
||||
* @module mockData
|
||||
*/
|
||||
|
||||
const { faker } = require("@faker-js/faker");
|
||||
const { readYamlFile } = require("./../plugins/readYamlFile.js");
|
||||
const { query } = require("./db.js");
|
||||
const fs = require("fs");
|
||||
|
||||
/**
|
||||
* Cache to store generated ID values to prevent duplicates
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
const generatedDataCache = new Set();
|
||||
|
||||
/**
|
||||
* Generates mock data for a specific data type based on OpenAPI schema properties.
|
||||
*
|
||||
* @function generateMockData
|
||||
* @param {string} type - The data type (string, integer, boolean, array, number, date, date-time)
|
||||
* @param {Object} properties - OpenAPI schema properties for the field
|
||||
* @param {Array} [properties.enum] - Enumerated values to choose from
|
||||
* @param {number} [properties.maxLength] - Maximum length for strings
|
||||
* @param {number} [properties.minLength] - Minimum length for strings
|
||||
* @returns {*} Generated mock data appropriate for the type
|
||||
* @private
|
||||
* @example
|
||||
* // Generate a string with max length 50
|
||||
* const name = generateMockData('string', { maxLength: 50 });
|
||||
*
|
||||
* // Generate from enum values
|
||||
* const status = generateMockData('string', { enum: ['active', 'inactive'] });
|
||||
*/
|
||||
const generateMockData = (type, properties) => {
|
||||
if (properties.hasOwnProperty("enum")) {
|
||||
let values = properties.enum;
|
||||
|
|
@ -55,6 +87,26 @@ const generateMockData = (type, properties) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates mock data for an entire object based on OpenAPI schema properties.
|
||||
*
|
||||
* @function generateDataFromSchema
|
||||
* @param {Object} properties - OpenAPI schema properties object
|
||||
* @param {Object} [values={}] - Override values for specific fields
|
||||
* @returns {Object} Generated mock object with all required fields
|
||||
* @private
|
||||
* @description This function:
|
||||
* - Iterates through all properties in the schema
|
||||
* - Generates appropriate mock data for each field
|
||||
* - Handles object relationships (libraries, items, etc.)
|
||||
* - Ensures unique values for ID fields
|
||||
* - Applies any override values provided
|
||||
*
|
||||
* Special handling for object relationships:
|
||||
* - home_library/holding_library -> generates library object
|
||||
* - item_type -> generates item_type object
|
||||
* - Automatically sets corresponding _id fields
|
||||
*/
|
||||
const generateDataFromSchema = (properties, values = {}) => {
|
||||
const mockData = {};
|
||||
const ids = {};
|
||||
|
|
@ -149,6 +201,37 @@ const generateDataFromSchema = (properties, values = {}) => {
|
|||
return mockData;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds an array of sample objects based on OpenAPI schema definitions.
|
||||
*
|
||||
* @function buildSampleObjects
|
||||
* @param {Object} params - Configuration parameters
|
||||
* @param {string} params.object - Object type to generate (must match YAML file name)
|
||||
* @param {Object} [params.values] - Override values for specific fields
|
||||
* @param {number} [params.count=1] - Number of objects to generate
|
||||
* @returns {Array<Object>} Array of generated objects
|
||||
* @throws {Error} When object type is not supported or generation fails
|
||||
* @description This function:
|
||||
* - Reads the OpenAPI schema from api/v1/swagger/definitions/{object}.yaml
|
||||
* - Generates the specified number of objects
|
||||
* - Applies any override values to all generated objects
|
||||
* - Ensures all objects conform to the API schema
|
||||
*
|
||||
* @example
|
||||
* // Generate 3 patron objects
|
||||
* const patrons = buildSampleObjects({
|
||||
* object: 'patron',
|
||||
* count: 3
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* // Generate 2 items with specific library
|
||||
* const items = buildSampleObjects({
|
||||
* object: 'item',
|
||||
* values: { library_id: 'CPL' },
|
||||
* count: 2
|
||||
* });
|
||||
*/
|
||||
const buildSampleObjects = ({ object, values, count = 1 }) => {
|
||||
const yamlPath = `api/v1/swagger/definitions/${object}.yaml`;
|
||||
if (!fs.existsSync(yamlPath)) {
|
||||
|
|
@ -168,6 +251,43 @@ const buildSampleObjects = ({ object, values, count = 1 }) => {
|
|||
return generatedObject;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds a single sample object based on OpenAPI schema definitions.
|
||||
*
|
||||
* @function buildSampleObject
|
||||
* @param {Object} params - Configuration parameters
|
||||
* @param {string} params.object - Object type to generate (must match YAML file name)
|
||||
* @param {Object} [params.values={}] - Override values for specific fields
|
||||
* @returns {Object} Generated object conforming to API schema
|
||||
* @throws {Error} When object type is not supported or generation fails
|
||||
* @description This is a convenience function that generates a single object
|
||||
* by calling buildSampleObjects with count=1 and returning the first result.
|
||||
*
|
||||
* Supported object types include:
|
||||
* - patron: Library patron/borrower
|
||||
* - item: Bibliographic item
|
||||
* - biblio: Bibliographic record
|
||||
* - library: Library/branch
|
||||
* - hold: Hold/reservation request
|
||||
* - checkout: Circulation checkout
|
||||
* - vendor: Acquisitions vendor
|
||||
* - basket: Acquisitions basket
|
||||
* - And others as defined in api/v1/swagger/definitions/
|
||||
*
|
||||
* @example
|
||||
* // Generate a single patron
|
||||
* const patron = buildSampleObject({ object: 'patron' });
|
||||
*
|
||||
* @example
|
||||
* // Generate an item with specific values
|
||||
* const item = buildSampleObject({
|
||||
* object: 'item',
|
||||
* values: {
|
||||
* barcode: '12345678',
|
||||
* home_library_id: 'CPL'
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
const buildSampleObject = ({ object, values = {} }) => {
|
||||
return buildSampleObjects({ object, values })[0];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,38 @@
|
|||
/**
|
||||
* YAML File Reading Utilities for Cypress Testing
|
||||
*
|
||||
* This module provides utilities for reading and parsing YAML files,
|
||||
* primarily used for loading OpenAPI schema definitions during test
|
||||
* data generation.
|
||||
*
|
||||
* @module readYamlFile
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const yaml = require("yaml");
|
||||
|
||||
/**
|
||||
* Reads and parses a YAML file.
|
||||
*
|
||||
* @function readYamlFile
|
||||
* @param {string} filePath - Path to the YAML file (relative or absolute)
|
||||
* @returns {Object} Parsed YAML content as a JavaScript object
|
||||
* @throws {Error} When file doesn't exist or YAML parsing fails
|
||||
* @description This function:
|
||||
* - Resolves the file path to an absolute path
|
||||
* - Checks if the file exists before attempting to read
|
||||
* - Reads the file content as UTF-8 text
|
||||
* - Parses the YAML content into a JavaScript object
|
||||
*
|
||||
* @example
|
||||
* // Read an OpenAPI schema definition
|
||||
* const patronSchema = readYamlFile('api/v1/swagger/definitions/patron.yaml');
|
||||
*
|
||||
* @example
|
||||
* // Read a configuration file
|
||||
* const config = readYamlFile('./config/test-config.yaml');
|
||||
*/
|
||||
const readYamlFile = filePath => {
|
||||
const absolutePath = path.resolve(filePath);
|
||||
if (!fs.existsSync(absolutePath)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue