UNPKG

@serenity-js/core

Version:

The core Serenity/JS framework, providing the Screenplay Pattern interfaces, as well as the test reporting and integration infrastructure

174 lines 6.85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExecutionSuccessful = exports.ExecutionSkipped = exports.ExecutionIgnored = exports.ImplementationPending = exports.ExecutionFailedWithAssertionError = exports.ExecutionFailedWithError = exports.ExecutionCompromised = exports.ProblemIndication = exports.Outcome = void 0; const tiny_types_1 = require("tiny-types"); const index_js_1 = require("../errors/index.js"); class Outcome extends tiny_types_1.TinyType { code; /** * Symbol used to brand Outcome instances for cross-module instanceof checks. * This addresses the dual-package hazard where the same class loaded from * both ESM and CJS creates distinct constructor functions. */ static TYPE_BRAND = Symbol.for('@serenity-js/core/Outcome'); /** * Custom instanceof check that works across module boundaries. * This addresses the dual-package hazard where the same class loaded from * both ESM and CJS creates distinct constructor functions. * * The check walks up the prototype chain of the instance and compares * constructor names, which remain consistent across module boundaries. */ static [Symbol.hasInstance](instance) { if (instance === null || typeof instance !== 'object') { return false; } // First, verify this is an Outcome instance using the brand if (instance[Outcome.TYPE_BRAND] !== true) { return false; } // When checking against the base Outcome class, any branded instance qualifies if (this.name === 'Outcome') { return true; } // For subclass checks, walk the prototype chain and compare by name // This works across ESM/CJS boundaries where constructor references differ let proto = Object.getPrototypeOf(instance); while (proto !== null) { if (proto.constructor?.name === this.name) { return true; } proto = Object.getPrototypeOf(proto); } return false; } static fromJSON = (o) => (0, tiny_types_1.match)(o.code) .when(ExecutionCompromised.Code, _ => ExecutionCompromised.fromJSON(o)) .when(ExecutionFailedWithError.Code, _ => ExecutionFailedWithError.fromJSON(o)) .when(ExecutionFailedWithAssertionError.Code, _ => ExecutionFailedWithAssertionError.fromJSON(o)) .when(ImplementationPending.Code, _ => ImplementationPending.fromJSON(o)) .when(ExecutionIgnored.Code, _ => ExecutionIgnored.fromJSON(o)) .when(ExecutionSkipped.Code, _ => ExecutionSkipped.fromJSON(o)) .when(ExecutionSuccessful.Code, _ => ExecutionSuccessful.fromJSON(o)) .else(_ => { throw new Error(`Outcome could not be deserialised: ${JSON.stringify(o)}`); }); constructor(code) { super(); this.code = code; // Brand the instance for cross-module instanceof checks this[Outcome.TYPE_BRAND] = true; } isWorseThan(another) { const code = (another instanceof Outcome) ? another.code : another.Code; return this.code < code; } toJSON() { return { code: this.code, }; } } exports.Outcome = Outcome; class ProblemIndication extends Outcome { error; constructor(error, code) { super(code); this.error = error; } toJSON() { return { code: this.code, error: index_js_1.ErrorSerialiser.serialise(this.error), }; } } exports.ProblemIndication = ProblemIndication; /** * Indicates a failure due to external events or systems that compromise the validity of the test. */ class ExecutionCompromised extends ProblemIndication { static Code = 1 << 0; static fromJSON = (o) => new ExecutionCompromised(index_js_1.ErrorSerialiser.deserialise(o.error)); constructor(error) { super(error, ExecutionCompromised.Code); } } exports.ExecutionCompromised = ExecutionCompromised; /** * Indicates a failure due to an error other than recognised external system and assertion failures */ class ExecutionFailedWithError extends ProblemIndication { static Code = 1 << 1; static fromJSON = (o) => new ExecutionFailedWithError(index_js_1.ErrorSerialiser.deserialise(o.error)); constructor(error) { super(error, ExecutionFailedWithError.Code); } } exports.ExecutionFailedWithError = ExecutionFailedWithError; /** * Execution of an Activity or Scene has failed due to an assertion error; */ class ExecutionFailedWithAssertionError extends ProblemIndication { static Code = 1 << 2; static fromJSON = (o) => new ExecutionFailedWithAssertionError(index_js_1.ErrorSerialiser.deserialise(o.error)); constructor(error) { super(error, ExecutionFailedWithAssertionError.Code); } } exports.ExecutionFailedWithAssertionError = ExecutionFailedWithAssertionError; /** * A pending Activity is one that has been specified but not yet implemented. * A pending Scene is one that has at least one pending Activity. */ class ImplementationPending extends ProblemIndication { static Code = 1 << 3; static fromJSON = (o) => new ImplementationPending(index_js_1.ErrorSerialiser.deserialise(o.error)); constructor(error) { super(error, ImplementationPending.Code); } } exports.ImplementationPending = ImplementationPending; /** * The result of the scenario should be ignored, most likely because it's going to be retried. */ class ExecutionIgnored extends ProblemIndication { static Code = 1 << 4; static fromJSON = (o) => new ExecutionIgnored(index_js_1.ErrorSerialiser.deserialise(o.error)); constructor(error) { super(error, ExecutionIgnored.Code); } } exports.ExecutionIgnored = ExecutionIgnored; /** * The Activity was not executed because a previous one has failed. * A whole Scene can be marked as skipped to indicate that it is currently "work-in-progress" */ class ExecutionSkipped extends Outcome { error; static Code = 1 << 5; static fromJSON = (o) => new ExecutionSkipped(o.error && index_js_1.ErrorSerialiser.deserialise(o.error)); constructor(error) { super(ExecutionSkipped.Code); this.error = error; } toJSON() { return { code: this.code, error: this.error && index_js_1.ErrorSerialiser.serialise(this.error), }; } } exports.ExecutionSkipped = ExecutionSkipped; /** * Scenario or activity ran as expected. */ class ExecutionSuccessful extends Outcome { static Code = 1 << 6; static fromJSON = (o) => new ExecutionSuccessful(); constructor() { super(ExecutionSuccessful.Code); } } exports.ExecutionSuccessful = ExecutionSuccessful; //# sourceMappingURL=outcomes.js.map