feat(medusa): adds collection endpoints to storefront (#711)
Adds: - `/store/collections/:id` - `/store/collections`
This commit is contained in:
@@ -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>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -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,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -22,7 +22,7 @@ describe("GET /admin/collections", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("calls product collection service list", () => {
|
it("calls product collection service list", () => {
|
||||||
expect(ProductCollectionServiceMock.list).toHaveBeenCalledTimes(1)
|
expect(ProductCollectionServiceMock.listAndCount).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -18,30 +18,24 @@ import { defaultFields, defaultRelations } from "."
|
|||||||
* $ref: "#/components/schemas/product_collection"
|
* $ref: "#/components/schemas/product_collection"
|
||||||
*/
|
*/
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
try {
|
const selector = {}
|
||||||
const selector = {}
|
|
||||||
|
|
||||||
const limit = parseInt(req.query.limit) || 10
|
const limit = parseInt(req.query.limit) || 10
|
||||||
const offset = parseInt(req.query.offset) || 0
|
const offset = parseInt(req.query.offset) || 0
|
||||||
|
|
||||||
const productCollectionService = req.scope.resolve(
|
const productCollectionService = req.scope.resolve("productCollectionService")
|
||||||
"productCollectionService"
|
|
||||||
)
|
|
||||||
|
|
||||||
const listConfig = {
|
const listConfig = {
|
||||||
select: defaultFields,
|
select: defaultFields,
|
||||||
relations: defaultRelations,
|
relations: defaultRelations,
|
||||||
skip: offset,
|
skip: offset,
|
||||||
take: limit,
|
take: limit,
|
||||||
}
|
|
||||||
|
|
||||||
const collections = await productCollectionService.list(
|
|
||||||
selector,
|
|
||||||
listConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
res.status(200).json({ collections })
|
|
||||||
} catch (err) {
|
|
||||||
throw err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [collections, count] = await productCollectionService.listAndCount(
|
||||||
|
selector,
|
||||||
|
listConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ collections, count })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"]
|
||||||
@@ -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 })
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import returnRoutes from "./returns"
|
|||||||
import returnReasonRoutes from "./return-reasons"
|
import returnReasonRoutes from "./return-reasons"
|
||||||
import swapRoutes from "./swaps"
|
import swapRoutes from "./swaps"
|
||||||
import variantRoutes from "./variants"
|
import variantRoutes from "./variants"
|
||||||
|
import collectionRoutes from "./collections"
|
||||||
import giftCardRoutes from "./gift-cards"
|
import giftCardRoutes from "./gift-cards"
|
||||||
|
|
||||||
const route = Router()
|
const route = Router()
|
||||||
@@ -32,6 +33,7 @@ export default (app, container, config) => {
|
|||||||
route.use(middlewares.authenticateCustomer())
|
route.use(middlewares.authenticateCustomer())
|
||||||
|
|
||||||
authRoutes(route)
|
authRoutes(route)
|
||||||
|
collectionRoutes(route)
|
||||||
customerRoutes(route, container)
|
customerRoutes(route, container)
|
||||||
productRoutes(route)
|
productRoutes(route)
|
||||||
orderRoutes(route)
|
orderRoutes(route)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { IdMap } from "medusa-test-utils"
|
import { IdMap } from "medusa-test-utils"
|
||||||
|
|
||||||
export const ProductCollectionServiceMock = {
|
export const ProductCollectionServiceMock = {
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
create: jest.fn().mockImplementation(data => {
|
create: jest.fn().mockImplementation((data) => {
|
||||||
return Promise.resolve({ id: IdMap.getId("col"), ...data })
|
return Promise.resolve({ id: IdMap.getId("col"), ...data })
|
||||||
}),
|
}),
|
||||||
retrieve: jest.fn().mockImplementation(id => {
|
retrieve: jest.fn().mockImplementation((id) => {
|
||||||
if (id === IdMap.getId("col")) {
|
if (id === IdMap.getId("col")) {
|
||||||
return Promise.resolve({ id: IdMap.getId("col"), title: "Suits" })
|
return Promise.resolve({ id: IdMap.getId("col"), title: "Suits" })
|
||||||
}
|
}
|
||||||
@@ -16,9 +16,12 @@ export const ProductCollectionServiceMock = {
|
|||||||
update: jest.fn().mockImplementation((id, value) => {
|
update: jest.fn().mockImplementation((id, value) => {
|
||||||
return Promise.resolve({ id, title: 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" }])
|
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(() => {
|
const mock = jest.fn().mockImplementation(() => {
|
||||||
|
|||||||
@@ -149,7 +149,22 @@ class ProductCollectionService extends BaseService {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const query = this.buildQuery_(selector, config)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user