jest.SpyOn @pnp/sp select() and filter()
Tags: node, jest, pnp, spfx
Published: 2023-09-13 07:50:22

It's a "Note to self" but maybe someone will find it useful. 

Building on top of [State of SPFx unit testing in 2023](https://mgwdevcom.wordpress.com/2023/05/29/state-of-spfx-unit-testing-in-2023) I'd like to make sure that the `select` and `filter` methods are invoked correctly from my function. 

## The code
I have a `ListDataProvider` class which provides a `GetListItemsBy` method. Depending on the parameters provided I will call eiter ` this.spfiContext.web.lists.getByTitle(listTitle).items.select(...viewFields).filter(filterBy)<T>(` or ` return await this.spfiContext.web.lists.getByTitle(listTitle).items.select(...viewFields)<T>();`

### ListDataProvider.ts
```ts
export type IListSelect={
    listTitle: string; viewFields: string[];
}
export type IListFilter = IListSelect & {
    filterByField: string; filterByVal: string[]; filterBySyntax?: string;
}
export default class ListDataProvider {
    constructor(protected spfiContext: SPFI) { }
    public async GetListItemsBy<T>(p: IListSelect | IListFilter): Promise<T>    {

        const { listTitle, viewFields } = p as IListSelect;
        const { filterByField, filterByVal, filterBySyntax } = p as IListFilter;

        if (filterBySyntax !== undefined || filterByField !== undefined ) {
            const filterBy = filterBySyntax
                ? `${this.getFilterBy(filterByField, filterByVal)} or ${this.getFilterByContains(filterByField, filterByVal, filterBySyntax)}`
                : this.getFilterBy(filterByField, filterByVal);
            return await this.spfiContext.web.lists.getByTitle(listTitle).items.select(...viewFields).filter(filterBy)<T>();
        }
        else{
            return await this.spfiContext.web.lists.getByTitle(listTitle).items.select(...viewFields)<T>();
        }
    }
}
```

## The test

To test the `ListDataProvider` I will mock the `SPFI` with `select` [and `filter`]:

###  ListDataProvider.test.ts

#### it("should call correct method when calling GetListItemsBy with no filter")

Calling `this.spfiContext.web.lists.getByTitle("TestList").items.select("Title")()`


```ts
    it("should call correct method when calling GetListItemsBy with no filter", async () => {

        mockSPFI = {
            web: {
                lists: {
                    getByTitle: jest.fn().mockReturnValue({
                        items: {
                            select: () => (() => ({ Title: "test" }))
                        }
                    })
                }
            }
        } as unknown as SPFI;

        jest.spyOn(mockSPFI.web.lists.getByTitle("TestList").items, "select");

        const provider = new ListDataProvider(mockSPFI);
        const results: Record<string, string> = await provider.GetListItemsBy({
            listTitle: "TestList",
            viewFields: ["Title"],
        })

        expect(results["Title"]).toBe("test");
        expect(mockSPFI.web.lists.getByTitle).toBeCalledWith("TestList");
        expect(mockSPFI.web.lists.getByTitle("TestList").items.select).toBeCalledWith("Title")
    });
```

#### it("should call correct method when calling GetListItemsBy with filter")

Calling `this.spfiContext.web.lists.getByTitle("TestList").items.select("Title").filter("Title eq 'test'")()`

```ts
    it("should call correct method when calling GetListItemsBy with filter", async () => {

        mockSPFI = {
            web: {
                lists: {
                    getByTitle: jest.fn().mockReturnValue({
                        items: {
                            select: jest.fn().mockReturnValue({
                                filter: () => (() => ({ Title: "test" }))
                            })
                        }
                    })
                }
            }
        } as unknown as SPFI;

        jest.spyOn(mockSPFI.web.lists.getByTitle("TestList").items, "select");
        jest.spyOn(mockSPFI.web.lists.getByTitle("TestList").items.select("Title"), "filter")

        const provider = new ListDataProvider(mockSPFI);
        const results: Record<string, string> = await provider.GetListItemsBy({
            listTitle: "TestList",
            viewFields: ["Title"],
            filterByField: "Title",
            filterByVal: ["test"]
        })

        expect(results["Title"]).toBe("test");
        expect(mockSPFI.web.lists.getByTitle).toBeCalledWith("TestList");
        expect(mockSPFI.web.lists.getByTitle("TestList").items.select).toBeCalledWith("Title")
        expect(mockSPFI.web.lists.getByTitle("TestList").items.select("").filter).toBeCalledWith("Title eq 'test'")
    });
```

#### it("should call correct method when calling GetListItemsBy with filter and filterBySyntax")

Calling `this.spfiContext.web.lists.getByTitle("TestList").items.select("Title").filter("ID eq '1506' or substringof('-1506-',ID)")()`

```ts
    it("should call correct method when calling GetListItemsBy with filter and filterBySyntax", async () => {

        mockSPFI = {
            web: {
                lists: {
                    getByTitle: jest.fn().mockReturnValue({
                        items: {
                            select: jest.fn().mockReturnValue({
                                filter: () => (() => ({ Title: "test" }))
                            })
                        }
                    })
                }
            }
        } as unknown as SPFI;

        jest.spyOn(mockSPFI.web.lists.getByTitle("TestList").items, "select");
        jest.spyOn(mockSPFI.web.lists.getByTitle("TestList").items.select("Title"), "filter")

        const provider = new ListDataProvider(mockSPFI);
        const results: Record<string, string> = await provider.GetListItemsBy({
            listTitle: "TestList",
            viewFields: ["Title"],
            filterByField: "ID",
            filterByVal: ["1506"],
            filterBySyntax: "-value-"
        })

        expect(results["Title"]).toBe("test");
        expect(mockSPFI.web.lists.getByTitle).toBeCalledWith("TestList");
        expect(mockSPFI.web.lists.getByTitle("TestList").items.select).toBeCalledWith("Title")
        expect(mockSPFI.web.lists.getByTitle("TestList").items.select("").filter).toBeCalledWith("ID eq '1506' or substringof('-1506-',ID)")
    });
```