Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing onChange event with async code #93

Open
lalberto8085 opened this issue Apr 2, 2024 · 3 comments
Open

Testing onChange event with async code #93

lalberto8085 opened this issue Apr 2, 2024 · 3 comments

Comments

@lalberto8085
Copy link

Hello,

I'm starting to use this for unit testing my front end code, so I need some help moving forward.

I have a Date attribute that will make an Xrm.WebApi.retrieveMultipleRecords call on the onChange handler. I saw the code sample on how to use sinon to mock the call, but it is sill async and I can't await it since fireOnChange is not "awaitable" (AFAIK).

Please point me in the right direction if there's any techniques or design patterns I'm missing.
Thanks in advace

@BetimBeja
Copy link
Contributor

How would you "await" the call in Dynamics? That is a promise and you can implement your logic in the "then" function. But there might be tricky situations that you might need to consider... like multiple updates before receiving a response.

@lalberto8085
Copy link
Author

Thanks for your response.

In this particular case I am able to get the data I need on the onLoad event, but
What happens if I need to load data when a field is changed on the form?
Is there any pattern I can use?

As for getting ready for successive changes, how could we test this? I'm just trying to learn, so if you can point me somewhere I'd be very grateful

@maichopra
Copy link

I think I understand what you are asking.
Here is an example of what I think you are trying to write, and how to test it.

Let me know if this is not what you were after, but if it is feel free to close the issue.

Code

var TST = TST || {}; //Set namespace with client or project initials

TST.Contact = {
    //Table - in this example, we are working with the Contact table

    //OnLoad events
    onLoad: function (executionContext) {
        "use strict";
        var formContext = executionContext.getFormContext();

        //On Load events - formatForm function used as a container to hold all functions you would like to run onLoad that format the form.
        TST.Contact.formatForm(executionContext);

        //On Change events
        formContext.getAttribute("tst_filterrecord").addOnChange(this.asyncAPI);
    },

    //On Save events
    onSave: function (executionContext) {
        "use strict";
    },

    //List all the functions you would like to run onLoad, related to formatting the form.
    formatForm: function (executionContext) {
        "use strict";
        var formContext = executionContext.getFormContext();
    },

    asyncAPI: async function (executionContext) {
        "use strict";
        var formContext = executionContext.getFormContext();

        var filterRecord = formContext.getAttribute("tst_filterrecord").getValue();
        var filterRecordID = filterRecord[0].id;

        await Xrm.WebApi.retrieveRecord("tst_searchentity", filterRecordID, "?$select=tst_name").then(
            function success(result) {
                console.log(result);
                // Columns
                const filterRecordName = result["tst_name"];

                // Set the field to the name of the returned record
                formContext.getAttribute("tst_targetfield").setValue(filterRecordName);
            },
            function (error) {
                console.log(error.message);
            },
        );
    },
};

export default TST.Contact;

Test

import { XrmMockGenerator, LookupAttributeMock } from "xrm-mock";
import Contact from "../../examples/asyncAPI";

import { describe, it, expect, beforeEach, vi } from "vitest";

describe("asyncAPI", () => {
    it("example to show how to handle async on change", async () => {
        var Xrm = XrmMockGenerator.initialise();
        const context = XrmMockGenerator.getEventContext();
        const formContext = context.getFormContext();

        // Create and add filterRecord attribute
        const filterRecord = XrmMockGenerator.Attribute.createLookup("tst_filterrecord", [
            {
                entityType: "tst_searchentity",
                id: "{some-guid}",
                name: "Filter Record Name Value",
            },
        ]);

        // Create and add targetField attribute
        const targetField = XrmMockGenerator.Attribute.createString({
            name: "tst_targetfield",
            value: "",
        });

        // Mock WebApi retrieveRecord to return a response
        vi.spyOn(Xrm.WebApi, "retrieveRecord").mockResolvedValue({
            tst_name: "Retrieved Record Name",
        });

        // Trigger the onLoad to wire the event
        Contact.onLoad(context);

        // Check the value before the onChange event
        expect(targetField.getValue()).toEqual("");

        // Fire the onChange event for filterRecord
        filterRecord.fireOnChange();

        // Wait for async API to complete
        await new Promise((resolve) => setTimeout(resolve, 0));

        // Assert the targetField value
        expect(targetField.getValue()).toEqual("Retrieved Record Name");
    });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants