test(connection): write model tests
This commit is contained in:
@@ -8,7 +8,7 @@ export default async (request, response) => {
|
|||||||
})
|
})
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
connection = await connection.update(connectionParams(request));
|
connection = await connection.updateFormattedData(connectionParams(request));
|
||||||
|
|
||||||
renderObject(response, connection);
|
renderObject(response, connection);
|
||||||
};
|
};
|
||||||
|
@@ -122,10 +122,20 @@ class Connection extends Base {
|
|||||||
return this.data ? true : false;
|
return this.data ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkEligibilityForCreation() {
|
async getApp() {
|
||||||
const app = await App.findOneByKey(this.key);
|
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) {
|
||||||
if (appConfig.disabled) {
|
if (appConfig.disabled) {
|
||||||
@@ -160,12 +170,6 @@ class Connection extends Base {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getApp() {
|
|
||||||
if (!this.key) return null;
|
|
||||||
|
|
||||||
return await App.findOneByKey(this.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
async testAndUpdateConnection() {
|
async testAndUpdateConnection() {
|
||||||
const app = await this.getApp();
|
const app = await this.getApp();
|
||||||
const $ = await globalVariable({ connection: this, app });
|
const $ = await globalVariable({ connection: this, app });
|
||||||
@@ -224,7 +228,7 @@ class Connection extends Base {
|
|||||||
async reset() {
|
async reset() {
|
||||||
const formattedData = this?.formattedData?.screenName
|
const formattedData = this?.formattedData?.screenName
|
||||||
? { screenName: this.formattedData.screenName }
|
? { screenName: this.formattedData.screenName }
|
||||||
: null;
|
: {};
|
||||||
|
|
||||||
const updatedConnection = await this.$query().patchAndFetch({
|
const updatedConnection = await this.$query().patchAndFetch({
|
||||||
formattedData,
|
formattedData,
|
||||||
@@ -233,7 +237,7 @@ class Connection extends Base {
|
|||||||
return updatedConnection;
|
return updatedConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
async update({ formattedData, appAuthClientId }) {
|
async updateFormattedData({ formattedData, appAuthClientId }) {
|
||||||
if (appAuthClientId) {
|
if (appAuthClientId) {
|
||||||
const appAuthClient = await AppAuthClient.query()
|
const appAuthClient = await AppAuthClient.query()
|
||||||
.findById(appAuthClientId)
|
.findById(appAuthClientId)
|
||||||
|
@@ -3,11 +3,15 @@ import AES from 'crypto-js/aes.js';
|
|||||||
import enc from 'crypto-js/enc-utf8.js';
|
import enc from 'crypto-js/enc-utf8.js';
|
||||||
import appConfig from '../config/app.js';
|
import appConfig from '../config/app.js';
|
||||||
import AppAuthClient from './app-auth-client.js';
|
import AppAuthClient from './app-auth-client.js';
|
||||||
|
import App from './app.js';
|
||||||
import AppConfig from './app-config.js';
|
import AppConfig from './app-config.js';
|
||||||
import Base from './base.js';
|
import Base from './base.js';
|
||||||
import Connection from './connection';
|
import Connection from './connection';
|
||||||
import Step from './step.js';
|
import Step from './step.js';
|
||||||
import User from './user.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', () => {
|
describe('Connection model', () => {
|
||||||
it('tableName should return correct name', () => {
|
it('tableName should return correct name', () => {
|
||||||
@@ -26,7 +30,8 @@ describe('Connection model', () => {
|
|||||||
expect(virtualAttributes).toStrictEqual(expectedAttributes);
|
expect(virtualAttributes).toStrictEqual(expectedAttributes);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('relationMappings should return correct associations', () => {
|
describe('relationMappings', () => {
|
||||||
|
it('should return correct associations', () => {
|
||||||
const relationMappings = Connection.relationMappings();
|
const relationMappings = Connection.relationMappings();
|
||||||
|
|
||||||
const expectedRelations = {
|
const expectedRelations = {
|
||||||
@@ -76,6 +81,16 @@ describe('Connection model', () => {
|
|||||||
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');
|
describe.todo('reconnectable');
|
||||||
|
|
||||||
describe('encryptData', () => {
|
describe('encryptData', () => {
|
||||||
@@ -160,4 +175,321 @@ describe('Connection model', () => {
|
|||||||
expect(connection.data).not.toEqual(formattedData);
|
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