Bugzilla – Attachment 184320 Details for
Bug 40447
Add documentation for cypress plugins
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 40447: Add comprehensive JSDoc documentation to Cypress plugins
Bug-40447-Add-comprehensive-JSDoc-documentation-to.patch (text/plain), 29.90 KB, created by
Martin Renvoize (ashimema)
on 2025-07-18 10:55:52 UTC
(
hide
)
Description:
Bug 40447: Add comprehensive JSDoc documentation to Cypress plugins
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2025-07-18 10:55:52 UTC
Size:
29.90 KB
patch
obsolete
>From 9d23dae71ec78a11dcb4d85d0b918edaa36bde85 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Fri, 18 Jul 2025 11:52:08 +0100 >Subject: [PATCH] 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. >--- > t/cypress/plugins/api-client.js | 121 ++++++++++++++++++ > t/cypress/plugins/auth.js | 28 +++++ > t/cypress/plugins/db.js | 49 ++++++++ > t/cypress/plugins/index.js | 48 +++++++ > t/cypress/plugins/insertData.js | 203 ++++++++++++++++++++++++++++++ > t/cypress/plugins/mockData.js | 120 ++++++++++++++++++ > t/cypress/plugins/readYamlFile.js | 31 +++++ > 7 files changed, 600 insertions(+) > >diff --git a/t/cypress/plugins/api-client.js b/t/cypress/plugins/api-client.js >index db246e419e4..750b5d1a3dc 100644 >--- a/t/cypress/plugins/api-client.js >+++ b/t/cypress/plugins/api-client.js >@@ -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({ >diff --git a/t/cypress/plugins/auth.js b/t/cypress/plugins/auth.js >index 6104c0c626d..1f01366ee5d 100644 >--- a/t/cypress/plugins/auth.js >+++ b/t/cypress/plugins/auth.js >@@ -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" >diff --git a/t/cypress/plugins/db.js b/t/cypress/plugins/db.js >index fb4568886cf..92f5234d460 100644 >--- a/t/cypress/plugins/db.js >+++ b/t/cypress/plugins/db.js >@@ -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); >diff --git a/t/cypress/plugins/index.js b/t/cypress/plugins/index.js >index 2f919b78b2f..5970890dc02 100644 >--- a/t/cypress/plugins/index.js >+++ b/t/cypress/plugins/index.js >@@ -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( >diff --git a/t/cypress/plugins/insertData.js b/t/cypress/plugins/insertData.js >index 4b522b2dc9a..3aa062611a3 100644 >--- a/t/cypress/plugins/insertData.js >+++ b/t/cypress/plugins/insertData.js >@@ -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"]; >diff --git a/t/cypress/plugins/mockData.js b/t/cypress/plugins/mockData.js >index a6fe15a099d..c7de7e052e9 100644 >--- a/t/cypress/plugins/mockData.js >+++ b/t/cypress/plugins/mockData.js >@@ -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]; > }; >diff --git a/t/cypress/plugins/readYamlFile.js b/t/cypress/plugins/readYamlFile.js >index 369650c44d5..321904c875a 100644 >--- a/t/cypress/plugins/readYamlFile.js >+++ b/t/cypress/plugins/readYamlFile.js >@@ -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)) { >-- >2.50.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 40447
: 184320