chore(): Add new regression tests to the remote joiner (#14119)
* Add tests * Add tests * Add tests
This commit is contained in:
committed by
GitHub
parent
2cc42ca0ef
commit
6057afdfaa
@@ -186,4 +186,62 @@ export const remoteJoinerData = {
|
||||
user_id: 1,
|
||||
},
|
||||
],
|
||||
link: [
|
||||
{
|
||||
id: 1,
|
||||
url: "https://example.com/post-1",
|
||||
product_id: 101,
|
||||
post_id: 501,
|
||||
metadata: {
|
||||
source: "blog",
|
||||
category: "tech",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
url: "https://example.com/post-2",
|
||||
product_id: 102,
|
||||
post_id: 502,
|
||||
metadata: {
|
||||
source: "news",
|
||||
category: "general",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
url: "https://example.com/post-3",
|
||||
product_id: 103,
|
||||
post_id: 503,
|
||||
metadata: {
|
||||
source: "forum",
|
||||
category: "discussion",
|
||||
},
|
||||
},
|
||||
],
|
||||
post: [
|
||||
{
|
||||
id: 501,
|
||||
title: "First Post",
|
||||
content: "Content of first post",
|
||||
author: "John Doe",
|
||||
published: true,
|
||||
views: 1000,
|
||||
},
|
||||
{
|
||||
id: 502,
|
||||
title: "Second Post",
|
||||
content: "Content of second post",
|
||||
author: "Jane Smith",
|
||||
published: true,
|
||||
views: 2500,
|
||||
},
|
||||
{
|
||||
id: 503,
|
||||
title: "Third Post",
|
||||
content: "Content of third post",
|
||||
author: "Bob Johnson",
|
||||
published: false,
|
||||
views: 150,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { JoinerServiceConfig } from "@medusajs/types"
|
||||
import { JoinerServiceConfig, ModuleJoinerConfig } from "@medusajs/types"
|
||||
import { remoteJoinerData } from "./../../__fixtures__/joiner/data"
|
||||
|
||||
export const serviceConfigs: JoinerServiceConfig[] = [
|
||||
export const serviceConfigs: (JoinerServiceConfig | ModuleJoinerConfig)[] = [
|
||||
{
|
||||
serviceName: "user",
|
||||
primaryKeys: ["id"],
|
||||
@@ -49,6 +49,13 @@ export const serviceConfigs: JoinerServiceConfig[] = [
|
||||
primaryKey: "id",
|
||||
alias: "user",
|
||||
},
|
||||
{
|
||||
foreignKey: "product_id",
|
||||
primaryKey: "id",
|
||||
serviceName: "link",
|
||||
alias: "links",
|
||||
inverse: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -106,6 +113,74 @@ export const serviceConfigs: JoinerServiceConfig[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
serviceName: "link",
|
||||
isLink: true,
|
||||
primaryKeys: ["id", "product_id", "post_id"],
|
||||
relationships: [
|
||||
{
|
||||
serviceName: "product",
|
||||
entity: "Product",
|
||||
primaryKey: "id",
|
||||
foreignKey: "product_id",
|
||||
alias: "product",
|
||||
args: {
|
||||
methodSuffix: "Products",
|
||||
},
|
||||
},
|
||||
{
|
||||
serviceName: "post",
|
||||
entity: "Post",
|
||||
primaryKey: "id",
|
||||
foreignKey: "post_id",
|
||||
alias: "post",
|
||||
args: {
|
||||
methodSuffix: "Posts",
|
||||
},
|
||||
},
|
||||
],
|
||||
extends: [
|
||||
{
|
||||
serviceName: "product",
|
||||
entity: "Product",
|
||||
fieldAlias: {
|
||||
posts: "links.post",
|
||||
},
|
||||
relationship: {
|
||||
serviceName: "link",
|
||||
primaryKey: "id",
|
||||
foreignKey: "product_id",
|
||||
alias: "links",
|
||||
},
|
||||
},
|
||||
{
|
||||
serviceName: "post",
|
||||
entity: "Post",
|
||||
fieldAlias: {
|
||||
product: "links.product",
|
||||
},
|
||||
relationship: {
|
||||
serviceName: "link",
|
||||
primaryKey: "id",
|
||||
foreignKey: "post_id",
|
||||
alias: "links",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
serviceName: "post",
|
||||
primaryKeys: ["id"],
|
||||
relationships: [
|
||||
{
|
||||
serviceName: "link",
|
||||
primaryKey: "id",
|
||||
foreignKey: "post_id",
|
||||
alias: "links",
|
||||
inverse: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export const mockServiceList = (serviceName) => {
|
||||
@@ -115,6 +190,8 @@ export const mockServiceList = (serviceName) => {
|
||||
productService: remoteJoinerData.product,
|
||||
variantService: remoteJoinerData.variant,
|
||||
orderService: remoteJoinerData.order,
|
||||
linkService: remoteJoinerData.link,
|
||||
postService: remoteJoinerData.post,
|
||||
}
|
||||
|
||||
let resultset = JSON.parse(JSON.stringify(src[serviceName]))
|
||||
@@ -134,6 +211,18 @@ export const mockServiceList = (serviceName) => {
|
||||
resultset = resultset.filter((item) => data.options.id.includes(item.id))
|
||||
}
|
||||
|
||||
// mock filtering on service link
|
||||
if (serviceName === "linkService" && data.options?.product_id) {
|
||||
resultset = resultset.filter((item) =>
|
||||
data.options.product_id.includes(item.product_id)
|
||||
)
|
||||
}
|
||||
|
||||
// mock filtering on service post
|
||||
if (serviceName === "postService" && data.options?.id) {
|
||||
resultset = resultset.filter((item) => data.options.id.includes(item.id))
|
||||
}
|
||||
|
||||
return {
|
||||
data: resultset,
|
||||
path: serviceName === "productService" ? "rows" : undefined,
|
||||
@@ -146,4 +235,6 @@ export const serviceMock = {
|
||||
userService: mockServiceList("userService"),
|
||||
productService: mockServiceList("productService"),
|
||||
variantService: mockServiceList("variantService"),
|
||||
linkService: mockServiceList("linkService"),
|
||||
postService: mockServiceList("postService"),
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ const container = {
|
||||
list: (...args) => {
|
||||
return serviceMock[serviceName].apply(this, args)
|
||||
},
|
||||
getByProductId: (...args) => {
|
||||
return serviceMock[serviceName].apply(this, args)
|
||||
},
|
||||
}
|
||||
},
|
||||
} as MedusaContainer
|
||||
@@ -610,4 +613,94 @@ describe("RemoteJoiner", () => {
|
||||
options: { id: expect.arrayContaining([103, 102]) },
|
||||
})
|
||||
})
|
||||
|
||||
it("should not lose fields when querying with specific nested fields and wildcard on deeply nested relations", async () => {
|
||||
// This ensures that when we have:
|
||||
// - A specific field from the root entity (product.name)
|
||||
// - A specific field from an intermediate relation (links.metadata)
|
||||
// - A wildcard on a relation accessed through that intermediate (links.post.*)
|
||||
// ...the intermediate field (links.metadata) is not lost
|
||||
const query = {
|
||||
alias: "product",
|
||||
fields: ["id", "name"],
|
||||
expands: [
|
||||
{
|
||||
property: "links",
|
||||
fields: ["metadata"],
|
||||
},
|
||||
{
|
||||
property: "posts",
|
||||
fields: ["*"],
|
||||
},
|
||||
],
|
||||
args: undefined,
|
||||
}
|
||||
|
||||
const result = await joiner.query(query)
|
||||
|
||||
expect(serviceMock.productService).toHaveBeenCalledTimes(1)
|
||||
expect(serviceMock.productService).toHaveBeenCalledWith({
|
||||
args: undefined,
|
||||
fields: expect.arrayContaining(["id", "name"]),
|
||||
expands: undefined,
|
||||
options: { id: undefined },
|
||||
})
|
||||
|
||||
expect(serviceMock.linkService).toHaveBeenCalledTimes(1)
|
||||
expect(serviceMock.linkService).toHaveBeenCalledWith({
|
||||
args: undefined,
|
||||
expands: undefined,
|
||||
fields: expect.arrayContaining(["metadata", "product_id"]),
|
||||
options: { product_id: expect.arrayContaining([101, 102, 103]) },
|
||||
})
|
||||
|
||||
expect(serviceMock.postService).toHaveBeenCalledTimes(1)
|
||||
expect(serviceMock.postService).toHaveBeenCalledWith({
|
||||
args: undefined,
|
||||
expands: undefined,
|
||||
fields: ["*", "id"],
|
||||
options: { id: [501, 502, 503] }, // All posts are fetched
|
||||
})
|
||||
|
||||
expect(result.rows).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: 101,
|
||||
name: "Product 1",
|
||||
links: expect.objectContaining({
|
||||
metadata: expect.objectContaining({
|
||||
source: expect.any(String),
|
||||
category: expect.any(String),
|
||||
}),
|
||||
}),
|
||||
posts: expect.objectContaining({
|
||||
id: 501,
|
||||
title: expect.any(String),
|
||||
content: expect.any(String),
|
||||
author: expect.any(String),
|
||||
published: expect.any(Boolean),
|
||||
views: expect.any(Number),
|
||||
}),
|
||||
}),
|
||||
])
|
||||
)
|
||||
|
||||
// Critical assertion: metadata must not be lost
|
||||
const firstProduct = result.rows[0]
|
||||
expect(firstProduct.links).toBeDefined()
|
||||
expect(firstProduct.links).toHaveProperty("metadata")
|
||||
expect(firstProduct.links.metadata).toEqual({
|
||||
source: "blog",
|
||||
category: "tech",
|
||||
})
|
||||
|
||||
// posts.* should include all fields
|
||||
expect(firstProduct).toHaveProperty("posts")
|
||||
expect(firstProduct.posts).toHaveProperty("id")
|
||||
expect(firstProduct.posts).toHaveProperty("title")
|
||||
expect(firstProduct.posts).toHaveProperty("content")
|
||||
expect(firstProduct.posts).toHaveProperty("author")
|
||||
expect(firstProduct.posts).toHaveProperty("published")
|
||||
expect(firstProduct.posts).toHaveProperty("views")
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user