Skip to content
Draft
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
1 change: 1 addition & 0 deletions src/controllers/validation/locations.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default {
.max(1000),
searchString: Joi.string().allow(''),
organizationName: Joi.string().min(3),
noServices: Joi.boolean(),
zipcodes: Joi.array().max(200).items(Joi.string().length(5).regex(/\d+/)),
taxonomyId: Joi.string(),
openAt: Joi.date().iso(),
Expand Down
21 changes: 18 additions & 3 deletions src/models/location.js
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,9 @@ module.exports = (sequelize, DataTypes, Op) => {
totalNumLocations = (await Location.findUniqueLocationIds(
filterParameters,
[distanceCondition],
{},
null,
noServices,
)).length;

locationIds = await Location.findUniqueLocationIds(
Expand All @@ -585,20 +588,32 @@ module.exports = (sequelize, DataTypes, Op) => {
// aren't natively supported by sequelize and would require a raw query.
// For now, the simplicity and security of sequelize seems worth the slight performance hit.
if (minResults && locationIds.length < minResults) {
totalNumLocations = (await Location.findUniqueLocationIds(filterParameters, [])).length;
totalNumLocations = (await Location.findUniqueLocationIds(
filterParameters,
[],
{},
null,
noServices,
)).length;
locationIds = await Location.findUniqueLocationIds(filterParameters, [], {
order,
limit: minResults,
offset,
}, selectedAttributeForOrderBy, noServices);
}
} else {
totalNumLocations = (await Location.findUniqueLocationIds(filterParameters, [])).length;
totalNumLocations = (await Location.findUniqueLocationIds(
filterParameters,
[],
{},
null,
noServices,
)).length;
locationIds = await Location.findUniqueLocationIds(filterParameters, [], {
limit,
offset,
order,
}, selectedAttributeForOrderBy);
}, selectedAttributeForOrderBy, noServices);
}

const additionalLocationData = locationFieldsOnly ? [
Expand Down
23 changes: 23 additions & 0 deletions test/integration/find-locations.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,29 @@ describe('find locations', () => {
]));
}));

it('should include locations without linked services when requested', async () => {
const noServiceLocation = await organization.createLocation({
name: 'Service-less center',
position: pointNearOrigin,
});

return request(app).get('/locations').query({
organizationName: 'test org',
noServices: true,
})
.expect(200)
.then((res) => {
const returnedLocations = res.body;
expect(returnedLocations).toHaveLength(4);
expect(returnedLocations).toEqual(expect.arrayContaining([
expect.objectContaining({ name: primaryLocation.name }),
expect.objectContaining({ name: otherServiceLocation.name }),
expect.objectContaining({ name: farLocation.name }),
expect.objectContaining({ name: noServiceLocation.name }),
]));
});
});

it('should not match locations whose organization doesn\'t have the string in its name', () =>
request(app).get('/locations').query({ organizationName: 'center' })
.expect(200)
Expand Down
28 changes: 27 additions & 1 deletion test/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,25 @@ jest.setTimeout(10000);
process.env.DATABASE_NAME = 'test';
process.env.DATABASE_LOGGING = 'false';

const models = require('../src/models');
jest.mock('openai', () => function OpenAI() {
return {
chat: {
completions: {
create: jest.fn(),
},
},
};
});

jest.mock('@aws-sdk/client-cognito-identity-provider', () => ({
CognitoIdentityProviderClient: jest.fn(() => ({
send: jest.fn(),
})),
ListUsersCommand: jest.fn(),
}));

const unitTestRun = process.argv.some(arg => arg.includes('test/unit'));
const models = unitTestRun ? null : require('../src/models');

async function execScript(script) {
// run the migrations
Expand All @@ -25,6 +43,10 @@ async function execScript(script) {
}

beforeAll(async () => {
if (unitTestRun) {
return;
}

// reset the database state
await models.sequelize.query(`
DO $$
Expand Down Expand Up @@ -53,6 +75,10 @@ beforeAll(async () => {
await execScript('npx sequelize-cli db:migrate --name 20240607172205-age-filter');
});
afterAll(async () => {
if (unitTestRun) {
return;
}

// eslint-disable-next-line no-implied-eval
await execScript('npx sequelize-cli db:migrate:undo --name 20240607172205-age-filter');
await models.sequelize.close();
Expand Down
38 changes: 38 additions & 0 deletions test/unit/location-search.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import createLocationModel from '../../src/models/location';

describe('Location.search', () => {
function createModel() {
const Location = {};
const sequelize = {
define: jest.fn(() => Location),
literal: jest.fn(value => value),
models: {
EventRelatedInfo: {},
HolidaySchedule: {},
Organization: {},
Service: {},
},
};

createLocationModel(sequelize, {}, {});
return Location;
}

it('threads noServices through non-radius organization searches', async () => {
const Location = createModel();
const filterParameters = { organizationName: 'Housing Works' };

Location.findUniqueLocationIds = jest.fn()
.mockResolvedValueOnce(['location-1'])
.mockResolvedValueOnce([]);

await Location.search({
filterParameters,
noServices: true,
});

expect(Location.findUniqueLocationIds).toHaveBeenCalledTimes(2);
expect(Location.findUniqueLocationIds.mock.calls.map(call => call[4]))
.toEqual([true, true]);
});
});