feat(medusa): adds collection endpoints to storefront (#711)

Adds:
- `/store/collections/:id`
- `/store/collections`
This commit is contained in:
Sebastian Rindom
2021-11-03 11:24:45 +01:00
committed by GitHub
parent a351398379
commit 58127564d7
12 changed files with 324 additions and 28 deletions

View File

@@ -0,0 +1,50 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`/store/collections /store/collections lists collections 1`] = `
Object {
"collections": Array [
Object {
"created_at": Any<String>,
"deleted_at": null,
"handle": "test-collection",
"id": "test-collection",
"metadata": null,
"title": "Test collection",
"updated_at": Any<String>,
},
Object {
"created_at": Any<String>,
"deleted_at": null,
"handle": "test-collection1",
"id": "test-collection1",
"metadata": null,
"title": "Test collection 1",
"updated_at": Any<String>,
},
Object {
"created_at": Any<String>,
"deleted_at": null,
"handle": "test-collection2",
"id": "test-collection2",
"metadata": null,
"title": "Test collection 2",
"updated_at": Any<String>,
},
],
"count": 3,
}
`;
exports[`/store/collections /store/collections/:id gets collection 1`] = `
Object {
"collection": Object {
"created_at": Any<String>,
"deleted_at": null,
"handle": "test-collection",
"id": "test-collection",
"metadata": null,
"title": "Test collection",
"updated_at": Any<String>,
},
}
`;

View File

@@ -0,0 +1,98 @@
const { ProductCollection } = require("@medusajs/medusa")
const path = require("path")
const setupServer = require("../../../helpers/setup-server")
const { useApi } = require("../../../helpers/use-api")
const { initDb, useDb } = require("../../../helpers/use-db")
const productSeeder = require("../../helpers/product-seeder")
jest.setTimeout(30000)
describe("/store/collections", () => {
let medusaProcess
let dbConnection
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
medusaProcess = await setupServer({ cwd, verbose: true })
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
medusaProcess.kill()
})
describe("/store/collections/:id", () => {
beforeEach(async () => {
try {
await productSeeder(dbConnection)
} catch (err) {
console.log(err)
throw err
}
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("gets collection", async () => {
const api = useApi()
const response = await api.get("/store/collections/test-collection")
expect(response.data).toMatchSnapshot({
collection: {
id: "test-collection",
created_at: expect.any(String),
updated_at: expect.any(String),
},
})
})
})
describe("/store/collections", () => {
beforeEach(async () => {
try {
await productSeeder(dbConnection)
} catch (err) {
console.log(err)
throw err
}
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("lists collections", async () => {
const api = useApi()
const response = await api.get("/store/collections")
expect(response.data).toMatchSnapshot({
collections: [
{
id: "test-collection",
created_at: expect.any(String),
updated_at: expect.any(String),
},
{
id: "test-collection1",
created_at: expect.any(String),
updated_at: expect.any(String),
},
{
id: "test-collection2",
created_at: expect.any(String),
updated_at: expect.any(String),
},
],
count: 3,
})
})
})
})

View File

@@ -22,7 +22,7 @@ describe("GET /admin/collections", () => {
})
it("calls product collection service list", () => {
expect(ProductCollectionServiceMock.list).toHaveBeenCalledTimes(1)
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledTimes(1)
})
})
})

View File

