Add custom routes to pages router (#7231)

* added custom routes

* fixed docs typos

* added page.customRoutes config validation

* added 404 response if missing custom route response

* added docs

* minor README formatting

* added CHANGELOG entry

* fixed bug in definitions builder that did not recognize array of custom type

* added missing route handler definition

* fixed custom routes definition
This commit is contained in:
Manuel
2021-03-07 13:51:35 +01:00
committed by GitHub
parent cac6951be0
commit de50b7b23d
10 changed files with 327 additions and 17 deletions

View File

@@ -252,6 +252,9 @@ describe('Pages Router', () => {
expect(Config.get(Parse.applicationId).pages.customUrls).toBe(
Definitions.PagesOptions.customUrls.default
);
expect(Config.get(Parse.applicationId).pages.customRoutes).toBe(
Definitions.PagesOptions.customRoutes.default
);
});
it('throws on invalid configuration', async () => {
@@ -296,6 +299,10 @@ describe('Pages Router', () => {
{ localizationFallbackLocale: 0 },
{ localizationFallbackLocale: {} },
{ localizationFallbackLocale: [] },
{ customRoutes: true },
{ customRoutes: 0 },
{ customRoutes: 'a' },
{ customRoutes: {} },
];
for (const option of options) {
await expectAsync(reconfigureServerWithPagesConfig(option)).toBeRejected();
@@ -972,6 +979,153 @@ describe('Pages Router', () => {
});
});
describe('custom route', () => {
it('handles custom route with GET', async () => {
config.pages.customRoutes = [
{
method: 'GET',
path: 'custom_page',
handler: async req => {
expect(req).toBeDefined();
expect(req.method).toBe('GET');
return { file: 'custom_page.html' };
},
},
];
await reconfigureServer(config);
const handlerSpy = spyOn(config.pages.customRoutes[0], 'handler').and.callThrough();
const url = `${config.publicServerURL}/apps/${config.appId}/custom_page`;
const response = await request({
url: url,
followRedirects: false,
}).catch(e => e);
expect(response.status).toBe(200);
expect(response.text).toMatch(config.appName);
expect(handlerSpy).toHaveBeenCalled();
});
it('handles custom route with POST', async () => {
config.pages.customRoutes = [
{
method: 'POST',
path: 'custom_page',
handler: async req => {
expect(req).toBeDefined();
expect(req.method).toBe('POST');
return { file: 'custom_page.html' };
},
},
];
const handlerSpy = spyOn(config.pages.customRoutes[0], 'handler').and.callThrough();
await reconfigureServer(config);
const url = `${config.publicServerURL}/apps/${config.appId}/custom_page`;
const response = await request({
url: url,
followRedirects: false,
method: 'POST',
}).catch(e => e);
expect(response.status).toBe(200);
expect(response.text).toMatch(config.appName);
expect(handlerSpy).toHaveBeenCalled();
});
it('handles multiple custom routes', async () => {
config.pages.customRoutes = [
{
method: 'GET',
path: 'custom_page',
handler: async req => {
expect(req).toBeDefined();
expect(req.method).toBe('GET');
return { file: 'custom_page.html' };
},
},
{
method: 'POST',
path: 'custom_page',
handler: async req => {
expect(req).toBeDefined();
expect(req.method).toBe('POST');
return { file: 'custom_page.html' };
},
},
];
const getHandlerSpy = spyOn(config.pages.customRoutes[0], 'handler').and.callThrough();
const postHandlerSpy = spyOn(config.pages.customRoutes[1], 'handler').and.callThrough();
await reconfigureServer(config);
const url = `${config.publicServerURL}/apps/${config.appId}/custom_page`;
const getResponse = await request({
url: url,
followRedirects: false,
method: 'GET',
}).catch(e => e);
expect(getResponse.status).toBe(200);
expect(getResponse.text).toMatch(config.appName);
expect(getHandlerSpy).toHaveBeenCalled();
const postResponse = await request({
url: url,
followRedirects: false,
method: 'POST',
}).catch(e => e);
expect(postResponse.status).toBe(200);
expect(postResponse.text).toMatch(config.appName);
expect(postHandlerSpy).toHaveBeenCalled();
});
it('handles custom route with async handler', async () => {
config.pages.customRoutes = [
{
method: 'GET',
path: 'custom_page',
handler: async req => {
expect(req).toBeDefined();
expect(req.method).toBe('GET');
const file = await new Promise(resolve =>
setTimeout(resolve('custom_page.html'), 1000)
);
return { file };
},
},
];
await reconfigureServer(config);
const handlerSpy = spyOn(config.pages.customRoutes[0], 'handler').and.callThrough();
const url = `${config.publicServerURL}/apps/${config.appId}/custom_page`;
const response = await request({
url: url,
followRedirects: false,
}).catch(e => e);
expect(response.status).toBe(200);
expect(response.text).toMatch(config.appName);
expect(handlerSpy).toHaveBeenCalled();
});
it('returns 404 if custom route does not return page', async () => {
config.pages.customRoutes = [
{
method: 'GET',
path: 'custom_page',
handler: async () => {},
},
];
await reconfigureServer(config);
const handlerSpy = spyOn(config.pages.customRoutes[0], 'handler').and.callThrough();
const url = `${config.publicServerURL}/apps/${config.appId}/custom_page`;
const response = await request({
url: url,
followRedirects: false,
}).catch(e => e);
expect(response.status).toBe(404);
expect(response.text).toMatch('Not found');
expect(handlerSpy).toHaveBeenCalled();
});
});
describe('custom endpoint', () => {
it('password reset works with custom endpoint', async () => {
config.pages.pagesEndpoint = 'customEndpoint';