import 'reflect-metadata' import * as express from 'express' import { InversifyExpressOfflineController } from './InversifyExpressOfflineController' import { results } from 'inversify-express-utils' import { User } from '../../Domain/User/User' import { GetUserFeatures } from '../../Domain/UseCase/GetUserFeatures/GetUserFeatures' import { CreateOfflineSubscriptionToken } from '../../Domain/UseCase/CreateOfflineSubscriptionToken/CreateOfflineSubscriptionToken' import { CreateOfflineSubscriptionTokenResponse } from '../../Domain/UseCase/CreateOfflineSubscriptionToken/CreateOfflineSubscriptionTokenResponse' import { AuthenticateOfflineSubscriptionToken } from '../../Domain/UseCase/AuthenticateOfflineSubscriptionToken/AuthenticateOfflineSubscriptionToken' import { OfflineUserSubscription } from '../../Domain/Subscription/OfflineUserSubscription' import { GetUserOfflineSubscription } from '../../Domain/UseCase/GetUserOfflineSubscription/GetUserOfflineSubscription' import { OfflineUserTokenData, TokenEncoderInterface } from '@standardnotes/security' import { SubscriptionName } from '@standardnotes/common' import { Logger } from 'winston' describe('InversifyExpressOfflineController', () => { let getUserFeatures: GetUserFeatures let getUserOfflineSubscription: GetUserOfflineSubscription let createOfflineSubscriptionToken: CreateOfflineSubscriptionToken let authenticateToken: AuthenticateOfflineSubscriptionToken let logger: Logger let tokenEncoder: TokenEncoderInterface const jwtTTL = 60 let request: express.Request let response: express.Response let user: User const createController = () => new InversifyExpressOfflineController( getUserFeatures, getUserOfflineSubscription, createOfflineSubscriptionToken, authenticateToken, tokenEncoder, jwtTTL, logger, ) beforeEach(() => { user = {} as jest.Mocked user.uuid = '123' getUserFeatures = {} as jest.Mocked getUserFeatures.execute = jest.fn() createOfflineSubscriptionToken = {} as jest.Mocked createOfflineSubscriptionToken.execute = jest.fn().mockReturnValue({ success: true, offlineSubscriptionToken: { token: 'test', }, } as jest.Mocked) getUserOfflineSubscription = {} as jest.Mocked getUserOfflineSubscription.execute = jest.fn().mockReturnValue({ success: true, subscription: { planName: SubscriptionName.ProPlan, }, }) authenticateToken = {} as jest.Mocked authenticateToken.execute = jest.fn().mockReturnValue({ success: true, email: 'test@test.com', subscriptions: [{} as jest.Mocked], }) logger = {} as jest.Mocked logger.debug = jest.fn() tokenEncoder = {} as jest.Mocked> tokenEncoder.encodeExpirableToken = jest.fn().mockReturnValue('foobar') request = { headers: {}, body: {}, params: {}, } as jest.Mocked response = { locals: {}, } as jest.Mocked }) it('should get offline user features', async () => { response.locals.offlineUserEmail = 'test@test.com' getUserFeatures.execute = jest.fn().mockReturnValue({ success: true }) const httpResponse = await createController().getOfflineFeatures(request, response) const result = await httpResponse.executeAsync() expect(getUserFeatures.execute).toHaveBeenCalledWith({ email: 'test@test.com', offline: true, }) expect(result.statusCode).toEqual(200) }) it('should get offline user subscription', async () => { response.locals.userEmail = 'test@test.com' const httpResponse = await createController().getSubscription(request, response) const result = await httpResponse.executeAsync() expect(getUserOfflineSubscription.execute).toHaveBeenCalledWith({ userEmail: 'test@test.com', }) expect(result.statusCode).toEqual(200) }) it('should not get offline user subscription if the procedure fails', async () => { response.locals.userEmail = 'test@test.com' getUserOfflineSubscription.execute = jest.fn().mockReturnValue({ success: false }) const httpResponse = await createController().getSubscription(request, response) const result = await httpResponse.executeAsync() expect(getUserOfflineSubscription.execute).toHaveBeenCalledWith({ userEmail: 'test@test.com', }) expect(result.statusCode).toEqual(400) }) it('should not get offline user features if the procedure fails', async () => { response.locals.offlineUserEmail = 'test@test.com' getUserFeatures.execute = jest.fn().mockReturnValue({ success: false }) const httpResponse = await createController().getOfflineFeatures(request, response) const result = await httpResponse.executeAsync() expect(getUserFeatures.execute).toHaveBeenCalledWith({ email: 'test@test.com', offline: true, }) expect(result.statusCode).toEqual(400) }) it('should create a offline subscription token for authenticated user', async () => { request.body.email = 'test@test.com' const httpResponse = await createController().createToken(request) const result = await httpResponse.executeAsync() expect(createOfflineSubscriptionToken.execute).toHaveBeenCalledWith({ userEmail: 'test@test.com', }) expect(result.statusCode).toEqual(200) }) it('should not create a offline subscription token for missing email in request', async () => { const httpResponse = await createController().createToken(request) const result = await httpResponse.executeAsync() expect(createOfflineSubscriptionToken.execute).not.toHaveBeenCalled() expect(result.statusCode).toEqual(400) }) it('should not create a offline subscription token if the workflow fails with no subscription', async () => { request.body.email = 'test@test.com' createOfflineSubscriptionToken.execute = jest.fn().mockReturnValue({ success: false, error: 'no-subscription', }) const httpResponse = await createController().createToken(request) const result = await httpResponse.executeAsync() expect(createOfflineSubscriptionToken.execute).toHaveBeenCalledWith({ userEmail: 'test@test.com', }) expect(httpResponse.json).toEqual({ success: false, error: { tag: 'no-subscription' } }) expect(result.statusCode).toEqual(200) }) it('should validate a offline subscription token for user', async () => { request.params.token = 'test' request.body.email = 'test@test.com' const httpResponse = await createController().validate(request) const result = await httpResponse.executeAsync() expect(authenticateToken.execute).toHaveBeenCalledWith({ token: 'test', userEmail: 'test@test.com', }) expect(result.statusCode).toEqual(200) }) it('should not validate a offline subscription token for user if it is invalid', async () => { request.body.email = 'test@test.com' request.params.token = 'test' authenticateToken.execute = jest.fn().mockReturnValue({ success: false, }) const httpResponse = await createController().validate(request) const result = await httpResponse.executeAsync() expect(authenticateToken.execute).toHaveBeenCalledWith({ token: 'test', userEmail: 'test@test.com', }) expect(result.statusCode).toEqual(401) }) it('should not validate a offline subscription token for user if email is missing', async () => { request.params.token = 'test' const httpResponse = await createController().validate(request) const result = await httpResponse.executeAsync() expect(authenticateToken.execute).not.toHaveBeenCalled() expect(result.statusCode).toEqual(400) }) })