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
22 changes: 22 additions & 0 deletions api/src/services/sap-smartedit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,20 @@ function rowSourceId(row: Record<string, string>, block: ImpexBlock): string | n
.filter((v) => v !== undefined && v !== '');
return parts.length ? parts.join('-') : null;
}

/**
* A SAP ContentPage's route: `/` for the homepage, else its label with one leading slash.
* Exports without a `homepage` column (HAC exports often omit it) fall back to SAP's
* default homepage label, `homepage`.
*/
function contentPageUrl(row: Record<string, string>): string | null {
const label = (row.label ?? '').trim();
const isHome = row.homepage === undefined
? /^\/?homepage$/i.test(label)
: String(row.homepage).trim().toLowerCase() === 'true';
if (isHome) return '/';
return label ? `/${label.replace(/^\/+/, '')}` : null;
}
interface Counters { assetsSkipped: number; refsSkipped: number }

/** Transform one ImpEx cell value to its Contentstack field value, by target type. */
Expand Down Expand Up @@ -942,6 +956,14 @@ async function createEntry(
if (defaultLabel || !existingEntry) {
if (!entry.title || !unambiguousDefault) entry.title = id;
}
// Every CT is a page with a mandatory `url` (ensureMandatoryFields), but SAP
// ContentPage has no url column: its route is the `label` (/faq), and the
// homepage flag means `/`. Without this every migrated page had an empty url,
// so a storefront querying pages by url found none.
if (srcType === 'ContentPage' && !entry.url) {
const pageUrl = contentPageUrl(row);
if (pageUrl) entry.url = pageUrl;
}
entryData[uid] = entry;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
INSERT_UPDATE ContentPage; uid[unique=true]; name; label
; home; "Home"; homepage
; about; "About"; about
10 changes: 10 additions & 0 deletions api/tests/fixtures/sap-smartedit/contentpage-url.impex
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
INSERT_UPDATE ContentPage; uid[unique=true]; name; label; homepage
; homepage; "Homepage"; homepage; true
; faq; "FAQ"; /faq; false
; shipping; "Shipping"; shipping; false
; nolabel; "No Label"; ; false
; campaign; "Campaign"; campaign; TRUE
; legacyhome; "Legacy Home"; homepage; false

UPDATE ContentPage; uid[unique=true]; name
; faq; "FAQ"
93 changes: 93 additions & 0 deletions api/tests/unit/services/sap-smartedit.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1343,3 +1343,96 @@ describe('sap-smartedit getAllAssets/createEntry — a genuine directory as the
expect(fs.readFileSync(onDisk).equals(fs.readFileSync(src))).toBe(true);
});
});

/**
* Every content type is created as a page with a mandatory `url`, but SAP
* ContentPage has no url column — its route lives in `label`, and the homepage
* is flagged `homepage=true`. Every migrated page used to get an empty url, so
* a storefront looking pages up by url (Spartacus) found none of them.
*/
describe('sap-smartedit createEntry — ContentPage url from label/homepage', () => {
const STACK_URL = 'test-stack-sap-smartedit-contentpage-url';
const OUT_URL = path.join(process.cwd(), './cmsMigrationData', STACK_URL);
const URL_FIXTURE = path.join(__dirname, '../../fixtures/sap-smartedit/contentpage-url.impex');
const CT = {
otherCmsTitle: 'ContentPage', contentstackUid: 'cs_contentpage',
fieldMapping: [
{ otherCmsField: 'name', contentstackFieldUid: 'title', contentstackFieldType: 'single_line_text' },
{ otherCmsField: 'label', contentstackFieldUid: 'label', contentstackFieldType: 'single_line_text' },
],
};
let byTitle: Record<string, any>;

beforeAll(async () => {
fs.rmSync(OUT_URL, { recursive: true, force: true });
await sapSmarteditService.createEntry(URL_FIXTURE, '', STACK_URL, 'test-project', [CT], {}, 'en-us', {});
const entries = JSON.parse(fs.readFileSync(path.join(OUT_URL, 'entries', 'cs_contentpage', 'en-us', 'en-us.json'), 'utf8'));
byTitle = Object.fromEntries(Object.values(entries).map((e: any) => [e.title, e]));
});

afterAll(() => {
fs.rmSync(OUT_URL, { recursive: true, force: true });
});

it('gives the homepage the root url', () => {
expect(byTitle.Homepage.url).toBe('/');
});

it('uses a label that is already a path as-is', () => {
expect(byTitle.FAQ.url).toBe('/faq');
});

it('adds the leading slash to a bare label', () => {
expect(byTitle.Shipping.url).toBe('/shipping');
});

it('writes no url when the page has neither label nor homepage flag', () => {
expect('url' in byTitle['No Label']).toBe(false);
});

it('keeps the url when a later partial UPDATE row carries no label', () => {
expect(byTitle.FAQ.url).toBe('/faq');
});

it('reads the homepage flag in any case (TRUE)', () => {
expect(byTitle.Campaign.url).toBe('/');
});

it('keeps /homepage for a page labelled homepage whose flag is false', () => {
expect(byTitle['Legacy Home'].url).toBe('/homepage');
});
});

/** HAC exports often have no `homepage` column; SAP's default homepage label is `homepage`. */
describe('sap-smartedit createEntry — ContentPage url without a homepage column', () => {
const STACK_NOFLAG = 'test-stack-sap-smartedit-contentpage-url-no-flag';
const OUT_NOFLAG = path.join(process.cwd(), './cmsMigrationData', STACK_NOFLAG);
const NOFLAG_FIXTURE = path.join(__dirname, '../../fixtures/sap-smartedit/contentpage-url-no-flag.impex');
const CT = {
otherCmsTitle: 'ContentPage', contentstackUid: 'cs_contentpage',
fieldMapping: [
{ otherCmsField: 'name', contentstackFieldUid: 'title', contentstackFieldType: 'single_line_text' },
{ otherCmsField: 'label', contentstackFieldUid: 'label', contentstackFieldType: 'single_line_text' },
],
};
let byTitle: Record<string, any>;

beforeAll(async () => {
fs.rmSync(OUT_NOFLAG, { recursive: true, force: true });
await sapSmarteditService.createEntry(NOFLAG_FIXTURE, '', STACK_NOFLAG, 'test-project', [CT], {}, 'en-us', {});
const entries = JSON.parse(fs.readFileSync(path.join(OUT_NOFLAG, 'entries', 'cs_contentpage', 'en-us', 'en-us.json'), 'utf8'));
byTitle = Object.fromEntries(Object.values(entries).map((e: any) => [e.title, e]));
});

afterAll(() => {
fs.rmSync(OUT_NOFLAG, { recursive: true, force: true });
});

it('gives the page labelled homepage the root url', () => {
expect(byTitle.Home.url).toBe('/');
});

it('still routes other pages by label', () => {
expect(byTitle.About.url).toBe('/about');
});
});
Loading