Skip to content

Commit

Permalink
Include fields in GET /applicationForms/{id} optionally
Browse files Browse the repository at this point in the history
Use query parameter `includeFields=true` to include application form
fields in the response from `GET /applicationForms/{id}`, otherwise a
shallow response with only direct attributes on application form will
be returned.

The implementation is more akin to the one for /proposals in PR #210.

Issue #132 Provide visibility of application form fields
  • Loading branch information
bickelj committed Feb 13, 2023
1 parent 99c738f commit 3b0f4f7
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 306 deletions.
221 changes: 158 additions & 63 deletions src/__tests__/applicationForm.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ describe('/applicationForms', () => {
it('returns an empty array when no data is present', async () => {
await agent
.get('/applicationForms')
.query({ includeFields: 'true' })
.set(dummyApiKey)
.expect(200, []);
});
Expand Down Expand Up @@ -82,7 +81,50 @@ describe('/applicationForms', () => {
);
});

it('returns all application forms and their fields present in the database', async () => {
it('returns an application form without its fields', async () => {
await db.query(`
INSERT INTO opportunities (title)
VALUES
( 'Summer opportunity 🩴' ),
( 'Spring opportunity 🌺' );
`);
await db.query(`
INSERT INTO application_forms (
opportunity_id,
version,
created_at
)
VALUES
( 1, 1, '2510-02-02 00:00:01+0000' ),
( 1, 2, '2510-02-02 00:00:02+0000' ),
( 2, 1, '2510-02-02 00:00:03+0000' )
`);
await db.query(`
INSERT INTO canonical_fields (
label,
short_code,
data_type,
created_at
)
VALUES
( 'Organization Name', 'organizationName', '{ type: "string" }', '2510-02-02 00:00:04+0000' ),
( 'Years of work', 'yearsOfWork', '{ type: "integer" }', '2510-02-02 00:00:05+0000' );
`);
await agent
.get('/applicationForms/2')
.set(dummyApiKey)
.expect(
200,
{
id: 2,
opportunityId: 1,
version: 2,
createdAt: '2510-02-02T00:00:02.000Z',
},
);
});

it('returns an application form with its fields', async () => {
await db.query(`
INSERT INTO opportunities (title)
VALUES
Expand Down Expand Up @@ -126,68 +168,35 @@ describe('/applicationForms', () => {
( 2, 2, 1, 'Duration of work in years', '2510-02-01 00:00:09+0000' )
`);
await agent
.get('/applicationForms')
.get('/applicationForms/2')
.query({ includeFields: 'true' })
.set(dummyApiKey)
.expect(
200,
[
{
id: 1,
opportunityId: 1,
version: 1,
fields: [],
createdAt: '2510-02-01T00:00:01.000Z',
},
{
id: 2,
opportunityId: 1,
version: 2,
fields: [
{
id: 4,
applicationFormId: 2,
canonicalFieldId: 2,
position: 1,
label: 'Duration of work in years',
createdAt: '2510-02-01T00:00:09.000Z',
},
{
id: 3,
applicationFormId: 2,
canonicalFieldId: 1,
position: 2,
label: 'Name of Organization',
createdAt: '2510-02-01T00:00:08.000Z',
},
],
createdAt: '2510-02-01T00:00:02.000Z',
},
{
id: 3,
opportunityId: 2,
version: 1,
fields: [
{
id: 1,
applicationFormId: 3,
canonicalFieldId: 2,
position: 1,
label: 'Anni Worki',
createdAt: '2510-02-01T00:00:06.000Z',
},
{
id: 2,
applicationFormId: 3,
canonicalFieldId: 1,
position: 2,
label: 'Org Nomen',
createdAt: '2510-02-01T00:00:07.000Z',
},
],
createdAt: '2510-02-01T00:00:03.000Z',
},
],
{
id: 2,
opportunityId: 1,
version: 2,
fields: [
{
id: 4,
applicationFormId: 2,
canonicalFieldId: 2,
position: 1,
label: 'Duration of work in years',
createdAt: '2510-02-01T00:00:09.000Z',
},
{
id: 3,
applicationFormId: 2,
canonicalFieldId: 1,
position: 2,
label: 'Name of Organization',
createdAt: '2510-02-01T00:00:08.000Z',
},
],
createdAt: '2510-02-01T00:00:02.000Z',
},
);
});

Expand All @@ -197,7 +206,7 @@ describe('/applicationForms', () => {
rows: [{ foo: 'not a valid result' }],
}) as Result<object>);
const result = await agent
.get('/applicationForms')
.get('/applicationForms/2')
.query({ includeFields: 'true' })
.set(dummyApiKey)
.expect(500);
Expand Down Expand Up @@ -237,7 +246,6 @@ describe('/applicationForms', () => {
});
const result = await agent
.get('/applicationForms')
.query({ includeFields: 'true' })
.set(dummyApiKey)
.expect(503);
expect(result.body).toMatchObject({
Expand All @@ -247,6 +255,94 @@ describe('/applicationForms', () => {
}],
});
});

