Skip to content

Commit

Permalink
Merge pull request #6 from allanhvam/dev
Browse files Browse the repository at this point in the history
feat: added LastItemModifiedDate to list, web getList handler, web po…
  • Loading branch information
allanhvam authored May 31, 2024
2 parents 6b3e765 + 354e43f commit dc8d380
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 165 deletions.
262 changes: 112 additions & 150 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "msw-sp",
"version": "1.4.0",
"version": "1.5.0",
"description": "MSW handlers for mocking SharePoint REST api.",
"main": "lib/index.js",
"engines": {
Expand Down
44 changes: 44 additions & 0 deletions src/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,51 @@ export const Utils = {

return f;
},
lowerCaseKeys: (o: any) => {
if (!o) {
return o;
}
const f: Record<string, any> = {};
const keys = Object.keys(o);
keys.forEach((key) => {
const newKey = key.charAt(0).toLowerCase() + key.slice(1);
f[newKey] = o[key];
});

return f;
},
objects: {
/**
* Returns object with only simple properties
*/
getSimple: (o: object): object => {
const keys = Object.keys(o);

const simple = {};
for (const key of keys) {
const value = o[key];
switch (typeof value) {
case "bigint":
case "boolean":
case "number":
case "string":
simple[key] = value;
}
}

return simple;
}
},
strings: {
getGUID: (): string => {
let d = Date.now();
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16);
});
},

