Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import sponsorCustomizedFormReducer from "../sponsor-customized-form-reducer";
import {
RECEIVE_SPONSOR_CUSTOMIZED_FORM,
RESET_SPONSOR_CUSTOMIZED_FORM
} from "../../../actions/sponsor-forms-actions";

const DEFAULT_ENTITY = {
id: 0,
code: "",
name: "",
allowed_add_ons: [],
opens_at: "",
expires_at: "",
instructions: "",
meta_fields: [],
items: []
};

const DEFAULT_STATE = { entity: DEFAULT_ENTITY };

describe("sponsorCustomizedFormReducer", () => {
describe("RECEIVE_SPONSOR_CUSTOMIZED_FORM", () => {
it("maps file_url to file_path for images on each item", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: {
id: 1,
code: "FORM1",
items: [
{
id: 10,
name: "Item A",
images: [
{ id: 100, file_url: "https://example.com/img1.png" },
{ id: 101, file_url: "https://example.com/img2.png" }
]
}
]
}
}
});

expect(result.entity.items[0].images).toEqual([
{
id: 100,
file_url: "https://example.com/img1.png",
file_path: "https://example.com/img1.png"
},
{
id: 101,
file_url: "https://example.com/img2.png",
file_path: "https://example.com/img2.png"
}
]);
});

it("handles items with no images", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: {
id: 1,
code: "FORM1",
items: [{ id: 10, name: "Item A", images: [] }]
}
}
});

expect(result.entity.items[0].images).toEqual([]);
});

it("handles empty items array", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: { id: 1, code: "FORM1", items: [] }
}
});

expect(result.entity.items).toEqual([]);
});

it("handles missing items field", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: { id: 1, code: "FORM1" }
}
});

expect(result.entity.items).toEqual([]);
});
Comment on lines +58 to +93
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a test for items where images is missing (not just empty).

You already validate images: [], but the reducer also handles images being absent. A direct test for that case will lock the intended fallback contract.

Suggested test case
   it("handles items with no images", () => {
@@
     expect(result.entity.items[0].images).toEqual([]);
   });