@@ -18,30 +18,24 @@ import { defaultFields, defaultRelations } from "."
* $ref: "#/components/schemas/product_collection"
*/
export default async (req, res) => {
try {
const selector = {}
const selector = {}
const limit = parseInt(req.query.limit) || 10
const offset = parseInt(req.query.offset) || 0
const limit = parseInt(req.query.limit) || 10
const offset = parseInt(req.query.offset) || 0
const productCollectionService = req.scope.resolve(
"productCollectionService"
)
const productCollectionService = req.scope.resolve("productCollectionService")
const listConfig = {
select: defaultFields,
relations: defaultRelations,
skip: offset,
take: limit,
}
const collections = await productCollectionService.list(
selector,
listConfig
)
res.status(200).json({ collections })
} catch (err) {
throw err
const listConfig = {
select: defaultFields,
relations: defaultRelations,
skip: offset,
take: limit,
}
const [collections, count] = await productCollectionService.listAndCount(
selector,
listConfig
)
res.status(200).json({ collections, count })
}

View File

@@ -0,0 +1,27 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection"
describe("GET /store/categories/:id", () => {
describe("get collection by id successfully", () => {
let subject
beforeAll(async () => {
subject = await request("GET", `/store/collections/${IdMap.getId("col")}`)
})
afterAll(() => {
jest.clearAllMocks()
})
it("calls retrieve from product collection service", () => {
expect(ProductCollectionServiceMock.retrieve).toHaveBeenCalledTimes(1)
expect(ProductCollectionServiceMock.retrieve).toHaveBeenCalledWith(
IdMap.getId("col")
)
})
it("returns variant decorated", () => {
expect(subject.body.collection.id).toEqual(IdMap.getId("col"))
})
})
})

View File

@@ -0,0 +1,21 @@
import { request } from "../../../../../helpers/test-request"
import { ProductCollectionServiceMock } from "../../../../../services/__mocks__/product-collection"
describe("GET /store/collections", () => {
describe("successful retrieval", () => {
let subject
beforeAll(async () => {
jest.clearAllMocks()
subject = await request("GET", `/store/collections`)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls product collection service list", () => {
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledTimes(1)
})
})
})

View File

@@ -0,0 +1,33 @@
/**
* @oas [get] /collections/{id}
* operationId: "GetCollectionsCollection"
* summary: "Retrieve a Product Collection"
* description: "Retrieves a Product Collection."
* parameters:
* - (path) id=* {string} The id of the Product Collection
* tags:
* - Collection
* responses:
* "200":
* description: OK
* content:
* application/json:
* schema:
* properties:
* collection:
* $ref: "#/components/schemas/product_collection"
*/
export default async (req, res) => {
const { id } = req.params
try {
const productCollectionService = req.scope.resolve(
"productCollectionService"
)
const collection = await productCollectionService.retrieve(id)
res.status(200).json({ collection })
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,16 @@
import { Router } from "express"
import middlewares from "../../../middlewares"
const route = Router()
export default (app) => {
app.use("/collections", route)
route.get("/", middlewares.wrap(require("./list-collections").default))
route.get("/:id", middlewares.wrap(require("./get-collection").default))
return app
}
export const defaultFields = ["id", "title", "handle"]
export const defaultRelations = ["products"]

View File

@@ -0,0 +1,37 @@
/**
* @oas [get] /collections
* operationId: "GetCollections"
* summary: "List Product Collections"
* description: "Retrieve a list of Product Collection."
* tags:
* - Collection
* responses:
* "200":
* description: OK
* content:
* application/json:
* schema:
* properties:
* collection:
* $ref: "#/components/schemas/product_collection"
*/
export default async (req, res) => {
const selector = {}
const limit = parseInt(req.query.limit) || 10
const offset = parseInt(req.query.offset) || 0
const productCollectionService = req.scope.resolve("productCollectionService")
const listConfig = {
skip: offset,
take: limit,
}
const [collections, count] = await productCollectionService.listAndCount(
selector,
listConfig
)
res.status(200).json({ collections, count })
}

View File

@@ -14,6 +14,7 @@ import returnRoutes from "./returns"
import returnReasonRoutes from "./return-reasons"
import swapRoutes from "./swaps"
import variantRoutes from "./variants"
import collectionRoutes from "./collections"
import giftCardRoutes from "./gift-cards"
const route = Router()
@@ -32,6 +33,7 @@ export default (app, container, config) => {
route.use(middlewares.authenticateCustomer())
authRoutes(route)
collectionRoutes(route)
customerRoutes(route, container)
productRoutes(route)
orderRoutes(route)

View File

@@ -1,13 +1,13 @@
import { IdMap } from "medusa-test-utils"
export const ProductCollectionServiceMock = {
withTransaction: function() {
withTransaction: function () {
return this
},
create: jest.fn().mockImplementation(data => {
create: jest.fn().mockImplementation((data) => {
return Promise.resolve({ id: IdMap.getId("col"), ...data })
}),
retrieve: jest.fn().mockImplementation(id => {
retrieve: jest.fn().mockImplementation((id) => {
if (id === IdMap.getId("col")) {
return Promise.resolve({ id: IdMap.getId("col"), title: "Suits" })
}
@@ -16,9 +16,12 @@ export const ProductCollectionServiceMock = {
update: jest.fn().mockImplementation((id, value) => {
return Promise.resolve({ id, title: value })
}),
list: jest.fn().mockImplementation(data => {
list: jest.fn().mockImplementation((data) => {
return Promise.resolve([{ id: IdMap.getId("col"), title: "Suits" }])
}),
listAndCount: jest.fn().mockImplementation((data) => {
return Promise.resolve([[{ id: IdMap.getId("col"), title: "Suits" }], 1])
}),
}
const mock = jest.fn().mockImplementation(() => {

View File

@@ -149,7 +149,22 @@ class ProductCollectionService extends BaseService {
)
const query = this.buildQuery_(selector, config)
return productCollectionRepo.find(query)
return await productCollectionRepo.find(query)
}
/**
* Lists product collections and add count.
* @param {Object} selector - the query object for find
* @param {Object} config - the config to be used for find
* @return {Promise} the result of the find operation
*/
async listAndCount(selector = {}, config = { skip: 0, take: 20 }) {
const productCollectionRepo = this.manager_.getCustomRepository(
this.productCollectionRepository_
)
const query = this.buildQuery_(selector, config)
return await productCollectionRepo.findAndCount(query)
}
}