Skip to content

Commit 810a1f2

Browse files
committed
Added unit tests, put IBAN in a separate class.
1 parent 643605a commit 810a1f2

File tree

6 files changed

+83
-27
lines changed

6 files changed

+83
-27
lines changed

Diff for: frontend/package.json

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
22
"name": "digidecs",
33
"type": "module",
4-
"version": "0.1.0",
4+
"version": "0.1.1",
55
"private": true,
66
"scripts": {
77
"dev": "vite",
8+
"test": "vitest --config './src/tests/vitest.config.ts'",
89
"build": "vue-tsc --noEmit && vite build",
910
"preview": "vite preview",
1011
"lint": "eslint . --fix --ignore-path .gitignore"
@@ -14,7 +15,7 @@
1415
"base64-arraybuffer": "^1.0.2",
1516
"core-js": "^3.29.0",
1617
"roboto-fontface": "*",
17-
"vue": "^3.2.0",
18+
"vue": "^3.5.13",
1819
"vue-i18n": "9",
1920
"vue-router": "^4.0.0",
2021
"vuetify": "^3.0.0"
@@ -26,7 +27,7 @@
2627
"@typescript-eslint/eslint-plugin": "^8.4.0",
2728
"@typescript-eslint/parser": "^8.4.0",
2829
"@vitejs/plugin-vue": "^4.0.0",
29-
"@vue/eslint-config-typescript": "^11.0.0",
30+
"@vue/test-utils": "^2.4.6",
3031
"eslint": "^9.9.1",
3132
"eslint-plugin-vue": "^9.28.0",
3233
"sass": "^1.60.0",
@@ -35,6 +36,8 @@
3536
"unplugin-fonts": "^1.0.3",
3637
"vite": "^4.2.0",
3738
"vite-plugin-vuetify": "^1.0.0",
39+
"vite-tsconfig-paths": "^5.1.4",
40+
"vitest": "^3.0.5",
3841
"vue-tsc": "^2.1.8"
3942
}
4043
}

Diff for: frontend/src/scripts/iban.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export abstract class IBAN{
2+
3+
static checkIBAN(iban: string): boolean {
4+
// Tested with:
5+
// GB33BUKB20201555555555 (correct)
6+
// GB94BARC10201530093459 (correct)
7+
// gB94BARC10201530093459 (correct, evaluates to its uppercase equivalent)
8+
// GB94BARC20201530093459 (incorrect checksum)
9+
iban = iban.toUpperCase();
10+
const ibanRegex = /^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$/;
11+
if (!ibanRegex.test(iban)) {
12+
return false;
13+
}
14+
15+
// ISO/IEC 7064:2003
16+
// Convert IBAN to numeric representation (rearrange and replace letter with corresponding numeric value)
17+
const numericIban = (iban.slice(4) + iban.slice(0,4))
18+
.replace(/[A-Z]/g, char => (parseInt(char, 36)).toString());
19+
// Match only sequences of 1-7 digits, convert each to number and add, then take result mod 97.
20+
const remainder = numericIban
21+
.match(/\d{1,7}/g)?.reduce((acc, block) => Number(acc + block) % 97, 0);
22+
return remainder===1;
23+
}
24+
25+
26+
}

Diff for: frontend/src/tests/IBAN.test.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { mount } from '@vue/test-utils';
3+
import { checkIBAN } from '../views/HomeView.vue';
4+
import {IBAN} from "../scripts/iban";
5+
6+
7+
describe('checkIBAN', () => {
8+
it('should return true for a valid IBAN', () => {
9+
const validIBAN = 'DE89370400440532013000';
10+
expect(IBAN.checkIBAN(validIBAN)).toBe(true);
11+
});
12+
13+
it('should return false for an invalid IBAN', () => {
14+
const invalidIBAN = 'DE89370400440532013001';
15+
expect(IBAN.checkIBAN(invalidIBAN)).toBe(false);
16+
});
17+
18+
it('should return false for an IBAN with incorrect length', () => {
19+
const shortIBAN = 'DE8937040044053201300';
20+
expect(IBAN.checkIBAN(shortIBAN)).toBe(false);
21+
});
22+
23+
it('should return false for an IBAN with invalid characters', () => {
24+
const invalidCharIBAN = 'DE89$70400440532013000';
25+
expect(IBAN.checkIBAN(invalidCharIBAN)).toBe(false);
26+
});
27+
28+
it('should return false for an empty IBAN', () => {
29+
const emptyIBAN = '';
30+
expect(IBAN.checkIBAN(emptyIBAN)).toBe(false);
31+
});
32+
});

Diff for: frontend/src/tests/vitest.config.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { defineConfig } from 'vitest/config';
2+
import vue from "@vitejs/plugin-vue";
3+
import viteTsconfigPaths from 'vite-tsconfig-paths';
4+
5+
export default defineConfig({
6+
test: {
7+
globals: true,
8+
environment: 'jsdom',
9+
coverage: {
10+
reporter: ['text', 'json', 'html'],
11+
},
12+
include: ["src/tests/*.test.js"],
13+
},
14+
plugins: [vue(),viteTsconfigPaths()],
15+
});

Diff for: frontend/src/views/HomeView.vue

+2-23
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ import {defineComponent} from "vue";
120120
import {InputValidationRules} from "@/main";
121121
import {Digidecs} from "@/scripts/digidecs";
122122
import MaterialBanner from "@/views/components/MaterialBanner.vue";
123+
import {IBAN} from "@/scripts/iban";
123124
124125
interface Data {
125126
error: string | undefined,
@@ -145,28 +146,6 @@ interface Data {
145146
}
146147
}
147148
148-
function checkIBAN(iban: string): boolean {
149-
// Tested with:
150-
// GB33BUKB20201555555555 (correct)
151-
// GB94BARC10201530093459 (correct)
152-
// gB94BARC10201530093459 (correct, evaluates to its uppercase equivalent)
153-
// GB94BARC20201530093459 (incorrect checksum)
154-
iban = iban.toUpperCase();
155-
const ibanRegex = /^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$/;
156-
if (!ibanRegex.test(iban)) {
157-
return false;
158-
}
159-
160-
// ISO/IEC 7064:2003
161-
// Convert IBAN to numeric representation (rearrange and replace letter with corresponding numeric value)
162-
const numericIban = (iban.slice(4) + iban.slice(0,4))
163-
.replace(/[A-Z]/g, char => (parseInt(char, 36)).toString());
164-
// Match only sequences of 1-7 digits, convert each to number and add, then take result mod 97.
165-
const remainder = numericIban
166-
.match(/\d{1,7}/g)?.reduce((acc, block) => Number(acc + block) % 97, 0);
167-
return remainder===1;
168-
}
169-
170149
export default defineComponent({
171150
components: {MaterialBanner},
172151
data(): Data {
@@ -180,7 +159,7 @@ export default defineComponent({
180159
],
181160
iban: [
182161
v => !!v || this.$t("home.form.rules.required"),
183-
v => checkIBAN(v) || this.$t("home.form.rules.ibanInvalid")
162+
v => IBAN.checkIBAN(v) || this.$t("home.form.rules.ibanInvalid")
184163
],
185164
email: [
186165
v => !!v || this.$t("home.form.rules.required"),

Diff for: frontend/tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"@/*": [
1818
"src/*"
1919
]
20-
}
20+
},
21+
"allowJs": true, // Necessary for vitest to work
2122
},
2223
"include": [
2324
"src/**/*.ts",

0 commit comments

Comments
 (0)