+  it("handles items with missing images field", () => {
+    const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
+      type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
+      payload: {
+        response: {
+          id: 1,
+          code: "FORM1",
+          items: [{ id: 10, name: "Item A" }]
+        }
+      }
+    });
+
+    expect(result.entity.items[0].images).toEqual([]);
+  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it("handles items with no images", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: {
id: 1,
code: "FORM1",
items: [{ id: 10, name: "Item A", images: [] }]
}
}
});
expect(result.entity.items[0].images).toEqual([]);
});
it("handles empty items array", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: { id: 1, code: "FORM1", items: [] }
}
});
expect(result.entity.items).toEqual([]);
});
it("handles missing items field", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: { id: 1, code: "FORM1" }
}
});
expect(result.entity.items).toEqual([]);
});
it("handles items with no images", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: {
id: 1,
code: "FORM1",
items: [{ id: 10, name: "Item A", images: [] }]
}
}
});
expect(result.entity.items[0].images).toEqual([]);
});
it("handles items with missing images field", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: {
id: 1,
code: "FORM1",
items: [{ id: 10, name: "Item A" }]
}
}
});
expect(result.entity.items[0].images).toEqual([]);
});
it("handles empty items array", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: { id: 1, code: "FORM1", items: [] }
}
});
expect(result.entity.items).toEqual([]);
});
it("handles missing items field", () => {
const result = sponsorCustomizedFormReducer(DEFAULT_STATE, {
type: RECEIVE_SPONSOR_CUSTOMIZED_FORM,
payload: {
response: { id: 1, code: "FORM1" }
}
});
expect(result.entity.items).toEqual([]);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/reducers/sponsors/__tests__/sponsor-customized-form-reducer.test.js`
around lines 58 - 93, Add a new unit test that dispatches
RECEIVE_SPONSOR_CUSTOMIZED_FORM to sponsorCustomizedFormReducer with a payload
whose response.items contains an item object that omits the images property
(e.g., { id: 10, name: "Item A" }), and assert that
result.entity.items[0].images is an empty array; use the same DEFAULT_STATE
setup and naming pattern as the existing tests to ensure the reducer's fallback
for missing images is validated.

});

describe("RESET_SPONSOR_CUSTOMIZED_FORM", () => {
it("resets to default state", () => {
const dirty = { entity: { id: 99, items: [{ id: 1 }] } };
const result = sponsorCustomizedFormReducer(dirty, {
type: RESET_SPONSOR_CUSTOMIZED_FORM
});
expect(result).toEqual(DEFAULT_STATE);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ const sponsorCustomizedFormItemsListReducer = (

const currentItem = {
...item,
images: (item.images || []).map((img) => ({
...img,
file_path: img.file_url
})),
meta_fields: item.meta_fields.length > 0 ? item.meta_fields : []
Comment on lines +113 to 117
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard meta_fields before reading .length to avoid reducer crashes.

item.meta_fields.length can throw when the backend omits meta_fields. This path should be normalized the same way as images to prevent runtime TypeError.

Suggested fix
       const currentItem = {
         ...item,
         images: (item.images || []).map((img) => ({
           ...img,
           file_path: img.file_url
         })),
-        meta_fields: item.meta_fields.length > 0 ? item.meta_fields : []
+        meta_fields: Array.isArray(item.meta_fields) ? item.meta_fields : []
       };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
images: (item.images || []).map((img) => ({
...img,
file_path: img.file_url
})),
meta_fields: item.meta_fields.length > 0 ? item.meta_fields : []
images: (item.images || []).map((img) => ({
...img,
file_path: img.file_url
})),
meta_fields: Array.isArray(item.meta_fields) ? item.meta_fields : []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/reducers/sponsors/sponsor-customized-form-items-list-reducer.js` around
lines 113 - 117, The reducer reads item.meta_fields.length without guarding for
a missing meta_fields which can throw; change the meta_fields normalization to
mirror images by first defaulting meta_fields to an empty array when falsy and
then using the length check — e.g., treat (item.meta_fields || []) as the source
for the length test and return either the original item.meta_fields when
non-empty or an empty array otherwise so the reducer never reads .length of
undefined (refer to the item.meta_fields expression in the
sponsor-customized-form-items-list-reducer).

};
return { ...state, currentItem };
Expand Down
16 changes: 12 additions & 4 deletions src/reducers/sponsors/sponsor-customized-form-reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ const DEFAULT_ENTITY = {
opens_at: "",
expires_at: "",
instructions: "",
meta_fields: []
meta_fields: [],
items: []
};

const DEFAULT_STATE = {
Expand All @@ -43,10 +44,17 @@ const sponsorCustomizedFormReducer = (state = DEFAULT_STATE, action) => {
return DEFAULT_STATE;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tomrndom
DEFAULT_ENTITY missing items field
fix: Add items: [] to DEFAULT_ENTITY

}
case RECEIVE_SPONSOR_CUSTOMIZED_FORM: {
return {
...state,
entity: payload.response
const entity = {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tomrndom
The fix addresses the bug for one data path (entity-level items from getSponsorManagedForm) but leaves the same bug active on the individual-item edit path (currentItem from getSponsorCustomizedFormItem), meaning images will still be silently dropped in the most common editing scenario. The missing regression test also means the fix is unverified.

...payload.response,
items: (payload.response.items || []).map((it) => ({
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tomrndom
Add a unit test for RECEIVE_SPONSOR_CUSTOMIZED_FORM in sponsor-customized-form-reducer.js covering: items with images (file_path mapped), items with no images, and empty items array

...it,
images: (it.images || []).map((img) => ({
...img,
file_path: img.file_url
}))
}))
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return { ...state, entity };
}
default:
return state;
Expand Down
Loading