it('returns 503 DatabaseError if an insufficient resources database error is thrown when selecting one', async () => {
jest.spyOn(db, 'sql')
.mockImplementationOnce(async () => {
throw new TinyPgError(
'Something went wrong',
undefined,
{
error: {
code: PostgresErrorCode.INSUFFICIENT_RESOURCES,
},
},
);
});
const result = await agent
.get('/applicationForms/3')
.set(dummyApiKey)
.expect(503);
expect(result.body).toMatchObject({
name: 'DatabaseError',
details: [{
code: PostgresErrorCode.INSUFFICIENT_RESOURCES,
}],
});
});

it('should error if the database returns an unexpected data structure', async () => {
jest.spyOn(db, 'sql')
.mockImplementationOnce(async () => ({
rows: [{ foo: 'not a valid applicationForm' }],
}) as Result<object>);
const result = await agent
.get('/applicationForms/5')
.set(dummyApiKey)
.expect(500);
expect(result.body).toMatchObject({
name: 'InternalValidationError',
details: expect.any(Array) as unknown[],
});
});

it('should return 404 when the applicationForm is not found (shallow)', async () => {
const result = await agent
.get('/applicationForms/6')
.set(dummyApiKey)
.expect(404);
expect(result.body).toMatchObject({
name: 'NotFoundError',
details: expect.any(Array) as unknown[],
});
});
it('should return 404 when the applicationForm is not found (with fields)', async () => {
const result = await agent
.get('/applicationForms/7')
.query({ includeFields: 'true' })
.set(dummyApiKey)
.expect(404);
expect(result.body).toMatchObject({
name: 'NotFoundError',
details: expect.any(Array) as unknown[],
});
});
});

it('returns 503 DatabaseError if an insufficient resources database error is thrown when selecting one', async () => {
jest.spyOn(db, 'sql')
.mockImplementationOnce(async () => {
throw new TinyPgError(
'Something went wrong',
undefined,
{
error: {
code: PostgresErrorCode.INSUFFICIENT_RESOURCES,
},
},
);
});
const result = await agent
.get('/applicationForms/4')
.set(dummyApiKey)
.query({ includeFields: 'true' })
.expect(503);
expect(result.body).toMatchObject({
name: 'DatabaseError',
details: [{
code: PostgresErrorCode.INSUFFICIENT_RESOURCES,
}],
});
});

describe('POST /', () => {
Expand Down Expand Up @@ -503,7 +599,6 @@ describe('/applicationForms', () => {
id: 1,
opportunityId: 1,
version: 1,
fields: [],
createdAt: new Date(),
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ SELECT
aff.created_at as "createdAt"
FROM application_form_fields aff
WHERE aff.application_form_id = :applicationFormId
ORDER BY aff.position;
1 change: 1 addition & 0 deletions src/database/queries/applicationForms/selectAll.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ SELECT af.id AS "id",
af.version AS "version",
af.created_at AS "createdAt"
FROM application_forms af;

13 changes: 0 additions & 13 deletions src/database/queries/applicationForms/selectAllWithFields.sql

This file was deleted.

1 change: 1 addition & 0 deletions src/database/queries/applicationForms/selectById.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ SELECT af.id AS "id",
af.created_at AS "createdAt"
FROM application_forms af
WHERE af.id = :id;

14 changes: 0 additions & 14 deletions src/database/queries/applicationForms/selectByIdWithFields.sql

This file was deleted.

21 changes: 0 additions & 21 deletions src/handlers/__tests__/applicationFormsHandlers.unit.test.ts

This file was deleted.

0 comments on commit 3b0f4f7

Please sign in to comment.