Skip to content

Commit

Permalink
feat(rave): add bare-bones RaveMark app
Browse files Browse the repository at this point in the history
  • Loading branch information
eventualbuddha committed Feb 27, 2024
1 parent 215d102 commit c266e58
Show file tree
Hide file tree
Showing 48 changed files with 4,518 additions and 750 deletions.
77 changes: 77 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,80 @@ jobs:
- store_artifacts:
path: apps/mark/integration-testing/test-results/

# @votingworks/rave-mark-backend
test-apps-rave-mark-backend:
executor: nodejs
resource_class: xlarge
steps:
- checkout-and-install
- run:
name: Build
command: |
pnpm --dir apps/rave-mark/backend build
- run:
name: Lint
command: |
pnpm --dir apps/rave-mark/backend lint
- run:
name: Test
command: |
pnpm --dir apps/rave-mark/backend test
environment:
JEST_JUNIT_OUTPUT_DIR: ./reports/
- store_test_results:
path: apps/rave-mark/backend/reports/

# @votingworks/rave-mark-frontend
test-apps-rave-mark-frontend:
executor: nodejs
resource_class: xlarge
steps:
- checkout-and-install
- run:
name: Build
command: |
pnpm --dir apps/rave-mark/frontend build
- run:
name: Lint
command: |
pnpm --dir apps/rave-mark/frontend lint
- run:
name: Test
command: |
pnpm --dir apps/rave-mark/frontend test
environment:
JEST_JUNIT_OUTPUT_DIR: ./reports/
- store_test_results:
path: apps/rave-mark/frontend/reports/

# @votingworks/rave-mark-integration-testing
test-apps-rave-mark-integration-testing:
executor: nodejs-browsers
resource_class: xlarge
steps:
- install-cypress-browser
- checkout-and-install
- run:
name: Build
command: |
pnpm --dir apps/rave-mark/integration-testing build
- run:
name: Lint
command: |
pnpm --dir apps/rave-mark/integration-testing lint
- run:
name: Test
command: |
pnpm --dir apps/rave-mark/integration-testing test
environment:
JEST_JUNIT_OUTPUT_DIR: ./reports/
- store_test_results:
path: apps/rave-mark/integration-testing/reports/
- store_artifacts:
path: apps/rave-mark/integration-testing/cypress/screenshots/
- store_artifacts:
path: apps/rave-mark/integration-testing/cypress/videos/

# @votingworks/scan-backend
test-apps-scan-backend:
executor: nodejs
Expand Down Expand Up @@ -1295,6 +1369,9 @@ workflows:
- test-apps-mark-backend
- test-apps-mark-frontend
- test-apps-mark-integration-testing
- test-apps-rave-mark-backend
- test-apps-rave-mark-frontend
- test-apps-rave-mark-integration-testing
- test-apps-scan-backend
- test-apps-scan-frontend
- test-docs-exercises
Expand Down
5 changes: 5 additions & 0 deletions apps/rave-mark/backend/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build
jest.config.js
coverage

public/vendor
18 changes: 18 additions & 0 deletions apps/rave-mark/backend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["plugin:vx/recommended"],
"rules": {
// Disable JSDOC rule as code is self-documenting.
"vx/gts-jsdoc": "off"
},
"overrides": [
// This file causes this rule to crash on private constructors.
// Started happening after TypeScript upgrade to v4.6. I was not able to
// find an issue on the GitHub repo for @typescript-eslint/eslint-plugin.
{
"files": ["src/db_client.ts", "src/store.ts"],
"rules": {
"@typescript-eslint/prefer-readonly": "off"
}
}
]
}
10 changes: 10 additions & 0 deletions apps/rave-mark/backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules
dev-workspace/
*~
*.log
coverage/
.DS_Store
debug-dump*.zip
/*.png
/*.jpeg
/*.jpg
16 changes: 16 additions & 0 deletions apps/rave-mark/backend/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const shared = require('../../../jest.config.shared');

/**
* @type {import('@jest/types').Config.InitialOptions}
*/
module.exports = {
...shared,
coverageThreshold: {
global: {
statements: 0,
branches: 0,
lines: 0,
functions: 0,
},
},
};
92 changes: 92 additions & 0 deletions apps/rave-mark/backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"name": "@votingworks/rave-mark-backend",
"version": "1.0.0",
"private": true,
"license": "GPL-3.0",
"author": "VotingWorks Eng <[email protected]>",
"main": "build/index.js",
"types": "build/index.d.ts",
"files": [
"build",
"Makefile",
"prodserver"
],
"scripts": {
"build": "tsc --build tsconfig.build.json",
"clean": "rm -rf build tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo",
"format": "prettier '**/*.+(css|graphql|json|less|md|mdx|sass|scss|yaml|yml)' --write",
"lint": "pnpm type-check && eslint .",
"lint:fix": "pnpm type-check && eslint . --fix",
"pre-commit": "lint-staged",
"start": "node ./build/index.js",
"test": "is-ci test:ci test:watch",
"test:ci": "jest --coverage --reporters=default --reporters=jest-junit --maxWorkers=7",
"test:coverage": "jest --coverage",
"test:debug": "node --inspect-brk $(which jest) --runInBand --no-cache",
"test:watch": "jest --watch",
"type-check": "tsc --build"
},
"lint-staged": {
"*.+(js|jsx|ts|tsx)": [
"stylelint",
"eslint --quiet --fix"
],
"*.+(css|graphql|json|less|md|mdx|sass|scss|yaml|yml)": [
"prettier --write"
],
"package.json": [
"sort-package-json"
]
},
"dependencies": {
"@votingworks/auth": "workspace:*",
"@votingworks/backend": "workspace:*",
"@votingworks/basics": "workspace:*",
"@votingworks/db": "workspace:*",
"@votingworks/dev-dock-backend": "workspace:*",
"@votingworks/fixtures": "workspace:*",
"@votingworks/grout": "workspace:*",
"@votingworks/logging": "workspace:*",
"@votingworks/types": "workspace:*",
"@votingworks/utils": "workspace:*",
"debug": "^4.3.4",
"dotenv": "^16.1.4",
"dotenv-expand": "^10.0.0",
"express": "^4.18.2",
"fs-extra": "^11.1.1",
"zod": "3.14.4"
},
"devDependencies": {
"@types/debug": "^4.1.8",
"@types/express": "^4.17.14",
"@types/fs-extra": "^11.0.1",
"@types/jest": "^29.5.2",
"@types/tmp": "^0.2.3",
"@typescript-eslint/eslint-plugin": "5.37.0",
"@typescript-eslint/parser": "5.37.0",
"@votingworks/test-utils": "workspace:*",
"eslint": "8.23.1",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-node": "^0.3.4",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^26.1.5",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vx": "workspace:*",
"is-ci-cli": "^2.1.2",
"jest": "^29.5.0",
"jest-junit": "^14.0.1",
"jest-watch-typeahead": "^0.6.4",
"lint-staged": "^10.5.3",
"nodemon": "^2.0.20",
"prettier": "2.6.2",
"stylelint": "^13.3.3",
"stylelint-config-palantir": "^4.0.1",
"stylelint-config-prettier": "^8.0.1",
"stylelint-config-styled-components": "^0.1.1",
"stylelint-processor-styled-components": "^1.10.0",
"tmp": "^0.2.1",
"ts-jest": "^29.1.0",
"typescript": "4.6.3"
},
"packageManager": "[email protected]"
}
Empty file.
19 changes: 19 additions & 0 deletions apps/rave-mark/backend/src/app.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as grout from '@votingworks/grout';
import { Server } from 'http';
import { createApp } from '../test/app_helpers';
import { Api } from './app';

