diff --git a/src/html-pipe.js b/src/html-pipe.js
index 7d78d56e..8099a6b4 100644
--- a/src/html-pipe.js
+++ b/src/html-pipe.js
@@ -131,7 +131,7 @@ export async function htmlPipe(state, req) {
state.timer?.update('metadata-fetch');
await Promise.all([
contentPromise,
- fetchMappedMetadata(state),
+ fetchMappedMetadata(state, res),
]);
if (res.error) {
diff --git a/src/steps/fetch-mapped-metadata.js b/src/steps/fetch-mapped-metadata.js
index fd577e94..28b36e45 100644
--- a/src/steps/fetch-mapped-metadata.js
+++ b/src/steps/fetch-mapped-metadata.js
@@ -12,6 +12,7 @@
import { PipelineStatusError } from '../PipelineStatusError.js';
import { Modifiers } from '../utils/modifiers.js';
+import { extractLastModified, updateLastModified } from '../utils/last-modified.js';
/**
* Loads metadata for a mapped path and puts it into `state.mappedMetadata`. If path is not
@@ -20,9 +21,10 @@ import { Modifiers } from '../utils/modifiers.js';
*
* @type PipelineStep
* @param {PipelineState} state
+ * @param {PipelineResponse} res
* @returns {Promise}
*/
-export default async function fetchMappedMetadata(state) {
+export default async function fetchMappedMetadata(state, res) {
state.mappedMetadata = Modifiers.EMPTY;
if (!state.mapped) {
return;
@@ -51,6 +53,7 @@ export default async function fetchMappedMetadata(state) {
state.mappedMetadata = Modifiers.fromModifierSheet(
data,
);
+ updateLastModified(state, res, extractLastModified(ret.headers));
return;
}
if (ret.status !== 404) {
diff --git a/test/FileS3Loader.js b/test/FileS3Loader.js
index dfd4f389..af6d9c15 100644
--- a/test/FileS3Loader.js
+++ b/test/FileS3Loader.js
@@ -53,15 +53,14 @@ export class FileS3Loader {
if (!dir) {
throw Error(`unknown bucketId: ${bucketId}`);
}
- // eslint-disable-next-line no-console
- let fileName = key.split('/').pop();
+ let fileName = key.split('/').slice(2).join('/');
fileName = this.rewrites.reduce((result, rewrite) => rewrite(key) || result, null) || fileName;
const status = this.statusCodeOverrides[fileName];
const headers = this.headerOverride[fileName] ?? new Map();
if (status) {
// eslint-disable-next-line no-console
- console.log(`FileS3Loader: loading ${bucketId}/${key} -> ${status}`);
+ console.log(`FileS3Loader: loading ${bucketId}/${fileName} -> ${status}`);
return {
status,
body: '',
@@ -73,7 +72,7 @@ export class FileS3Loader {
try {
const body = await readFile(file, 'utf-8');
// eslint-disable-next-line no-console
- console.log(`FileS3Loader: loading ${bucketId}/${key} -> 200`);
+ console.log(`FileS3Loader: loading ${bucketId}/${fileName} -> 200`);
return {
status: 200,
body,
@@ -86,7 +85,7 @@ export class FileS3Loader {
};
} catch (e) {
// eslint-disable-next-line no-console
- console.log(`FileS3Loader: loading ${bucketId}/${key} -> 404 (${e.message})`);
+ console.log(`FileS3Loader: loading ${bucketId}/${fileName} -> 404 (${e.message})`);
return {
status: 404,
body: '',
diff --git a/test/fixtures/code/404-test.html b/test/fixtures/code/super-test/404-test.html
similarity index 100%
rename from test/fixtures/code/404-test.html
rename to test/fixtures/code/super-test/404-test.html
diff --git a/test/fixtures/code/my-block.selector.html b/test/fixtures/code/super-test/my-block.selector.html
similarity index 100%
rename from test/fixtures/code/my-block.selector.html
rename to test/fixtures/code/super-test/my-block.selector.html
diff --git a/test/fixtures/code/index.html b/test/fixtures/code/super-test/spa/index.html
similarity index 100%
rename from test/fixtures/code/index.html
rename to test/fixtures/code/super-test/spa/index.html
diff --git a/test/fixtures/code/static.html b/test/fixtures/code/super-test/static.html
similarity index 100%
rename from test/fixtures/code/static.html
rename to test/fixtures/code/super-test/static.html
diff --git a/test/fixtures/content/blog/index.md b/test/fixtures/content/blog/index.md
new file mode 100644
index 00000000..def65cb4
--- /dev/null
+++ b/test/fixtures/content/blog/index.md
@@ -0,0 +1,3 @@
+
+# Hello
+
diff --git a/test/fixtures/content/generic-product/metadata.json b/test/fixtures/content/generic-product/metadata.json
new file mode 100644
index 00000000..8a8bdc4e
--- /dev/null
+++ b/test/fixtures/content/generic-product/metadata.json
@@ -0,0 +1,66 @@
+{
+ ":version": 3,
+ ":type": "multi-sheet",
+ ":names": [
+ "default"
+ ],
+ "default": {
+ "total": 2,
+ "offset": 0,
+ "limit": 2,
+ "data": [
+ {
+ "URL": "/page-*",
+ "Category": "rendering-test"
+ },
+ {
+ "url": "**/page-*-blocks",
+ "Glob Test": "match ** and * combo"
+ },
+ {
+ "Url": "**/marketing/**",
+ "Category": "Marketing"
+ },
+ {
+ "URL": "/page-metadata-json.html",
+ "Image": "/media_cf867e391c0b433ec3d416c979aafa1f8e4aae9c.png",
+ "Keywords": "Baz, Bar, Foo",
+ "og:publisher": "Adobe"
+ },
+ {
+ "URL": "/page-metadata-json",
+ "Image": "/media_cf867e391c0b433ec3d416c979aafa1f8e4aae9c.png",
+ "Keywords": "Baz, Bar, Foo",
+ "og:publisher": "Adobe"
+ },
+ {
+ "URL": "/exact-match.html",
+ "Keywords": "Exactomento",
+ "og:publisher": "Adobe",
+ "Short Title": "E"
+ },
+ {
+ "URL": "/page-metadata-block",
+ "Short Title": "global-meta"
+ },
+ {
+ "URL": "/exact-match",
+ "Keywords": "Exactomento",
+ "og:publisher": "Adobe",
+ "Short Title": "E"
+ },
+ {
+ "URL": "/exact-folder/",
+ "Keywords": "Exactomento Folder",
+ "og:publisher": "Adobe",
+ "Short Title": "E"
+ },
+ {
+ "URL": "/products**",
+ "Keywords": "Exactomento Mapped Folder",
+ "og:publisher": "Adobe",
+ "Short Title": "E"
+ }
+ ]
+ }
+}
diff --git a/test/fixtures/content/one-section/index.md b/test/fixtures/content/one-section/index.md
index e69de29b..def65cb4 100644
--- a/test/fixtures/content/one-section/index.md
+++ b/test/fixtures/content/one-section/index.md
@@ -0,0 +1,3 @@
+
+# Hello
+
diff --git a/test/fixtures/content/default-article.md b/test/fixtures/content/special/default-article.md
similarity index 100%
rename from test/fixtures/content/default-article.md
rename to test/fixtures/content/special/default-article.md
diff --git a/test/rendering.test.js b/test/rendering.test.js
index 341ebc00..8af612d1 100644
--- a/test/rendering.test.js
+++ b/test/rendering.test.js
@@ -179,8 +179,7 @@ describe('Rendering', () => {
// eslint-disable-next-line no-param-reassign
url = new URL(`https://helix-pages.com/${url}`);
}
- const spec = url.pathname.split('/').pop();
- const expFile = path.resolve(__testdir, 'fixtures', 'content', `${spec}.html`);
+ const expFile = path.resolve(__testdir, 'fixtures', 'content', `${url.pathname.substring(1)}.html`);
let expHtml = null;
try {
expHtml = await readFile(expFile, 'utf-8');
@@ -209,7 +208,7 @@ describe('Rendering', () => {
}
if (!spec) {
// eslint-disable-next-line no-param-reassign
- spec = url.pathname.split('/').pop();
+ spec = url.pathname.substring(1);
}
const response = await render(url, '.plain');
const actHtml = response.body;
@@ -526,8 +525,8 @@ describe('Rendering', () => {
it('renders 404.html if content not found', async () => {
loader
- .rewrite('404.html', '404-test.html')
- .headers('404-test.html', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2009 17:50:00 GMT');
+ .rewrite('404.html', 'super-test/404-test.html')
+ .headers('super-test/404-test.html', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2009 17:50:00 GMT');
const { body, headers } = await testRender('not-found-with-handler', 'html', 404);
assert.deepStrictEqual(Object.fromEntries(headers.entries()), {
'content-type': 'text/html; charset=utf-8',
@@ -542,8 +541,8 @@ describe('Rendering', () => {
it('renders 404.html if content not found for .plain.html', async () => {
loader
- .rewrite('404.html', '404-test.html')
- .headers('404-test.html', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2009 17:50:00 GMT');
+ .rewrite('super-test/404.html', 'super-test/404-test.html')
+ .headers('super-test/404-test.html', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2009 17:50:00 GMT');
const { body, headers } = await testRender('not-found-with-handler.plain.html', 'html', 404);
assert.deepStrictEqual(Object.fromEntries(headers.entries()), {
'content-type': 'text/html; charset=utf-8',
@@ -557,8 +556,8 @@ describe('Rendering', () => {
it('renders 404.html if content not found for static html', async () => {
loader
- .rewrite('404.html', '404-test.html')
- .headers('404-test.html', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2009 17:50:00 GMT');
+ .rewrite('super-test/404.html', 'super-test/404-test.html')
+ .headers('super-test/404-test.html', 'x-amz-meta-x-source-last-modified', 'Wed, 12 Oct 2009 17:50:00 GMT');
const { body, headers } = await testRender('not-found-with-handler.html', 'html', 404);
assert.deepStrictEqual(Object.fromEntries(headers.entries()), {
'content-type': 'text/html; charset=utf-8',
@@ -631,7 +630,7 @@ describe('Rendering', () => {
});
it('renders redirect for static html (code)', async () => {
- loader.headers('static.html', 'x-amz-meta-redirect-location', '/foo');
+ loader.headers('super-test/static.html', 'x-amz-meta-redirect-location', '/foo');
const ret = await render(new URL('https://localhost/static.html'), '', 301);
assert.strictEqual(ret.headers.get('location'), '/foo');
});
@@ -671,6 +670,7 @@ describe('Rendering', () => {
assert.deepStrictEqual(Object.fromEntries(resp.headers.entries()), {
'access-control-allow-origin': '*',
'content-type': 'text/html; charset=utf-8',
+ 'last-modified': 'Fri, 30 Apr 2021 03:47:18 GMT',
'x-surrogate-key': 'AkcHu8fRFT7HarTR foo-id_metadata super-test--helix-pages--adobe_head foo-id AkcHu8fRFT7HarTR_metadata z8NGXvKB0X5Fzcnd',
link: '; rel=modulepreload; as=script; crossorigin=use-credentials',
});
@@ -696,8 +696,8 @@ describe('Rendering', () => {
it('respect folder mapping: render 404 if mapped missing', async () => {
loader.status('document1.md', 404);
loader.status('articles/document1.md', 404);
- loader.status('default-article.md', 404);
- loader.rewrite('404.html', '404-test.html');
+ loader.status('special/default-article.md', 404);
+ loader.rewrite('super-test/404.html', 'super-test/404-test.html');
const resp = await render(new URL('https://helix-pipeline.com/articles/document1'), '', 404);
assert.strictEqual(resp.body, 'There might be dragons.\n');
@@ -717,6 +717,9 @@ describe('Rendering', () => {
});
it('respect metadata with folder mapping: self and descendents', async () => {
+ loader
+ .headers('generic-product/metadata.json', 'last-modified', 'Thu Nov 07 2024 00:00:00 GMT+0000');
+
let resp = await render(new URL('https://helix-pipeline.com/products'));
assert.strictEqual(resp.status, 200);
assert.match(resp.body, //);
@@ -731,14 +734,14 @@ describe('Rendering', () => {
assert.deepStrictEqual(Object.fromEntries(resp.headers.entries()), {
'access-control-allow-origin': '*',
'content-type': 'text/html; charset=utf-8',
- 'last-modified': 'Fri, 30 Apr 2021 03:47:18 GMT',
+ 'last-modified': 'Thu Nov 07 2024 00:00:00 GMT+0000',
'x-surrogate-key': 'AkcHu8fRFT7HarTR foo-id_metadata super-test--helix-pages--adobe_head foo-id AkcHu8fRFT7HarTR_metadata z8NGXvKB0X5Fzcnd',
link: '; rel=modulepreload; as=script; crossorigin=use-credentials',
});
});
it('handles error while loading mapped metadata', async () => {
- loader.status('metadata.json', 500);
+ loader.status('generic-product/metadata.json', 500);
await render(new URL('https://helix-pipeline.com/products'), null, 502);
});
diff --git a/test/steps/fetch-mapped-metadata.test.js b/test/steps/fetch-mapped-metadata.test.js
index 9cd28320..5fb28279 100644
--- a/test/steps/fetch-mapped-metadata.test.js
+++ b/test/steps/fetch-mapped-metadata.test.js
@@ -11,7 +11,7 @@
*/
/* eslint-env mocha */
import assert from 'assert';
-import { PipelineStatusError } from '../../src/index.js';
+import { PipelineResponse, PipelineStatusError } from '../../src/index.js';
import { StaticS3Loader } from '../StaticS3Loader.js';
import fetchMappedMetadata from '../../src/steps/fetch-mapped-metadata.js';
import { FileS3Loader } from '../FileS3Loader.js';
@@ -30,7 +30,7 @@ describe('Fetch Mapped Metadata', () => {
s3Loader: new FileS3Loader()
.rewrite('foo-id/live/mapped/metadata.json', 'metadata-kv.json'),
};
- await fetchMappedMetadata(state);
+ await fetchMappedMetadata(state, new PipelineResponse());
assert.deepEqual(state.mappedMetadata.getModifiers('/new/foo'), {
description: 'Lorem ipsum dolor sit amet.',
keywords: 'ACME, CORP, PR',
@@ -53,7 +53,7 @@ describe('Fetch Mapped Metadata', () => {
body: 'this is no json!',
headers: new Map(),
}),
- });
+ }, new PipelineResponse());
await assert.rejects(promise, new PipelineStatusError(500, 'failed parsing of /mapped/metadata.json: Unexpected token \'h\', "this is no json!" is not valid JSON'));
});
@@ -74,7 +74,7 @@ describe('Fetch Mapped Metadata', () => {
}),
});
await assert.rejects(promise, new PipelineStatusError(500, 'failed loading of /mapped/metadata.json: data must be an array'));
- });
+ }, new PipelineResponse());
it('ignores metadata with no data array', async () => {
const state = {
@@ -94,7 +94,7 @@ describe('Fetch Mapped Metadata', () => {
};
await fetchMappedMetadata(state);
assert.strictEqual(state.mappedMetadata, Modifiers.EMPTY);
- });
+ }, new PipelineResponse());
it('throws error on generic error', async () => {
const promise = fetchMappedMetadata({
@@ -113,5 +113,5 @@ describe('Fetch Mapped Metadata', () => {
}),
});
await assert.rejects(promise, new PipelineStatusError(502, 'failed to load /mapped/metadata.json: 500'));
- });
+ }, new PipelineResponse());
});