Skip to content

Commit

Permalink
Refactor product add and update specs to use location helper functions
Browse files Browse the repository at this point in the history
 - Replace manual location object creation with helper functions in product add and update tests
 - Add city tag generation based on location in product add and update tests
 - Include scheduleMetafieldId in product get service response
 - Update product update service to fetch locations from LocationModel and handle potential errors
  • Loading branch information
jamalsoueidan committed May 25, 2024
1 parent 7de46cb commit 67351b0
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 62 deletions.
18 changes: 10 additions & 8 deletions src/functions/customer/controllers/product/add.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
createHttpRequest,
} from "~/library/jest/azure";

import mongoose from "mongoose";
import { LocationOriginTypes, LocationTypes } from "~/functions/location";
import { createUser } from "~/library/jest/helpers";
import {
createLocation,
getDumbLocationObject,
} from "~/library/jest/helpers/location";
import { createSchedule } from "~/library/jest/helpers/schedule";
import { shopifyAdmin } from "~/library/shopify";
import { GidFormat } from "~/library/zod";
Expand Down Expand Up @@ -126,14 +128,13 @@ describe("CustomerProductControllerAdd", () => {
customerId,
metafieldId: "gid://shopify/Metafield/533232",
});
const location = await createLocation({ customerId: user.customerId });

const locations = [
{
metafieldId: "1",
location: new mongoose.Types.ObjectId(),
locationType: LocationTypes.DESTINATION,
originType: LocationOriginTypes.COMMERCIAL,
},
getDumbLocationObject({
...location,
location: location._id,
}),
];