trimStart: (s: string, trim: string) => {
while (s.indexOf(trim) === 0) {
s = s.substring(trim.length);
Expand Down
14 changes: 12 additions & 2 deletions src/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ export const handlers = (options: Tenant | { tenant: Tenant, delay?: DelayMode |
const title = info.params.title.toString();
return response(await tenantMock.sites.getSite(site).rootWeb.lists.getByTitle(title).fields.get(), info);
}),
...get("/_api/web/getList\\(':listRelativeUrl'\\)", async (info) => {
const site = info.params.site?.toString() || "/";
const listRelativeUrl = info.params.listRelativeUrl.toString();
return response(await tenantMock.sites.getSite(site).rootWeb.getList(listRelativeUrl).get(), info);
}),
...get("/_api/web/getList\\(':listRelativeUrl'\\)/fields", async (info) => {
const site = info.params.site?.toString() || "/";
const listRelativeUrl = info.params.listRelativeUrl.toString();
Expand Down Expand Up @@ -263,7 +268,7 @@ export const handlers = (options: Tenant | { tenant: Tenant, delay?: DelayMode |
return response(await tenantMock.sites.getSite(site).rootWeb.siteUsers.getById(id).get(), info);
}),
...get("/_api/*", async (info) => {
return response(new Response(undefined, { status: 501, statusText: "Not Implemented" }), info);
return response(new Response(undefined, { status: 501, statusText: "Not Implemented (GET)" }), info);
}),

// MARK: POST
Expand All @@ -276,6 +281,11 @@ export const handlers = (options: Tenant | { tenant: Tenant, delay?: DelayMode |
const payload = await info.request.json() as any;
return response(tenantMock.sites.getSite(site).rootWeb.ensureUser(payload), info);
}),
...post("/_api/web/lists", async (info) => {
const site = info.params.site?.toString() || "/";
const payload = await info.request.json() as any;
return response(await tenantMock.sites.getSite(site).rootWeb.lists.post(payload), info);
}),
...post("/_api/web/getList\\(':listRelativeUrl'\\)/getitems", async (info) => {
const site = info.params.site?.toString() || "/";
const listRelativeUrl = info.params.listRelativeUrl.toString();
Expand All @@ -288,7 +298,7 @@ export const handlers = (options: Tenant | { tenant: Tenant, delay?: DelayMode |
return response(await tenantMock.sites.getSite(site).rootWeb.lists.getByTitle(title).items.post(payload), info);
}),
...post("/_api/*", async (...params) => {
return response(new Response(undefined, { status: 501, statusText: "Not Implemented" }), ...params);
return response(new Response(undefined, { status: 501, statusText: "Not Implemented (POST)" }), ...params);
}),
];
};
31 changes: 25 additions & 6 deletions src/mocks/ListMock.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Utils } from "../Utils.js";
import type { List } from "../types/List.js";
import { BasePermissionsMock } from "./BasePermissionsMock.js";
import { FieldsMock } from "./FieldsMock.js";
Expand Down Expand Up @@ -53,14 +54,32 @@ export class ListMock {
return new Response(undefined, { status: 404 });
}

const created = this.list?.created ?? new Date(0).toISOString();

const getLastItemModifiedDate = () => {
const getDate = (item: Record<string, any>) => {
if (item.Modified) {
return new Date(item.Modified).getTime();
}
if (item.Created) {
return new Date(item.Created).getTime();
}
return new Date(0).getTime();
};
const sortedItems = [...this.list?.items ?? []].sort((a, b) => getDate(b) - getDate(a));
const lastModifiedItem = sortedItems[0];
const lastItemModifiedDate = lastModifiedItem?.Modified ?? lastModifiedItem?.Created ?? created;
return lastItemModifiedDate;
};

return new Response(
JSON.stringify({
Id: this.list.id,
Title: this.list.title,
ItemCount: this.list.items.length,
Hidden: this.list.hidden,
BaseTemplate: this.list.baseTemplate,
Created: this.list.created,
...Utils.upperCaseKeys(Utils.objects.getSimple(this.list)),
...{
Created: created,
LastItemModifiedDate: getLastItemModifiedDate(),
ItemCount: this.list.items.length,
},
}),
{ status: 200 },
);
Expand Down
14 changes: 14 additions & 0 deletions src/mocks/ListsMock.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Utils } from "../Utils.js";
import type { List } from "../types/List.js";
import { ListMock } from "./ListMock.js";

Expand Down Expand Up @@ -36,4 +37,17 @@ export class ListsMock {
{ status: 200 },
);
};

post = async (payload: any) => {
if (this.lists === undefined) {
this.lists = [];
}
const list = Utils.lowerCaseKeys(payload) as List;
list.id = Utils.strings.getGUID();
list.created = new Date().toISOString();
list.items = [];
this.lists.push(list);

return await new ListMock(list).get();
};
}
61 changes: 55 additions & 6 deletions src/tests/lists.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,38 @@ void describe("lists", async () => {
"Title": "Event",
"Start": "2024-04-22T06:00:00Z",
"End": "2024-04-22T14:00:00Z",
"ID": 457,
"ID": 1,
"Modified": "2023-01-04T11:56:54Z",
"Created": "2023-01-01T06:01:48Z",
"AuthorId": 1073741822,
"EditorId": 1073741822,
},
{
"FileSystemObjectType": 0,
"Id": 2,
"ContentTypeId": "0x0100EE277107DD3E9F4CBC7D33048BB8CB92",
"Title": "Event 2",
"Start": "2024-04-23T06:00:00Z",
"End": "2024-04-23T14:00:00Z",
"ID": 2,
"Modified": "2024-01-04T11:56:54Z",
"Created": "2023-10-10T06:01:48Z",
"Created": "2024-01-01T06:01:48Z",
"AuthorId": 1073741822,
"EditorId": 1073741822,
},
{
"FileSystemObjectType": 0,
"Id": 3,
"ContentTypeId": "0x0100EE277107DD3E9F4CBC7D33048BB8CB92",
"Title": "Event 3",
"Start": "2024-04-24T06:00:00Z",
"End": "2024-04-24T14:00:00Z",
"ID": 2,
"Modified": "2022-01-04T11:56:54Z",
"Created": "2022-01-01T06:01:48Z",
"AuthorId": 1073741822,
"EditorId": 1073741822,
}
},
]
},
],
Expand Down Expand Up @@ -100,7 +126,7 @@ void describe("lists", async () => {
const emptyListInfo = await emptyList();
assert.equal(emptyListInfo.Title, "Empty");
assert.equal(emptyListInfo.ItemCount, 0);

assert.equal(emptyListInfo.LastItemModifiedDate, new Date(0).toISOString());
const items = await emptyList.items();
assert.equal(items.length, 0);
}
Expand All @@ -109,9 +135,32 @@ void describe("lists", async () => {
await test("events", async () => {
const sp = spfi().using(SPFx(getContext("/sites/events")));

const events = await sp.web.getList("/sites/events/lists/events").items();
assert.equal(events.length, 1);
const eventList = sp.web.getList("/sites/events/lists/events");
const eventListInfo = await eventList();
const events = await eventList.items();
assert.equal(events.length, 3);
const event = events[0];
assert.equal(event["Title"], "Event");

assert.equal(eventListInfo.LastItemModifiedDate, "2024-01-04T11:56:54Z");
});

await test("add", async () => {
const sp = spfi().using(SPFx(getContext("/sites/events")));

const title = new Date().getTime().toString();
const listInfo = await sp.web.lists.add(title, "Description", 100, true, {
NoCrawl: true,
});

assert.equal(listInfo.Title, title);

const lists = await sp.web.lists();
const list = lists.find(l => l.Title === title);
assert.ok(list);
assert.equal(list.Description, "Description");
assert.equal(list.BaseTemplate, 100);
assert.equal(list.ContentTypesEnabled, true);
assert.equal(list.NoCrawl, true);
});
});

0 comments on commit dc8d380

Please sign in to comment.