-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Connection list route and placeholder view * Rename controller * Coontroller tests
- Loading branch information
1 parent
deef224
commit a53af57
Showing
14 changed files
with
247 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* @param { import("knex").Knex } knex | ||
* @returns { Promise<void> } | ||
*/ | ||
exports.up = async function (knex) { | ||
await knex.schema.alterTable('connection', (def) => { | ||
def.index('updated_at', 'idx_connection_updated_at') | ||
}) | ||
} | ||
|
||
/** | ||
* @param { import("knex").Knex } knex | ||
* @returns { Promise<void> } | ||
*/ | ||
exports.down = async function (knex) { | ||
await knex.schema.alterTable('connection', (def) => { | ||
def.dropIndex('updated_at', 'idx_connection_updated_at') | ||
}) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Readable } from 'node:stream' | ||
|
||
import pino from 'pino' | ||
|
||
import Database from '../../../models/db/index.js' | ||
import ConnectionTemplates from '../../../views/connection' | ||
|
||
export const withMocks = () => { | ||
const templateMock = { | ||
listPage: (connections) => `list_${connections.map((c) => `${c.company_name}-${c.status}`).join('_')}_list`, | ||
} as ConnectionTemplates | ||
const mockLogger = pino({ level: 'silent' }) | ||
const dbMock = { | ||
get: () => Promise.resolve([{ company_name: 'foo', status: 'verified' }]), | ||
} as unknown as Database | ||
|
||
return { | ||
templateMock, | ||
mockLogger, | ||
dbMock, | ||
} | ||
} | ||
|
||
export const toHTMLString = async (stream: Readable) => { | ||
const chunks: Uint8Array[] = [] | ||
for await (const chunk of stream) { | ||
chunks.push(chunk as Uint8Array) | ||
} | ||
return Buffer.concat(chunks).toString('utf8') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { describe, it } from 'mocha' | ||
import sinon from 'sinon' | ||
|
||
import { toHTMLString, withMocks } from './helpers' | ||
|
||
import { ConnectionController } from '../index.js' | ||
|
||
describe('ConnectionController', () => { | ||
let expect: Chai.ExpectStatic | ||
before(async () => { | ||
expect = (await import('chai')).expect | ||
}) | ||
|
||
afterEach(() => { | ||
sinon.restore() | ||
}) | ||
|
||
describe('listConnections', () => { | ||
it('should return rendered list template', async () => { | ||
let { dbMock, mockLogger, templateMock } = withMocks() | ||
const controller = new ConnectionController(dbMock, templateMock, mockLogger) | ||
const result = await controller.listConnections().then(toHTMLString) | ||
expect(result).to.equal('list_foo-verified_list') | ||
}) | ||
|
||
it('should call db as expected', async () => { | ||
let { dbMock, mockLogger, templateMock } = withMocks() | ||
const controller = new ConnectionController(dbMock, templateMock, mockLogger) | ||
const spy = sinon.spy(dbMock, 'get') | ||
await controller.listConnections().then(toHTMLString) | ||
expect(spy.calledWith('connection', {}, [['updated_at', 'desc']])).to.equal(true) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Get, Produces, Route, SuccessResponse } from 'tsoa' | ||
import { inject, injectable, singleton } from 'tsyringe' | ||
|
||
import { Logger, type ILogger } from '../../logger.js' | ||
import Database from '../../models/db/index.js' | ||
import ConnectionTemplates from '../../views/connection.js' | ||
import { HTML, HTMLController } from '../HTMLController.js' | ||
|
||
@singleton() | ||
@injectable() | ||
@Route('/connection') | ||
@Produces('text/html') | ||
export class ConnectionController extends HTMLController { | ||
constructor( | ||
private db: Database, | ||
private connectionTemplates: ConnectionTemplates, | ||
@inject(Logger) private logger: ILogger | ||
) { | ||
super() | ||
this.logger = logger.child({ controller: '/' }) | ||
} | ||
|
||
/** | ||
* Retrieves the connection list page | ||
*/ | ||
@SuccessResponse(200) | ||
@Get('/') | ||
public async listConnections(): Promise<HTML> { | ||
this.logger.debug('connections page requested') | ||
const connections = await this.db.get('connection', {}, [['updated_at', 'desc']]) | ||
return this.html(this.connectionTemplates.listPage(connections)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { describe, it } from 'mocha' | ||
|
||
import ConnectionTemplates from '../connection' | ||
|
||
describe('ConnectionTemplates', () => { | ||
let expect: Chai.ExpectStatic | ||
before(async () => { | ||
expect = (await import('chai')).expect | ||
}) | ||
|
||
describe('listPage', () => { | ||
it('should render with no connections', async () => { | ||
const templates = new ConnectionTemplates() | ||
const rendered = await templates.listPage([]) | ||
expect(rendered).to.matchSnapshot() | ||
}) | ||
|
||
it('should render with single connection', async () => { | ||
const templates = new ConnectionTemplates() | ||
const rendered = await templates.listPage([ | ||
{ | ||
company_name: 'Company A', | ||
status: 'disconnected', | ||
}, | ||
]) | ||
expect(rendered).to.matchSnapshot() | ||
}) | ||
|
||
it('should escape html in name', async () => { | ||
const templates = new ConnectionTemplates() | ||
const rendered = await templates.listPage([ | ||
{ | ||
company_name: '<div>I own you</div>', | ||
status: 'verified_both', | ||
}, | ||
]) | ||
expect(rendered).to.matchSnapshot() | ||
}) | ||
|
||
it('should render multiple with each status', async () => { | ||
const templates = new ConnectionTemplates() | ||
const rendered = await templates.listPage([ | ||
{ | ||
company_name: 'Company A', | ||
status: 'disconnected', | ||
}, | ||
{ | ||
company_name: 'Company B', | ||
status: 'pending', | ||
}, | ||
{ | ||
company_name: 'Company C', | ||
status: 'unverified', | ||
}, | ||
{ | ||
company_name: 'Company D', | ||
status: 'verified_both', | ||
}, | ||
{ | ||
company_name: 'Company E', | ||
status: 'verified_them', | ||
}, | ||
{ | ||
company_name: 'Company F', | ||
status: 'verified_us', | ||
}, | ||
]) | ||
expect(rendered).to.matchSnapshot() | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`ConnectionTemplates listPage should escape html in name 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title>Veritable - Connections</title></head><body hx-ext=\\"json-enc\\"><div><div><div>I own you</div></div><div>verified_both</div></div></body></html>"`; | ||
exports[`ConnectionTemplates listPage should render multiple with each status 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title>Veritable - Connections</title></head><body hx-ext=\\"json-enc\\"><div><div>Company A</div><div>disconnected</div></div><div><div>Company B</div><div>pending</div></div><div><div>Company C</div><div>unverified</div></div><div><div>Company D</div><div>verified_both</div></div><div><div>Company E</div><div>verified_them</div></div><div><div>Company F</div><div>verified_us</div></div></body></html>"`; | ||
exports[`ConnectionTemplates listPage should render with no connections 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title>Veritable - Connections</title></head><body hx-ext=\\"json-enc\\"></body></html>"`; | ||
exports[`ConnectionTemplates listPage should render with single connection 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title>Veritable - Connections</title></head><body hx-ext=\\"json-enc\\"><div><div>Company A</div><div>disconnected</div></div></body></html>"`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,15 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Button should render the disabled button 1`] = `"<div class=\\"button-group\\"><button disabled hx-target=\\"closest .button-group\\" hx-trigger=\\"counter-loaded from:body\\" hx-get=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div>"`; | ||
exports[`RootTemplates Button should render the disabled button 1`] = `"<div class=\\"button-group\\"><button disabled hx-target=\\"closest .button-group\\" hx-trigger=\\"counter-loaded from:body\\" hx-get=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div>"`; | ||
exports[`Button should render the enabled button 1`] = `"<div class=\\"button-group\\"><button hx-target=\\"closest .button-group\\" hx-post=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div>"`; | ||
exports[`RootTemplates Button should render the enabled button 1`] = `"<div class=\\"button-group\\"><button hx-target=\\"closest .button-group\\" hx-post=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div>"`; | ||
exports[`Counter should render the counter on second call with value 1 1`] = `"<div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>1</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div>"`; | ||
exports[`RootTemplates Counter should render the counter on second call with value 1 1`] = `"<div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>1</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div>"`; | ||
exports[`Counter should render the counter with value 0 1`] = `"<div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>0</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div>"`; | ||
exports[`RootTemplates Counter should render the counter with value 0 1`] = `"<div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>0</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div>"`; | ||
exports[`Root should escape html in title 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title><div>Malicious Content</div></title></head><body hx-ext=\\"json-enc\\"><div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>0</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div><div class=\\"button-group\\"><button hx-target=\\"closest .button-group\\" hx-post=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div></body></html>"`; | ||
exports[`RootTemplates Root should escape html in title 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title><div>Malicious Content</div></title></head><body hx-ext=\\"json-enc\\"><div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>0</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div><div class=\\"button-group\\"><button hx-target=\\"closest .button-group\\" hx-post=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div></body></html>"`; | ||
exports[`Root should render counter 1 on second load 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title>title</title></head><body hx-ext=\\"json-enc\\"><div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>1</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div><div class=\\"button-group\\"><button hx-target=\\"closest .button-group\\" hx-post=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div></body></html>"`; | ||
exports[`RootTemplates Root should render counter 1 on second load 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title>title</title></head><body hx-ext=\\"json-enc\\"><div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>1</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div><div class=\\"button-group\\"><button hx-target=\\"closest .button-group\\" hx-post=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div></body></html>"`; | ||
exports[`Root should render root page 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title>title</title></head><body hx-ext=\\"json-enc\\"><div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>0</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div><div class=\\"button-group\\"><button hx-target=\\"closest .button-group\\" hx-post=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div></body></html>"`; | ||
exports[`RootTemplates Root should render root page 1`] = `"<!DOCTYPE html><html lang=\\"en\\"><head><script src=\\"lib/htmx.org/htmx.min.js\\"></script><script src=\\"lib/htmx.org/ext/json-enc.js\\"></script><link rel=\\"icon\\" type=\\"image/ico\\" sizes=\\"48x48\\" href=\\"/public/images/favicon.ico\\"/><link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"/public/styles/main.css\\"/><title>title</title></head><body hx-ext=\\"json-enc\\"><div id=\\"counter\\" hx-get=\\"/example/counter\\" hx-trigger=\\"button-click from:body\\" hx-swap=\\"outerHTML\\"><span>0</span><img class=\\"spinner htmx-indicator\\" src=\\"/public/images/spinner.svg\\"/></div><div class=\\"button-group\\"><button hx-target=\\"closest .button-group\\" hx-post=\\"/example/button\\" hx-swap=\\"outerHTML\\">Click me!</button></div></body></html>"`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import Html from '@kitajs/html' | ||
import { singleton } from 'tsyringe' | ||
import { Page } from './common' | ||
|
||
interface connection { | ||
company_name: string | ||
status: 'pending' | 'unverified' | 'verified_them' | 'verified_us' | 'verified_both' | 'disconnected' | ||
} | ||
|
||
@singleton() | ||
export default class ConnectionTemplates { | ||
constructor() {} | ||
|
||
public listPage = (connections: connection[]) => { | ||
return ( | ||
<Page title="Veritable - Connections"> | ||
{connections.map((connection) => ( | ||
<div> | ||
<div>{Html.escapeHtml(connection.company_name)}</div> | ||
<div>{connection.status}</div> | ||
</div> | ||
))} | ||
</Page> | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters