Skip to content

Commit 6dd1172

Browse files
committed
Merge remote-tracking branch 'origin/feat-slack-channel' into feat-slack-channel
2 parents dbc1ec5 + a4dfa80 commit 6dd1172

File tree

16 files changed

+445
-64
lines changed

16 files changed

+445
-64
lines changed

__tests__/alerts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ describe('mutation clearOpportunityAlert', () => {
408408
it('should clear opportunityId from alerts', async () => {
409409
loggedUser = '1';
410410

411-
saveFixtures(con, OpportunityJob, [
411+
await saveFixtures(con, OpportunityJob, [
412412
{
413413
...opportunitiesFixture[0],
414414
id: '45bef485-ba42-4fd9-8c8c-a2ea4b2d1d62',

__tests__/boot.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ const LOGGED_IN_BODY = {
159159
clickbaitTries: null,
160160
hasLocationSet: false,
161161
location: null,
162+
hideExperience: false,
162163
},
163164
marketingCta: null,
164165
feeds: [],

__tests__/helpers.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747
BrokkrService,
4848
ExtractMarkdownResponse,
4949
ParseCVResponse,
50+
ParseError,
5051
} from '@dailydotdev/schema';
5152
import { createClient, type ClickHouseClient } from '@clickhouse/client';
5253
import * as clickhouseCommon from '../src/common/clickhouse';
@@ -450,7 +451,9 @@ export const createMockBrokkrTransport = () =>
450451
},
451452
parseCV: (request) => {
452453
if (request.blobName === 'empty-cv-mock') {
453-
return new ParseCVResponse({});
454+
return new ParseCVResponse({
455+
errors: [new ParseError({ message: 'Empty CV' })],
456+
});
454457
}
455458

456459
return new ParseCVResponse({

__tests__/notifications/index.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
NotificationDoneByContext,
1111
NotificationGiftPlusContext,
1212
type NotificationOpportunityMatchContext,
13+
type NotificationParsedCVProfileContext,
1314
type NotificationPostAnalyticsContext,
1415
NotificationPostContext,
1516
NotificationPostModerationContext,
@@ -2179,9 +2180,10 @@ describe('parsed_cv_profile notifications', () => {
21792180

21802181
it('should notify when parsed CV profile is ready', async () => {
21812182
const type = NotificationType.ParsedCVProfile;
2182-
const ctx: NotificationUserContext = {
2183+
const ctx: NotificationParsedCVProfileContext = {
21832184
userIds: ['1'],
21842185
user: usersFixture[0] as Reference<User>,
2186+
status: 'success',
21852187
};
21862188

21872189
const actual = generateNotificationV2(type, ctx);
@@ -2202,5 +2204,40 @@ describe('parsed_cv_profile notifications', () => {
22022204
type: 'user',
22032205
},
22042206
]);
2207+
expect(actual.notification.title).toBe(
2208+
'Great news — we parsed your CV successfully, and your experience has been added to <u>your profile</u>!',
2209+
);
2210+
});
2211+
2212+
it('should notify when parsed CV profile failed', async () => {
2213+
const type = NotificationType.ParsedCVProfile;
2214+
const ctx: NotificationParsedCVProfileContext = {
2215+
userIds: ['1'],
2216+
user: usersFixture[0] as Reference<User>,
2217+
status: 'failed',
2218+
};
2219+
2220+
const actual = generateNotificationV2(type, ctx);
2221+
expect(actual.notification.type).toEqual(type);
2222+
expect(actual.userIds).toEqual(['1']);
2223+
expect(actual.notification.public).toEqual(true);
2224+
expect(actual.notification.referenceId).toEqual('1');
2225+
expect(actual.notification.targetUrl).toEqual(
2226+
'http://localhost:5002/idoshamun',
2227+
);
2228+
expect(actual.attachments!.length).toEqual(0);
2229+
expect(actual.avatars).toEqual([
2230+
{
2231+
image: 'https://daily.dev/ido.jpg',
2232+
name: 'Ido',
2233+
referenceId: '1',
2234+
targetUrl: 'http://localhost:5002/idoshamun',
2235+
type: 'user',
2236+
},
2237+
]);
2238+
2239+
expect(actual.notification.title).toBe(
2240+
"We couldn't parse your CV — sorry about that! The good news is you can still add your experience manually in <u>your profile</u>.",
2241+
);
22052242
});
22062243
});

__tests__/schema/profile.ts

Lines changed: 130 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,65 @@ describe('query userExperiences', () => {
320320
});
321321
});
322322

323+
it('should return empty list when viewing another user with hideExperience enabled', async () => {
324+
loggedUser = '1';
325+
326+
// Set user 2's hideExperience to true
327+
await con.getRepository(User).update({ id: '2' }, { hideExperience: true });
328+
329+
const res = await client.query(USER_EXPERIENCES_QUERY, {
330+
variables: { userId: '2' },
331+
});
332+
333+
expect(res.errors).toBeFalsy();
334+
expect(res.data.userExperiences.edges).toHaveLength(0);
335+
expect(res.data.userExperiences.pageInfo.hasNextPage).toBe(false);
336+
});
337+
338+
it('should return own experiences even with hideExperience enabled', async () => {
339+
loggedUser = '1';
340+
341+
// Set user 1's hideExperience to true
342+
await con.getRepository(User).update({ id: '1' }, { hideExperience: true });
343+
344+
const res = await client.query(USER_EXPERIENCES_QUERY, {
345+
variables: { userId: '1' },
346+
});
347+
348+
expect(res.errors).toBeFalsy();
349+
expect(res.data.userExperiences.edges).toHaveLength(4);
350+
});
351+
352+
it('should return experiences for another user when hideExperience is false', async () => {
353+
loggedUser = '1';
354+
355+
// Explicitly set user 2's hideExperience to false
356+
await con
357+
.getRepository(User)
358+
.update({ id: '2' }, { hideExperience: false });
359+
360+
const res = await client.query(USER_EXPERIENCES_QUERY, {
361+
variables: { userId: '2' },
362+
});
363+
364+
expect(res.errors).toBeFalsy();
365+
expect(res.data.userExperiences.edges).toHaveLength(1);
366+
});
367+
368+
it('should return empty list for anonymous user when owner has hideExperience enabled', async () => {
369+
loggedUser = null;
370+
371+
// Set user 2's hideExperience to true
372+
await con.getRepository(User).update({ id: '2' }, { hideExperience: true });
373+
374+
const res = await client.query(USER_EXPERIENCES_QUERY, {
375+
variables: { userId: '2' },
376+
});
377+
378+
expect(res.errors).toBeFalsy();
379+
expect(res.data.userExperiences.edges).toHaveLength(0);
380+
});
381+
323382
it('should return cursor for each edge', async () => {
324383
loggedUser = '1';
325384

@@ -447,17 +506,15 @@ describe('query userExperienceById', () => {
447506
});
448507
});
449508

450-
it('should return error when experience does not exist', async () => {
509+
it('should return null when experience does not exist', async () => {
451510
loggedUser = '1';
452511

453-
await testQueryErrorCode(
454-
client,
455-
{
456-
query: USER_EXPERIENCE_BY_ID_QUERY,
457-
variables: { id: 'f47ac10b-58cc-4372-a567-3e02b2c3d479' }, // manually adjusted to be unique
458-
},
459-
'NOT_FOUND',
460-
);
512+
const res = await client.query(USER_EXPERIENCE_BY_ID_QUERY, {
513+
variables: { id: 'f47ac10b-58cc-4372-a567-3e02b2c3d479' }, // manually adjusted to be unique
514+
});
515+
516+
expect(res.errors).toBeFalsy();
517+
expect(res.data.userExperienceById).toBeNull();
461518
});
462519

463520
it('should work for non-logged-in users', async () => {
@@ -486,6 +543,70 @@ describe('query userExperienceById', () => {
486543
title: 'Product Manager',
487544
});
488545
});
546+
547+
it('should return null when viewing another user experience with hideExperience enabled', async () => {
548+
loggedUser = '1';
549+
550+
// Set user 2's hideExperience to true
551+
await con.getRepository(User).update({ id: '2' }, { hideExperience: true });
552+
553+
const res = await client.query(USER_EXPERIENCE_BY_ID_QUERY, {
554+
variables: { id: 'd4e5f6a7-89ab-4def-c012-456789012345' }, // User 2's experience
555+
});
556+
557+
expect(res.errors).toBeFalsy();
558+
expect(res.data.userExperienceById).toBeNull();
559+
});
560+
561+
it('should return own experience even with hideExperience enabled', async () => {
562+
loggedUser = '1';
563+
564+
// Set user 1's hideExperience to true
565+
await con.getRepository(User).update({ id: '1' }, { hideExperience: true });
566+
567+
const res = await client.query(USER_EXPERIENCE_BY_ID_QUERY, {
568+
variables: { id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479' }, // User 1's experience
569+
});
570+
571+
expect(res.errors).toBeFalsy();
572+
expect(res.data.userExperienceById).toMatchObject({
573+
id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
574+
title: 'Senior Software Engineer',
575+
});
576+
});
577+
578+
it('should return experience from another user when hideExperience is false', async () => {
579+
loggedUser = '1';
580+
581+
// Explicitly set user 2's hideExperience to false
582+
await con
583+
.getRepository(User)
584+
.update({ id: '2' }, { hideExperience: false });
585+
586+
const res = await client.query(USER_EXPERIENCE_BY_ID_QUERY, {
587+
variables: { id: 'd4e5f6a7-89ab-4def-c012-456789012345' },
588+
});
589+
590+
expect(res.errors).toBeFalsy();
591+
expect(res.data.userExperienceById).toMatchObject({
592+
id: 'd4e5f6a7-89ab-4def-c012-456789012345',
593+
title: 'Product Manager',
594+
});
595+
});
596+
597+
it('should return null for anonymous user when owner has hideExperience enabled', async () => {
598+
loggedUser = null;
599+
600+
// Set user 1's hideExperience to true
601+
await con.getRepository(User).update({ id: '1' }, { hideExperience: true });
602+
603+
const res = await client.query(USER_EXPERIENCE_BY_ID_QUERY, {
604+
variables: { id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479' }, // User 1's experience
605+
});
606+
607+
expect(res.errors).toBeFalsy();
608+
expect(res.data.userExperienceById).toBeNull();
609+
});
489610
});
490611

491612
describe('mutation upsertUserGeneralExperience', () => {

__tests__/updateUserInfo.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ describe('mutation updateUserInfo', () => {
9696
country
9797
city
9898
}
99+
hideExperience
99100
}
100101
}
101102
`;
@@ -662,4 +663,53 @@ describe('mutation updateUserInfo', () => {
662663
expect(updatedUser?.readmeHtml).toContain('<h1>');
663664
// locationId check skipped - requires DatasetLocation records
664665
});
666+
667+
it('should update hideExperience', async () => {
668+
loggedUser = '1';
669+
const repo = con.getRepository(User);
670+
671+
// Verify initial state is false
672+
const user = await repo.findOneBy({ id: loggedUser });
673+
expect(user?.hideExperience).toBe(false);
674+
675+
const res = await client.mutate(MUTATION, {
676+
variables: {
677+
data: {
678+
hideExperience: true,
679+
username: 'testuser',
680+
name: 'Test User',
681+
},
682+
},
683+
});
684+
685+
expect(res.errors).toBeFalsy();
686+
expect(res.data.updateUserInfo.hideExperience).toBe(true);
687+
688+
const updatedUser = await repo.findOneBy({ id: loggedUser });
689+
expect(updatedUser?.hideExperience).toBe(true);
690+
});
691+
692+
it('should update hideExperience to false', async () => {
693+
loggedUser = '1';
694+
const repo = con.getRepository(User);
695+
696+
// Set hideExperience to true first
697+
await repo.update({ id: loggedUser }, { hideExperience: true });
698+
699+
const res = await client.mutate(MUTATION, {
700+
variables: {
701+
data: {
702+
hideExperience: false,
703+
username: 'testuser',
704+
name: 'Test User',
705+
},
706+
},
707+
});
708+
709+
expect(res.errors).toBeFalsy();
710+
expect(res.data.updateUserInfo.hideExperience).toBe(false);
711+
712+
const updatedUser = await repo.findOneBy({ id: loggedUser });
713+
expect(updatedUser?.hideExperience).toBe(false);
714+
});
665715
});

0 commit comments

Comments
 (0)