Skip to content

Commit

Permalink
Merge pull request #61 from mbland/add-calculators-collection
Browse files Browse the repository at this point in the history
Add calculator collection module
  • Loading branch information
mbland authored Dec 18, 2023
2 parents 91b3040 + 935202d commit 66b8c7e
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 18 deletions.
2 changes: 1 addition & 1 deletion strcalc/src/main/frontend/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default class App {
* @param {object} params - parameters made available to all initializers
* @param {Element} params.appElem - parent Element containing all components
* @param {string} params.apiUrl - API backend server URL
* @param {Function} params.postForm - posts form data to API
* @param {object} params.calculators - calculator implementations
*/
init(params) {
// In this example application, none of the components depend on one
Expand Down
9 changes: 7 additions & 2 deletions strcalc/src/main/frontend/components/app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ import StringCalculatorPage from '../test/page'
// @vitest-environment jsdom
describe('initial state after calling App.init()', () => {
const page = StringCalculatorPage.new()
const calculators = {
'first': { label: 'First calculator', impl: null },
'second': { label: 'Second calculator', impl: null },
'third': { label: 'Third calculator', impl: null }
}

afterEach(() => page.clear())
afterAll(() => page.remove())

test('contains the "Hello, World!" placeholder', async () => {
new App().init({ appElem: page.appElem })
test('contains the "Hello, World!" title', async () => {
new App().init({ appElem: page.appElem, calculators })

const e = page.title()
expect(e.textContent).toContain('Hello, World!')
Expand Down
2 changes: 1 addition & 1 deletion strcalc/src/main/frontend/components/calculator.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<input type="text" name="numbers" id="numbers" required />
<fieldset class="impl">
<p>Select which implementation to use:</p>
{{#each implementations}}{{#with this}}
{{#each calcOptions}}{{#with this}}
<label for="impl-{{ value }}">{{ label }}</label>
<input type="radio" id="impl-{{ value }}" name="impl" value="{{ value }}"
{{#if @first}}checked{{/if}}/>{{#unless @last}}<br/>{{/unless}}
Expand Down
20 changes: 10 additions & 10 deletions strcalc/src/main/frontend/components/calculator.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,31 @@ export default class Calculator {
* @param {object} params - parameters made available to all initializers
* @param {Element} params.appElem - parent Element containing all components
* @param {string} params.apiUrl - API backend server URL
* @param {Function} params.postForm - posts form data to API
* @param {object} params.calculators - calculator implementations
*/
init({ appElem, apiUrl, postForm }) {
const implementations = [
{ label: 'Tomcat backend (Java)', value: 'java' },
{ label: 'In-browser frontend (JavaScript)', value: 'javascript' }
]
const t = Template({ apiUrl, implementations })
init({ appElem, apiUrl, calculators }) {
const calcOptions = Object.entries(calculators)
.map(([k, v]) => ({ value: k, label: v.label }))
const t = Template({ apiUrl, calcOptions })
const [ form, resultElem ] = t.children

appElem.appendChild(t)
document.querySelector('#numbers').focus()
form.addEventListener(
'submit', e => Calculator.#submitRequest(e, resultElem, postForm)
'submit', e => Calculator.#submitRequest(e, resultElem, calculators)
)
}

// https://simonplend.com/how-to-use-fetch-to-post-form-data-as-json-to-your-api/
static async #submitRequest(event, resultElem, postForm) {
static async #submitRequest(event, resultElem, calculators) {
event.preventDefault()

const form = event.currentTarget
const selected = form.querySelector('input[name="impl"]:checked').value
const result = resultElem.querySelector('p')

try {
const response = await postForm(event.currentTarget)
const response = await calculators[selected].impl(form)
result.textContent = `Result: ${response.result}`
} catch (err) {
result.textContent = err
Expand Down
11 changes: 9 additions & 2 deletions strcalc/src/main/frontend/components/calculator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Calculator from './calculator'
import { afterAll, afterEach, describe, expect, test, vi } from 'vitest'
import { resolvedUrl } from '../test/helpers.js'
import { resolvedUrl } from '../test/helpers'
import StringCalculatorPage from '../test/page'

// @vitest-environment jsdom
Expand All @@ -16,7 +16,14 @@ describe('Calculator', () => {

const setup = () => {
const postForm = vi.fn()
new Calculator().init({ appElem: page.appElem, apiUrl: './add', postForm })
const calculators = {
'api': { label: 'API', impl: postForm },
'browser': { label: 'Browser', impl: () => {} }
}

new Calculator().init({
appElem: page.appElem, apiUrl: './add', calculators
})
return { page, postForm }
}

Expand Down
15 changes: 15 additions & 0 deletions strcalc/src/main/frontend/components/calculators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import { postForm } from './request'

/**
* Collection of production String Calculator implementations
*/
export default {
'api': { label: 'Tomcat backend API (Java)', impl: postForm },
'browser': { label: 'In-browser (JavaScript)', impl: postForm }
}
4 changes: 2 additions & 2 deletions strcalc/src/main/frontend/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* @module main
*/
import App from './components/app.js'
import { postForm } from './components/request'
import calculators from './components/calculators'

/**
* Calls the app initializer with production parameters.
Expand All @@ -30,7 +30,7 @@ document.addEventListener(
'DOMContentLoaded',
() => {
const appElem = document.querySelector('#app')
new App().init({ appElem, apiUrl: './add', postForm })
new App().init({ appElem, apiUrl: './add', calculators })
},
{ once: true }
)

0 comments on commit 66b8c7e

Please sign in to comment.