FromCallbackScenario is a Module Scenario that allows you to test all of the business requirements of a given module, function, or section of code. You should use this module when your entry point function returns its results through a callback.

We saw with the HttpRequestScenario, that it was able to test the response itself. This isn't possible with Module Scenarios. With the Module Scenarios, you will need to provide a function to test the results yourself. You do this by passing your function into the .test function. You can see an example of this below.

Important Notes

  • You do NOT provide a callback in your inputParams. Maddox will automatically provide a function as the last parameter into your entry point function.
  • Below there are only two parameters passed into the testing function. Rest assured, the FromCallbackScenario will pass all of the parameters expected in your callback.
  • You will see that our DB Proxy is still returning a Promise. This doesn't mean that our module must return a promise though. You can see here that we can still test a callback scenario when lower level proxy functionality returns a Promise or synchronously.
const Maddox = require("maddox");

const Scenario = Maddox.scenarios.FromCallbackScenario;

describe("When testing a function that uses a callback.", () => {

  let context;

  beforeEach(() => {
    context = {};

    context.setupEntryPoint = () => {
      context.entryPointObject = MyModule; // The entry point of our module.
      context.entryPointFunction = "entryPoint";
    };

    context.setupInputParams = () => {
      context.inputParams = {
        dataToSave: {foo: "foo"}
      };
    };

    context.setupDbProxy = () => {
      // When reusing parameters it is best practice to copy them to ensure the referenced data changes are not causing...
      // unexpected errors in your tests.  Maddox will do this for you, but it is good to make it obvious in your test.
      context.dbProxyParams = JSON.parse(JSON.stringify(context.inputParams));
      context.dbProxyResponse = {code: 200};
    };

    context.setupExpected = () => {
      context.expectedResponse = {success: true};
      context.expectedStatusCode = 200;
    };
  });

  it("it should send data to the database.", function (done) {

    context.setupEntryPoint();
    context.setupInputParams();
    context.setupDbProxy();
    context.setupExpected();

    new Scenario(this)
      .mockThisFunction("DbProxy", "save", DbProxy)

      .withEntryPoint(context.entryPointObject, context.entryPointFunction)
      .withInputParams([context.inputParams])

      .shouldBeCalledWith("DbProxy", "save", [context.dbProxyParams])
      .doesReturnWithPromise("DbProxy", "save", context.dbProxyResponse)
      
      .test(function (err, response) {
      	Maddox.compare.shouldEqual({actual: err, expected: undefined});
        Maddox.compare.shouldEqual({actual: response, expected: testContext.expectedResponse});
        done();
      }).catch(function (err) {
        done(err);
      });
  });

  it("it should process the error from the database.", function (done) {

    context.setupDbProxy = () => {
      const dbError = new Error("Failed to save data.");

      dbError.code = 12345;

      // When reusing parameters it is best practice to copy them to ensure the referenced data changes are not causing...
      // unexpected errors in your tests.  Maddox will do this for you, but it is good to make it obvious in your test.
      context.dbProxyParams = JSON.parse(JSON.stringify(context.inputParams));
      context.dbProxyResponse = dbError;
    };

    // Let's pretend that our code returns the error code from the db in our response when the database fails.
    context.setupExpected = () => {
      context.expectedResponse = {success: true, code: 12345};
      context.expectedStatusCode = 500;
    };

    context.setupEntryPoint();
    context.setupInputParams();
    context.setupDbProxy();
    context.setupExpected();

    new Scenario(this)
      .mockThisFunction("DbProxy", "save", DbProxy)

      .withEntryPoint(context.entryPointObject, context.entryPointFunction)
      .withInputParams([context.inputParams])

      // Notice that we have changed this to "doesErrorWithPromise" instead of "doesReturnWithPromise"...
      // since we are testing a scenario for the DbProxy to error.
      .shouldBeCalledWith("DbProxy", "save", [context.dbProxyParams])
      .doesErrorWithPromise("DbProxy", "save", context.dbProxyResponse)
      
      .test(function (err, response) {
      	Maddox.compare.shouldEqual({actual: err, expected: undefined});
        Maddox.compare.shouldEqual({actual: response, expected: testContext.expectedResponse});
        done();
      }).catch(function (err) {
        done(err);
      });
  });
});