Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/release-on-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,36 @@ jobs:
- name: Run tests
run: npm test

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info
fail_ci_if_error: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

- name: Build Windows MSI
run: npm run build:win

- name: Bump version (patch)
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
npm version patch -m "ci: bump version to %s [skip ci]"
git push origin HEAD:main --follow-tags

- name: Get version
id: get_version
run: echo "version=$(node -p \"require('./package.json').version\")" >> $GITHUB_OUTPUT

- name: Create GitHub Tag
run: git tag v${{ steps.get_version.outputs.version }}
continue-on-error: true
- name: Push Tag
run: git push origin v${{ steps.get_version.outputs.version }}
continue-on-error: true

- name: Upload MSI artifact
uses: actions/upload-artifact@v4
with:
Expand All @@ -38,5 +65,6 @@ jobs:
uses: softprops/action-gh-release@v2
with:
files: dist/*.msi
tag_name: v${{ steps.get_version.outputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@

# electron-builder
/dist

# Test coverage reports
/coverage
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Cash Counter

![Build Status](https://github.com/ddjlabs/cashcounter/actions/workflows/release-on-main.yml/badge.svg)
![Tests](https://img.shields.io/badge/tests-passing-brightgreen)
<!-- Add a real coverage badge if you use a coverage service like Codecov or Coveralls -->

A minimal offline Electron app to count U.S. currency with printing and PDF export.

- Cross-platform (Windows, macOS, Linux). Initial release focuses on Windows MSI.
Expand Down
1 change: 1 addition & 0 deletions jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
module.exports = {
testEnvironment: 'node',
roots: ['<rootDir>/tests'],
coverageDirectory: '<rootDir>/tests/coverage',
moduleFileExtensions: ['js', 'json'],
collectCoverage: true,
collectCoverageFrom: ['src/lib/**/*.js'],
Expand Down
38 changes: 38 additions & 0 deletions tests/coverage/clover.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<coverage generated="1756726836483" clover="3.2.0">
<project timestamp="1756726836483" name="All files">
<metrics statements="29" coveredstatements="27" conditionals="28" coveredconditionals="24" methods="5" coveredmethods="5" elements="62" coveredelements="56" complexity="0" loc="29" ncloc="29" packages="1" files="1" classes="1"/>
<file name="calc.js" path="E:\DEV\ddjlabs\cashcounter\src\lib\calc.js">
<metrics statements="29" coveredstatements="27" conditionals="28" coveredconditionals="24" methods="5" coveredmethods="5"/>
<line num="3" count="1" type="stmt"/>
<line num="19" count="20" type="cond" truecount="5" falsecount="0"/>
<line num="20" count="10" type="cond" truecount="4" falsecount="0"/>
<line num="21" count="8" type="cond" truecount="1" falsecount="1"/>
<line num="22" count="8" type="cond" truecount="2" falsecount="0"/>
<line num="23" count="3" type="stmt"/>
<line num="24" count="3" type="cond" truecount="2" falsecount="0"/>
<line num="26" count="0" type="stmt"/>
<line num="30" count="6" type="stmt"/>
<line num="31" count="6" type="stmt"/>
<line num="36" count="2" type="stmt"/>
<line num="37" count="2" type="stmt"/>
<line num="38" count="24" type="stmt"/>
<line num="39" count="24" type="cond" truecount="4" falsecount="1"/>
<line num="40" count="24" type="stmt"/>
<line num="41" count="24" type="stmt"/>
<line num="42" count="24" type="stmt"/>
<line num="44" count="2" type="stmt"/>
<line num="48" count="1" type="stmt"/>
<line num="49" count="1" type="stmt"/>
<line num="50" count="12" type="stmt"/>
<line num="51" count="12" type="cond" truecount="2" falsecount="0"/>
<line num="52" count="2" type="stmt"/>
<line num="55" count="1" type="stmt"/>
<line num="58" count="1" type="stmt"/>
<line num="61" count="1" type="cond" truecount="3" falsecount="1"/>
<line num="62" count="1" type="stmt"/>
<line num="66" count="1" type="cond" truecount="1" falsecount="1"/>
<line num="67" count="0" type="stmt"/>
</file>
</project>
</coverage>
2 changes: 2 additions & 0 deletions tests/coverage/coverage-final.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"E:\\DEV\\ddjlabs\\cashcounter\\src\\lib\\calc.js": {"path":"E:\\DEV\\ddjlabs\\cashcounter\\src\\lib\\calc.js","statementMap":{"0":{"start":{"line":3,"column":22},"end":{"line":16,"column":1}},"1":{"start":{"line":19,"column":2},"end":{"line":19,"column":73}},"2":{"start":{"line":19,"column":61},"end":{"line":19,"column":73}},"3":{"start":{"line":20,"column":2},"end":{"line":20,"column":78}},"4":{"start":{"line":20,"column":33},"end":{"line":20,"column":78}},"5":{"start":{"line":21,"column":2},"end":{"line":25,"column":3}},"6":{"start":{"line":22,"column":4},"end":{"line":22,"column":50}},"7":{"start":{"line":22,"column":37},"end":{"line":22,"column":50}},"8":{"start":{"line":23,"column":14},"end":{"line":23,"column":27}},"9":{"start":{"line":24,"column":4},"end":{"line":24,"column":41}},"10":{"start":{"line":26,"column":2},"end":{"line":26,"column":15}},"11":{"start":{"line":30,"column":18},"end":{"line":30,"column":48}},"12":{"start":{"line":31,"column":2},"end":{"line":31,"column":23}},"13":{"start":{"line":36,"column":19},"end":{"line":36,"column":20}},"14":{"start":{"line":37,"column":15},"end":{"line":43,"column":4}},"15":{"start":{"line":38,"column":16},"end":{"line":38,"column":34}},"16":{"start":{"line":39,"column":16},"end":{"line":39,"column":81}},"17":{"start":{"line":40,"column":21},"end":{"line":40,"column":34}},"18":{"start":{"line":41,"column":4},"end":{"line":41,"column":27}},"19":{"start":{"line":42,"column":4},"end":{"line":42,"column":82}},"20":{"start":{"line":44,"column":2},"end":{"line":44,"column":70}},"21":{"start":{"line":48,"column":17},"end":{"line":48,"column":19}},"22":{"start":{"line":49,"column":2},"end":{"line":54,"column":3}},"23":{"start":{"line":50,"column":14},"end":{"line":50,"column":32}},"24":{"start":{"line":51,"column":4},"end":{"line":53,"column":5}},"25":{"start":{"line":52,"column":6},"end":{"line":52,"column":94}},"26":{"start":{"line":55,"column":2},"end":{"line":55,"column":16}},"27":{"start":{"line":58,"column":17},"end":{"line":58,"column":104}},"28":{"start":{"line":61,"column":0},"end":{"line":63,"column":1}},"29":{"start":{"line":62,"column":2},"end":{"line":62,"column":28}},"30":{"start":{"line":66,"column":0},"end":{"line":68,"column":1}},"31":{"start":{"line":67,"column":2},"end":{"line":67,"column":29}}},"fnMap":{"0":{"name":"isWholeNonNegativeInteger","decl":{"start":{"line":18,"column":9},"end":{"line":18,"column":34}},"loc":{"start":{"line":18,"column":42},"end":{"line":27,"column":1}},"line":18},"1":{"name":"toCurrency","decl":{"start":{"line":29,"column":9},"end":{"line":29,"column":19}},"loc":{"start":{"line":29,"column":33},"end":{"line":32,"column":1}},"line":29},"2":{"name":"computeTotals","decl":{"start":{"line":34,"column":9},"end":{"line":34,"column":22}},"loc":{"start":{"line":34,"column":36},"end":{"line":45,"column":1}},"line":34},"3":{"name":"(anonymous_3)","decl":{"start":{"line":37,"column":33},"end":{"line":37,"column":34}},"loc":{"start":{"line":37,"column":38},"end":{"line":43,"column":3}},"line":37},"4":{"name":"validateCounts","decl":{"start":{"line":47,"column":9},"end":{"line":47,"column":23}},"loc":{"start":{"line":47,"column":37},"end":{"line":56,"column":1}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":19,"column":2},"end":{"line":19,"column":73}},"type":"if","locations":[{"start":{"line":19,"column":2},"end":{"line":19,"column":73}},{"start":{},"end":{}}],"line":19},"1":{"loc":{"start":{"line":19,"column":6},"end":{"line":19,"column":59}},"type":"binary-expr","locations":[{"start":{"line":19,"column":6},"end":{"line":19,"column":18}},{"start":{"line":19,"column":22},"end":{"line":19,"column":36}},{"start":{"line":19,"column":40},"end":{"line":19,"column":59}}],"line":19},"2":{"loc":{"start":{"line":20,"column":2},"end":{"line":20,"column":78}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":20,"column":78}},{"start":{},"end":{}}],"line":20},"3":{"loc":{"start":{"line":20,"column":40},"end":{"line":20,"column":77}},"type":"binary-expr","locations":[{"start":{"line":20,"column":40},"end":{"line":20,"column":63}},{"start":{"line":20,"column":67},"end":{"line":20,"column":77}}],"line":20},"4":{"loc":{"start":{"line":21,"column":2},"end":{"line":25,"column":3}},"type":"if","locations":[{"start":{"line":21,"column":2},"end":{"line":25,"column":3}},{"start":{},"end":{}}],"line":21},"5":{"loc":{"start":{"line":22,"column":4},"end":{"line":22,"column":50}},"type":"if","locations":[{"start":{"line":22,"column":4},"end":{"line":22,"column":50}},{"start":{},"end":{}}],"line":22},"6":{"loc":{"start":{"line":24,"column":11},"end":{"line":24,"column":40}},"type":"binary-expr","locations":[{"start":{"line":24,"column":11},"end":{"line":24,"column":30}},{"start":{"line":24,"column":34},"end":{"line":24,"column":40}}],"line":24},"7":{"loc":{"start":{"line":39,"column":16},"end":{"line":39,"column":81}},"type":"cond-expr","locations":[{"start":{"line":39,"column":66},"end":{"line":39,"column":67}},{"start":{"line":39,"column":70},"end":{"line":39,"column":81}}],"line":39},"8":{"loc":{"start":{"line":39,"column":16},"end":{"line":39,"column":63}},"type":"binary-expr","locations":[{"start":{"line":39,"column":16},"end":{"line":39,"column":26}},{"start":{"line":39,"column":30},"end":{"line":39,"column":47}},{"start":{"line":39,"column":51},"end":{"line":39,"column":63}}],"line":39},"9":{"loc":{"start":{"line":51,"column":4},"end":{"line":53,"column":5}},"type":"if","locations":[{"start":{"line":51,"column":4},"end":{"line":53,"column":5}},{"start":{},"end":{}}],"line":51},"10":{"loc":{"start":{"line":61,"column":0},"end":{"line":63,"column":1}},"type":"if","locations":[{"start":{"line":61,"column":0},"end":{"line":63,"column":1}},{"start":{},"end":{}}],"line":61},"11":{"loc":{"start":{"line":61,"column":4},"end":{"line":61,"column":51}},"type":"binary-expr","locations":[{"start":{"line":61,"column":4},"end":{"line":61,"column":33}},{"start":{"line":61,"column":37},"end":{"line":61,"column":51}}],"line":61},"12":{"loc":{"start":{"line":66,"column":0},"end":{"line":68,"column":1}},"type":"if","locations":[{"start":{"line":66,"column":0},"end":{"line":68,"column":1}},{"start":{},"end":{}}],"line":66}},"s":{"0":1,"1":20,"2":10,"3":10,"4":2,"5":8,"6":8,"7":5,"8":3,"9":3,"10":0,"11":6,"12":6,"13":2,"14":2,"15":24,"16":24,"17":24,"18":24,"19":24,"20":2,"21":1,"22":1,"23":12,"24":12,"25":2,"26":1,"27":1,"28":1,"29":1,"30":1,"31":0},"f":{"0":20,"1":6,"2":2,"3":24,"4":1},"b":{"0":[10,10],"1":[20,19,19],"2":[2,8],"3":[2,2],"4":[8,0],"5":[5,3],"6":[3,3],"7":[0,24],"8":[24,24,24],"9":[2,10],"10":[1,0],"11":[1,1],"12":[0,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"a91750652625845625e006d541c9b4ea7d563cc1"}
}
224 changes: 224 additions & 0 deletions tests/coverage/lcov-report/base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
body, html {
margin:0; padding: 0;
height: 100%;
}
body {
font-family: Helvetica Neue, Helvetica, Arial;
font-size: 14px;
color:#333;
}
.small { font-size: 12px; }
*, *:after, *:before {
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
box-sizing:border-box;
}
h1 { font-size: 20px; margin: 0;}
h2 { font-size: 14px; }
pre {
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
margin: 0;
padding: 0;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
}
a { color:#0074D9; text-decoration:none; }
a:hover { text-decoration:underline; }
.strong { font-weight: bold; }
.space-top1 { padding: 10px 0 0 0; }
.pad2y { padding: 20px 0; }
.pad1y { padding: 10px 0; }
.pad2x { padding: 0 20px; }
.pad2 { padding: 20px; }
.pad1 { padding: 10px; }
.space-left2 { padding-left:55px; }
.space-right2 { padding-right:20px; }
.center { text-align:center; }
.clearfix { display:block; }
.clearfix:after {
content:'';
display:block;
height:0;
clear:both;
visibility:hidden;
}
.fl { float: left; }
@media only screen and (max-width:640px) {
.col3 { width:100%; max-width:100%; }
.hide-mobile { display:none!important; }
}

.quiet {
color: #7f7f7f;
color: rgba(0,0,0,0.5);
}
.quiet a { opacity: 0.7; }

.fraction {
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
font-size: 10px;
color: #555;
background: #E8E8E8;
padding: 4px 5px;
border-radius: 3px;
vertical-align: middle;
}

div.path a:link, div.path a:visited { color: #333; }
table.coverage {
border-collapse: collapse;
margin: 10px 0 0 0;
padding: 0;
}

table.coverage td {
margin: 0;
padding: 0;
vertical-align: top;
}
table.coverage td.line-count {
text-align: right;
padding: 0 5px 0 20px;
}
table.coverage td.line-coverage {
text-align: right;
padding-right: 10px;
min-width:20px;
}

table.coverage td span.cline-any {
display: inline-block;
padding: 0 5px;
width: 100%;
}
.missing-if-branch {
display: inline-block;
margin-right: 5px;
border-radius: 3px;
position: relative;
padding: 0 4px;
background: #333;
color: yellow;
}

.skip-if-branch {
display: none;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: #ccc;
color: white;
}
.missing-if-branch .typ, .skip-if-branch .typ {
color: inherit !important;
}
.coverage-summary {
border-collapse: collapse;
width: 100%;
}
.coverage-summary tr { border-bottom: 1px solid #bbb; }
.keyline-all { border: 1px solid #ddd; }
.coverage-summary td, .coverage-summary th { padding: 10px; }
.coverage-summary tbody { border: 1px solid #bbb; }
.coverage-summary td { border-right: 1px solid #bbb; }
.coverage-summary td:last-child { border-right: none; }
.coverage-summary th {
text-align: left;
font-weight: normal;
white-space: nowrap;
}
.coverage-summary th.file { border-right: none !important; }
.coverage-summary th.pct { }
.coverage-summary th.pic,
.coverage-summary th.abs,
.coverage-summary td.pct,
.coverage-summary td.abs { text-align: right; }
.coverage-summary td.file { white-space: nowrap; }
.coverage-summary td.pic { min-width: 120px !important; }
.coverage-summary tfoot td { }

.coverage-summary .sorter {
height: 10px;
width: 7px;
display: inline-block;
margin-left: 0.5em;
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
}
.coverage-summary .sorted .sorter {
background-position: 0 -20px;
}
.coverage-summary .sorted-desc .sorter {
background-position: 0 -10px;
}
.status-line { height: 10px; }
/* yellow */
.cbranch-no { background: yellow !important; color: #111; }
/* dark red */
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
.low .chart { border:1px solid #C21F39 }
.highlighted,
.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
background: #C21F39 !important;
}
/* medium red */
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
/* light red */
.low, .cline-no { background:#FCE1E5 }
/* light green */
.high, .cline-yes { background:rgb(230,245,208) }
/* medium green */
.cstat-yes { background:rgb(161,215,106) }
/* dark green */
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
.high .chart { border:1px solid rgb(77,146,33) }
/* dark yellow (gold) */
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
.medium .chart { border:1px solid #f9cd0b; }
/* light yellow */
.medium { background: #fff4c2; }

.cstat-skip { background: #ddd; color: #111; }
.fstat-skip { background: #ddd; color: #111 !important; }
.cbranch-skip { background: #ddd !important; color: #111; }

span.cline-neutral { background: #eaeaea; }

.coverage-summary td.empty {
opacity: .5;
padding-top: 4px;
padding-bottom: 4px;
line-height: 1;
color: #888;
}

.cover-fill, .cover-empty {
display:inline-block;
height: 12px;
}
.chart {
line-height: 0;
}
.cover-empty {
background: white;
}
.cover-full {
border-right: none !important;
}
pre.prettyprint {
border: none !important;
padding: 0 !important;
margin: 0 !important;
}
.com { color: #999 !important; }
.ignore-none { color: #999; font-weight: normal; }

.wrapper {
min-height: 100%;
height: auto !important;
height: 100%;
margin: 0 auto -48px;
}
.footer, .push {
height: 48px;
}
Loading
Loading