const body: CustomerProductControllerAddRequest["body"] = {
Expand Down Expand Up @@ -167,6 +168,7 @@ describe("CustomerProductControllerAdd", () => {
`product-${mockProduct.productDuplicate?.newProduct?.handle}`,
`scheduleid-${newSchedule._id}`,
`locationid-${body.locations[0].location}`,
`city-${location.city.replace(/ /g, "-").toLowerCase()}`,
];

const mockProductUpdate: ProductUpdateMutation = {
Expand Down
17 changes: 16 additions & 1 deletion src/functions/customer/controllers/product/update.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import {

import { TimeUnit } from "~/functions/schedule";
import { createUser } from "~/library/jest/helpers";
import {
createLocation,
getDumbLocationObject,
} from "~/library/jest/helpers/location";
import { getProductObject } from "~/library/jest/helpers/product";
import { createScheduleWithProducts } from "~/library/jest/helpers/schedule";
import { shopifyAdmin } from "~/library/shopify";
Expand Down Expand Up @@ -44,8 +48,18 @@ describe("CustomerProductControllerUpdate", () => {

it("should be able to update product inside schedule", async () => {
const user = await createUser({ customerId });
const location = await createLocation({ customerId: user.customerId });

const product = getProductObject({
productId,
locations: [
getDumbLocationObject({
...location,
location: location._id,
}),
],
});

const product = getProductObject({ productId });
const newSchedule = await createScheduleWithProducts({
name: "adsasd",
customerId,
Expand Down Expand Up @@ -76,6 +90,7 @@ describe("CustomerProductControllerUpdate", () => {
`product-${product.productHandle}`,
`scheduleid-${newSchedule._id}`,
`locationid-${product.locations[0].location}`,
`city-${location.city.replace(/ /g, "-").toLowerCase()}`,
],
parentId: {
id: "gid://shopify/Metafield/44429081510215",
Expand Down
13 changes: 12 additions & 1 deletion src/functions/customer/services/product/add.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import mongoose from "mongoose";
import { LocationOriginTypes, LocationTypes } from "~/functions/location";
import { ScheduleProduct } from "~/functions/schedule";
import { createUser } from "~/library/jest/helpers";
import { getDumbLocationObject } from "~/library/jest/helpers/location";
import {
createLocation,
getDumbLocationObject,
} from "~/library/jest/helpers/location";
import { createSchedule } from "~/library/jest/helpers/schedule";
import { shopifyAdmin } from "~/library/shopify";
import {
Expand Down Expand Up @@ -141,6 +144,13 @@ describe("CustomerProductServiceAdd", () => {
it("should add a new product to the schedule", async () => {
const customerId = 123;
const user = await createUser({ customerId });
const location = await createLocation({ customerId: user.customerId });
productBody = {
...productBody,
locations: [
getDumbLocationObject({ ...location, location: location._id }),
],
};

const newSchedule = await createSchedule({
name: "Test Schedule",
Expand All @@ -160,6 +170,7 @@ describe("CustomerProductServiceAdd", () => {
`product-${mockProduct.productDuplicate?.newProduct?.handle}`,
`scheduleid-${newSchedule._id}`,
`locationid-${productBody.locations[0].location}`,
`city-${location.city.replace(/ /g, "-").toLowerCase()}`,
];

const mockProductUpdate: ProductUpdateMutation = {
Expand Down
1 change: 1 addition & 0 deletions src/functions/customer/services/product/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ export const CustomerProductServiceGet = async (
...product,
scheduleId: schedule._id,
scheduleName: schedule.name,
scheduleMetafieldId: schedule.metafieldId,
};
};
9 changes: 9 additions & 0 deletions src/functions/customer/services/product/update.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { TimeUnit } from "~/functions/schedule";
import { createUser } from "~/library/jest/helpers";
import {
createLocation,
getDumbLocationObject,
} from "~/library/jest/helpers/location";
import { getProductObject } from "~/library/jest/helpers/product";
import { createScheduleWithProducts } from "~/library/jest/helpers/schedule";
import { shopifyAdmin } from "~/library/shopify";
Expand Down Expand Up @@ -132,13 +136,17 @@ describe("CustomerProductServiceUpdate", () => {

it("should update an existing product in the schedule", async () => {
const user = await createUser({ customerId });
const location = await createLocation({ customerId: user.customerId });

const newSchedule = await createScheduleWithProducts({
name,
customerId,
metafieldId: "gid://shopify/Metafield/533232",
products: [
getProductObject({
locations: [
getDumbLocationObject({ ...location, location: location._id }),
],
parentId: GidFormat.parse(
mockProductUpdate.productUpdate?.product?.parentId?.value
),
Expand Down Expand Up @@ -225,6 +233,7 @@ describe("CustomerProductServiceUpdate", () => {
`product-${product.productHandle}`,
`scheduleid-${newSchedule._id}`,
`locationid-${product.locations[0].location}`,
`city-${location.city.replace(/ /g, "-").toLowerCase()}`,
];

expect(shopifyAdmin.request).toHaveBeenCalledTimes(2);
Expand Down
89 changes: 42 additions & 47 deletions src/functions/customer/services/product/update.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Schedule, ScheduleModel, ScheduleProduct } from "~/functions/schedule";
import { UserModel } from "~/functions/user";
import { NotFoundError } from "~/library/handler";
import { shopifyAdmin } from "~/library/shopify";
import { MetafieldInput } from "~/types/admin.types";
import { CustomerServiceGet } from "../customer/get";
import { LocationModel } from "./../../../location/location.model";
import { PRODUCT_FRAGMENT } from "./add";
import { CustomerProductServiceGet } from "./get";

export type CustomerProductServiceUpdate = {
customerId: Schedule["customerId"];
Expand All @@ -18,46 +20,15 @@ export const CustomerProductServiceUpdate = async (
{ customerId, productId }: CustomerProductServiceUpdate,
body: CustomerProductServiceUpdateBody
) => {
const user = await UserModel.findOne({
const user = await CustomerServiceGet({
customerId,
})
.orFail(
new NotFoundError([
{
path: ["customerId"],
message: "NOT_FOUND",
code: "custom",
},
])
)
.lean();

const schedule = await ScheduleModel.findOne({
customerId,
"products.productId": productId,
})
.orFail(
new NotFoundError([
{
code: "custom",
message: "PRODUCT_NOT_FOUND",
path: ["productId"],
},
])
)
.lean();

const oldProduct = schedule.products.find((p) => p.productId === productId);
});

if (!oldProduct) {
throw new NotFoundError([
{
code: "custom",
message: "PRODUCT_NOT_FOUND",
path: ["productId"],
},
]);
}
const { scheduleId, scheduleMetafieldId, scheduleName, ...oldProduct } =
await CustomerProductServiceGet({
customerId,
productId,
});

const metafields: MetafieldInput[] = [
...(body.hasOwnProperty("hideFromProfile")
Expand Down Expand Up @@ -141,15 +112,29 @@ export const CustomerProductServiceUpdate = async (
});
}

const locations = oldProduct.locations.concat(
const bodyLocations = oldProduct.locations.concat(
(body.locations || [])?.filter(
(item2) =>
!oldProduct.locations.some(
(item1) => item1.location.toString() === item2.location.toString() // must use toString since location is type of objectId
(item1) => item1.location.toString() === item2.location.toString() // must use toString since location could be type of objectId
)
)
);

const locations = await LocationModel.find({
_id: { $in: bodyLocations.map((l) => l.location) },
});

if (locations.length !== bodyLocations.length) {
throw new NotFoundError([
{
path: ["customerId", "locations"],
message: "LOCATIONS_ERROR",
code: "custom",
},
]);
}

const newProduct = {
...oldProduct,
...body,
Expand All @@ -174,7 +159,12 @@ export const CustomerProductServiceUpdate = async (
...oldProduct.price,
...body.price,
},
locations: locations,
locations: locations.map((l) => ({
metafieldId: l.metafieldId,
locationType: l.locationType,
originType: l.originType,
location: l._id,
})),
options: mergeArraysUnique(
oldProduct?.options || [],
body?.options || [],
Expand All @@ -196,7 +186,7 @@ export const CustomerProductServiceUpdate = async (
...metafields,
{
id: oldProduct?.scheduleIdMetafieldId,
value: schedule.metafieldId,
value: scheduleMetafieldId,
},
],
tags: [
Expand All @@ -207,9 +197,14 @@ export const CustomerProductServiceUpdate = async (
`parentid-${oldProduct.parentId}`,
`productid-${oldProduct.productId}`,
`product-${oldProduct.productHandle}`,
`scheduleid-${schedule._id}`,
`scheduleid-${scheduleId}`,
]
.concat(newProduct.locations.map((l) => `locationid-${l.location}`))
.concat(locations.map((l) => `locationid-${l._id}`))
.concat(
locations.map(
(l) => `city-${l.city.replace(/ /g, "-").toLowerCase()}`
)
)
.join(", "),
},
});
Expand Down Expand Up @@ -244,8 +239,8 @@ export const CustomerProductServiceUpdate = async (

return {
...newProduct,
scheduleId: schedule._id.toString(),
scheduleName: schedule.name,
scheduleId: scheduleId.toString(),
scheduleName,
};
};

Expand Down
10 changes: 5 additions & 5 deletions src/library/jest/helpers/location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export const getDumbLocationObject = (
}
> = {}
) => ({
metafieldId: `gid://${faker.number.int({ min: 1, max: 5 })}`,
location: new mongoose.Types.ObjectId(),
locationType: LocationTypes.DESTINATION,
originType: LocationOriginTypes.COMMERCIAL,
...props,
metafieldId:
props.metafieldId || `gid://${faker.number.int({ min: 1, max: 5 })}`,
location: props.location || new mongoose.Types.ObjectId(),
locationType: props.locationType || LocationTypes.DESTINATION,
originType: props.originType || LocationOriginTypes.COMMERCIAL,
});

export const getLocationObject = (props: Partial<Location> = {}): Location => ({
Expand Down

0 comments on commit 67351b0

Please sign in to comment.