Untitled
unknown
plain_text
10 months ago
9.7 kB
6
Indexable
import XAPI_VALIDATION_TYPES from '../constants/xApiConstants';
const fs = require('fs');
const path = require('path');
const eventReporter = require('./eventReporter');
const config = require('../../config');
class EventValidator {
lastPostData = '';
occuranceNum = 0;
testcase = {};
eventTestCases = [];
results = [];
eventData = {};
/**
* Parse testcase from csv with the following format
* |testcasename|scope|jsonPath(name)|expectedvalue|validationtype|identifiertype|
* @param {*} testCaseFile csv file to be parsed
* @param {*} testId testId for this test
* @param {*} testCaseName name of testcase
*/
constructor(testCaseFile, testId, testCaseName) {
this.testcases = [];
this.testId = testId;
this.testCaseName = testCaseName;
fs.readFile(
path.join(config.testData_root, 'events', 'testcases', testCaseFile),
'utf-8',
(err, data) => {
if (err) throw err.message;
const lines = data.split('\n');
const headers = lines[0].split(',');
let eventTestCaseName = '';
for (let i = 1; i < lines.length; i += 1) {
// parse the line that has comma within delimited comma
const lineWithoutEnclosedComma = this.parseValueEnclosedWithComma(
lines[i],
);
const lineData = lineWithoutEnclosedComma.split(',');
const eventTestCase = {};
const testcaseName = lineData[0];
const scope = lineData[1];
if (testcaseName !== '') {
// eslint-disable-next-line prefer-destructuring
eventTestCaseName = `${scope}|${testcaseName}`;
const newEventTestCase = {};
newEventTestCase[eventTestCaseName] = [];
this.testcases.push(newEventTestCase);
}
for (let j = 1; j < headers.length; j += 1) {
eventTestCase[headers[j]] = lineData[j].split('`').join(',');
}
this.testcases[this.testcases.length - 1][eventTestCaseName].push(
eventTestCase,
);
}
},
);
}
/**
* Replace the comma for line that has comma within delimited comma with another character
* Replace double quote for the line that has comma within delimited comma with single quote
* @param {string} line line to be parsed
* @return {string} parsed line
*/
parseValueEnclosedWithComma(line) {
let startingIndex = line.indexOf(',"');
let priorStartingIndex = startingIndex;
const startingIndex2 = startingIndex + 1;
let newLine = line;
do {
if (startingIndex >= 0) {
priorStartingIndex = startingIndex;
newLine =
newLine.substring(0, startingIndex + 1) +
newLine.substring(startingIndex + 2);
startingIndex = newLine.indexOf('""', startingIndex);
}
} while (startingIndex >= 0);
const endingIndex = newLine.indexOf('",', priorStartingIndex);
newLine =
endingIndex >= 0
? newLine.substring(0, endingIndex) + newLine.substring(endingIndex + 1)
: newLine;
const enclosedValueWithComma = newLine.substring(
startingIndex2,
endingIndex,
);
const enclosedValueWithoutComma = enclosedValueWithComma.replace(/,/g, '`');
const lineWithoutEnclosedComma =
newLine.substring(0, startingIndex2) +
enclosedValueWithoutComma +
newLine.substring(endingIndex);
return lineWithoutEnclosedComma;
}
/**
* Enable CDP network plugin to track network events
*/
async enableCDP() {
browser.cdp('Network', 'enable');
}
/**
* Add event listener
*/
async addEventListener() {
browser.on('Network.requestWillBeSent', (params) => {
const { postData } = params.request;
// eslint-disable-next-line prefer-destructuring
this.testcase = this.testcases[0];
if (this.testcase) {
const keys = Object.keys(this.testcase);
const eventTestCaseName = keys[0];
const scope = eventTestCaseName.split('|')[0];
if (postData && postData.includes(scope)) {
let postDataJson;
try {
postDataJson = JSON.parse(postData);
} catch (error) {
//
}
if (postDataJson && postDataJson.object) {
if (this.occuranceNum < 1 && this.lastPostData !== postData) {
this.validateEvent(eventTestCaseName, postData, postDataJson);
}
this.occuranceNum =
this.lastPostData === postData ? (this.occuranceNum = +1) : 0;
}
}
}
});
}
/**
* Validate events
* - validation types:
* - baseline: use as the baseline for validation type 'same value as previous request'
* and 'not same value as previous request'
* - same value as previous request: validate value should be same with actual value saved from last event
* - not same value as previous request: validate value should be different with actual value saved from last event
* - exact: validate value is exactly equal to specified expected value in csv testcase
* - pattern: validate value has same pattern as specified expected pattern in csv testcase
* - variable: validate value is the same as the value saved in specified variable in csv testcase
* - boolean: validate value is the same as the specified boolean value in csv testcase
* @param {*} eventTestCaseName event test case name on csv
* @param {*} postData post data of the event
* @param {*} postDataJson post data of the event in json
*/
async validateEvent(eventTestCaseName, postData, postDataJson) {
this.eventTestCases = this.testcase[eventTestCaseName];
const eventTestResults = {};
const eventResults = [];
let passResultsCount = 0;
for (const eventTestCase of this.eventTestCases) {
const result = {};
result.eventTestCase = eventTestCase;
const { name, value, type } = eventTestCase;
// if name is skip, simply skip and do not validate the event
if (name !== 'skip') {
// transerve json path from delimited name to find the actual value
const paths = name.split('|');
let subjson = postDataJson[paths[0]];
for (let i = 1; i < paths.length; i += 1) {
subjson = subjson[paths[i]];
// if json path is not found, report missing element
if (subjson === undefined) {
result.actualValue = 'Missing element';
break;
}
}
// if json path is found, validate actual value against expected value from testcase
if (subjson !== undefined) {
// if actual value is object, then stringify
subjson =
typeof subjson === 'object'
? JSON.stringify(subjson)
: subjson.toString();
result.actualValue = subjson;
// validation for different validation type
switch (type) {
case XAPI_VALIDATION_TYPES.BASELINE:
result.status = 'Pass';
this.eventData[name] = result.actualValue;
break;
case XAPI_VALIDATION_TYPES.SAME_AS_PREVIOUS_REQUEST:
result.status =
subjson === this.eventData[name] ? 'Pass' : 'Fail';
result.eventTestCase.value = this.eventData[name];
break;
case XAPI_VALIDATION_TYPES.NOT_SAME_AS_PREVIOUS_REQUEST:
result.status =
subjson !== this.eventData[name] ? 'Pass' : 'Fail';
eventTestCase.value = `not same as ${this.eventData[name]}`;
this.eventData[name] = subjson;
break;
case XAPI_VALIDATION_TYPES.EXACT:
result.status = subjson === value ? 'Pass' : 'Fail';
break;
case XAPI_VALIDATION_TYPES.VARIABLE:
// eslint-disable-next-line no-case-declarations
const valueFromGame = global.xApiVariables[this.testId][value];
result.eventTestCase.value = valueFromGame;
result.status = subjson === valueFromGame ? 'Pass' : 'Fail';
break;
case XAPI_VALIDATION_TYPES.BOOLEAN:
result.status = subjson === value.toLowerCase() ? 'Pass' : 'Fail';
break;
case XAPI_VALIDATION_TYPES.PATTERN:
result.status = new RegExp(value).test(subjson) ? 'Pass' : 'Fail';
break;
default:
result.status = 'Fail';
this.eventData[name] = result.actualValue;
result.actualValue = 'unrecognized validation type';
break;
}
}
passResultsCount =
result.status === 'Pass' ? passResultsCount + 1 : passResultsCount;
eventResults.push(result);
}
}
// setting event test results attribute to be used in report
eventTestResults[eventTestCaseName] = eventResults;
// eslint-disable-next-line prefer-destructuring
eventTestResults.testCaseName = eventTestCaseName;
eventTestResults.passResultsCount = passResultsCount;
eventTestResults.failResultsCount = eventResults.length - passResultsCount;
if (eventResults.length > 0) this.results.push(eventTestResults);
// shift to next test case
this.testcases.shift();
this.lastPostData = postData;
}
/**
* Generate result and report for this test
*/
async generateResult() {
await eventReporter.registerGameEvents(this.testCaseName, this.results);
await eventReporter.generateTestCaseReport(this.testCaseName);
}
}
module.exports = EventValidator;
Editor is loading...
Leave a Comment