test(connection): write model tests
This commit is contained in:
@@ -8,7 +8,7 @@ export default async (request, response) => {
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
connection = await connection.update(connectionParams(request));
|
||||
connection = await connection.updateFormattedData(connectionParams(request));
|
||||
|
||||
renderObject(response, connection);
|
||||
};
|
||||
|
@@ -122,10 +122,20 @@ class Connection extends Base {
|
||||
return this.data ? true : false;
|
||||
}
|
||||
|
||||
async checkEligibilityForCreation() {
|
||||
const app = await App.findOneByKey(this.key);
|
||||
async getApp() {
|
||||
if (!this.key) return null;
|
||||
|
||||
const appConfig = await AppConfig.query().findOne({ key: this.key });
|
||||
return await App.findOneByKey(this.key);
|
||||
}
|
||||
|
||||
async getAppConfig() {
|
||||
return await AppConfig.query().findOne({ key: this.key });
|
||||
}
|
||||
|
||||
async checkEligibilityForCreation() {
|
||||
const app = await this.getApp();
|
||||
|
||||
const appConfig = await this.getAppConfig();
|
||||
|
||||
if (appConfig) {
|
||||
if (appConfig.disabled) {
|
||||
@@ -160,12 +170,6 @@ class Connection extends Base {
|
||||
return this;
|
||||
}
|
||||
|
||||
async getApp() {
|
||||
if (!this.key) return null;
|
||||
|
||||
return await App.findOneByKey(this.key);
|
||||
}
|
||||
|
||||
async testAndUpdateConnection() {
|
||||
const app = await this.getApp();
|
||||
const $ = await globalVariable({ connection: this, app });
|
||||
@@ -224,7 +228,7 @@ class Connection extends Base {
|
||||
async reset() {
|
||||
const formattedData = this?.formattedData?.screenName
|
||||
? { screenName: this.formattedData.screenName }
|
||||
: null;
|
||||
: {};
|
||||
|
||||
const updatedConnection = await this.$query().patchAndFetch({
|
||||
formattedData,
|
||||
@@ -233,7 +237,7 @@ class Connection extends Base {
|
||||
return updatedConnection;
|
||||
}
|
||||
|
||||
async update({ formattedData, appAuthClientId }) {
|
||||
async updateFormattedData({ formattedData, appAuthClientId }) {
|
||||
if (appAuthClientId) {
|
||||
const appAuthClient = await AppAuthClient.query()
|
||||
.findById(appAuthClientId)
|
||||
|
@@ -3,11 +3,15 @@ import AES from 'crypto-js/aes.js';
|
||||
import enc from 'crypto-js/enc-utf8.js';
|
||||
import appConfig from '../config/app.js';
|
||||
import AppAuthClient from './app-auth-client.js';
|
||||
import App from './app.js';
|
||||
import AppConfig from './app-config.js';
|
||||
import Base from './base.js';
|
||||
import Connection from './connection';
|
||||
import Step from './step.js';
|
||||
import User from './user.js';
|
||||
import { createConnection } from '../../test/factories/connection.js';
|
||||
import { createAppConfig } from '../../test/factories/app-config.js';
|
||||
import { createAppAuthClient } from '../../test/factories/app-auth-client.js';
|
||||
|
||||
describe('Connection model', () => {
|
||||
it('tableName should return correct name', () => {
|
||||
@@ -26,54 +30,65 @@ describe('Connection model', () => {
|
||||
expect(virtualAttributes).toStrictEqual(expectedAttributes);
|
||||
});
|
||||
|
||||
it('relationMappings should return correct associations', () => {
|
||||
const relationMappings = Connection.relationMappings();
|
||||
describe('relationMappings', () => {
|
||||
it('should return correct associations', () => {
|
||||
const relationMappings = Connection.relationMappings();
|
||||
|
||||
const expectedRelations = {
|
||||
user: {
|
||||
relation: Base.BelongsToOneRelation,
|
||||
modelClass: User,
|
||||
join: {
|
||||
from: 'connections.user_id',
|
||||
to: 'users.id',
|
||||
const expectedRelations = {
|
||||
user: {
|
||||
relation: Base.BelongsToOneRelation,
|
||||
modelClass: User,
|
||||
join: {
|
||||
from: 'connections.user_id',
|
||||
to: 'users.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
steps: {
|
||||
relation: Base.HasManyRelation,
|
||||
modelClass: Step,
|
||||
join: {
|
||||
from: 'connections.id',
|
||||
to: 'steps.connection_id',
|
||||
steps: {
|
||||
relation: Base.HasManyRelation,
|
||||
modelClass: Step,
|
||||
join: {
|
||||
from: 'connections.id',
|
||||
to: 'steps.connection_id',
|
||||
},
|
||||
},
|
||||
},
|
||||
triggerSteps: {
|
||||
relation: Base.HasManyRelation,
|
||||
modelClass: Step,
|
||||
join: {
|
||||
from: 'connections.id',
|
||||
to: 'steps.connection_id',
|
||||
triggerSteps: {
|
||||
relation: Base.HasManyRelation,
|
||||
modelClass: Step,
|
||||
join: {
|
||||
from: 'connections.id',
|
||||
to: 'steps.connection_id',
|
||||
},
|
||||
filter: expect.any(Function),
|
||||
},
|
||||
filter: expect.any(Function),
|
||||
},
|
||||
appConfig: {
|
||||
relation: Base.BelongsToOneRelation,
|
||||
modelClass: AppConfig,
|
||||
join: {
|
||||
from: 'connections.key',
|
||||
to: 'app_configs.key',
|
||||
appConfig: {
|
||||
relation: Base.BelongsToOneRelation,
|
||||
modelClass: AppConfig,
|
||||
join: {
|
||||
from: 'connections.key',
|
||||
to: 'app_configs.key',
|
||||
},
|
||||
},
|
||||
},
|
||||
appAuthClient: {
|
||||
relation: Base.BelongsToOneRelation,
|
||||
modelClass: AppAuthClient,
|
||||
join: {
|
||||
from: 'connections.app_auth_client_id',
|
||||
to: 'app_auth_clients.id',
|
||||
appAuthClient: {
|
||||
relation: Base.BelongsToOneRelation,
|
||||
modelClass: AppAuthClient,
|
||||
join: {
|
||||
from: 'connections.app_auth_client_id',
|
||||
to: 'app_auth_clients.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
expect(relationMappings).toStrictEqual(expectedRelations);
|
||||
expect(relationMappings).toStrictEqual(expectedRelations);
|
||||
});
|
||||
|
||||
it('triggerSteps should return only trigger typed steps', () => {
|
||||
const relations = Connection.relationMappings();
|
||||
const whereSpy = vi.fn();
|
||||
|
||||
relations.triggerSteps.filter({ where: whereSpy });
|
||||
|
||||
expect(whereSpy).toHaveBeenCalledWith('type', '=', 'trigger');
|
||||
});
|
||||
});
|
||||
|
||||
describe.todo('reconnectable');
|
||||
@@ -160,4 +175,321 @@ describe('Connection model', () => {
|
||||
expect(connection.data).not.toEqual(formattedData);
|
||||
});
|
||||
});
|
||||
|
||||
describe('eligibleForEncryption', () => {
|
||||
it('should access formattedData', async () => {
|
||||
const connection = new Connection();
|
||||
connection.formattedData = { clientId: 'sample-id' };
|
||||
|
||||
const spy = vi.spyOn(connection, 'formattedData', 'get');
|
||||
|
||||
connection.eligibleForEncryption();
|
||||
|
||||
expect(spy).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('should return true when formattedData property exists', async () => {
|
||||
const connection = new Connection();
|
||||
connection.formattedData = { clientId: 'sample-id' };
|
||||
|
||||
expect(connection.eligibleForEncryption()).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when formattedData property doesn't exist", async () => {
|
||||
const connection = new Connection();
|
||||
connection.formattedData = undefined;
|
||||
|
||||
expect(connection.eligibleForEncryption()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('eligibleForDecryption', () => {
|
||||
it('should access formattedData', async () => {
|
||||
const connection = new Connection();
|
||||
connection.data = 'encrypted-data';
|
||||
|
||||
const spy = vi.spyOn(connection, 'data', 'get');
|
||||
|
||||
connection.eligibleForDecryption();
|
||||
|
||||
expect(spy).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('should return true when data property exists', async () => {
|
||||
const connection = new Connection();
|
||||
connection.data = 'encrypted-data';
|
||||
|
||||
expect(connection.eligibleForDecryption()).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false when data property doesn't exist", async () => {
|
||||
const connection = new Connection();
|
||||
connection.data = undefined;
|
||||
|
||||
expect(connection.eligibleForDecryption()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getApp', () => {
|
||||
it('should return connection app when valid key exists', async () => {
|
||||
const connection = new Connection();
|
||||
connection.key = 'gitlab';
|
||||
|
||||
const connectionApp = await connection.getApp();
|
||||
const app = await App.findOneByKey('gitlab');
|
||||
|
||||
expect(connectionApp).toStrictEqual(app);
|
||||
});
|
||||
|
||||
it('should throw an error when invalid key exists', async () => {
|
||||
const connection = new Connection();
|
||||
connection.key = 'invalid-key';
|
||||
|
||||
await expect(() => connection.getApp()).rejects.toThrowError(
|
||||
`An application with the "invalid-key" key couldn't be found.`
|
||||
);
|
||||
});
|
||||
|
||||
it('should return null when no key exists', async () => {
|
||||
const connection = new Connection();
|
||||
|
||||
await expect(connection.getApp()).resolves.toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
it('getAppConfig should return connection app config', async () => {
|
||||
const connection = new Connection();
|
||||
connection.key = 'gitlab';
|
||||
|
||||
const appConfig = await createAppConfig({ key: 'gitlab' });
|
||||
|
||||
const connectionAppConfig = await connection.getAppConfig();
|
||||
|
||||
expect(connectionAppConfig).toStrictEqual(appConfig);
|
||||
});
|
||||
|
||||
describe.todo('checkEligibilityForCreation', async () => {});
|
||||
|
||||
describe('testAndUpdateConnection', () => {
|
||||
it('should verify connection and persist it', async () => {
|
||||
const connection = await createConnection({ verified: false });
|
||||
|
||||
const isStillVerifiedSpy = vi.fn().mockReturnValue(true);
|
||||
|
||||
const originalApp = await connection.getApp();
|
||||
|
||||
const getAppSpy = vi
|
||||
.spyOn(connection, 'getApp')
|
||||
.mockImplementation(() => {
|
||||
return {
|
||||
...originalApp,
|
||||
auth: {
|
||||
...originalApp.auth,
|
||||
isStillVerified: isStillVerifiedSpy,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const updatedConnection = await connection.testAndUpdateConnection();
|
||||
|
||||
expect(getAppSpy).toHaveBeenCalledOnce();
|
||||
expect(isStillVerifiedSpy).toHaveBeenCalledOnce();
|
||||
expect(updatedConnection.verified).toBe(true);
|
||||
});
|
||||
|
||||
it.todo('should unverify connection and persist it');
|
||||
});
|
||||
|
||||
describe('verifyAndUpdateConnection', () => {
|
||||
it('should verify connection with valid token', async () => {
|
||||
const connection = await createConnection({
|
||||
verified: false,
|
||||
draft: true,
|
||||
});
|
||||
|
||||
const verifyCredentialsSpy = vi.fn().mockResolvedValue(true);
|
||||
|
||||
const originalApp = await connection.getApp();
|
||||
|
||||
vi.spyOn(connection, 'getApp').mockImplementation(() => {
|
||||
return {
|
||||
...originalApp,
|
||||
auth: {
|
||||
...originalApp.auth,
|
||||
verifyCredentials: verifyCredentialsSpy,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const updatedConnection = await connection.verifyAndUpdateConnection();
|
||||
|
||||
expect(verifyCredentialsSpy).toHaveBeenCalledOnce();
|
||||
expect(updatedConnection.verified).toBe(true);
|
||||
expect(updatedConnection.draft).toBe(false);
|
||||
});
|
||||
|
||||
it('should throw an error with invalid token', async () => {
|
||||
const connection = await createConnection({
|
||||
verified: false,
|
||||
draft: true,
|
||||
});
|
||||
|
||||
const verifyCredentialsSpy = vi
|
||||
.fn()
|
||||
.mockRejectedValue(new Error('Invalid token!'));
|
||||
|
||||
const originalApp = await connection.getApp();
|
||||
|
||||
vi.spyOn(connection, 'getApp').mockImplementation(() => {
|
||||
return {
|
||||
...originalApp,
|
||||
auth: {
|
||||
...originalApp.auth,
|
||||
verifyCredentials: verifyCredentialsSpy,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await expect(() =>
|
||||
connection.verifyAndUpdateConnection()
|
||||
).rejects.toThrowError('Invalid token!');
|
||||
expect(verifyCredentialsSpy).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
||||
describe('verifyWebhook', () => {
|
||||
it('should verify webhook on remote', async () => {
|
||||
const connection = await createConnection({ key: 'typeform' });
|
||||
|
||||
const verifyWebhookSpy = vi.fn().mockResolvedValue('verified-webhook');
|
||||
|
||||
const originalApp = await connection.getApp();
|
||||
|
||||
vi.spyOn(connection, 'getApp').mockImplementation(() => {
|
||||
return {
|
||||
...originalApp,
|
||||
auth: {
|
||||
...originalApp.auth,
|
||||
verifyWebhook: verifyWebhookSpy,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
expect(await connection.verifyWebhook()).toBe('verified-webhook');
|
||||
});
|
||||
|
||||
it('should return true if connection does not have value in key property', async () => {
|
||||
const connection = await createConnection({ key: null });
|
||||
|
||||
expect(await connection.verifyWebhook()).toBe(true);
|
||||
});
|
||||
|
||||
it('should throw an error at failed webhook verification', async () => {
|
||||
const connection = await createConnection({ key: 'typeform' });
|
||||
|
||||
const verifyWebhookSpy = vi.fn().mockRejectedValue('unverified-webhook');
|
||||
|
||||
const originalApp = await connection.getApp();
|
||||
|
||||
vi.spyOn(connection, 'getApp').mockImplementation(() => {
|
||||
return {
|
||||
...originalApp,
|
||||
auth: {
|
||||
...originalApp.auth,
|
||||
verifyWebhook: verifyWebhookSpy,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await expect(() => connection.verifyWebhook()).rejects.toThrowError(
|
||||
'unverified-webhook'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('generateAuthUrl should return authentication url', async () => {
|
||||
const connection = await createConnection({
|
||||
key: 'typeform',
|
||||
formattedData: {
|
||||
url: 'https://automatisch.io/authentication-url',
|
||||
},
|
||||
});
|
||||
|
||||
const generateAuthUrlSpy = vi.fn();
|
||||
|
||||
const originalApp = await connection.getApp();
|
||||
|
||||
vi.spyOn(connection, 'getApp').mockImplementation(() => {
|
||||
return {
|
||||
...originalApp,
|
||||
auth: {
|
||||
...originalApp.auth,
|
||||
generateAuthUrl: generateAuthUrlSpy,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
expect(await connection.generateAuthUrl()).toStrictEqual({
|
||||
url: 'https://automatisch.io/authentication-url',
|
||||
});
|
||||
});
|
||||
|
||||
describe('reset', () => {
|
||||
it('should keep screen name when exists and reset the rest of the formatted data', async () => {
|
||||
const connection = await createConnection({
|
||||
formattedData: {
|
||||
screenName: 'Sample connection',
|
||||
token: 'sample-token',
|
||||
},
|
||||
});
|
||||
|
||||
await connection.reset();
|
||||
|
||||
const refetchedConnection = await connection.$query();
|
||||
|
||||
expect(refetchedConnection.formattedData).toStrictEqual({
|
||||
screenName: 'Sample connection',
|
||||
});
|
||||
});
|
||||
|
||||
it('should empty formatted data object when screen name does not exist', async () => {
|
||||
const connection = await createConnection({
|
||||
formattedData: {
|
||||
token: 'sample-token',
|
||||
},
|
||||
});
|
||||
|
||||
await connection.reset();
|
||||
|
||||
const refetchedConnection = await connection.$query();
|
||||
|
||||
expect(refetchedConnection.formattedData).toStrictEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateFormattedData', () => {
|
||||
it('should extend connection data with app auth client auth defaults', async () => {
|
||||
const appAuthClient = await createAppAuthClient({
|
||||
formattedAuthDefaults: {
|
||||
clientId: 'sample-id',
|
||||
},
|
||||
});
|
||||
|
||||
const connection = await createConnection({
|
||||
appAuthClientId: appAuthClient.id,
|
||||
formattedData: {
|
||||
token: 'sample-token',
|
||||
},
|
||||
});
|
||||
|
||||
const updatedConnection = await connection.updateFormattedData({
|
||||
appAuthClientId: appAuthClient.id,
|
||||
});
|
||||
|
||||
expect(updatedConnection.formattedData).toStrictEqual({
|
||||
clientId: 'sample-id',
|
||||
token: 'sample-token',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user