Last active
October 23, 2024 05:54
-
-
Save muthuishere/484408168dccc0c241eb5497f4cbee10 to your computer and use it in GitHub Desktop.
Bb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const xml2js = require('xml2js'); | |
class SoapUIProjectParser { | |
constructor() { | |
// Configure parser to preserve whitespace and attributes | |
this.parser = new xml2js.Parser({ | |
preserveChildrenOrder: true, | |
explicitChildren: false, | |
explicitArray: true | |
}); | |
// Configure builder for SoapUI 5.5.0 compatibility | |
this.builder = new xml2js.Builder({ | |
renderOpts: { pretty: true, indent: ' ' }, | |
xmldec: { version: '1.0', encoding: 'UTF-8' }, | |
cdata: true | |
}); | |
this.rawXml = null; | |
} | |
async loadProject(filePath) { | |
try { | |
const xmlData = await fs.promises.readFile(filePath, 'utf8'); | |
this.rawXml = await this.parser.parseStringPromise(xmlData); | |
return true; | |
} catch (error) { | |
throw new Error(`Failed to load SoapUI project: ${error.message}`); | |
} | |
} | |
setTestCasesStatus(testCaseNames) { | |
if (!this.rawXml || !this.rawXml['con:soapui-project']) { | |
throw new Error('No project loaded'); | |
} | |
const summary = { | |
enabled: [], | |
disabled: [], | |
notFound: [...testCaseNames], | |
totalModified: 0 | |
}; | |
// Get all test suites | |
const testSuites = this.rawXml['con:soapui-project']['con:testSuite'] || []; | |
testSuites.forEach(testSuite => { | |
const testCases = testSuite['con:testCase'] || []; | |
testCases.forEach(testCase => { | |
if (!testCase['$']) { | |
testCase['$'] = {}; | |
} | |
const testCaseName = testCase['$']['name'] || ''; | |
const isTargetTestCase = testCaseNames.includes(testCaseName); | |
const currentlyDisabled = testCase['$']['disabled'] === 'true'; | |
// Set disabled attribute based on whether it's in the target list | |
if (isTargetTestCase) { | |
// Enable the test case | |
if (currentlyDisabled) { | |
testCase['$']['disabled'] = 'false'; | |
summary.totalModified++; | |
} | |
summary.enabled.push(testCaseName); | |
summary.notFound = summary.notFound.filter(name => name !== testCaseName); | |
} else { | |
// Disable the test case | |
if (!currentlyDisabled) { | |
testCase['$']['disabled'] = 'true'; | |
summary.totalModified++; | |
} | |
summary.disabled.push(testCaseName); | |
} | |
}); | |
}); | |
return summary; | |
} | |
async saveProject(outputPath) { | |
if (!this.rawXml) { | |
throw new Error('No project loaded to save'); | |
} | |
try { | |
// Ensure SoapUI 5.5.0 namespace is present | |
if (!this.rawXml['con:soapui-project']['$']) { | |
this.rawXml['con:soapui-project']['$'] = {}; | |
} | |
this.rawXml['con:soapui-project']['$']['xmlns:con'] = 'http://eviware.com/soapui/config'; | |
// Generate XML | |
let xmlOutput = this.builder.buildObject(this.rawXml); | |
// SoapUI 5.5.0 specific formatting | |
xmlOutput = xmlOutput | |
.replace(/^\s*[\r\n]/gm, '\n') // Clean up empty lines | |
.replace(/\r\n/g, '\n'); // Normalize line endings | |
await fs.promises.writeFile(outputPath, xmlOutput, 'utf8'); | |
return true; | |
} catch (error) { | |
throw new Error(`Failed to save project: ${error.message}`); | |
} | |
} | |
} | |
// Example usage | |
async function main() { | |
const parser = new SoapUIProjectParser(); | |
try { | |
// Load existing project | |
await parser.loadProject('./original-project.xml'); | |
// Specify test cases to enable (all others will be disabled) | |
const testCasesToEnable = ['Login Test', 'Validate User']; | |
// Apply changes | |
const summary = parser.setTestCasesStatus(testCasesToEnable); | |
// Log changes | |
console.log('Modification Summary:', JSON.stringify(summary, null, 2)); | |
// Save modified project | |
await parser.saveProject('./modified-project.xml'); | |
console.log('Project successfully modified and saved!'); | |
} catch (error) { | |
console.error('Error:', error.message); | |
process.exit(1); | |
} | |
} | |
module.exports = SoapUIProjectParser; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const xml2js = require('xml2js'); | |
class SoapUIProjectParser { | |
constructor() { | |
// Configure parser to preserve everything | |
this.parser = new xml2js.Parser({ | |
explicitArray: false, | |
preserveChildrenOrder: true, | |
xmldec: { 'version': '1.0', 'encoding': 'UTF-8' }, | |
// Preserve all attributes and formatting | |
attrNameProcessors: [], | |
attrValueProcessors: [], | |
tagNameProcessors: [], | |
valueProcessors: [] | |
}); | |
// Configure builder to maintain exact format | |
this.builder = new xml2js.Builder({ | |
renderOpts: { pretty: true }, | |
xmldec: { 'version': '1.0', 'encoding': 'UTF-8' }, | |
// Keep original formatting | |
headless: true, | |
rootName: 'con:soapui-project' | |
}); | |
} | |
async modifyTestCases(inputFile, outputFile, testCaseNames) { | |
try { | |
// Read the original file content | |
const originalContent = await fs.promises.readFile(inputFile, 'utf8'); | |
// Parse while preserving everything | |
let project = await this.parser.parseStringPromise(originalContent); | |
const summary = { | |
enabled: [], | |
disabled: [], | |
notFound: [...testCaseNames] | |
}; | |
// Handle both single testSuite and array of testSuites | |
const testSuites = project['con:soapui-project']['con:testSuite']; | |
const testSuiteArray = Array.isArray(testSuites) ? testSuites : [testSuites]; | |
testSuiteArray.forEach(testSuite => { | |
if (testSuite && testSuite['con:testCase']) { | |
// Handle both single testCase and array of testCases | |
const testCases = Array.isArray(testSuite['con:testCase']) | |
? testSuite['con:testCase'] | |
: [testSuite['con:testCase']]; | |
testCases.forEach(testCase => { | |
if (testCase && testCase['$']) { | |
const testCaseName = testCase['$']['name']; | |
const shouldEnable = testCaseNames.includes(testCaseName); | |
// Only modify the disabled attribute | |
testCase['$']['disabled'] = (!shouldEnable).toString(); | |
// Update summary | |
if (shouldEnable) { | |
summary.enabled.push(testCaseName); | |
summary.notFound = summary.notFound.filter(name => name !== testCaseName); | |
} else { | |
summary.disabled.push(testCaseName); | |
} | |
} | |
}); | |
} | |
}); | |
// Get the XML declaration from original file | |
const xmlDeclaration = originalContent.split('\n')[0]; | |
// Build the modified XML while preserving everything else | |
let modifiedContent = this.builder.buildObject(project); | |
// Ensure we keep the original XML declaration | |
modifiedContent = xmlDeclaration + '\n' + modifiedContent; | |
// Write back to file | |
await fs.promises.writeFile(outputFile, modifiedContent); | |
return summary; | |
} catch (error) { | |
throw new Error(`Failed to process SoapUI project: ${error.message}`); | |
} | |
} | |
} | |
// Example usage | |
async function main() { | |
try { | |
const parser = new SoapUIProjectParser(); | |
const result = await parser.modifyTestCases( | |
'original-project.xml', // Input file | |
'modified-project.xml', // Output file | |
['Login Test', 'Payment Validation'] // Test cases to enable | |
); | |
console.log('Modification Summary:', result); | |
} catch (error) { | |
console.error('Error:', error.message); | |
} | |
} | |
module.exports = SoapUIProjectParser; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const xml2js = require('xml2js'); | |
const path = require('path'); | |
class SoapUIProjectParser { | |
constructor() { | |
this.parser = new xml2js.Parser(); | |
this.SOAPUI_NS = 'http://eviware.com/soapui/config'; | |
} | |
async parseProject(filePath) { | |
try { | |
const xmlData = await fs.promises.readFile(filePath, 'utf8'); | |
const result = await this.parser.parseStringPromise(xmlData); | |
return this.extractProjectInfo(result); | |
} catch (error) { | |
throw new Error(`Failed to parse SoapUI project: ${error.message}`); | |
} | |
} | |
getSafeValue(obj, key, defaultValue = '') { | |
return obj && obj[key] ? obj[key] : defaultValue; | |
} | |
getArraySafe(obj, key) { | |
return obj && Array.isArray(obj[key]) ? obj[key] : []; | |
} | |
extractProjectInfo(parsedXml) { | |
const projectKey = 'con:soapui-project'; | |
const project = parsedXml[projectKey] || {}; | |
const attributes = project['$'] || {}; | |
return { | |
projectInfo: { | |
name: this.getSafeValue(attributes, 'name'), | |
id: this.getSafeValue(attributes, 'id'), | |
created: this.getSafeValue(attributes, 'created'), | |
updated: this.getSafeValue(attributes, 'updated'), | |
version: this.getSafeValue(attributes, 'soapui-version', '5.5.0') | |
}, | |
testSuites: this.extractTestSuites(this.getArraySafe(project, 'con:testSuite')), | |
endpoints: this.extractEndpoints(this.getArraySafe(project, 'con:interface')), | |
properties: this.extractProperties( | |
this.getArraySafe(project['con:properties'] || [], 'con:property') | |
) | |
}; | |
} | |
extractTestSuites(testSuites) { | |
return testSuites.map(suite => { | |
const attributes = suite['$'] || {}; | |
return { | |
name: this.getSafeValue(attributes, 'name'), | |
id: this.getSafeValue(attributes, 'id'), | |
testCases: this.extractTestCases(this.getArraySafe(suite, 'con:testCase')) | |
}; | |
}); | |
} | |
extractTestCases(testCases) { | |
return testCases.map(testCase => { | |
const attributes = testCase['$'] || {}; | |
return { | |
name: this.getSafeValue(attributes, 'name'), | |
id: this.getSafeValue(attributes, 'id'), | |
steps: this.extractTestSteps(this.getArraySafe(testCase, 'con:testStep')) | |
}; | |
}); | |
} | |
extractTestSteps(testSteps) { | |
return testSteps.map(step => { | |
const attributes = step['$'] || {}; | |
return { | |
type: this.getSafeValue(attributes, 'type'), | |
name: this.getSafeValue(attributes, 'name'), | |
id: this.getSafeValue(attributes, 'id'), | |
config: this.extractStepConfig(step) | |
}; | |
}); | |
} | |
extractStepConfig(step) { | |
const config = {}; | |
const stepConfig = (step['con:config'] || [])[0] || {}; | |
if (stepConfig['con:request'] && stepConfig['con:request'][0]) { | |
const request = stepConfig['con:request'][0]; | |
const requestAttributes = request['$'] || {}; | |
config['request'] = { | |
endpoint: this.getSafeValue(requestAttributes, 'endpoint'), | |
method: this.getSafeValue(requestAttributes, 'method'), | |
parameters: this.extractParameters( | |
this.getArraySafe(request['con:parameters'] && request['con:parameters'][0], 'con:parameter') | |
), | |
// SoapUI 5.5.0 specific fields | |
mediaType: this.getSafeValue(requestAttributes, 'mediaType'), | |
postQueryString: this.getSafeValue(requestAttributes, 'postQueryString', false), | |
timeout: this.getSafeValue(requestAttributes, 'timeout', '0'), | |
followRedirects: this.getSafeValue(requestAttributes, 'followRedirects', 'true'), | |
encoding: this.getSafeValue(requestAttributes, 'encoding', 'UTF-8') | |
}; | |
} | |
if (stepConfig['con:assertions'] && stepConfig['con:assertions'][0]) { | |
config['assertions'] = this.extractAssertions(stepConfig['con:assertions'][0]); | |
} | |
// SoapUI 5.5.0 specific configurations | |
if (stepConfig['con:credentials'] && stepConfig['con:credentials'][0]) { | |
config['credentials'] = this.extractCredentials(stepConfig['con:credentials'][0]); | |
} | |
return config; | |
} | |
extractParameters(parameters) { | |
return parameters.map(param => { | |
const attributes = param['$'] || {}; | |
return { | |
name: this.getSafeValue(attributes, 'name'), | |
value: this.getSafeValue(attributes, 'value'), | |
type: this.getSafeValue(attributes, 'type', 'string'), | |
// SoapUI 5.5.0 specific fields | |
style: this.getSafeValue(attributes, 'style', 'PLAIN'), | |
required: this.getSafeValue(attributes, 'required', 'false'), | |
defaultValue: this.getSafeValue(attributes, 'default') | |
}; | |
}); | |
} | |
extractAssertions(assertions) { | |
const assertionTypes = [ | |
'con:XPathAssertion', | |
'con:ResponseSLAAssertion', | |
'con:SimpleContainsAssertion', | |
'con:ValidHttpStatusCodesAssertion', | |
'con:JsonPathAssertion', // Added for 5.5.0 | |
'con:GroovyScriptAssertion', // Added for 5.5.0 | |
'con:RestResponseStatusAssertion' // Added for 5.5.0 | |
]; | |
return assertionTypes.reduce((acc, type) => { | |
const typeAssertions = this.getArraySafe(assertions, type); | |
if (typeAssertions.length > 0) { | |
acc.push(...typeAssertions.map(assertion => ({ | |
type: type.replace('con:', ''), | |
...this.extractAssertionDetails(assertion) | |
}))); | |
} | |
return acc; | |
}, []); | |
} | |
extractAssertionDetails(assertion) { | |
const details = {}; | |
if (assertion['con:xpath']) { | |
details['xpath'] = this.getSafeValue(assertion['con:xpath'], '0'); | |
} | |
if (assertion['con:expression']) { | |
details['expression'] = this.getSafeValue(assertion['con:expression'], '0'); | |
} | |
if (assertion['con:sla']) { | |
details['sla'] = this.getSafeValue(assertion['con:sla'], '0'); | |
} | |
// SoapUI 5.5.0 specific assertion details | |
if (assertion['con:jsonPath']) { | |
details['jsonPath'] = this.getSafeValue(assertion['con:jsonPath'], '0'); | |
} | |
if (assertion['con:script']) { | |
details['script'] = this.getSafeValue(assertion['con:script'], '0'); | |
} | |
return details; | |
} | |
extractEndpoints(interfaces) { | |
return interfaces.map(intf => { | |
const attributes = intf['$'] || {}; | |
const endpoints = this.getArraySafe( | |
intf['con:endpoints'] && intf['con:endpoints'][0], | |
'con:endpoint' | |
); | |
return { | |
name: this.getSafeValue(attributes, 'name'), | |
type: this.getSafeValue(attributes, 'type'), | |
endpoints: endpoints.map(endpoint => this.getSafeValue(endpoint['$'], 'url')) | |
}; | |
}); | |
} | |
extractProperties(properties) { | |
return properties.map(prop => { | |
const attributes = prop['$'] || {}; | |
return { | |
name: this.getSafeValue(attributes, 'name'), | |
value: this.getSafeValue(attributes, 'value'), | |
// SoapUI 5.5.0 specific fields | |
type: this.getSafeValue(attributes, 'type', 'string'), | |
isEncrypted: this.getSafeValue(attributes, 'encrypted', 'false') | |
}; | |
}); | |
} | |
extractCredentials(credentials) { | |
return { | |
username: this.getSafeValue(credentials['con:username'], '0'), | |
password: this.getSafeValue(credentials['con:password'], '0'), | |
domain: this.getSafeValue(credentials['con:domain'], '0'), | |
authType: this.getSafeValue(credentials['$'], 'authType', 'No Authorization') | |
}; | |
} | |
} | |
// Example usage | |
async function main() { | |
const parser = new SoapUIProjectParser(); | |
try { | |
const projectInfo = await parser.parseProject('path/to/your/soapui-project.xml'); | |
console.log(JSON.stringify(projectInfo, null, 2)); | |
} catch (error) { | |
console.error('Error parsing project:', error.message); | |
} | |
} | |
module.exports = SoapUIProjectParser; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment