feat(product, types, utils): tags, types, options, categories and collections for product module (#4535)

* Feat: create product with product module

* feat: create product wip

* feat: create product wip

* feat: update product relation and generate image migration

* lint

* conitnue implementation

* continue implementation and add integration tests for produceService.create

* Add integration tests for product creation at the module level for the complete flow

* only use persist since write operations are always wrapped in a transaction which will be committed and flushed

* simplify the transaction wrapper to make future changes easier

* feat: move some utils to the utils package to simplify its usage

* tests: fix unit tests

* feat: create variants along side the product

* Add more integration tests an update migrations

* chore: Update actions workflow to include packages integration tests

* small types and utils cleanup

* chore: Add support for database debug option

* chore: Add missing types in package.json from types and util, validate that all the models are sync with medusa

* expose retrieve method

* fix types issues

* fix unit tests and move integration tests workflow with the plugins integration tests

* chore: remove migration function export from the definition to prevent them to be ran by the medusa cli just in case

* fix package.json script

* chore: workflows

* feat: start creating the create product workflow

* feat: add empty step for prices and sales channel

* tests: update scripts and action envs

* fix imports

* feat: Add proper soft deleted support + add product deletion service public api

* chore: update migrations

* chore: update migrations

* chore: update todo

* feat: Add product deletion to the create-product workflow as compensation

* chore: cleanup product utils

* feat: Add support for cascade soft-remove

* feat: refactor repository to take into account withDeleted

* fix integration tests

* Add support for force delete -> delete, cleanup repositories and improvements

* Add support for restoring a product and add integration tests

* cleaup + tests

* types

* fix integration tests

* remove unnecessary comments

* move specific mikro orm usage to the DAL

* Cleanup workflow functions

* Make deleted_at optional at the property level and add url index for the images

* address feedback + cleanup

* fix export

* merge migrations into one

* feat(product, types): added missing product variant methods (#4475)

* chore: added missing product variant methods

* chore: address PR feedback

* chore: catch undefined case for retrieve + specs for variant service

* chore: align TEntity + add changeset

* chore: revert changeset, TEntity to ProductVariant

* chore: write tests for pagination, unskip the test

* Create chilled-mice-deliver.md

* update integration fixtuers

* update pipeline node version

* rename github action

* fix pipeline

* feat(medusa, types): added missing category tests and service methods (#4499)

* chore: added missing category tests and service methods

* chore: added type changes to module service

* chore: address pr feedback

* update repositories manager usage and serialisation from the write public API

* move serializisation to the DAL

* rename template args

* chore: added collection methods for module and collection service (#4505)

* chore: added collection methods for module and collection service

* Create fresh-islands-teach.md

* chore: move retrieve entity to utils package

* chore: make products optional in DTO type

---------

Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>

* feat(product): Apply transaction decorators to the services (#4512)

* chore: added tags and types methods for product module

* chore: remove console log

* chore: fork managers on every repository call

* chore: add forked manager decorator

* chore: rename to inject manager from inject forked manager

* chore: added product tag and type create/update/delete

* chore: added collection create/update/delete

* chore: fix naming

* update injectManager and related behaviour

* simplify get active manager

* chore: reset package.json

* makes the base repository methods related to manager generic

* makes some wrapper generic enough

* add some todos

* chore: added options CRUD

* clean up

* chore: fix issue with deleted_at not being updated

* wip

* chore: added categories write operations

* chore: remove async nature of injection decorator

* chore: added changeset

* chore: reset package.json

* chore: add manager injection to all contextable methods

* chore: fix unit tests

---------

Co-authored-by: adrien2p <adrien.deperetti@gmail.com>
Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>
Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2023-07-27 09:52:17 +02:00
1 parent f561601bf6
commit 131477faf0
43 files changed
+4218 -229

No files matched your search

@@ -2,7 +2,7 @@ export const productCategoriesData = [
{
id: "category-0",
name: "category 0",
parent_category_id: null
parent_category_id: null,
},
{
id: "category-1",
@@ -26,3 +26,43 @@ export const productCategoriesData = [
parent_category_id: "category-1-b"
},
]
export const productCategoriesRankData = [
{
id: "category-0-0",
name: "category 0 0",
parent_category_id: null,
rank: 0,
},
{
id: "category-0-1",
name: "category 0 1",
parent_category_id: null,
rank: 1,
},
{
id: "category-0-2",
name: "category 0 2",
parent_category_id: null,
rank: 2,
},
{
id: "category-0-0-0",
name: "category 0 0-0",
parent_category_id: "category-0-0",
rank: 0,
},
{
id: "category-0-0-1",
name: "category 0 0-1",
parent_category_id: "category-0-0",
rank: 1,
},
{
id: "category-0-0-2",
name: "category 0 0-2",
parent_category_id: "category-0-0",
rank: 2,
},
]
@@ -30,6 +30,24 @@ export async function createProductAndTags(
return products
}
export async function createProductAndTypes(
manager: SqlEntityManager,
data: {
id?: string
title: string
status: ProductTypes.ProductStatus
type?: { id: string; value: string }
}[]
) {
const products: any[] = data.map((productData) => {
return manager.create(Product, productData)
})
await manager.persistAndFlush(products)
return products
}
export async function createProductVariants(
manager: SqlEntityManager,
data: any[]
@@ -5,7 +5,7 @@ import { ProductCategoryRepository } from "@repositories"
import { ProductCategoryService } from "@services"
import { createProductCategories } from "../../../__fixtures__/product-category"
import { productCategoriesData } from "../../../__fixtures__/product-category/data"
import { productCategoriesData, productCategoriesRankData } from "../../../__fixtures__/product-category/data"
import { TestDatabase } from "../../../utils"
jest.setTimeout(30000)
@@ -24,7 +24,7 @@ describe("Product category Service", () => {
manager: repositoryManager,
})
service = new ProductCategoryService({
service = new ProductCategoryService<ProductCategory>({
productCategoryRepository,
})
})
@@ -560,4 +560,287 @@ describe("Product category Service", () => {
])
})
})
describe("create", () => {
it("should create a category successfully", async () => {
await service.create({
name: "New Category",
parent_category_id: null,
})
const [productCategory] = await service.list({
name: "New Category"
}, {
select: ["name", "rank"]
})
expect(productCategory).toEqual(
expect.objectContaining({
name: "New Category",
rank: "0",
})
)
})
it("should append rank from an existing category depending on parent", async () => {
await service.create({
name: "New Category",
parent_category_id: null,
rank: 0
})
await service.create({
name: "New Category 2",
parent_category_id: null,
})
const [productCategoryNew] = await service.list({
name: "New Category 2"
}, {
select: ["name", "rank"]
})
expect(productCategoryNew).toEqual(
expect.objectContaining({
name: "New Category 2",
rank: "1",
})
)
await service.create({
name: "New Category 2.1",
parent_category_id: productCategoryNew.id,
})
const [productCategoryWithParent] = await service.list({
name: "New Category 2.1"
}, {
select: ["name", "rank", "parent_category_id"]
})
expect(productCategoryWithParent).toEqual(
expect.objectContaining({
name: "New Category 2.1",
parent_category_id: productCategoryNew.id,
rank: "0",
})
)
})
})
describe("update", () => {
let productCategoryZero
let productCategoryOne
let productCategoryTwo
let productCategoryZeroZero
let productCategoryZeroOne
let productCategoryZeroTwo
let categories
beforeEach(async () => {
testManager = await TestDatabase.forkManager()
categories = await createProductCategories(
testManager,
productCategoriesRankData
)
productCategoryZero = categories[0]
productCategoryOne = categories[1]
productCategoryTwo = categories[2]
productCategoryZeroZero = categories[3]
productCategoryZeroOne = categories[4]
productCategoryZeroTwo = categories[5]
})
it("should update the name of the category successfully", async () => {
await service.update(productCategoryZero.id, {
name: "New Category"
})
const productCategory = await service.retrieve(productCategoryZero.id, {
select: ["name"]
})
expect(productCategory.name).toEqual("New Category")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.update("does-not-exist", {
name: "New Category"
})
} catch (e) {
error = e
}
expect(error.message).toEqual(`ProductCategory not found ({ id: 'does-not-exist' })`)
})
it("should reorder rank successfully in the same parent", async () => {
await service.update(productCategoryTwo.id, {
rank: 0,
})
const productCategories = await service.list({
parent_category_id: null
}, {
select: ["name", "rank"]
})
expect(productCategories).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productCategoryTwo.id,
rank: "0",
}),
expect.objectContaining({
id: productCategoryZero.id,
rank: "1",
}),
expect.objectContaining({
id: productCategoryOne.id,
rank: "2",
})
])
)
})
it("should reorder rank successfully when changing parent", async () => {
await service.update(productCategoryTwo.id, {
rank: 0,
parent_category_id: productCategoryZero.id
})
const productCategories = await service.list({
parent_category_id: productCategoryZero.id
}, {
select: ["name", "rank"]
})
expect(productCategories).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productCategoryTwo.id,
rank: "0",
}),
expect.objectContaining({
id: productCategoryZeroZero.id,
rank: "1",
}),
expect.objectContaining({
id: productCategoryZeroOne.id,
rank: "2",
}),
expect.objectContaining({
id: productCategoryZeroTwo.id,
rank: "3",
})
])
)
})
it("should reorder rank successfully when changing parent and in first position", async () => {
await service.update(productCategoryTwo.id, {
rank: 0,
parent_category_id: productCategoryZero.id
})
const productCategories = await service.list({
parent_category_id: productCategoryZero.id
}, {
select: ["name", "rank"]
})
expect(productCategories).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productCategoryTwo.id,
rank: "0",
}),
expect.objectContaining({
id: productCategoryZeroZero.id,
rank: "1",
}),
expect.objectContaining({
id: productCategoryZeroOne.id,
rank: "2",
}),
expect.objectContaining({
id: productCategoryZeroTwo.id,
rank: "3",
})
])
)
})
})
describe("delete", () => {
let productCategoryZero
let productCategoryOne
let productCategoryTwo
let categories
beforeEach(async () => {
testManager = await TestDatabase.forkManager()
categories = await createProductCategories(
testManager,
productCategoriesRankData
)
productCategoryZero = categories[0]
productCategoryOne = categories[1]
productCategoryTwo = categories[2]
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.delete("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual(`ProductCategory not found ({ id: 'does-not-exist' })`)
})
it("should throw an error when it has children", async () => {
let error
try {
await service.delete(productCategoryZero.id)
} catch (e) {
error = e
}
expect(error.message).toEqual(`Deleting ProductCategory (category-0-0) with category children is not allowed`)
})
it("should reorder siblings rank successfully on deleting", async () => {
await service.delete(productCategoryOne.id)
const productCategories = await service.list({
parent_category_id: null
}, {
select: ["id", "rank"]
})
expect(productCategories).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productCategoryZero.id,
rank: "0",
}),
expect.objectContaining({
id: productCategoryTwo.id,
rank: "1",
})
])
)
})
})
})
@@ -273,4 +273,90 @@ describe("Product collection Service", () => {
)
})
})
describe("delete", () => {
const collectionId = "collection-1"
const collectionData = {
id: collectionId,
title: "collection 1",
}
beforeEach(async () => {
testManager = await TestDatabase.forkManager()
await createCollections(testManager, [collectionData])
})
it("should delete the product collection given an ID successfully", async () => {
await service.delete(
[collectionId],
)
const collections = await service.list({
id: collectionId
})
expect(collections).toHaveLength(0)
})
})
describe("update", () => {
const collectionId = "collection-1"
const collectionData = {
id: collectionId,
title: "collection 1",
}
beforeEach(async () => {
testManager = await TestDatabase.forkManager()
await createCollections(testManager, [collectionData])
})
it("should update the value of the collection successfully", async () => {
await service.update(
[{
id: collectionId,
title: "New Collection"
}]
)
const productCollection = await service.retrieve(collectionId)
expect(productCollection.title).toEqual("New Collection")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.update([
{
id: "does-not-exist",
title: "New Collection"
}
])
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductCollection with id "does-not-exist" not found')
})
})
describe("create", () => {
it("should create a collection successfully", async () => {
await service.create(
[{
title: "New Collection"
}]
)
const [productCollection] = await service.list({
title: "New Collection"
})
expect(productCollection.title).toEqual("New Collection")
})
})
})
@@ -6,6 +6,7 @@ import { ProductTypes } from "@medusajs/types"
import { initialize } from "../../../../src"
import { DB_URL, TestDatabase } from "../../../utils"
import { createProductCategories } from "../../../__fixtures__/product-category"
import { productCategoriesRankData } from "../../../__fixtures__/product-category/data"
describe("ProductModuleService product categories", () => {
let service: IProductModuleService
@@ -201,7 +202,9 @@ describe("ProductModuleService product categories", () => {
describe("retrieveCategory", () => {
it("should return the requested category", async () => {
const result = await service.retrieveCategory(productCategoryOne.id)
const result = await service.retrieveCategory(productCategoryOne.id, {
select: ["id", "name"]
})
expect(result).toEqual(
expect.objectContaining({
@@ -244,5 +247,288 @@ describe("ProductModuleService product categories", () => {
expect(error.message).toEqual("ProductCategory with id: does-not-exist was not found")
})
})
describe("createCategory", () => {
it("should create a category successfully", async () => {
await service.createCategory({
name: "New Category",
parent_category_id: productCategoryOne.id,
})
const [productCategory] = await service.listCategories({
name: "New Category"
}, {
select: ["name", "rank"]
})
expect(productCategory).toEqual(
expect.objectContaining({
name: "New Category",
rank: "0",
})
)
})
it("should append rank from an existing category depending on parent", async () => {
await service.createCategory({
name: "New Category",
parent_category_id: productCategoryOne.id,
rank: 0
})
await service.createCategory({
name: "New Category 2",
parent_category_id: productCategoryOne.id,
})
const [productCategoryNew] = await service.listCategories({
name: "New Category 2"
}, {
select: ["name", "rank"]
})
expect(productCategoryNew).toEqual(
expect.objectContaining({
name: "New Category 2",
rank: "1",
})
)
await service.createCategory({
name: "New Category 2.1",
parent_category_id: productCategoryNew.id,
})
const [productCategoryWithParent] = await service.listCategories({
name: "New Category 2.1"
}, {
select: ["name", "rank", "parent_category_id"]
})
expect(productCategoryWithParent).toEqual(
expect.objectContaining({
name: "New Category 2.1",
parent_category_id: productCategoryNew.id,
rank: "0",
})
)
})
})
describe("updateCategory", () => {
let productCategoryZero
let productCategoryOne
let productCategoryTwo
let productCategoryZeroZero
let productCategoryZeroOne
let productCategoryZeroTwo
let categories
beforeEach(async () => {
testManager = await TestDatabase.forkManager()
categories = await createProductCategories(
testManager,
productCategoriesRankData
)
productCategoryZero = categories[0]
productCategoryOne = categories[1]
productCategoryTwo = categories[2]
productCategoryZeroZero = categories[3]
productCategoryZeroOne = categories[4]
productCategoryZeroTwo = categories[5]
})
it("should update the name of the category successfully", async () => {
await service.updateCategory(productCategoryZero.id, {
name: "New Category"
})
const productCategory = await service.retrieveCategory(productCategoryZero.id, {
select: ["name"]
})
expect(productCategory.name).toEqual("New Category")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.updateCategory("does-not-exist", {
name: "New Category"
})
} catch (e) {
error = e
}
expect(error.message).toEqual(`ProductCategory not found ({ id: 'does-not-exist' })`)
})
it("should reorder rank successfully in the same parent", async () => {
await service.updateCategory(productCategoryTwo.id, {
rank: 0,
})
const productCategories = await service.listCategories({
parent_category_id: null
}, {
select: ["name", "rank"]
})
expect(productCategories).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productCategoryTwo.id,
rank: "0",
}),
expect.objectContaining({
id: productCategoryZero.id,
rank: "1",
}),
expect.objectContaining({
id: productCategoryOne.id,
rank: "2",
})
])
)
})
it("should reorder rank successfully when changing parent", async () => {
await service.updateCategory(productCategoryTwo.id, {
rank: 0,
parent_category_id: productCategoryZero.id
})
const productCategories = await service.listCategories({
parent_category_id: productCategoryZero.id
}, {
select: ["name", "rank"]
})
expect(productCategories).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productCategoryTwo.id,
rank: "0",
}),
expect.objectContaining({
id: productCategoryZeroZero.id,
rank: "1",
}),
expect.objectContaining({
id: productCategoryZeroOne.id,
rank: "2",
}),
expect.objectContaining({
id: productCategoryZeroTwo.id,
rank: "3",
})
])
)
})
it("should reorder rank successfully when changing parent and in first position", async () => {
await service.updateCategory(productCategoryTwo.id, {
rank: 0,
parent_category_id: productCategoryZero.id
})
const productCategories = await service.listCategories({
parent_category_id: productCategoryZero.id
}, {
select: ["name", "rank"]
})
expect(productCategories).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productCategoryTwo.id,
rank: "0",
}),
expect.objectContaining({
id: productCategoryZeroZero.id,
rank: "1",
}),
expect.objectContaining({
id: productCategoryZeroOne.id,
rank: "2",
}),
expect.objectContaining({
id: productCategoryZeroTwo.id,
rank: "3",
})
])
)
})
})
describe("deleteCategory", () => {
let productCategoryZero
let productCategoryOne
let productCategoryTwo
let categories
beforeEach(async () => {
testManager = await TestDatabase.forkManager()
categories = await createProductCategories(
testManager,
productCategoriesRankData
)
productCategoryZero = categories[0]
productCategoryOne = categories[1]
productCategoryTwo = categories[2]
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.deleteCategory("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual(`ProductCategory not found ({ id: 'does-not-exist' })`)
})
it("should throw an error when it has children", async () => {
let error
try {
await service.deleteCategory(productCategoryZero.id)
} catch (e) {
error = e
}
expect(error.message).toEqual(`Deleting ProductCategory (category-0-0) with category children is not allowed`)
})
it("should reorder siblings rank successfully on deleting", async () => {
await service.deleteCategory(productCategoryOne.id)
const productCategories = await service.listCategories({
parent_category_id: null
}, {
select: ["id", "rank"]
})
expect(productCategories).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: productCategoryZero.id,
rank: "0",
}),
expect.objectContaining({
id: productCategoryTwo.id,
rank: "1",
})
])
)
})
})
})
@@ -246,5 +246,71 @@ describe("ProductModuleService product collections", () => {
expect(error.message).toEqual("ProductCollection with id: does-not-exist was not found")
})
})
describe("deleteCollections", () => {
const collectionId = "test-1"
it("should delete the product collection given an ID successfully", async () => {
await service.deleteCollections(
[collectionId],
)
const collections = await service.listCollections({
id: collectionId
})
expect(collections).toHaveLength(0)
})
})
describe("updateCollections", () => {
const collectionId = "test-1"
it("should update the value of the collection successfully", async () => {
await service.updateCollections(
[{
id: collectionId,
title: "New Collection"
}]
)
const productCollection = await service.retrieveCollection(collectionId)
expect(productCollection.title).toEqual("New Collection")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.updateCollections([
{
id: "does-not-exist",
title: "New Collection"
}
])
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductCollection with id "does-not-exist" not found')
})
})
describe("createCollections", () => {
it("should create a collection successfully", async () => {
const res = await service.createCollections(
[{
title: "New Collection"
}]
)
const [productCollection] = await service.listCollections({
title: "New Collection"
})
expect(productCollection.title).toEqual("New Collection")
})
})
})
@@ -0,0 +1,300 @@
import { initialize } from "../../../../src"
import { DB_URL, TestDatabase } from "../../../utils"
import { IProductModuleService } from "@medusajs/types"
import { Product, ProductOption } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { ProductTypes } from "@medusajs/types"
describe("ProductModuleService product options", () => {
let service: IProductModuleService
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let optionOne: ProductOption
let optionTwo: ProductOption
let productOne: Product
let productTwo: Product
beforeEach(async () => {
await TestDatabase.setupDatabase()
repositoryManager = await TestDatabase.forkManager()
service = await initialize({
database: {
clientUrl: DB_URL,
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
},
})
testManager = await TestDatabase.forkManager()
productOne = testManager.create(Product, {
id: "product-1",
title: "product 1",
status: ProductTypes.ProductStatus.PUBLISHED,
})
productTwo = testManager.create(Product, {
id: "product-2",
title: "product 2",
status: ProductTypes.ProductStatus.PUBLISHED,
})
optionOne = testManager.create(ProductOption, {
id: "option-1",
title: "option 1",
product: productOne,
})
optionTwo = testManager.create(ProductOption, {
id: "option-2",
title: "option 1",
product: productTwo,
})
await testManager.persistAndFlush([optionOne, optionTwo])
})
afterEach(async () => {
await TestDatabase.clearDatabase()
})
describe("listOptions", () => {
it("should return options and count queried by ID", async () => {
const options = await service.listOptions({
id: optionOne.id,
})
expect(options).toEqual([
expect.objectContaining({
id: optionOne.id,
}),
])
})
it("should return options and count based on the options and filter parameter", async () => {
let options = await service.listOptions(
{
id: optionOne.id,
},
{
take: 1,
}
)
expect(options).toEqual([
expect.objectContaining({
id: optionOne.id,
}),
])
options = await service.listOptions({}, { take: 1, skip: 1 })
expect(options).toEqual([
expect.objectContaining({
id: optionTwo.id,
}),
])
})
it("should return only requested fields and relations for options", async () => {
const options = await service.listOptions(
{
id: optionOne.id,
},
{
select: ["title", "product.id"],
relations: ["product"],
take: 1
}
)
expect(options).toEqual([
{
id: optionOne.id,
title: optionOne.title,
product_id: productOne.id,
product: {
id: productOne.id,
},
},
])
})
})
describe("listAndCountOptions", () => {
it("should return options and count queried by ID", async () => {
const [options, count] = await service.listAndCountOptions({
id: optionOne.id,
})
expect(count).toEqual(1)
expect(options).toEqual([
expect.objectContaining({
id: optionOne.id,
}),
])
})
it("should return options and count based on the options and filter parameter", async () => {
let [options, count] = await service.listAndCountOptions(
{
id: optionOne.id,
},
{
take: 1,
}
)
expect(count).toEqual(1)
expect(options).toEqual([
expect.objectContaining({
id: optionOne.id,
}),
])
;[options, count] = await service.listAndCountOptions({}, { take: 1 })
expect(count).toEqual(2)
;[options, count] = await service.listAndCountOptions({}, { take: 1, skip: 1 })
expect(count).toEqual(2)
expect(options).toEqual([
expect.objectContaining({
id: optionTwo.id,
}),
])
})
it("should return only requested fields and relations for options", async () => {
const [options, count] = await service.listAndCountOptions(
{
id: optionOne.id,
},
{
select: ["title", "product.id"],
relations: ["product"],
take: 1
}
)
expect(count).toEqual(1)
expect(options).toEqual([{
id: optionOne.id,
title: optionOne.title,
product_id: productOne.id,
product: {
id: productOne.id,
},
}])
})
})
describe("retrieveOption", () => {
it("should return the requested option", async () => {
const option = await service.retrieveOption(optionOne.id)
expect(option).toEqual(
expect.objectContaining({
id: optionOne.id,
}),
)
})
it("should return requested attributes when requested through config", async () => {
const option = await service.retrieveOption(
optionOne.id,
{
select: ["id", "product.title"],
relations: ["product"],
}
)
expect(option).toEqual(
expect.objectContaining({
id: optionOne.id,
product: {
id: "product-1",
title: "product 1",
},
}),
)
})
it("should throw an error when a option with ID does not exist", async () => {
let error
try {
await service.retrieveOption("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual("ProductOption with id: does-not-exist was not found")
})
})
describe("deleteOptions", () => {
const optionId = "option-1"
it("should delete the product option given an ID successfully", async () => {
await service.deleteOptions(
[optionId],
)
const options = await service.listOptions({
id: optionId
})
expect(options).toHaveLength(0)
})
})
describe("updateOptions", () => {
const optionId = "option-1"
it("should update the title of the option successfully", async () => {
await service.updateOptions(
[{
id: optionId,
title: "new test"
}]
)
const productOption = await service.retrieveOption(optionId)
expect(productOption.title).toEqual("new test")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.updateOptions([
{
id: "does-not-exist",
}
])
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductOption with id "does-not-exist" not found')
})
})
describe("createOptions", () => {
it("should create a option successfully", async () => {
const res = await service.createOptions([{
title: "test",
product_id: productOne.id
}])
const productOption = await service.listOptions({
title: "test"
})
expect(productOption[0]?.title).toEqual("test")
})
})
})
@@ -0,0 +1,303 @@
import { initialize } from "../../../../src"
import { DB_URL, TestDatabase } from "../../../utils"
import { IProductModuleService } from "@medusajs/types"
import { Product, ProductTag } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { ProductTypes } from "@medusajs/types"
describe("ProductModuleService product tags", () => {
let service: IProductModuleService
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let tagOne: ProductTag
let tagTwo: ProductTag
let productOne: Product
let productTwo: Product
beforeEach(async () => {
await TestDatabase.setupDatabase()
repositoryManager = await TestDatabase.forkManager()
service = await initialize({
database: {
clientUrl: DB_URL,
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
},
})
testManager = await TestDatabase.forkManager()
productOne = testManager.create(Product, {
id: "product-1",
title: "product 1",
status: ProductTypes.ProductStatus.PUBLISHED,
})
productTwo = testManager.create(Product, {
id: "product-2",
title: "product 2",
status: ProductTypes.ProductStatus.PUBLISHED,
})
tagOne = testManager.create(ProductTag, {
id: "tag-1",
value: "tag 1",
products: [productOne],
})
tagTwo = testManager.create(ProductTag, {
id: "tag-2",
value: "tag",
products: [productTwo],
})
await testManager.persistAndFlush([tagOne, tagTwo])
})
afterEach(async () => {
await TestDatabase.clearDatabase()
})
describe("listTags", () => {
it("should return tags and count queried by ID", async () => {
const tags = await service.listTags({
id: tagOne.id,
})
expect(tags).toEqual([
expect.objectContaining({
id: tagOne.id,
}),
])
})
it("should return tags and count based on the options and filter parameter", async () => {
let tags = await service.listTags(
{
id: tagOne.id,
},
{
take: 1,
}
)
expect(tags).toEqual([
expect.objectContaining({
id: tagOne.id,
}),
])
tags = await service.listTags({}, { take: 1, skip: 1 })
expect(tags).toEqual([
expect.objectContaining({
id: tagTwo.id,
}),
])
})
it("should return only requested fields and relations for tags", async () => {
const tags = await service.listTags(
{
id: tagOne.id,
},
{
select: ["value", "products.id"],
relations: ["products"],
take: 1
}
)
expect(tags).toEqual([
{
id: tagOne.id,
value: tagOne.value,
products: [{
id: productOne.id,
}],
},
])
})
})
describe("listAndCountTags", () => {
it("should return tags and count queried by ID", async () => {
const [tags, count] = await service.listAndCountTags({
id: tagOne.id,
})
expect(count).toEqual(1)
expect(tags).toEqual([
expect.objectContaining({
id: tagOne.id,
}),
])
})
it("should return tags and count based on the options and filter parameter", async () => {
let [tags, count] = await service.listAndCountTags(
{
id: tagOne.id,
},
{
take: 1,
}
)
expect(count).toEqual(1)
expect(tags).toEqual([
expect.objectContaining({
id: tagOne.id,
}),
])
;[tags, count] = await service.listAndCountTags({}, { take: 1 })
expect(count).toEqual(2)
;[tags, count] = await service.listAndCountTags({}, { take: 1, skip: 1 })
expect(count).toEqual(2)
expect(tags).toEqual([
expect.objectContaining({
id: tagTwo.id,
}),
])
})
it("should return only requested fields and relations for tags", async () => {
const [tags, count] = await service.listAndCountTags(
{
id: tagOne.id,
},
{
select: ["value", "products.id"],
relations: ["products"],
take: 1
}
)
expect(count).toEqual(1)
expect(tags).toEqual([
{
id: tagOne.id,
value: tagOne.value,
products: [{
id: productOne.id,
}],
},
])
})
})
describe("retrieveTag", () => {
it("should return the requested tag", async () => {
const tag = await service.retrieveTag(tagOne.id)
expect(tag).toEqual(
expect.objectContaining({
id: tagOne.id,
}),
)
})
it("should return requested attributes when requested through config", async () => {
const tag = await service.retrieveTag(
tagOne.id,
{
select: ["id", "value", "products.title"],
relations: ["products"],
}
)
expect(tag).toEqual(
expect.objectContaining({
id: tagOne.id,
value: tagOne.value,
products: [{
id: "product-1",
title: "product 1",
}],
}),
)
})
it("should throw an error when a tag with ID does not exist", async () => {
let error
try {
await service.retrieveTag("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual("ProductTag with id: does-not-exist was not found")
})
})
describe("deleteTags", () => {
const tagId = "tag-1"
it("should delete the product tag given an ID successfully", async () => {
await service.deleteTags(
[tagId],
)
const tags = await service.listTags({
id: tagId
})
expect(tags).toHaveLength(0)
})
})
describe("updateTags", () => {
const tagId = "tag-1"
it("should update the value of the tag successfully", async () => {
await service.updateTags(
[{
id: tagId,
value: "UK"
}]
)
const productTag = await service.retrieveTag(tagId)
expect(productTag.value).toEqual("UK")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.updateTags([
{
id: "does-not-exist",
value: "UK"
}
])
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductTag with id "does-not-exist" not found')
})
})
describe("createTags", () => {
it("should create a tag successfully", async () => {
const res = await service.createTags(
[{
value: "UK"
}]
)
const productTag = await service.listTags({
value: "UK"
})
expect(productTag[0]?.value).toEqual("UK")
})
})
})
@@ -0,0 +1,275 @@
import { initialize } from "../../../../src"
import { DB_URL, TestDatabase } from "../../../utils"
import { IProductModuleService } from "@medusajs/types"
import { ProductType } from "@models"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { ProductTypes } from "@medusajs/types"
describe("ProductModuleService product types", () => {
let service: IProductModuleService
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let typeOne: ProductType
let typeTwo: ProductType
beforeEach(async () => {
await TestDatabase.setupDatabase()
repositoryManager = await TestDatabase.forkManager()
service = await initialize({
database: {
clientUrl: DB_URL,
schema: process.env.MEDUSA_PRODUCT_DB_SCHEMA,
},
})
testManager = await TestDatabase.forkManager()
typeOne = testManager.create(ProductType, {
id: "type-1",
value: "type 1",
})
typeTwo = testManager.create(ProductType, {
id: "type-2",
value: "type",
})
await testManager.persistAndFlush([typeOne, typeTwo])
})
afterEach(async () => {
await TestDatabase.clearDatabase()
})
describe("listTypes", () => {
it("should return types and count queried by ID", async () => {
const types = await service.listTypes({
id: typeOne.id,
})
expect(types).toEqual([
expect.objectContaining({
id: typeOne.id,
}),
])
})
it("should return types and count based on the options and filter parameter", async () => {
let types = await service.listTypes(
{
id: typeOne.id,
},
{
take: 1,
}
)
expect(types).toEqual([
expect.objectContaining({
id: typeOne.id,
}),
])
types = await service.listTypes({}, { take: 1, skip: 1 })
expect(types).toEqual([
expect.objectContaining({
id: typeTwo.id,
}),
])
})
it("should return only requested fields for types", async () => {
const types = await service.listTypes(
{
id: typeOne.id,
},
{
select: ["value"],
take: 1
}
)
expect(types).toEqual([
{
id: typeOne.id,
value: typeOne.value,
},
])
})
})
describe("listAndCountTypes", () => {
it("should return types and count queried by ID", async () => {
const [types, count] = await service.listAndCountTypes({
id: typeOne.id,
})
expect(count).toEqual(1)
expect(types).toEqual([
expect.objectContaining({
id: typeOne.id,
}),
])
})
it("should return types and count based on the options and filter parameter", async () => {
let [types, count] = await service.listAndCountTypes(
{
id: typeOne.id,
},
{
take: 1,
}
)
expect(count).toEqual(1)
expect(types).toEqual([
expect.objectContaining({
id: typeOne.id,
}),
])
;[types, count] = await service.listAndCountTypes({}, { take: 1 })
expect(count).toEqual(2)
;[types, count] = await service.listAndCountTypes({}, { take: 1, skip: 1 })
expect(count).toEqual(2)
expect(types).toEqual([
expect.objectContaining({
id: typeTwo.id,
}),
])
})
it("should return only requested fields for types", async () => {
const [types, count] = await service.listAndCountTypes(
{
id: typeOne.id,
},
{
select: ["value"],
take: 1
}
)
expect(count).toEqual(1)
expect(types).toEqual([
{
id: typeOne.id,
value: typeOne.value,
},
])
})
})
describe("retrieveType", () => {
it("should return the requested type", async () => {
const type = await service.retrieveType(typeOne.id)
expect(type).toEqual(
expect.objectContaining({
id: typeOne.id,
}),
)
})
it("should return requested attributes when requested through config", async () => {
const type = await service.retrieveType(
typeOne.id,
{
select: ["id", "value"],
}
)
expect(type).toEqual(
{
id: typeOne.id,
value: typeOne.value,
},
)
})
it("should throw an error when a type with ID does not exist", async () => {
let error
try {
await service.retrieveType("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual("ProductType with id: does-not-exist was not found")
})
})
describe("deleteTypes", () => {
const typeId = "type-1"
it("should delete the product type given an ID successfully", async () => {
await service.deleteTypes(
[typeId],
)
const types = await service.listTypes({
id: typeId
})
expect(types).toHaveLength(0)
})
})
describe("updateTypes", () => {
const typeId = "type-1"
it("should update the value of the type successfully", async () => {
await service.updateTypes(
[{
id: typeId,
value: "UK"
}]
)
const productType = await service.retrieveType(typeId)
expect(productType.value).toEqual("UK")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.updateTypes([
{
id: "does-not-exist",
value: "UK"
}
])
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductType with id "does-not-exist" not found')
})
})
describe("createTypes", () => {
it("should create a type successfully", async () => {
const res = await service.createTypes(
[{
value: "UK"
}]
)
const productType = await service.listTypes({
value: "UK"
})
expect(productType[0]?.value).toEqual("UK")
})
})
})
@@ -0,0 +1,320 @@
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { ProductOptionService } from "@services"
import { ProductOptionRepository } from "@repositories"
import { Product } from "@models"
import { TestDatabase } from "../../../utils"
import { createOptions } from "../../../__fixtures__/product"
import { ProductTypes } from "@medusajs/types"
jest.setTimeout(30000)
describe("ProductOption Service", () => {
let service: ProductOptionService
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let productOne: Product
let productTwo: Product
let data!: Product[]
const productOneData = {
id: "product-1",
title: "product 1",
status: ProductTypes.ProductStatus.PUBLISHED,
}
const productTwoData = {
id: "product-2",
title: "product 2",
status: ProductTypes.ProductStatus.PUBLISHED,
}
beforeEach(async () => {
await TestDatabase.setupDatabase()
repositoryManager = await TestDatabase.forkManager()
const productOptionRepository = new ProductOptionRepository({
manager: repositoryManager,
})
service = new ProductOptionService({
productOptionRepository,
})
testManager = await TestDatabase.forkManager()
productOne = testManager.create(Product, productOneData)
productTwo = testManager.create(Product, productTwoData)
data = await createOptions(testManager, [
{
id: "option-1",
title: "Option 1",
product: productOne,
},
{
id: "option-2",
title: "Option 2",
product: productOne,
},
])
})
afterEach(async () => {
await TestDatabase.clearDatabase()
})
describe("list", () => {
it("list product option", async () => {
const optionResults = await service.list()
expect(optionResults).toEqual([
expect.objectContaining({
id: "option-1",
title: "Option 1",
}),
expect.objectContaining({
id: "option-2",
title: "Option 2",
}),
])
})
it("list product option by id", async () => {
const optionResults = await service.list({ id: "option-2" })
expect(optionResults).toEqual([
expect.objectContaining({
id: "option-2",
title: "Option 2",
}),
])
})
it("list product option by title matching string", async () => {
const optionResults = await service.list({ title: "Option 1" })
expect(optionResults).toEqual([
expect.objectContaining({
id: "option-1",
title: "Option 1",
}),
])
})
})
describe("listAndCount", () => {
it("should return product option and count", async () => {
const [optionResults, count] = await service.listAndCount()
expect(count).toEqual(2)
expect(optionResults).toEqual([
expect.objectContaining({
id: "option-1",
title: "Option 1",
}),
expect.objectContaining({
id: "option-2",
title: "Option 2",
}),
])
})
it("should return product option and count when filtered", async () => {
const [optionResults, count] = await service.listAndCount({ id: "option-2" })
expect(count).toEqual(1)
expect(optionResults).toEqual([
expect.objectContaining({
id: "option-2",
}),
])
})
it("should return product option and count when using skip and take", async () => {
const [optionResults, count] = await service.listAndCount({}, { skip: 1, take: 1 })
expect(count).toEqual(2)
expect(optionResults).toEqual([
expect.objectContaining({
id: "option-2",
}),
])
})
it("should return requested fields", async () => {
const [optionResults, count] = await service.listAndCount({}, {
take: 1,
select: ["title"],
})
const serialized = JSON.parse(JSON.stringify(optionResults))
expect(count).toEqual(2)
expect(serialized).toEqual([
expect.objectContaining({
id: "option-1",
}),
])
})
})
describe("retrieve", () => {
const optionId = "option-1"
const optionValue = "Option 1"
it("should return option for the given id", async () => {
const option = await service.retrieve(
optionId,
)
expect(option).toEqual(
expect.objectContaining({
id: optionId
})
)
})
it("should throw an error when option with id does not exist", async () => {
let error
try {
await service.retrieve("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductOption with id: does-not-exist was not found')
})
it("should throw an error when an id is not provided", async () => {
let error
try {
await service.retrieve(undefined as unknown as string)
} catch (e) {
error = e
}
expect(error.message).toEqual('"productOptionId" must be defined')
})
it("should return option based on config select param", async () => {
const option = await service.retrieve(
optionId,
{
select: ["id", "title"],
}
)
const serialized = JSON.parse(JSON.stringify(option))
expect(serialized).toEqual(
{
id: optionId,
title: optionValue,
}
)
})
})
describe("delete", () => {
const optionId = "option-1"
it("should delete the product option given an ID successfully", async () => {
await service.delete(
[optionId],
)
const options = await service.list({
id: optionId
})
expect(options).toHaveLength(0)
})
})
describe("update", () => {
const optionId = "option-1"
it("should update the title of the option successfully", async () => {
await service.update(
[{
id: optionId,
title: "UK",
}]
)
const productOption = await service.retrieve(optionId)
expect(productOption.title).toEqual("UK")
})
it("should update the relationship of the option successfully", async () => {
await service.update(
[{
id: optionId,
product_id: productTwo.id,
}]
)
const productOption = await service.retrieve(optionId, {
relations: ["product"]
})
expect(productOption).toEqual(
expect.objectContaining({
id: optionId,
product: expect.objectContaining({
id: productTwo.id
})
})
)
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.update([
{
id: "does-not-exist",
title: "UK",
}
])
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductOption with id "does-not-exist" not found')
})
})
describe("create", () => {
it("should create a option successfully", async () => {
await service.create(
[{
title: "UK",
product: productOne
}]
)
const [productOption] = await service.list({
title: "UK"
}, {
relations: ["product"],
})
expect(productOption).toEqual(
expect.objectContaining({
title: "UK",
product: expect.objectContaining({
id: productOne.id
})
})
)
})
})
})
@@ -10,12 +10,45 @@ import { TestDatabase } from "../../../utils"
jest.setTimeout(30000)
describe("Product tag Service", () => {
describe("ProductTag Service", () => {
let service: ProductTagService
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let data!: Product[]
const productsData = [
{
id: "test-1",
title: "product 1",
status: ProductTypes.ProductStatus.PUBLISHED,
tags: [
{
id: "tag-1",
value: "France",
},
],
},
{
id: "test-2",
title: "product",
status: ProductTypes.ProductStatus.PUBLISHED,
tags: [
{
id: "tag-2",
value: "Germany",
},
{
id: "tag-3",
value: "United States",
},
{
id: "tag-4",
value: "United Kingdom",
},
],
},
]
beforeEach(async () => {
await TestDatabase.setupDatabase()
repositoryManager = await TestDatabase.forkManager()
@@ -27,6 +60,10 @@ describe("Product tag Service", () => {
service = new ProductTagService({
productTagRepository,
})
testManager = await TestDatabase.forkManager()
data = await createProductAndTags(testManager, productsData)
})
afterEach(async () => {
@@ -34,45 +71,6 @@ describe("Product tag Service", () => {
})
describe("list", () => {
const productsData = [
{
id: "test-1",
title: "product 1",
status: ProductTypes.ProductStatus.PUBLISHED,
tags: [
{
id: "tag-1",
value: "France",
},
],
},
{
id: "test-2",
title: "product",
status: ProductTypes.ProductStatus.PUBLISHED,
tags: [
{
id: "tag-2",
value: "Germany",
},
{
id: "tag-3",
value: "United States",
},
{
id: "tag-4",
value: "United Kingdom",
},
],
},
]
beforeEach(async () => {
testManager = await TestDatabase.forkManager()
data = await createProductAndTags(testManager, productsData)
})
it("list product tags", async () => {
const tagsResults = await service.list()
@@ -118,4 +116,223 @@ describe("Product tag Service", () => {
])
})
})
describe("listAndCount", () => {
it("should return product tags and count", async () => {
const [tagsResults, count] = await service.listAndCount()
expect(count).toEqual(4)
expect(tagsResults).toEqual([
expect.objectContaining({
id: "tag-1",
value: "France",
}),
expect.objectContaining({
id: "tag-2",
value: "Germany",
}),
expect.objectContaining({
id: "tag-3",
value: "United States",
}),
expect.objectContaining({
id: "tag-4",
value: "United Kingdom",
}),
])
})
it("should return product tags and count when filtered", async () => {
const [tagsResults, count] = await service.listAndCount({ id: data[0].tags![0].id })
expect(count).toEqual(1)
expect(tagsResults).toEqual([
expect.objectContaining({
id: "tag-1",
}),
])
})
it("should return product tags and count when using skip and take", async () => {
const [tagsResults, count] = await service.listAndCount({}, { skip: 1, take: 2 })
expect(count).toEqual(4)
expect(tagsResults).toEqual([
expect.objectContaining({
id: "tag-2",
}),
expect.objectContaining({
id: "tag-3",
}),
])
})
it("should return requested fields and relations", async () => {
const [tagsResults, count] = await service.listAndCount({}, {
take: 1,
select: ["value", "products.id"],
relations: ["products"]
})
const serialized = JSON.parse(JSON.stringify(tagsResults))
expect(count).toEqual(4)
expect(serialized).toEqual([
expect.objectContaining({
id: "tag-1",
products: [{
id: "test-1"
}]
}),
])
})
})
describe("retrieve", () => {
const tagId = "tag-1"
const tagValue = "France"
const productId = "test-1"
it("should return tag for the given id", async () => {
const tag = await service.retrieve(
tagId,
)
expect(tag).toEqual(
expect.objectContaining({
id: tagId
})
)
})
it("should throw an error when tag with id does not exist", async () => {
let error
try {
await service.retrieve("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductTag with id: does-not-exist was not found')
})
it("should throw an error when an id is not provided", async () => {
let error
try {
await service.retrieve(undefined as unknown as string)
} catch (e) {
error = e
}
expect(error.message).toEqual('"productTagId" must be defined')
})
it("should return tag based on config select param", async () => {
const tag = await service.retrieve(
tagId,
{
select: ["id", "value"],
}
)
const serialized = JSON.parse(JSON.stringify(tag))
expect(serialized).toEqual(
{
id: tagId,
value: tagValue,
}
)
})
it("should return tag based on config relation param", async () => {
const tag = await service.retrieve(
tagId,
{
select: ["id", "value", "products.id"],
relations: ["products"]
}
)
const serialized = JSON.parse(JSON.stringify(tag))
expect(serialized).toEqual(
{
id: tagId,
value: tagValue,
products: [{
id: productId
}]
}
)
})
})
describe("delete", () => {
const tagId = "tag-1"
it("should delete the product tag given an ID successfully", async () => {
await service.delete(
[tagId],
)
const tags = await service.list({
id: tagId
})
expect(tags).toHaveLength(0)
})
})
describe("update", () => {
const tagId = "tag-1"
it("should update the value of the tag successfully", async () => {
await service.update(
[{
id: tagId,
value: "UK"
}]
)
const productTag = await service.retrieve(tagId)
expect(productTag.value).toEqual("UK")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.update([
{
id: "does-not-exist",
value: "UK"
}
])
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductTag with id "does-not-exist" not found')
})
})
describe("create", () => {
it("should create a tag successfully", async () => {
await service.create(
[{
value: "UK"
}]
)
const [productTag] = await service.list({
value: "UK"
})
expect(productTag.value).toEqual("UK")
})
})
})
@@ -0,0 +1,280 @@
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { ProductTypeService } from "@services"
import { ProductTypeRepository } from "@repositories"
import { Product } from "@models"
import { TestDatabase } from "../../../utils"
import { createProductAndTypes } from "../../../__fixtures__/product"
import { ProductTypes } from "@medusajs/types"
jest.setTimeout(30000)
describe("ProductType Service", () => {
let service: ProductTypeService
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let data!: Product[]
const productsData = [
{
id: "product-1",
title: "product 1",
status: ProductTypes.ProductStatus.PUBLISHED,
type: {
id: "type-1",
value: "Type 1",
},
},
{
id: "product-2",
title: "product",
status: ProductTypes.ProductStatus.PUBLISHED,
type: {
id: "type-2",
value: "Type 2",
}
},
]
beforeEach(async () => {
await TestDatabase.setupDatabase()
repositoryManager = await TestDatabase.forkManager()
const productTypeRepository = new ProductTypeRepository({
manager: repositoryManager,
})
service = new ProductTypeService({
productTypeRepository,
})
testManager = await TestDatabase.forkManager()
data = await createProductAndTypes(testManager, productsData)
})
afterEach(async () => {
await TestDatabase.clearDatabase()
})
describe("list", () => {
it("list product type", async () => {
const typeResults = await service.list()
expect(typeResults).toEqual([
expect.objectContaining({
id: "type-1",
value: "Type 1",
}),
expect.objectContaining({
id: "type-2",
value: "Type 2",
}),
])
})
it("list product type by id", async () => {
const typeResults = await service.list({ id: data[0].type.id })
expect(typeResults).toEqual([
expect.objectContaining({
id: "type-1",
value: "Type 1",
}),
])
})
it("list product type by value matching string", async () => {
const typeResults = await service.list({ value: "Type 1" })
expect(typeResults).toEqual([
expect.objectContaining({
id: "type-1",
value: "Type 1",
}),
])
})
})
describe("listAndCount", () => {
it("should return product type and count", async () => {
const [typeResults, count] = await service.listAndCount()
expect(count).toEqual(2)
expect(typeResults).toEqual([
expect.objectContaining({
id: "type-1",
value: "Type 1",
}),
expect.objectContaining({
id: "type-2",
value: "Type 2",
}),
])
})
it("should return product type and count when filtered", async () => {
const [typeResults, count] = await service.listAndCount({ id: data[0].type.id })
expect(count).toEqual(1)
expect(typeResults).toEqual([
expect.objectContaining({
id: "type-1",
}),
])
})
it("should return product type and count when using skip and take", async () => {
const [typeResults, count] = await service.listAndCount({}, { skip: 1, take: 1 })
expect(count).toEqual(2)
expect(typeResults).toEqual([
expect.objectContaining({
id: "type-2",
}),
])
})
it("should return requested fields", async () => {
const [typeResults, count] = await service.listAndCount({}, {
take: 1,
select: ["value"],
})
const serialized = JSON.parse(JSON.stringify(typeResults))
expect(count).toEqual(2)
expect(serialized).toEqual([
expect.objectContaining({
id: "type-1",
}),
])
})
})
describe("retrieve", () => {
const typeId = "type-1"
const typeValue = "Type 1"
it("should return type for the given id", async () => {
const type = await service.retrieve(
typeId,
)
expect(type).toEqual(
expect.objectContaining({
id: typeId
})
)
})
it("should throw an error when type with id does not exist", async () => {
let error
try {
await service.retrieve("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductType with id: does-not-exist was not found')
})
it("should throw an error when an id is not provided", async () => {
let error
try {
await service.retrieve(undefined as unknown as string)
} catch (e) {
error = e
}
expect(error.message).toEqual('"productTypeId" must be defined')
})
it("should return type based on config select param", async () => {
const type = await service.retrieve(
typeId,
{
select: ["id", "value"],
}
)
const serialized = JSON.parse(JSON.stringify(type))
expect(serialized).toEqual(
{
id: typeId,
value: typeValue,
}
)
})
})
describe("delete", () => {
const typeId = "type-1"
it("should delete the product type given an ID successfully", async () => {
await service.delete(
[typeId],
)
const types = await service.list({
id: typeId
})
expect(types).toHaveLength(0)
})
})
describe("update", () => {
const typeId = "type-1"
it("should update the value of the type successfully", async () => {
await service.update(
[{
id: typeId,
value: "UK"
}]
)
const productType = await service.retrieve(typeId)
expect(productType.value).toEqual("UK")
})
it("should throw an error when an id does not exist", async () => {
let error
try {
await service.update([
{
id: "does-not-exist",
value: "UK"
}
])
} catch (e) {
error = e
}
expect(error.message).toEqual('ProductType with id "does-not-exist" not found')
})
})
describe("create", () => {
it("should create a type successfully", async () => {
await service.create(
[{
value: "UK"
}]
)
const [productType] = await service.list({
value: "UK"
})
expect(productType.value).toEqual("UK")
})
})
})