let apiClient: grout.Client<Api>;
let server: Server;

beforeEach(() => {
({ apiClient, server } = createApp());
});

afterEach(() => {
server?.close();
});

test('has an API client', () => {
expect(apiClient).toBeDefined();
});
17 changes: 17 additions & 0 deletions apps/rave-mark/backend/src/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useDevDockRouter } from '@votingworks/dev-dock-backend';
import * as grout from '@votingworks/grout';
import express, { Application } from 'express';

function buildApi() {
return grout.createApi({});
}

export type Api = ReturnType<typeof buildApi>;

export function buildApp(): Application {
const app: Application = express();
const api = buildApi();
app.use('/api', grout.buildRouter(api, express));
useDevDockRouter(app, express);
return app;
}
11 changes: 11 additions & 0 deletions apps/rave-mark/backend/src/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
declare namespace NodeJS {
export interface ProcessEnv {
readonly CI?: string;
readonly NODE_ENV: 'development' | 'production' | 'test';
readonly PORT?: string;
readonly VX_MACHINE_ID?: string;
readonly VX_CODE_VERSION?: string;
readonly VX_SCREEN_ORIENTATION?: 'portrait' | 'landscape';
readonly MARK_WORKSPACE?: string;
}
}
22 changes: 22 additions & 0 deletions apps/rave-mark/backend/src/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { unsafeParse } from '@votingworks/types';
import { z } from 'zod';

/**
* Default port for the VxMark API.
*/
// eslint-disable-next-line vx/gts-safe-number-parse
export const PORT = Number(process.env.PORT || 3002);

const NodeEnvSchema = z.union([
z.literal('development'),
z.literal('test'),
z.literal('production'),
]);

/**
* Which node environment is this?
*/
export const NODE_ENV = unsafeParse(
NodeEnvSchema,
process.env.NODE_ENV ?? 'development'
);
52 changes: 52 additions & 0 deletions apps/rave-mark/backend/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Logger, LogSource, LogEventId } from '@votingworks/logging';
import fs from 'fs';
import * as dotenv from 'dotenv';
import * as dotenvExpand from 'dotenv-expand';
import * as server from './server';
import { NODE_ENV, PORT } from './globals';

export type { Api } from './app';

// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
const dotEnvPath = '.env';
const dotenvFiles: string[] = [
`${dotEnvPath}.${NODE_ENV}.local`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' ? `${dotEnvPath}.local` : '',
`${dotEnvPath}.${NODE_ENV}`,
dotEnvPath,
NODE_ENV !== 'test' ? `../../../${dotEnvPath}.local` : '',
`../../../${dotEnvPath}`,
].filter(Boolean);

// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
for (const dotenvFile of dotenvFiles) {
if (fs.existsSync(dotenvFile)) {
dotenvExpand.expand(dotenv.config({ path: dotenvFile }));
}
}

const logger = new Logger(LogSource.VxMarkBackend);

function main(): number {
server.start({ port: PORT, logger });
return 0;
}

if (require.main === module) {
try {
process.exitCode = main();
} catch (error) {
void logger.log(LogEventId.ApplicationStartup, 'system', {
message: `Error in starting VxMark backend: ${(error as Error).stack}`,
disposition: 'failure',
});
process.exitCode = 1;
}
}
14 changes: 14 additions & 0 deletions apps/rave-mark/backend/src/server.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { fakeLogger } from '@votingworks/logging';
import { PORT } from './globals';
import { start } from './server';

test('can start server', () => {
const logger = fakeLogger();

const server = start({
logger,
port: PORT,
});
expect(server.listening).toBeTruthy();
server.close();
});
Loading

0 comments on commit c266e58

Please sign in to comment.