Skip to content

Commit

Permalink
VxAdmin: Backend Report Printing (#4583)
Browse files Browse the repository at this point in the history
- move report printing from frontend to backend in VxAdmin
- add "FilePrinter" to mock the printer in integration tests
- replace signature "X" with SVG in reports
  • Loading branch information
adghayes authored Feb 9, 2024
1 parent e84e2da commit 7a0f9bb
Show file tree
Hide file tree
Showing 141 changed files with 5,162 additions and 4,230 deletions.
5 changes: 4 additions & 1 deletion apps/admin/backend/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ module.exports = {
// tsconfig.json values.
roots: ['<rootDir>/src'],
setupFiles: ['<rootDir>/test/set_env_vars.ts'],
setupFilesAfterEnv: ['<rootDir>/test/setupTests.ts'],
setupFilesAfterEnv: [
'<rootDir>/test/setupTests.ts',
'<rootDir>/test/setup_custom_matchers.ts',
],
coverageThreshold: {
global: {
statements: 100,
Expand Down
8 changes: 8 additions & 0 deletions apps/admin/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
"@votingworks/grout": "workspace:*",
"@votingworks/image-utils": "workspace:*",
"@votingworks/logging": "workspace:*",
"@votingworks/printing": "workspace:*",
"@votingworks/types": "workspace:*",
"@votingworks/ui": "workspace:*",
"@votingworks/usb-drive": "workspace:*",
"@votingworks/utils": "workspace:*",
"compression": "^1.7.4",
Expand All @@ -60,6 +62,8 @@
"micromatch": "^4.0.5",
"multer": "^1.4.5-lts.1",
"object-hash": "^3.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"tmp": "^0.2.1",
"uuid": "9.0.1",
"zip-stream": "^4.1.0",
Expand All @@ -72,13 +76,16 @@
"@types/express": "4.17.14",
"@types/fs-extra": "11.0.1",
"@types/jest": "^29.5.3",
"@types/jest-image-snapshot": "^6.4.0",
"@types/lodash.memoize": "^4.1.9",
"@types/lodash.set": "^4.3.7",
"@types/luxon": "^3.0.0",
"@types/micromatch": "^4.0.2",
"@types/multer": "^1.4.7",
"@types/node": "16.18.23",
"@types/object-hash": "^3.0.6",
"@types/react": "18.2.18",
"@types/react-dom": "^18.2.7",
"@types/supertest": "^2.0.10",
"@types/tmp": "0.2.4",
"@types/uuid": "9.0.5",
Expand All @@ -91,6 +98,7 @@
"fast-check": "2.23.2",
"is-ci-cli": "2.2.0",
"jest": "^29.6.2",
"jest-image-snapshot": "^6.4.0",
"jest-junit": "^16.0.0",
"jest-watch-typeahead": "^2.2.2",
"lint-staged": "11.0.0",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ it('logs success if export succeeds', async () => {
const offLimitsPath = '/root/hidden';
const failedExportResult = await apiClient.exportBallotCountReportCsv({
path: offLimitsPath,
filter: {},
groupBy: {},
includeSheetCounts: false,
});
expect(failedExportResult.isErr()).toEqual(true);
expect(logger.log).toHaveBeenLastCalledWith(
Expand Down Expand Up @@ -91,6 +94,9 @@ it('logs failure if export fails', async () => {
const path = tmpNameSync();
const exportResult = await apiClient.exportBallotCountReportCsv({
path,
filter: {},
groupBy: {},
includeSheetCounts: false,
});
expect(exportResult.isOk()).toEqual(true);
expect(logger.log).toHaveBeenLastCalledWith(
Expand All @@ -106,8 +112,8 @@ it('logs failure if export fails', async () => {

async function getParsedExport({
apiClient,
groupBy,
filter,
groupBy = {},
filter = {},
}: {
apiClient: Client<Api>;
groupBy?: Tabulation.GroupBy;
Expand All @@ -118,6 +124,7 @@ async function getParsedExport({
path,
groupBy,
filter,
includeSheetCounts: false,
});
expect(exportResult.isOk()).toEqual(true);
return parseCsv(readFileSync(path, 'utf-8').toString());
Expand Down
116 changes: 116 additions & 0 deletions apps/admin/backend/src/app.ballot_count_report_data.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { electionTwoPartyPrimaryFixtures } from '@votingworks/fixtures';
import {
BooleanEnvironmentVariableName,
buildManualResultsFixture,
getFeatureFlagMock,
} from '@votingworks/utils';
import {
buildTestEnvironment,
configureMachine,
mockElectionManagerAuth,
} from '../test/app';

jest.setTimeout(60_000);

// mock SKIP_CVR_ELECTION_HASH_CHECK to allow us to use old cvr fixtures
const featureFlagMock = getFeatureFlagMock();
jest.mock('@votingworks/utils', () => {
return {
...jest.requireActual('@votingworks/utils'),
isFeatureFlagEnabled: (flag: BooleanEnvironmentVariableName) =>
featureFlagMock.isEnabled(flag),
};
});

beforeEach(() => {
jest.restoreAllMocks();
featureFlagMock.enableFeatureFlag(
BooleanEnvironmentVariableName.SKIP_CVR_ELECTION_HASH_CHECK
);
featureFlagMock.enableFeatureFlag(
BooleanEnvironmentVariableName.SKIP_CAST_VOTE_RECORDS_AUTHENTICATION
);
});

afterEach(() => {
featureFlagMock.resetFeatureFlags();
});

test('card counts', async () => {
const { electionDefinition, castVoteRecordExport } =
electionTwoPartyPrimaryFixtures;
const { election } = electionDefinition;

const { apiClient, auth } = buildTestEnvironment();
await configureMachine(apiClient, auth, electionDefinition);
mockElectionManagerAuth(auth, electionDefinition.electionHash);

const loadFileResult = await apiClient.addCastVoteRecordFile({
path: castVoteRecordExport.asDirectoryPath(),
});
loadFileResult.assertOk('load file failed');

await apiClient.setManualResults({
precinctId: 'precinct-1',
ballotStyleId: '1M',
votingMethod: 'precinct',
manualResults: buildManualResultsFixture({
election,
ballotCount: 10,
contestResultsSummaries: {},
}),
});

expect(
await apiClient.getCardCounts({
filter: { ballotStyleIds: ['1M'] },
groupBy: {},
})
).toEqual([
{
bmd: 56,
hmpb: [],
manual: 10,
},
]);

expect(
await apiClient.getCardCounts({
filter: {},
groupBy: { groupByPrecinct: true },
})
).toEqual([
{
precinctId: 'precinct-1',
bmd: 56,
hmpb: [],
manual: 10,
},
{
precinctId: 'precinct-2',
bmd: 56,
hmpb: [],
manual: 0,
},
]);

expect(
await apiClient.getCardCounts({
filter: { ballotStyleIds: ['1M'] },
groupBy: { groupByPrecinct: true },
})
).toEqual([
{
precinctId: 'precinct-1',
bmd: 28,
hmpb: [],
manual: 10,
},
{
precinctId: 'precinct-2',
bmd: 28,
hmpb: [],
manual: 0,
},
]);
});
Loading

0 comments on commit 7a0f9bb

Please sign in to comment.