diff --git a/packages/hoppscotch-backend/package.json b/packages/hoppscotch-backend/package.json index 6e3a31005..10be4a53e 100644 --- a/packages/hoppscotch-backend/package.json +++ b/packages/hoppscotch-backend/package.json @@ -18,7 +18,8 @@ "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "jest --config ./test/jest-e2e.json" + "test:e2e": "jest --config ./test/jest-e2e.json", + "postinstall": "prisma generate" }, "dependencies": { "@nestjs/apollo": "^10.1.6", @@ -29,11 +30,13 @@ "@prisma/client": "^4.7.1", "apollo-server-express": "^3.11.1", "apollo-server-plugin-base": "^3.7.1", + "express": "^4.17.1", "fp-ts": "^2.13.1", "graphql": "^15.5.0", "graphql-query-complexity": "^0.12.0", "graphql-redis-subscriptions": "^2.5.0", "graphql-subscriptions": "^2.0.0", + "io-ts": "^2.2.16", "ioredis": "^5.2.4", "prisma": "^4.7.1", "reflect-metadata": "^0.1.13", @@ -44,8 +47,9 @@ "@nestjs/cli": "^9.1.5", "@nestjs/schematics": "^9.0.3", "@nestjs/testing": "^9.2.1", + "@relmify/jest-fp-ts": "^2.0.2", "@types/express": "^4.17.14", - "@types/jest": "29.2.3", + "@types/jest": "^27.5.2", "@types/node": "^18.11.10", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^5.45.0", @@ -53,7 +57,8 @@ "eslint": "^8.29.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.2.1", - "jest": "29.3.1", + "jest": "^29.3.1", + "jest-mock-extended": "^3.0.1", "prettier": "^2.8.0", "source-map-support": "^0.5.21", "supertest": "^6.3.2", @@ -69,6 +74,9 @@ "json", "ts" ], + "moduleNameMapper": { + "^src/(.*)$": "/$1" + }, "rootDir": "src", "testRegex": ".*\\.spec\\.ts$", "transform": { @@ -80,4 +88,4 @@ "coverageDirectory": "../coverage", "testEnvironment": "node" } -} +} \ No newline at end of file diff --git a/packages/hoppscotch-backend/src/user-settings/user-settings.service.spec.ts b/packages/hoppscotch-backend/src/user-settings/user-settings.service.spec.ts new file mode 100644 index 000000000..25b25a7b8 --- /dev/null +++ b/packages/hoppscotch-backend/src/user-settings/user-settings.service.spec.ts @@ -0,0 +1,131 @@ +import { mockDeep, mockReset } from 'jest-mock-extended'; +import { PrismaService } from 'src/prisma/prisma.service'; +import { PubSubService } from 'src/pubsub/pubsub.service'; +import { UserSettingsService } from './user-settings.service'; +import '@relmify/jest-fp-ts'; +import { + JSON_INVALID, + USER_NOT_FOUND, + USER_SETTINGS_INVALID_PROPERTIES, + USER_SETTINGS_UPDATE_FAILED, +} from 'src/errors'; + +const mockPrisma = mockDeep(); +const mockPubSub = mockDeep(); + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +const userSettingsService = new UserSettingsService( + mockPrisma, + mockPubSub as any, +); + +const user = { + uid: 'user-uid', + displayName: 'user-display-name', + email: 'user-email', + photoURL: 'user-photo-url', +}; +const userSettings = { + id: '1', + userUid: user.uid, + properties: { key: 'k', value: 'v' }, + updatedOn: new Date('2022-12-19T12:43:18.635Z'), +}; + +beforeEach(() => { + mockReset(mockPrisma); + mockPubSub.publish.mockClear(); +}); + +describe('UserSettingsService', () => { + describe('createUserSettings', () => { + test('should create a user settings with valid user and properties', async () => { + mockPrisma.userSettings.create.mockResolvedValue(userSettings); + + const result = await userSettingsService.createUserSettings( + user, + JSON.stringify(userSettings.properties), + ); + + expect(result).toEqualRight({ + ...userSettings, + properties: JSON.stringify(userSettings.properties), + }); + }); + test('should reject for invalid user', async () => { + const result = await userSettingsService.createUserSettings( + null as any, + JSON.stringify(userSettings.properties), + ); + + expect(result).toEqualLeft(USER_NOT_FOUND); + }); + test('should reject for invalid properties', async () => { + const result = await userSettingsService.createUserSettings( + user, + 'invalid-properties', + ); + expect(result).toEqualLeft(JSON_INVALID); + }); + test('should reject for null properties', async () => { + const result = await userSettingsService.createUserSettings( + user, + null as any, + ); + expect(result).toEqualLeft(USER_SETTINGS_INVALID_PROPERTIES); + }); + }); + describe('updateUserSettings', () => { + test('should update a user settings for valid user and properties', async () => { + mockPrisma.userSettings.update.mockResolvedValue(userSettings); + + const result = await userSettingsService.updateUserSettings( + user, + JSON.stringify(userSettings.properties), + ); + + expect(result).toEqualRight({ + ...userSettings, + properties: JSON.stringify(userSettings.properties), + }); + }); + test('should reject for invalid user', async () => { + const result = await userSettingsService.updateUserSettings( + null as any, + JSON.stringify(userSettings.properties), + ); + expect(result).toEqualLeft(USER_SETTINGS_UPDATE_FAILED); + }); + test('should reject for invalid properties', async () => { + const result = await userSettingsService.updateUserSettings( + user, + 'invalid-properties', + ); + expect(result).toEqualLeft(JSON_INVALID); + }); + test('should reject for null properties', async () => { + const result = await userSettingsService.updateUserSettings( + user, + null as any, + ); + expect(result).toEqualLeft(USER_SETTINGS_INVALID_PROPERTIES); + }); + test('should publish message on pubnub after update successfully', async () => { + mockPrisma.userSettings.update.mockResolvedValue(userSettings); + + await userSettingsService.updateUserSettings( + user, + JSON.stringify(userSettings.properties), + ); + + expect(mockPubSub.publish).toBeCalledWith( + `user_settings/${user.uid}/updated`, + { + ...userSettings, + properties: JSON.stringify(userSettings.properties), + }, + ); + }); + }); +});