Skip to content

Commit b023296

Browse files
authored
fix: pr feedback (#3285)
1 parent d3a2360 commit b023296

File tree

5 files changed

+213
-249
lines changed

5 files changed

+213
-249
lines changed

__tests__/schema/opportunity.ts

Lines changed: 91 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -455,14 +455,14 @@ describe('query opportunityById', () => {
455455
});
456456
});
457457

458-
describe('query getOpportunities', () => {
458+
describe('query opportunities', () => {
459459
const GET_OPPORTUNITIES_QUERY = /* GraphQL */ `
460460
query GetOpportunities(
461461
$state: ProtoEnumValue
462462
$first: Int
463463
$after: String
464464
) {
465-
getOpportunities(state: $state, first: $first, after: $after) {
465+
opportunities(state: $state, first: $first, after: $after) {
466466
pageInfo {
467467
hasNextPage
468468
hasPreviousPage
@@ -515,8 +515,8 @@ describe('query getOpportunities', () => {
515515
});
516516

517517
expect(res.errors).toBeFalsy();
518-
expect(res.data.getOpportunities.edges).toHaveLength(3);
519-
expect(res.data.getOpportunities.pageInfo.hasNextPage).toBe(false);
518+
expect(res.data.opportunities.edges).toHaveLength(3);
519+
expect(res.data.opportunities.pageInfo.hasNextPage).toBe(false);
520520
});
521521

522522
it('should return only recruiter DRAFT opportunities for authenticated non-team member', async () => {
@@ -527,8 +527,8 @@ describe('query getOpportunities', () => {
527527
});
528528

529529
expect(res.errors).toBeFalsy();
530-
expect(res.data.getOpportunities.edges).toHaveLength(1);
531-
expect(res.data.getOpportunities.edges[0].node).toEqual(
530+
expect(res.data.opportunities.edges).toHaveLength(1);
531+
expect(res.data.opportunities.edges[0].node).toEqual(
532532
expect.objectContaining({
533533
id: '550e8400-e29b-41d4-a716-446655440003',
534534
state: OpportunityState.DRAFT,
@@ -544,8 +544,8 @@ describe('query getOpportunities', () => {
544544
});
545545

546546
expect(res.errors).toBeFalsy();
547-
expect(res.data.getOpportunities.edges).toHaveLength(1);
548-
expect(res.data.getOpportunities.edges[0].node).toEqual(
547+
expect(res.data.opportunities.edges).toHaveLength(1);
548+
expect(res.data.opportunities.edges[0].node).toEqual(
549549
expect.objectContaining({
550550
id: '550e8400-e29b-41d4-a716-446655440004',
551551
state: OpportunityState.DRAFT,
@@ -562,8 +562,8 @@ describe('query getOpportunities', () => {
562562
});
563563

564564
expect(res.errors).toBeFalsy();
565-
expect(res.data.getOpportunities.edges).toHaveLength(2);
566-
const nodes = res.data.getOpportunities.edges.map(
565+
expect(res.data.opportunities.edges).toHaveLength(2);
566+
const nodes = res.data.opportunities.edges.map(
567567
(e: { node: unknown }) => e.node,
568568
);
569569
expect(nodes).toEqual(
@@ -590,9 +590,9 @@ describe('query getOpportunities', () => {
590590
});
591591

592592
expect(res.errors).toBeFalsy();
593-
expect(res.data.getOpportunities.edges).toHaveLength(2);
594-
expect(res.data.getOpportunities.pageInfo.hasNextPage).toBe(true);
595-
expect(res.data.getOpportunities.pageInfo.endCursor).toBeTruthy();
593+
expect(res.data.opportunities.edges).toHaveLength(2);
594+
expect(res.data.opportunities.pageInfo.hasNextPage).toBe(true);
595+
expect(res.data.opportunities.pageInfo.endCursor).toBeTruthy();
596596
});
597597

598598
it('should support pagination with after cursor', async () => {
@@ -604,19 +604,17 @@ describe('query getOpportunities', () => {
604604
});
605605

606606
expect(firstPage.errors).toBeFalsy();
607-
const endCursor = firstPage.data.getOpportunities.pageInfo.endCursor;
607+
const endCursor = firstPage.data.opportunities.pageInfo.endCursor;
608608

609609
// Get second page
610610
const secondPage = await client.query(GET_OPPORTUNITIES_QUERY, {
611611
variables: { state: OpportunityState.LIVE, first: 2, after: endCursor },
612612
});
613613

614614
expect(secondPage.errors).toBeFalsy();
615-
expect(secondPage.data.getOpportunities.edges).toHaveLength(1);
616-
expect(secondPage.data.getOpportunities.pageInfo.hasNextPage).toBe(false);
617-
expect(secondPage.data.getOpportunities.pageInfo.hasPreviousPage).toBe(
618-
true,
619-
);
615+
expect(secondPage.data.opportunities.edges).toHaveLength(1);
616+
expect(secondPage.data.opportunities.pageInfo.hasNextPage).toBe(false);
617+
expect(secondPage.data.opportunities.pageInfo.hasPreviousPage).toBe(true);
620618
});
621619
});
622620

@@ -736,14 +734,14 @@ describe('query getOpportunityMatch', () => {
736734
});
737735
});
738736

739-
describe('query getOpportunityMatches', () => {
737+
describe('query opportunityMatches', () => {
740738
const GET_OPPORTUNITY_MATCHES_QUERY = /* GraphQL */ `
741739
query GetOpportunityMatches(
742740
$opportunityId: ID!
743741
$first: Int
744742
$after: String
745743
) {
746-
getOpportunityMatches(
744+
opportunityMatches(
747745
opportunityId: $opportunityId
748746
first: $first
749747
after: $after
@@ -827,9 +825,9 @@ describe('query getOpportunityMatches', () => {
827825
});
828826

829827
expect(res.errors).toBeFalsy();
830-
expect(res.data.getOpportunityMatches.edges).toHaveLength(3);
828+
expect(res.data.opportunityMatches.edges).toHaveLength(3);
831829

832-
const statuses = res.data.getOpportunityMatches.edges.map(
830+
const statuses = res.data.opportunityMatches.edges.map(
833831
(e: { node: { status: string } }) => e.node.status,
834832
);
835833

@@ -856,7 +854,7 @@ describe('query getOpportunityMatches', () => {
856854

857855
expect(res.errors).toBeFalsy();
858856

859-
const acceptedMatch = res.data.getOpportunityMatches.edges.find(
857+
const acceptedMatch = res.data.opportunityMatches.edges.find(
860858
(e: { node: { status: string } }) =>
861859
e.node.status === 'candidate_accepted',
862860
);
@@ -884,7 +882,7 @@ describe('query getOpportunityMatches', () => {
884882

885883
expect(res.errors).toBeFalsy();
886884

887-
const acceptedMatch = res.data.getOpportunityMatches.edges.find(
885+
const acceptedMatch = res.data.opportunityMatches.edges.find(
888886
(e: { node: { status: string } }) =>
889887
e.node.status === 'candidate_accepted',
890888
);
@@ -915,9 +913,9 @@ describe('query getOpportunityMatches', () => {
915913
});
916914

917915
expect(res.errors).toBeFalsy();
918-
expect(res.data.getOpportunityMatches.edges).toHaveLength(2);
919-
expect(res.data.getOpportunityMatches.pageInfo.hasNextPage).toBe(true);
920-
expect(res.data.getOpportunityMatches.pageInfo.endCursor).toBeTruthy();
916+
expect(res.data.opportunityMatches.edges).toHaveLength(2);
917+
expect(res.data.opportunityMatches.pageInfo.hasNextPage).toBe(true);
918+
expect(res.data.opportunityMatches.pageInfo.endCursor).toBeTruthy();
921919
});
922920

923921
it('should support pagination with after cursor', async () => {
@@ -932,14 +930,12 @@ describe('query getOpportunityMatches', () => {
932930
});
933931

934932
expect(firstPage.errors).toBeFalsy();
935-
expect(firstPage.data.getOpportunityMatches.edges).toHaveLength(2);
936-
expect(firstPage.data.getOpportunityMatches.pageInfo.hasNextPage).toBe(
937-
true,
938-
);
939-
const firstUserIds = firstPage.data.getOpportunityMatches.edges.map(
933+
expect(firstPage.data.opportunityMatches.edges).toHaveLength(2);
934+
expect(firstPage.data.opportunityMatches.pageInfo.hasNextPage).toBe(true);
935+
const firstUserIds = firstPage.data.opportunityMatches.edges.map(
940936
(e: { node: { userId: string } }) => e.node.userId,
941937
);
942-
const endCursor = firstPage.data.getOpportunityMatches.pageInfo.endCursor;
938+
const endCursor = firstPage.data.opportunityMatches.pageInfo.endCursor;
943939

944940
// Get second page
945941
const secondPage = await client.query(GET_OPPORTUNITY_MATCHES_QUERY, {
@@ -951,15 +947,13 @@ describe('query getOpportunityMatches', () => {
951947
});
952948

953949
expect(secondPage.errors).toBeFalsy();
954-
expect(secondPage.data.getOpportunityMatches.edges).toHaveLength(1);
955-
expect(secondPage.data.getOpportunityMatches.pageInfo.hasNextPage).toBe(
956-
false,
957-
);
950+
expect(secondPage.data.opportunityMatches.edges).toHaveLength(1);
951+
expect(secondPage.data.opportunityMatches.pageInfo.hasNextPage).toBe(false);
958952
// Verify we got different results
959953
expect(firstUserIds).not.toContain(
960-
secondPage.data.getOpportunityMatches.edges[0].node.userId,
954+
secondPage.data.opportunityMatches.edges[0].node.userId,
961955
);
962-
expect(secondPage.data.getOpportunityMatches.pageInfo.hasPreviousPage).toBe(
956+
expect(secondPage.data.opportunityMatches.pageInfo.hasPreviousPage).toBe(
963957
true,
964958
);
965959
});
@@ -1014,8 +1008,63 @@ describe('query getOpportunityMatches', () => {
10141008
});
10151009

10161010
expect(res.errors).toBeFalsy();
1017-
expect(res.data.getOpportunityMatches.edges).toHaveLength(0);
1018-
expect(res.data.getOpportunityMatches.pageInfo.hasNextPage).toBe(false);
1011+
expect(res.data.opportunityMatches.edges).toHaveLength(0);
1012+
expect(res.data.opportunityMatches.pageInfo.hasNextPage).toBe(false);
1013+
});
1014+
1015+
it('should not expose salaryExpectation to recruiters viewing other candidates', async () => {
1016+
loggedUser = '1'; // Recruiter
1017+
1018+
// Add salaryExpectation to user 2's candidate preferences
1019+
await con.getRepository(UserCandidatePreference).update(
1020+
{ userId: usersFixture[1].id },
1021+
{
1022+
salaryExpectation: {
1023+
min: 120000,
1024+
period: SalaryPeriod.ANNUALLY,
1025+
},
1026+
},
1027+
);
1028+
1029+
const GET_OPPORTUNITY_MATCHES_WITH_SALARY_QUERY = /* GraphQL */ `
1030+
query GetOpportunityMatchesWithSalary($opportunityId: ID!, $first: Int) {
1031+
opportunityMatches(opportunityId: $opportunityId, first: $first) {
1032+
edges {
1033+
node {
1034+
userId
1035+
updatedAt
1036+
candidatePreferences {
1037+
status
1038+
role
1039+
salaryExpectation {
1040+
min
1041+
period
1042+
}
1043+
}
1044+
}
1045+
}
1046+
}
1047+
}
1048+
`;
1049+
1050+
const res = await client.query(GET_OPPORTUNITY_MATCHES_WITH_SALARY_QUERY, {
1051+
variables: {
1052+
opportunityId: '550e8400-e29b-41d4-a716-446655440001',
1053+
first: 10,
1054+
},
1055+
});
1056+
1057+
expect(res.errors).toBeFalsy();
1058+
1059+
// Find the match for user 2 (candidate with salaryExpectation)
1060+
const user2Match = res.data.opportunityMatches.edges.find(
1061+
(e: { node: { userId: string } }) => e.node.userId === '2',
1062+
);
1063+
1064+
expect(user2Match).toBeDefined();
1065+
expect(user2Match.node.candidatePreferences.role).toBe('Senior Developer');
1066+
// salaryExpectation should be null for recruiter viewing another candidate
1067+
expect(user2Match.node.candidatePreferences.salaryExpectation).toBeNull();
10191068
});
10201069
});
10211070

@@ -1874,22 +1923,6 @@ describe('mutation acceptOpportunityMatch', () => {
18741923
'Access denied! Match is not pending',
18751924
);
18761925
});
1877-
1878-
it('should return error when the opportunity is not live', async () => {
1879-
loggedUser = '1';
1880-
1881-
await testMutationErrorCode(
1882-
client,
1883-
{
1884-
mutation: MUTATION,
1885-
variables: {
1886-
id: '550e8400-e29b-41d4-a716-446655440003',
1887-
},
1888-
},
1889-
'FORBIDDEN',
1890-
'Access denied! Opportunity is not live',
1891-
);
1892-
});
18931926
});
18941927

18951928
describe('mutation rejectOpportunityMatch', () => {
@@ -1990,22 +2023,6 @@ describe('mutation rejectOpportunityMatch', () => {
19902023
'Access denied! Match is not pending',
19912024
);
19922025
});
1993-
1994-
it('should return error when the opportunity is not live', async () => {
1995-
loggedUser = '1';
1996-
1997-
await testMutationErrorCode(
1998-
client,
1999-
{
2000-
mutation: MUTATION,
2001-
variables: {
2002-
id: '550e8400-e29b-41d4-a716-446655440003',
2003-
},
2004-
},
2005-
'FORBIDDEN',
2006-
'Access denied! Opportunity is not live',
2007-
);
2008-
});
20092026
});
20102027

20112028
describe('mutation recruiterAcceptOpportunityMatch', () => {
@@ -2107,40 +2124,6 @@ describe('mutation recruiterAcceptOpportunityMatch', () => {
21072124
);
21082125
});
21092126

2110-
it('should return error when the opportunity is not live', async () => {
2111-
loggedUser = '1';
2112-
2113-
await saveFixtures(con, OpportunityUser, [
2114-
{
2115-
opportunityId: opportunitiesFixture[2].id,
2116-
userId: usersFixture[0].id,
2117-
type: OpportunityUserType.Recruiter,
2118-
},
2119-
]);
2120-
2121-
// Update the existing Pending match to CandidateAccepted
2122-
await con.getRepository(OpportunityMatch).update(
2123-
{
2124-
opportunityId: opportunitiesFixture[2].id,
2125-
userId: usersFixture[0].id,
2126-
},
2127-
{ status: OpportunityMatchStatus.CandidateAccepted },
2128-
);
2129-
2130-
await testMutationErrorCode(
2131-
client,
2132-
{
2133-
mutation: MUTATION,
2134-
variables: {
2135-
opportunityId: '550e8400-e29b-41d4-a716-446655440003', // DRAFT opportunity
2136-
candidateUserId: '1',
2137-
},
2138-
},
2139-
'FORBIDDEN',
2140-
'Access denied! Opportunity is not live',
2141-
);
2142-
});
2143-
21442127
it('should return error when match does not exist', async () => {
21452128
loggedUser = '1';
21462129

@@ -2427,40 +2410,6 @@ describe('mutation recruiterRejectOpportunityMatch', () => {
24272410
);
24282411
});
24292412

2430-
it('should return error when the opportunity is not live', async () => {
2431-
loggedUser = '1';
2432-
2433-
await saveFixtures(con, OpportunityUser, [
2434-
{
2435-
opportunityId: opportunitiesFixture[2].id,
2436-
userId: usersFixture[0].id,
2437-
type: OpportunityUserType.Recruiter,
2438-
},
2439-
]);
2440-
2441-
// Update the existing Pending match to CandidateAccepted
2442-
await con.getRepository(OpportunityMatch).update(
2443-
{
2444-
opportunityId: opportunitiesFixture[2].id,
2445-
userId: usersFixture[0].id,
2446-
},
2447-
{ status: OpportunityMatchStatus.CandidateAccepted },
2448-
);
2449-
2450-
await testMutationErrorCode(
2451-
client,
2452-
{
2453-
mutation: MUTATION,
2454-
variables: {
2455-
opportunityId: '550e8400-e29b-41d4-a716-446655440003', // DRAFT opportunity
2456-
candidateUserId: '1',
2457-
},
2458-
},
2459-
'FORBIDDEN',
2460-
'Access denied! Opportunity is not live',
2461-
);
2462-
});
2463-
24642413
it('should return error when match does not exist', async () => {
24652414
loggedUser = '1';
24662415

0 commit comments

Comments
 (0)