Source: TestResult.js

/**
 * Represents the result of a test
 */
class TestResult {
    /**
     * @param {Test} test - The test that generated these results
     */
    constructor(test) {
        this._test = test;
        this._interactionResults = [];
    }

    /**
     * Add one interaction result in the list of results for this test
     * @param {InteractionResult} interactionResult - The interaction result to add
     */
    addInteractionResult(interactionResult) {
        this._interactionResults.push(interactionResult);
    }

    /**
     * Get the list of interaction results for this test
     * @return {InteractionResult[]} The interaction results for this test
     */
    get interactionResults() {
        return this._interactionResults;
    }

    /****
     * Set the list of interaction results for this test
     * @param {InteractionResult[]} results - The list of interaction results for this test
     */
    set interactionResults(results) {
        this._interactionResults = results;
    }

    /**
     * Indicates if the current test was skipped, the cause could be that it was manually skipped or there was
     * an external error on the process
     * @return {boolean}
     */
    get skipped() {
        if (this.test && this.test.testSuite && this.test.testSuite.ignoreExternalErrors) {
            const errorOnProcess = this.interactionResults.some(r => r.error && r.error.error_category === "system");
            return this.test.skip || errorOnProcess;
        }
        return this.test.skip;
    }

    /**
     * Returns true if all of the interactions in this test have passed, false otherwise
     * @return {boolean}
     */
    get passed() {
        for (const result of this.interactionResults) {
            if (!result.passed) {
                return false;
            }
        }
        return true;
    }

    /**
     * Returns the Test that generated these results
     * @return {Test} the Test that generated these results
     */
    get test() {
        return this._test;
    }

    /**
     * Returns the locale of the current test results
     * @return {string} the locale of the current test results
     */
    get locale() {
        return this._locale;
    }

    /****
     * Set the locale of the current results
     * @param {string} locale - the locale of the current results
     */
    set locale(locale) {
        this._locale = locale;
    }

    /**
     * returns a non circular DTO version of the testResult object
     * @return {object}
     */
    toDTO() {
        return {
            conversationId: this.conversationId,
            interactionResults: this.interactionResults.map(interactionResult => interactionResult.toDTO()),
            locale: this.locale,
            passed: this.passed,
            skipped: this.skipped,
            test: this.test.toDTO(),
        };
    }
}

/**
 * Represents the result for a single interaction
 */
class InteractionResult {
    /**
     * @param {TestInteraction} interaction - The interaction that generated these results
     * @param {Assertion} assertion - The evaluated assertion
     * @param {Error|string} error - the possible error
     * @param {boolean} errorOnProcess - indicates if there was an external error while processing the interaction
     * @param {Date} timestamp - the timestamp of when the interaction was processed
     */
    constructor(interaction, assertion, error, errorOnProcess, timestamp) {
        this._interaction = interaction;
        this._assertion = assertion;
        this._error = error;
        this._errorOnProcess = errorOnProcess;
        this._timestamp = timestamp ? timestamp : new Date();
    }

    /**
     * returns the interaction that generated this result
     * @return {TestInteraction}
     */
    get interaction() {
        return this._interaction;
    }

    /**
     * returns the evaluated assertion
     * @return {Assertion}
     */
    get assertion() {
        return this._assertion;
    }

    /**
     * returns true if this assertion have a goto
     * @return {boolean}
     */
    get goto() {
        if (this._assertion && this._assertion.goto) {
            return this._assertion.goto;
        }
        return undefined;
    }

    /**
     * returns true if this assertion have the exit command
     * @return {boolean}
     */
    get exited() {
        return this._assertion && this._assertion.exit;
    }

    /**
     * returns true if this interaction has its assertion passed correctly
     * @return {boolean}
     */
    get passed() {
        return this._error === undefined && this._errors === undefined;
    }

    /**
     * returns a generated Error object from the assertion if the interaction failed
     * @return {Error}
     */
    get error() {
        return this._error;
    }

    /**
     * returns an error generated unrelated to the assertion if the interaction throws an exception during the process
     * @return {Error}
     */
    get errorOnProcess() {
        return this._errorOnProcess;
    }

    /**
     * returns the error message to print for the user
     * @return {string}
     */
    get errorMessage() {
        if (this._error && this._error instanceof Error) {
            return this._error.message + "\n" + this._error.stack;
        }

        if (this._error && this._error.error) {
            return this._error.error;
        }

        return this._error;
    }

    /**
     * returns the timestamp of when this interaction was executed
     * @return {string}
     */
    get timestamp() {
        return this._timestamp;
    }

    /**
     * returns the raw response that was evaluated during the interaction
     * @return {object}
     */
    set rawResponse(value) {
        this._rawResponse = value;
    }

    /**
     * Add errors in case we are dealing with multiple errors per Interaction
     * @param {string} error - The error message added
     */
    addError(error) {
        if (!this._errors) {
            this._errors = [];
        }
        this._errors.push(error);
    }

    /**
     * Get errors in case we are dealing with multiple errors per Interaction
     * @return {string[]}
     */
    get errors() {
        return this._errors;
    }

    /**
     * returns a non circular DTO version of the interaction object
     * @return {object}
     */
    toDTO() {
        return {
            errorMessage: this.errorMessage,
            errorOnProcess: this._errorOnProcess,
            error_category: this.error && this.error.error_category,
            errors: this.errors,
            exited: this.exited,
            passed: this.passed,
            rawResponse: this._rawResponse,
        };
    }
}

exports.TestResult = TestResult;
exports.InteractionResult = InteractionResult;